]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - sys/netinet/libalias/alias_db.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / sys / netinet / libalias / alias_db.c
1 /*-
2  * Copyright (c) 2001 Charles Mott <cm@linktel.net>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 /*
31     Alias_db.c encapsulates all data structures used for storing
32     packet aliasing data.  Other parts of the aliasing software
33     access data through functions provided in this file.
34
35     Data storage is based on the notion of a "link", which is
36     established for ICMP echo/reply packets, UDP datagrams and
37     TCP stream connections.  A link stores the original source
38     and destination addresses.  For UDP and TCP, it also stores
39     source and destination port numbers, as well as an alias
40     port number.  Links are also used to store information about
41     fragments.
42
43     There is a facility for sweeping through and deleting old
44     links as new packets are sent through.  A simple timeout is
45     used for ICMP and UDP links.  TCP links are left alone unless
46     there is an incomplete connection, in which case the link
47     can be deleted after a certain amount of time.
48
49
50     Initial version: August, 1996  (cjm)
51
52     Version 1.4: September 16, 1996 (cjm)
53         Facility for handling incoming links added.
54
55     Version 1.6: September 18, 1996 (cjm)
56         ICMP data handling simplified.
57
58     Version 1.7: January 9, 1997 (cjm)
59         Fragment handling simplified.
60         Saves pointers for unresolved fragments.
61         Permits links for unspecified remote ports
62           or unspecified remote addresses.
63         Fixed bug which did not properly zero port
64           table entries after a link was deleted.
65         Cleaned up some obsolete comments.
66
67     Version 1.8: January 14, 1997 (cjm)
68         Fixed data type error in StartPoint().
69         (This error did not exist prior to v1.7
70         and was discovered and fixed by Ari Suutari)
71
72     Version 1.9: February 1, 1997
73         Optionally, connections initiated from packet aliasing host
74         machine will will not have their port number aliased unless it
75         conflicts with an aliasing port already being used. (cjm)
76
77         All options earlier being #ifdef'ed are now available through
78         a new interface, SetPacketAliasMode().  This allows run time
79         control (which is now available in PPP+pktAlias through the
80         'alias' keyword). (ee)
81
82         Added ability to create an alias port without
83         either destination address or port specified.
84         port type = ALIAS_PORT_UNKNOWN_DEST_ALL (ee)
85
86         Removed K&R style function headers
87         and general cleanup. (ee)
88
89         Added packetAliasMode to replace compiler #defines's (ee)
90
91         Allocates sockets for partially specified
92         ports if ALIAS_USE_SOCKETS defined. (cjm)
93
94     Version 2.0: March, 1997
95         SetAliasAddress() will now clean up alias links
96         if the aliasing address is changed. (cjm)
97
98         PacketAliasPermanentLink() function added to support permanent
99         links.  (J. Fortes suggested the need for this.)
100         Examples:
101
102         (192.168.0.1, port 23)  <-> alias port 6002, unknown dest addr/port
103
104         (192.168.0.2, port 21)  <-> alias port 3604, known dest addr
105                                                      unknown dest port
106
107         These permanent links allow for incoming connections to
108         machines on the local network.  They can be given with a
109         user-chosen amount of specificity, with increasing specificity
110         meaning more security. (cjm)
111
112         Quite a bit of rework to the basic engine.  The portTable[]
113         array, which kept track of which ports were in use was replaced
114         by a table/linked list structure. (cjm)
115
116         SetExpire() function added. (cjm)
117
118         DeleteLink() no longer frees memory association with a pointer
119         to a fragment (this bug was first recognized by E. Eklund in
120         v1.9).
121
122     Version 2.1: May, 1997 (cjm)
123         Packet aliasing engine reworked so that it can handle
124         multiple external addresses rather than just a single
125         host address.
126
127         PacketAliasRedirectPort() and PacketAliasRedirectAddr()
128         added to the API.  The first function is a more generalized
129         version of PacketAliasPermanentLink().  The second function
130         implements static network address translation.
131
132     Version 3.2: July, 2000 (salander and satoh)
133         Added FindNewPortGroup to get contiguous range of port values.
134
135         Added QueryUdpTcpIn and QueryUdpTcpOut to look for an aliasing
136         link but not actually add one.
137
138         Added FindRtspOut, which is closely derived from FindUdpTcpOut,
139         except that the alias port (from FindNewPortGroup) is provided
140         as input.
141
142     See HISTORY file for additional revisions.
143 */
144
145 #ifdef _KERNEL
146 #include <machine/stdarg.h>
147 #include <sys/param.h>
148 #include <sys/kernel.h>
149 #include <sys/lock.h>
150 #include <sys/module.h>
151 #include <sys/rwlock.h>
152 #include <sys/syslog.h>
153 #else
154 #include <stdarg.h>
155 #include <stdlib.h>
156 #include <stdio.h>
157 #include <sys/errno.h>
158 #include <sys/time.h>
159 #include <unistd.h> 
160 #endif
161
162 #include <sys/socket.h>
163 #include <netinet/tcp.h>
164
165 #ifdef _KERNEL  
166 #include <netinet/libalias/alias.h>
167 #include <netinet/libalias/alias_local.h>
168 #include <netinet/libalias/alias_mod.h>
169 #include <net/if.h>
170 #else
171 #include "alias.h"
172 #include "alias_local.h"
173 #include "alias_mod.h"
174 #endif
175
176 static          LIST_HEAD(, libalias) instancehead = LIST_HEAD_INITIALIZER(instancehead);
177
178
179 /*
180    Constants (note: constants are also defined
181               near relevant functions or structs)
182 */
183
184 /* Parameters used for cleanup of expired links */
185 /* NOTE: ALIAS_CLEANUP_INTERVAL_SECS must be less then LINK_TABLE_OUT_SIZE */
186 #define ALIAS_CLEANUP_INTERVAL_SECS  64
187 #define ALIAS_CLEANUP_MAX_SPOKES     (LINK_TABLE_OUT_SIZE/5)
188
189 /* Timeouts (in seconds) for different link types */
190 #define ICMP_EXPIRE_TIME             60
191 #define UDP_EXPIRE_TIME              60
192 #define PROTO_EXPIRE_TIME            60
193 #define FRAGMENT_ID_EXPIRE_TIME      10
194 #define FRAGMENT_PTR_EXPIRE_TIME     30
195
196 /* TCP link expire time for different cases */
197 /* When the link has been used and closed - minimal grace time to
198    allow ACKs and potential re-connect in FTP (XXX - is this allowed?)  */
199 #ifndef TCP_EXPIRE_DEAD
200 #define TCP_EXPIRE_DEAD           10
201 #endif
202
203 /* When the link has been used and closed on one side - the other side
204    is allowed to still send data */
205 #ifndef TCP_EXPIRE_SINGLEDEAD
206 #define TCP_EXPIRE_SINGLEDEAD     90
207 #endif
208
209 /* When the link isn't yet up */
210 #ifndef TCP_EXPIRE_INITIAL
211 #define TCP_EXPIRE_INITIAL       300
212 #endif
213
214 /* When the link is up */
215 #ifndef TCP_EXPIRE_CONNECTED
216 #define TCP_EXPIRE_CONNECTED   86400
217 #endif
218
219
220 /* Dummy port number codes used for FindLinkIn/Out() and AddLink().
221    These constants can be anything except zero, which indicates an
222    unknown port number. */
223
224 #define NO_DEST_PORT     1
225 #define NO_SRC_PORT      1
226
227
228
229 /* Data Structures
230
231     The fundamental data structure used in this program is
232     "struct alias_link".  Whenever a TCP connection is made,
233     a UDP datagram is sent out, or an ICMP echo request is made,
234     a link record is made (if it has not already been created).
235     The link record is identified by the source address/port
236     and the destination address/port. In the case of an ICMP
237     echo request, the source port is treated as being equivalent
238     with the 16-bit ID number of the ICMP packet.
239
240     The link record also can store some auxiliary data.  For
241     TCP connections that have had sequence and acknowledgment
242     modifications, data space is available to track these changes.
243     A state field is used to keep track in changes to the TCP
244     connection state.  ID numbers of fragments can also be
245     stored in the auxiliary space.  Pointers to unresolved
246     fragments can also be stored.
247
248     The link records support two independent chainings.  Lookup
249     tables for input and out tables hold the initial pointers
250     the link chains.  On input, the lookup table indexes on alias
251     port and link type.  On output, the lookup table indexes on
252     source address, destination address, source port, destination
253     port and link type.
254 */
255
256 struct ack_data_record {        /* used to save changes to ACK/sequence
257                                  * numbers */
258         u_long          ack_old;
259         u_long          ack_new;
260         int             delta;
261         int             active;
262 };
263
264 struct tcp_state {              /* Information about TCP connection        */
265         int             in;     /* State for outside -> inside             */
266         int             out;    /* State for inside  -> outside            */
267         int             index;  /* Index to ACK data array                 */
268         int             ack_modified;   /* Indicates whether ACK and
269                                          * sequence numbers */
270         /* been modified                           */
271 };
272
273 #define N_LINK_TCP_DATA   3     /* Number of distinct ACK number changes
274                                  * saved for a modified TCP stream */
275 struct tcp_dat {
276         struct tcp_state state;
277         struct ack_data_record ack[N_LINK_TCP_DATA];
278         int             fwhole; /* Which firewall record is used for this
279                                  * hole? */
280 };
281
282 struct server {                 /* LSNAT server pool (circular list) */
283         struct in_addr  addr;
284         u_short         port;
285         struct server  *next;
286 };
287
288 struct alias_link {             /* Main data structure */
289         struct libalias *la;
290         struct in_addr  src_addr;       /* Address and port information        */
291         struct in_addr  dst_addr;
292         struct in_addr  alias_addr;
293         struct in_addr  proxy_addr;
294         u_short         src_port;
295         u_short         dst_port;
296         u_short         alias_port;
297         u_short         proxy_port;
298         struct server  *server;
299
300         int             link_type;      /* Type of link: TCP, UDP, ICMP,
301                                          * proto, frag */
302
303 /* values for link_type */
304 #define LINK_ICMP                     IPPROTO_ICMP
305 #define LINK_UDP                      IPPROTO_UDP
306 #define LINK_TCP                      IPPROTO_TCP
307 #define LINK_FRAGMENT_ID              (IPPROTO_MAX + 1)
308 #define LINK_FRAGMENT_PTR             (IPPROTO_MAX + 2)
309 #define LINK_ADDR                     (IPPROTO_MAX + 3)
310 #define LINK_PPTP                     (IPPROTO_MAX + 4)
311
312         int             flags;  /* indicates special characteristics   */
313         int             pflags; /* protocol-specific flags */
314
315 /* flag bits */
316 #define LINK_UNKNOWN_DEST_PORT     0x01
317 #define LINK_UNKNOWN_DEST_ADDR     0x02
318 #define LINK_PERMANENT             0x04
319 #define LINK_PARTIALLY_SPECIFIED   0x03 /* logical-or of first two bits */
320 #define LINK_UNFIREWALLED          0x08
321
322         int             timestamp;      /* Time link was last accessed         */
323         int             expire_time;    /* Expire time for link                */
324 #ifndef NO_USE_SOCKETS
325         int             sockfd; /* socket descriptor                   */
326 #endif
327                         LIST_ENTRY    (alias_link) list_out;    /* Linked list of
328                                                                  * pointers for     */
329                         LIST_ENTRY    (alias_link) list_in;     /* input and output
330                                                                  * lookup tables  */
331
332         union {                 /* Auxiliary data                      */
333                 char           *frag_ptr;
334                 struct in_addr  frag_addr;
335                 struct tcp_dat *tcp;
336         }               data;
337 };
338
339 /* Clean up procedure. */
340 static void finishoff(void);
341
342 /* Kernel module definition. */
343 #ifdef  _KERNEL
344 MALLOC_DEFINE(M_ALIAS, "libalias", "packet aliasing");
345
346 MODULE_VERSION(libalias, 1);
347
348 static int
349 alias_mod_handler(module_t mod, int type, void *data)
350 {
351         int error;
352
353         switch (type) {
354         case MOD_LOAD:
355                 error = 0;
356                 handler_chain_init();
357                 break;
358         case MOD_QUIESCE:
359         case MOD_UNLOAD:
360                 handler_chain_destroy();
361                 finishoff();
362                 error = 0;
363                 break;
364         default:
365                 error = EINVAL;
366         }
367
368         return (error);
369 }
370
371 static moduledata_t alias_mod = {
372        "alias", alias_mod_handler, NULL
373 };
374
375 DECLARE_MODULE(alias, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
376 #endif
377
378 /* Internal utility routines (used only in alias_db.c)
379
380 Lookup table starting points:
381     StartPointIn()           -- link table initial search point for
382                                 incoming packets
383     StartPointOut()          -- link table initial search point for
384                                 outgoing packets
385
386 Miscellaneous:
387     SeqDiff()                -- difference between two TCP sequences
388     ShowAliasStats()         -- send alias statistics to a monitor file
389 */
390
391
392 /* Local prototypes */
393 static u_int    StartPointIn(struct in_addr, u_short, int);
394
395 static          u_int
396 StartPointOut(struct in_addr, struct in_addr,
397     u_short, u_short, int);
398
399 static int      SeqDiff(u_long, u_long);
400
401 #ifndef NO_FW_PUNCH
402 /* Firewall control */
403 static void     InitPunchFW(struct libalias *);
404 static void     UninitPunchFW(struct libalias *);
405 static void     ClearFWHole(struct alias_link *);
406
407 #endif
408
409 /* Log file control */
410 static void     ShowAliasStats(struct libalias *);
411 static int      InitPacketAliasLog(struct libalias *);
412 static void     UninitPacketAliasLog(struct libalias *);
413
414 void SctpShowAliasStats(struct libalias *la);
415
416 static          u_int
417 StartPointIn(struct in_addr alias_addr,
418     u_short alias_port,
419     int link_type)
420 {
421         u_int n;
422
423         n = alias_addr.s_addr;
424         if (link_type != LINK_PPTP)
425                 n += alias_port;
426         n += link_type;
427         return (n % LINK_TABLE_IN_SIZE);
428 }
429
430
431 static          u_int
432 StartPointOut(struct in_addr src_addr, struct in_addr dst_addr,
433     u_short src_port, u_short dst_port, int link_type)
434 {
435         u_int n;
436
437         n = src_addr.s_addr;
438         n += dst_addr.s_addr;
439         if (link_type != LINK_PPTP) {
440                 n += src_port;
441                 n += dst_port;
442         }
443         n += link_type;
444
445         return (n % LINK_TABLE_OUT_SIZE);
446 }
447
448
449 static int
450 SeqDiff(u_long x, u_long y)
451 {
452 /* Return the difference between two TCP sequence numbers */
453
454 /*
455     This function is encapsulated in case there are any unusual
456     arithmetic conditions that need to be considered.
457 */
458
459         return (ntohl(y) - ntohl(x));
460 }
461
462 #ifdef _KERNEL
463
464 static void
465 AliasLog(char *str, const char *format, ...)
466 {               
467         va_list ap;
468         
469         va_start(ap, format);
470         vsnprintf(str, LIBALIAS_BUF_SIZE, format, ap);
471         va_end(ap);
472 }
473 #else
474 static void
475 AliasLog(FILE *stream, const char *format, ...)
476 {
477         va_list ap;
478         
479         va_start(ap, format);
480         vfprintf(stream, format, ap);
481         va_end(ap);
482         fflush(stream);
483 }
484 #endif
485
486 static void
487 ShowAliasStats(struct libalias *la)
488 {
489
490         LIBALIAS_LOCK_ASSERT(la);
491 /* Used for debugging */
492         if (la->logDesc) {
493                 int tot  = la->icmpLinkCount + la->udpLinkCount + 
494                   (la->sctpLinkCount>>1) + /* sctp counts half associations */
495                         la->tcpLinkCount + la->pptpLinkCount +
496                         la->protoLinkCount + la->fragmentIdLinkCount +
497                         la->fragmentPtrLinkCount;
498                 
499                 AliasLog(la->logDesc,
500                          "icmp=%u, udp=%u, tcp=%u, sctp=%u, pptp=%u, proto=%u, frag_id=%u frag_ptr=%u / tot=%u",
501                          la->icmpLinkCount,
502                          la->udpLinkCount,
503                          la->tcpLinkCount,
504                          la->sctpLinkCount>>1, /* sctp counts half associations */
505                          la->pptpLinkCount,
506                          la->protoLinkCount,
507                          la->fragmentIdLinkCount,
508                          la->fragmentPtrLinkCount, tot);
509 #ifndef _KERNEL
510                 AliasLog(la->logDesc, " (sock=%u)\n", la->sockCount); 
511 #endif
512         }
513 }
514
515 void SctpShowAliasStats(struct libalias *la)
516 {
517
518         ShowAliasStats(la);
519 }
520
521
522 /* Internal routines for finding, deleting and adding links
523
524 Port Allocation:
525     GetNewPort()             -- find and reserve new alias port number
526     GetSocket()              -- try to allocate a socket for a given port
527
528 Link creation and deletion:
529     CleanupAliasData()      - remove all link chains from lookup table
530     IncrementalCleanup()    - look for stale links in a single chain
531     DeleteLink()            - remove link
532     AddLink()               - add link
533     ReLink()                - change link
534
535 Link search:
536     FindLinkOut()           - find link for outgoing packets
537     FindLinkIn()            - find link for incoming packets
538
539 Port search:
540     FindNewPortGroup()      - find an available group of ports
541 */
542
543 /* Local prototypes */
544 static int      GetNewPort(struct libalias *, struct alias_link *, int);
545 #ifndef NO_USE_SOCKETS
546 static u_short  GetSocket(struct libalias *, u_short, int *, int);
547 #endif
548 static void     CleanupAliasData(struct libalias *);
549
550 static void     IncrementalCleanup(struct libalias *);
551
552 static void     DeleteLink(struct alias_link *);
553
554 static struct alias_link *
555 AddLink(struct libalias *, struct in_addr, struct in_addr, struct in_addr,
556     u_short, u_short, int, int);
557
558 static struct alias_link *
559 ReLink(struct alias_link *,
560     struct in_addr, struct in_addr, struct in_addr,
561     u_short, u_short, int, int);
562
563 static struct alias_link *
564                 FindLinkOut   (struct libalias *, struct in_addr, struct in_addr, u_short, u_short, int, int);
565
566 static struct alias_link *
567                 FindLinkIn    (struct libalias *, struct in_addr, struct in_addr, u_short, u_short, int, int);
568
569
570 #define ALIAS_PORT_BASE            0x08000
571 #define ALIAS_PORT_MASK            0x07fff
572 #define ALIAS_PORT_MASK_EVEN       0x07ffe
573 #define GET_NEW_PORT_MAX_ATTEMPTS       20
574
575 #define GET_ALIAS_PORT                  -1
576 #define GET_ALIAS_ID        GET_ALIAS_PORT
577
578 #define FIND_EVEN_ALIAS_BASE             1
579
580 /* GetNewPort() allocates port numbers.  Note that if a port number
581    is already in use, that does not mean that it cannot be used by
582    another link concurrently.  This is because GetNewPort() looks for
583    unused triplets: (dest addr, dest port, alias port). */
584
585 static int
586 GetNewPort(struct libalias *la, struct alias_link *lnk, int alias_port_param)
587 {
588         int i;
589         int max_trials;
590         u_short port_sys;
591         u_short port_net;
592
593         LIBALIAS_LOCK_ASSERT(la);
594 /*
595    Description of alias_port_param for GetNewPort().  When
596    this parameter is zero or positive, it precisely specifies
597    the port number.  GetNewPort() will return this number
598    without check that it is in use.
599
600    When this parameter is GET_ALIAS_PORT, it indicates to get a randomly
601    selected port number.
602 */
603
604         if (alias_port_param == GET_ALIAS_PORT) {
605                 /*
606                  * The aliasing port is automatically selected by one of
607                  * two methods below:
608                  */
609                 max_trials = GET_NEW_PORT_MAX_ATTEMPTS;
610
611                 if (la->packetAliasMode & PKT_ALIAS_SAME_PORTS) {
612                         /*
613                          * When the PKT_ALIAS_SAME_PORTS option is chosen,
614                          * the first try will be the actual source port. If
615                          * this is already in use, the remainder of the
616                          * trials will be random.
617                          */
618                         port_net = lnk->src_port;
619                         port_sys = ntohs(port_net);
620                 } else {
621                         /* First trial and all subsequent are random. */
622                         port_sys = arc4random() & ALIAS_PORT_MASK;
623                         port_sys += ALIAS_PORT_BASE;
624                         port_net = htons(port_sys);
625                 }
626         } else if (alias_port_param >= 0 && alias_port_param < 0x10000) {
627                 lnk->alias_port = (u_short) alias_port_param;
628                 return (0);
629         } else {
630 #ifdef LIBALIAS_DEBUG
631                 fprintf(stderr, "PacketAlias/GetNewPort(): ");
632                 fprintf(stderr, "input parameter error\n");
633 #endif
634                 return (-1);
635         }
636
637
638 /* Port number search */
639         for (i = 0; i < max_trials; i++) {
640                 int go_ahead;
641                 struct alias_link *search_result;
642
643                 search_result = FindLinkIn(la, lnk->dst_addr, lnk->alias_addr,
644                     lnk->dst_port, port_net,
645                     lnk->link_type, 0);
646
647                 if (search_result == NULL)
648                         go_ahead = 1;
649                 else if (!(lnk->flags & LINK_PARTIALLY_SPECIFIED)
650                     && (search_result->flags & LINK_PARTIALLY_SPECIFIED))
651                         go_ahead = 1;
652                 else
653                         go_ahead = 0;
654
655                 if (go_ahead) {
656 #ifndef NO_USE_SOCKETS
657                         if ((la->packetAliasMode & PKT_ALIAS_USE_SOCKETS)
658                             && (lnk->flags & LINK_PARTIALLY_SPECIFIED)
659                             && ((lnk->link_type == LINK_TCP) ||
660                             (lnk->link_type == LINK_UDP))) {
661                                 if (GetSocket(la, port_net, &lnk->sockfd, lnk->link_type)) {
662                                         lnk->alias_port = port_net;
663                                         return (0);
664                                 }
665                         } else {
666 #endif
667                                 lnk->alias_port = port_net;
668                                 return (0);
669 #ifndef NO_USE_SOCKETS
670                         }
671 #endif
672                 }
673                 port_sys = arc4random() & ALIAS_PORT_MASK;
674                 port_sys += ALIAS_PORT_BASE;
675                 port_net = htons(port_sys);
676         }
677
678 #ifdef LIBALIAS_DEBUG
679         fprintf(stderr, "PacketAlias/GetnewPort(): ");
680         fprintf(stderr, "could not find free port\n");
681 #endif
682
683         return (-1);
684 }
685
686 #ifndef NO_USE_SOCKETS
687 static          u_short
688 GetSocket(struct libalias *la, u_short port_net, int *sockfd, int link_type)
689 {
690         int err;
691         int sock;
692         struct sockaddr_in sock_addr;
693
694         LIBALIAS_LOCK_ASSERT(la);
695         if (link_type == LINK_TCP)
696                 sock = socket(AF_INET, SOCK_STREAM, 0);
697         else if (link_type == LINK_UDP)
698                 sock = socket(AF_INET, SOCK_DGRAM, 0);
699         else {
700 #ifdef LIBALIAS_DEBUG
701                 fprintf(stderr, "PacketAlias/GetSocket(): ");
702                 fprintf(stderr, "incorrect link type\n");
703 #endif
704                 return (0);
705         }
706
707         if (sock < 0) {
708 #ifdef LIBALIAS_DEBUG
709                 fprintf(stderr, "PacketAlias/GetSocket(): ");
710                 fprintf(stderr, "socket() error %d\n", *sockfd);
711 #endif
712                 return (0);
713         }
714         sock_addr.sin_family = AF_INET;
715         sock_addr.sin_addr.s_addr = htonl(INADDR_ANY);
716         sock_addr.sin_port = port_net;
717
718         err = bind(sock,
719             (struct sockaddr *)&sock_addr,
720             sizeof(sock_addr));
721         if (err == 0) {
722                 la->sockCount++;
723                 *sockfd = sock;
724                 return (1);
725         } else {
726                 close(sock);
727                 return (0);
728         }
729 }
730 #endif
731
732 /* FindNewPortGroup() returns a base port number for an available
733    range of contiguous port numbers. Note that if a port number
734    is already in use, that does not mean that it cannot be used by
735    another link concurrently.  This is because FindNewPortGroup()
736    looks for unused triplets: (dest addr, dest port, alias port). */
737
738 int
739 FindNewPortGroup(struct libalias *la,
740     struct in_addr dst_addr,
741     struct in_addr alias_addr,
742     u_short src_port,
743     u_short dst_port,
744     u_short port_count,
745     u_char proto,
746     u_char align)
747 {
748         int i, j;
749         int max_trials;
750         u_short port_sys;
751         int link_type;
752
753         LIBALIAS_LOCK_ASSERT(la);
754         /*
755          * Get link_type from protocol
756          */
757
758         switch (proto) {
759         case IPPROTO_UDP:
760                 link_type = LINK_UDP;
761                 break;
762         case IPPROTO_TCP:
763                 link_type = LINK_TCP;
764                 break;
765         default:
766                 return (0);
767                 break;
768         }
769
770         /*
771          * The aliasing port is automatically selected by one of two
772          * methods below:
773          */
774         max_trials = GET_NEW_PORT_MAX_ATTEMPTS;
775
776         if (la->packetAliasMode & PKT_ALIAS_SAME_PORTS) {
777                 /*
778                  * When the ALIAS_SAME_PORTS option is chosen, the first
779                  * try will be the actual source port. If this is already
780                  * in use, the remainder of the trials will be random.
781                  */
782                 port_sys = ntohs(src_port);
783
784         } else {
785
786                 /* First trial and all subsequent are random. */
787                 if (align == FIND_EVEN_ALIAS_BASE)
788                         port_sys = arc4random() & ALIAS_PORT_MASK_EVEN;
789                 else
790                         port_sys = arc4random() & ALIAS_PORT_MASK;
791
792                 port_sys += ALIAS_PORT_BASE;
793         }
794
795 /* Port number search */
796         for (i = 0; i < max_trials; i++) {
797
798                 struct alias_link *search_result;
799
800                 for (j = 0; j < port_count; j++)
801                         if (0 != (search_result = FindLinkIn(la, dst_addr, alias_addr,
802                             dst_port, htons(port_sys + j),
803                             link_type, 0)))
804                                 break;
805
806                 /* Found a good range, return base */
807                 if (j == port_count)
808                         return (htons(port_sys));
809
810                 /* Find a new base to try */
811                 if (align == FIND_EVEN_ALIAS_BASE)
812                         port_sys = arc4random() & ALIAS_PORT_MASK_EVEN;
813                 else
814                         port_sys = arc4random() & ALIAS_PORT_MASK;
815
816                 port_sys += ALIAS_PORT_BASE;
817         }
818
819 #ifdef LIBALIAS_DEBUG
820         fprintf(stderr, "PacketAlias/FindNewPortGroup(): ");
821         fprintf(stderr, "could not find free port(s)\n");
822 #endif
823
824         return (0);
825 }
826
827 static void
828 CleanupAliasData(struct libalias *la)
829 {
830         struct alias_link *lnk;
831         int i;
832
833         LIBALIAS_LOCK_ASSERT(la);
834         for (i = 0; i < LINK_TABLE_OUT_SIZE; i++) {
835                 lnk = LIST_FIRST(&la->linkTableOut[i]);
836                 while (lnk != NULL) {
837                         struct alias_link *link_next = LIST_NEXT(lnk, list_out);
838                         DeleteLink(lnk);
839                         lnk = link_next;
840                 }
841         }
842
843         la->cleanupIndex = 0;
844 }
845
846
847 static void
848 IncrementalCleanup(struct libalias *la)
849 {
850         struct alias_link *lnk, *lnk_tmp;
851
852         LIBALIAS_LOCK_ASSERT(la);
853         LIST_FOREACH_SAFE(lnk, &la->linkTableOut[la->cleanupIndex++],
854             list_out, lnk_tmp) {
855                 if (la->timeStamp - lnk->timestamp > lnk->expire_time)
856                         DeleteLink(lnk);
857         }
858
859         if (la->cleanupIndex == LINK_TABLE_OUT_SIZE)
860                 la->cleanupIndex = 0;
861 }
862
863 static void
864 DeleteLink(struct alias_link *lnk)
865 {
866         struct libalias *la = lnk->la;
867
868         LIBALIAS_LOCK_ASSERT(la);
869 /* Don't do anything if the link is marked permanent */
870         if (la->deleteAllLinks == 0 && lnk->flags & LINK_PERMANENT)
871                 return;
872
873 #ifndef NO_FW_PUNCH
874 /* Delete associated firewall hole, if any */
875         ClearFWHole(lnk);
876 #endif
877
878 /* Free memory allocated for LSNAT server pool */
879         if (lnk->server != NULL) {
880                 struct server *head, *curr, *next;
881
882                 head = curr = lnk->server;
883                 do {
884                         next = curr->next;
885                         free(curr);
886                 } while ((curr = next) != head);
887         }
888 /* Adjust output table pointers */
889         LIST_REMOVE(lnk, list_out);
890
891 /* Adjust input table pointers */
892         LIST_REMOVE(lnk, list_in);
893 #ifndef NO_USE_SOCKETS
894 /* Close socket, if one has been allocated */
895         if (lnk->sockfd != -1) {
896                 la->sockCount--;
897                 close(lnk->sockfd);
898         }
899 #endif
900 /* Link-type dependent cleanup */
901         switch (lnk->link_type) {
902         case LINK_ICMP:
903                 la->icmpLinkCount--;
904                 break;
905         case LINK_UDP:
906                 la->udpLinkCount--;
907                 break;
908         case LINK_TCP:
909                 la->tcpLinkCount--;
910                 free(lnk->data.tcp);
911                 break;
912         case LINK_PPTP:
913                 la->pptpLinkCount--;
914                 break;
915         case LINK_FRAGMENT_ID:
916                 la->fragmentIdLinkCount--;
917                 break;
918         case LINK_FRAGMENT_PTR:
919                 la->fragmentPtrLinkCount--;
920                 if (lnk->data.frag_ptr != NULL)
921                         free(lnk->data.frag_ptr);
922                 break;
923         case LINK_ADDR:
924                 break;
925         default:
926                 la->protoLinkCount--;
927                 break;
928         }
929
930 /* Free memory */
931         free(lnk);
932
933 /* Write statistics, if logging enabled */
934         if (la->packetAliasMode & PKT_ALIAS_LOG) {
935                 ShowAliasStats(la);
936         }
937 }
938
939
940 static struct alias_link *
941 AddLink(struct libalias *la, struct in_addr src_addr,
942     struct in_addr dst_addr,
943     struct in_addr alias_addr,
944     u_short src_port,
945     u_short dst_port,
946     int alias_port_param,       /* if less than zero, alias   */
947     int link_type)
948 {                               /* port will be automatically *//* chosen.
949                                  * If greater than    */
950         u_int start_point;      /* zero, equal to alias port  */
951         struct alias_link *lnk;
952
953         LIBALIAS_LOCK_ASSERT(la);
954         lnk = malloc(sizeof(struct alias_link));
955         if (lnk != NULL) {
956                 /* Basic initialization */
957                 lnk->la = la;
958                 lnk->src_addr = src_addr;
959                 lnk->dst_addr = dst_addr;
960                 lnk->alias_addr = alias_addr;
961                 lnk->proxy_addr.s_addr = INADDR_ANY;
962                 lnk->src_port = src_port;
963                 lnk->dst_port = dst_port;
964                 lnk->proxy_port = 0;
965                 lnk->server = NULL;
966                 lnk->link_type = link_type;
967 #ifndef NO_USE_SOCKETS
968                 lnk->sockfd = -1;
969 #endif
970                 lnk->flags = 0;
971                 lnk->pflags = 0;
972                 lnk->timestamp = la->timeStamp;
973
974                 /* Expiration time */
975                 switch (link_type) {
976                 case LINK_ICMP:
977                         lnk->expire_time = ICMP_EXPIRE_TIME;
978                         break;
979                 case LINK_UDP:
980                         lnk->expire_time = UDP_EXPIRE_TIME;
981                         break;
982                 case LINK_TCP:
983                         lnk->expire_time = TCP_EXPIRE_INITIAL;
984                         break;
985                 case LINK_PPTP:
986                         lnk->flags |= LINK_PERMANENT;   /* no timeout. */
987                         break;
988                 case LINK_FRAGMENT_ID:
989                         lnk->expire_time = FRAGMENT_ID_EXPIRE_TIME;
990                         break;
991                 case LINK_FRAGMENT_PTR:
992                         lnk->expire_time = FRAGMENT_PTR_EXPIRE_TIME;
993                         break;
994                 case LINK_ADDR:
995                         break;
996                 default:
997                         lnk->expire_time = PROTO_EXPIRE_TIME;
998                         break;
999                 }
1000
1001                 /* Determine alias flags */
1002                 if (dst_addr.s_addr == INADDR_ANY)
1003                         lnk->flags |= LINK_UNKNOWN_DEST_ADDR;
1004                 if (dst_port == 0)
1005                         lnk->flags |= LINK_UNKNOWN_DEST_PORT;
1006
1007                 /* Determine alias port */
1008                 if (GetNewPort(la, lnk, alias_port_param) != 0) {
1009                         free(lnk);
1010                         return (NULL);
1011                 }
1012                 /* Link-type dependent initialization */
1013                 switch (link_type) {
1014                         struct tcp_dat *aux_tcp;
1015
1016                 case LINK_ICMP:
1017                         la->icmpLinkCount++;
1018                         break;
1019                 case LINK_UDP:
1020                         la->udpLinkCount++;
1021                         break;
1022                 case LINK_TCP:
1023                         aux_tcp = malloc(sizeof(struct tcp_dat));
1024                         if (aux_tcp != NULL) {
1025                                 int i;
1026
1027                                 la->tcpLinkCount++;
1028                                 aux_tcp->state.in = ALIAS_TCP_STATE_NOT_CONNECTED;
1029                                 aux_tcp->state.out = ALIAS_TCP_STATE_NOT_CONNECTED;
1030                                 aux_tcp->state.index = 0;
1031                                 aux_tcp->state.ack_modified = 0;
1032                                 for (i = 0; i < N_LINK_TCP_DATA; i++)
1033                                         aux_tcp->ack[i].active = 0;
1034                                 aux_tcp->fwhole = -1;
1035                                 lnk->data.tcp = aux_tcp;
1036                         } else {
1037 #ifdef LIBALIAS_DEBUG
1038                                 fprintf(stderr, "PacketAlias/AddLink: ");
1039                                 fprintf(stderr, " cannot allocate auxiliary TCP data\n");
1040 #endif
1041                                 free(lnk);
1042                                 return (NULL);
1043                         }
1044                         break;
1045                 case LINK_PPTP:
1046                         la->pptpLinkCount++;
1047                         break;
1048                 case LINK_FRAGMENT_ID:
1049                         la->fragmentIdLinkCount++;
1050                         break;
1051                 case LINK_FRAGMENT_PTR:
1052                         la->fragmentPtrLinkCount++;
1053                         break;
1054                 case LINK_ADDR:
1055                         break;
1056                 default:
1057                         la->protoLinkCount++;
1058                         break;
1059                 }
1060
1061                 /* Set up pointers for output lookup table */
1062                 start_point = StartPointOut(src_addr, dst_addr,
1063                     src_port, dst_port, link_type);
1064                 LIST_INSERT_HEAD(&la->linkTableOut[start_point], lnk, list_out);
1065
1066                 /* Set up pointers for input lookup table */
1067                 start_point = StartPointIn(alias_addr, lnk->alias_port, link_type);
1068                 LIST_INSERT_HEAD(&la->linkTableIn[start_point], lnk, list_in);
1069         } else {
1070 #ifdef LIBALIAS_DEBUG
1071                 fprintf(stderr, "PacketAlias/AddLink(): ");
1072                 fprintf(stderr, "malloc() call failed.\n");
1073 #endif
1074         }
1075         if (la->packetAliasMode & PKT_ALIAS_LOG) {
1076                 ShowAliasStats(la);
1077         }
1078         return (lnk);
1079 }
1080
1081 static struct alias_link *
1082 ReLink(struct alias_link *old_lnk,
1083     struct in_addr src_addr,
1084     struct in_addr dst_addr,
1085     struct in_addr alias_addr,
1086     u_short src_port,
1087     u_short dst_port,
1088     int alias_port_param,       /* if less than zero, alias   */
1089     int link_type)
1090 {                               /* port will be automatically *//* chosen.
1091                                  * If greater than    */
1092         struct alias_link *new_lnk;     /* zero, equal to alias port  */
1093         struct libalias *la = old_lnk->la;
1094
1095         LIBALIAS_LOCK_ASSERT(la);
1096         new_lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1097             src_port, dst_port, alias_port_param,
1098             link_type);
1099 #ifndef NO_FW_PUNCH
1100         if (new_lnk != NULL &&
1101             old_lnk->link_type == LINK_TCP &&
1102             old_lnk->data.tcp->fwhole > 0) {
1103                 PunchFWHole(new_lnk);
1104         }
1105 #endif
1106         DeleteLink(old_lnk);
1107         return (new_lnk);
1108 }
1109
1110 static struct alias_link *
1111 _FindLinkOut(struct libalias *la, struct in_addr src_addr,
1112     struct in_addr dst_addr,
1113     u_short src_port,
1114     u_short dst_port,
1115     int link_type,
1116     int replace_partial_links)
1117 {
1118         u_int i;
1119         struct alias_link *lnk;
1120
1121         LIBALIAS_LOCK_ASSERT(la);
1122         i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type);
1123         LIST_FOREACH(lnk, &la->linkTableOut[i], list_out) {
1124                 if (lnk->dst_addr.s_addr == dst_addr.s_addr &&
1125                     lnk->src_addr.s_addr == src_addr.s_addr &&
1126                     lnk->src_port == src_port &&
1127                     lnk->dst_port == dst_port &&
1128                     lnk->link_type == link_type &&
1129                     lnk->server == NULL) {
1130                         lnk->timestamp = la->timeStamp;
1131                         break;
1132                 }
1133         }
1134
1135 /* Search for partially specified links. */
1136         if (lnk == NULL && replace_partial_links) {
1137                 if (dst_port != 0 && dst_addr.s_addr != INADDR_ANY) {
1138                         lnk = _FindLinkOut(la, src_addr, dst_addr, src_port, 0,
1139                             link_type, 0);
1140                         if (lnk == NULL)
1141                                 lnk = _FindLinkOut(la, src_addr, la->nullAddress, src_port,
1142                                     dst_port, link_type, 0);
1143                 }
1144                 if (lnk == NULL &&
1145                     (dst_port != 0 || dst_addr.s_addr != INADDR_ANY)) {
1146                         lnk = _FindLinkOut(la, src_addr, la->nullAddress, src_port, 0,
1147                             link_type, 0);
1148                 }
1149                 if (lnk != NULL) {
1150                         lnk = ReLink(lnk,
1151                             src_addr, dst_addr, lnk->alias_addr,
1152                             src_port, dst_port, lnk->alias_port,
1153                             link_type);
1154                 }
1155         }
1156         return (lnk);
1157 }
1158
1159 static struct alias_link *
1160 FindLinkOut(struct libalias *la, struct in_addr src_addr,
1161     struct in_addr dst_addr,
1162     u_short src_port,
1163     u_short dst_port,
1164     int link_type,
1165     int replace_partial_links)
1166 {
1167         struct alias_link *lnk;
1168
1169         LIBALIAS_LOCK_ASSERT(la);
1170         lnk = _FindLinkOut(la, src_addr, dst_addr, src_port, dst_port,
1171             link_type, replace_partial_links);
1172
1173         if (lnk == NULL) {
1174                 /*
1175                  * The following allows permanent links to be specified as
1176                  * using the default source address (i.e. device interface
1177                  * address) without knowing in advance what that address
1178                  * is.
1179                  */
1180                 if (la->aliasAddress.s_addr != INADDR_ANY &&
1181                     src_addr.s_addr == la->aliasAddress.s_addr) {
1182                         lnk = _FindLinkOut(la, la->nullAddress, dst_addr, src_port, dst_port,
1183                             link_type, replace_partial_links);
1184                 }
1185         }
1186         return (lnk);
1187 }
1188
1189
1190 static struct alias_link *
1191 _FindLinkIn(struct libalias *la, struct in_addr dst_addr,
1192     struct in_addr alias_addr,
1193     u_short dst_port,
1194     u_short alias_port,
1195     int link_type,
1196     int replace_partial_links)
1197 {
1198         int flags_in;
1199         u_int start_point;
1200         struct alias_link *lnk;
1201         struct alias_link *lnk_fully_specified;
1202         struct alias_link *lnk_unknown_all;
1203         struct alias_link *lnk_unknown_dst_addr;
1204         struct alias_link *lnk_unknown_dst_port;
1205
1206         LIBALIAS_LOCK_ASSERT(la);
1207 /* Initialize pointers */
1208         lnk_fully_specified = NULL;
1209         lnk_unknown_all = NULL;
1210         lnk_unknown_dst_addr = NULL;
1211         lnk_unknown_dst_port = NULL;
1212
1213 /* If either the dest addr or port is unknown, the search
1214    loop will have to know about this. */
1215
1216         flags_in = 0;
1217         if (dst_addr.s_addr == INADDR_ANY)
1218                 flags_in |= LINK_UNKNOWN_DEST_ADDR;
1219         if (dst_port == 0)
1220                 flags_in |= LINK_UNKNOWN_DEST_PORT;
1221
1222 /* Search loop */
1223         start_point = StartPointIn(alias_addr, alias_port, link_type);
1224         LIST_FOREACH(lnk, &la->linkTableIn[start_point], list_in) {
1225                 int flags;
1226
1227                 flags = flags_in | lnk->flags;
1228                 if (!(flags & LINK_PARTIALLY_SPECIFIED)) {
1229                         if (lnk->alias_addr.s_addr == alias_addr.s_addr
1230                             && lnk->alias_port == alias_port
1231                             && lnk->dst_addr.s_addr == dst_addr.s_addr
1232                             && lnk->dst_port == dst_port
1233                             && lnk->link_type == link_type) {
1234                                 lnk_fully_specified = lnk;
1235                                 break;
1236                         }
1237                 } else if ((flags & LINK_UNKNOWN_DEST_ADDR)
1238                     && (flags & LINK_UNKNOWN_DEST_PORT)) {
1239                         if (lnk->alias_addr.s_addr == alias_addr.s_addr
1240                             && lnk->alias_port == alias_port
1241                             && lnk->link_type == link_type) {
1242                                 if (lnk_unknown_all == NULL)
1243                                         lnk_unknown_all = lnk;
1244                         }
1245                 } else if (flags & LINK_UNKNOWN_DEST_ADDR) {
1246                         if (lnk->alias_addr.s_addr == alias_addr.s_addr
1247                             && lnk->alias_port == alias_port
1248                             && lnk->link_type == link_type
1249                             && lnk->dst_port == dst_port) {
1250                                 if (lnk_unknown_dst_addr == NULL)
1251                                         lnk_unknown_dst_addr = lnk;
1252                         }
1253                 } else if (flags & LINK_UNKNOWN_DEST_PORT) {
1254                         if (lnk->alias_addr.s_addr == alias_addr.s_addr
1255                             && lnk->alias_port == alias_port
1256                             && lnk->link_type == link_type
1257                             && lnk->dst_addr.s_addr == dst_addr.s_addr) {
1258                                 if (lnk_unknown_dst_port == NULL)
1259                                         lnk_unknown_dst_port = lnk;
1260                         }
1261                 }
1262         }
1263
1264
1265
1266         if (lnk_fully_specified != NULL) {
1267                 lnk_fully_specified->timestamp = la->timeStamp;
1268                 lnk = lnk_fully_specified;
1269         } else if (lnk_unknown_dst_port != NULL)
1270                 lnk = lnk_unknown_dst_port;
1271         else if (lnk_unknown_dst_addr != NULL)
1272                 lnk = lnk_unknown_dst_addr;
1273         else if (lnk_unknown_all != NULL)
1274                 lnk = lnk_unknown_all;
1275         else
1276                 return (NULL);
1277
1278         if (replace_partial_links &&
1279             (lnk->flags & LINK_PARTIALLY_SPECIFIED || lnk->server != NULL)) {
1280                 struct in_addr src_addr;
1281                 u_short src_port;
1282
1283                 if (lnk->server != NULL) {      /* LSNAT link */
1284                         src_addr = lnk->server->addr;
1285                         src_port = lnk->server->port;
1286                         lnk->server = lnk->server->next;
1287                 } else {
1288                         src_addr = lnk->src_addr;
1289                         src_port = lnk->src_port;
1290                 }
1291
1292                 if (link_type == LINK_SCTP) {
1293                   lnk->src_addr = src_addr;
1294                   lnk->src_port = src_port;
1295                   return(lnk);
1296                 }
1297                 lnk = ReLink(lnk,
1298                     src_addr, dst_addr, alias_addr,
1299                     src_port, dst_port, alias_port,
1300                     link_type);
1301         }
1302         return (lnk);
1303 }
1304
1305 static struct alias_link *
1306 FindLinkIn(struct libalias *la, struct in_addr dst_addr,
1307     struct in_addr alias_addr,
1308     u_short dst_port,
1309     u_short alias_port,
1310     int link_type,
1311     int replace_partial_links)
1312 {
1313         struct alias_link *lnk;
1314
1315         LIBALIAS_LOCK_ASSERT(la);
1316         lnk = _FindLinkIn(la, dst_addr, alias_addr, dst_port, alias_port,
1317             link_type, replace_partial_links);
1318
1319         if (lnk == NULL) {
1320                 /*
1321                  * The following allows permanent links to be specified as
1322                  * using the default aliasing address (i.e. device
1323                  * interface address) without knowing in advance what that
1324                  * address is.
1325                  */
1326                 if (la->aliasAddress.s_addr != INADDR_ANY &&
1327                     alias_addr.s_addr == la->aliasAddress.s_addr) {
1328                         lnk = _FindLinkIn(la, dst_addr, la->nullAddress, dst_port, alias_port,
1329                             link_type, replace_partial_links);
1330                 }
1331         }
1332         return (lnk);
1333 }
1334
1335
1336
1337
1338 /* External routines for finding/adding links
1339
1340 -- "external" means outside alias_db.c, but within alias*.c --
1341
1342     FindIcmpIn(), FindIcmpOut()
1343     FindFragmentIn1(), FindFragmentIn2()
1344     AddFragmentPtrLink(), FindFragmentPtr()
1345     FindProtoIn(), FindProtoOut()
1346     FindUdpTcpIn(), FindUdpTcpOut()
1347     AddPptp(), FindPptpOutByCallId(), FindPptpInByCallId(),
1348     FindPptpOutByPeerCallId(), FindPptpInByPeerCallId()
1349     FindOriginalAddress(), FindAliasAddress()
1350
1351 (prototypes in alias_local.h)
1352 */
1353
1354
1355 struct alias_link *
1356 FindIcmpIn(struct libalias *la, struct in_addr dst_addr,
1357     struct in_addr alias_addr,
1358     u_short id_alias,
1359     int create)
1360 {
1361         struct alias_link *lnk;
1362
1363         LIBALIAS_LOCK_ASSERT(la);
1364         lnk = FindLinkIn(la, dst_addr, alias_addr,
1365             NO_DEST_PORT, id_alias,
1366             LINK_ICMP, 0);
1367         if (lnk == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1368                 struct in_addr target_addr;
1369
1370                 target_addr = FindOriginalAddress(la, alias_addr);
1371                 lnk = AddLink(la, target_addr, dst_addr, alias_addr,
1372                     id_alias, NO_DEST_PORT, id_alias,
1373                     LINK_ICMP);
1374         }
1375         return (lnk);
1376 }
1377
1378
1379 struct alias_link *
1380 FindIcmpOut(struct libalias *la, struct in_addr src_addr,
1381     struct in_addr dst_addr,
1382     u_short id,
1383     int create)
1384 {
1385         struct alias_link *lnk;
1386
1387         LIBALIAS_LOCK_ASSERT(la);
1388         lnk = FindLinkOut(la, src_addr, dst_addr,
1389             id, NO_DEST_PORT,
1390             LINK_ICMP, 0);
1391         if (lnk == NULL && create) {
1392                 struct in_addr alias_addr;
1393
1394                 alias_addr = FindAliasAddress(la, src_addr);
1395                 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1396                     id, NO_DEST_PORT, GET_ALIAS_ID,
1397                     LINK_ICMP);
1398         }
1399         return (lnk);
1400 }
1401
1402
1403 struct alias_link *
1404 FindFragmentIn1(struct libalias *la, struct in_addr dst_addr,
1405     struct in_addr alias_addr,
1406     u_short ip_id)
1407 {
1408         struct alias_link *lnk;
1409
1410         LIBALIAS_LOCK_ASSERT(la);
1411         lnk = FindLinkIn(la, dst_addr, alias_addr,
1412             NO_DEST_PORT, ip_id,
1413             LINK_FRAGMENT_ID, 0);
1414
1415         if (lnk == NULL) {
1416                 lnk = AddLink(la, la->nullAddress, dst_addr, alias_addr,
1417                     NO_SRC_PORT, NO_DEST_PORT, ip_id,
1418                     LINK_FRAGMENT_ID);
1419         }
1420         return (lnk);
1421 }
1422
1423
1424 struct alias_link *
1425 FindFragmentIn2(struct libalias *la, struct in_addr dst_addr,   /* Doesn't add a link if
1426                                                                  * one */
1427     struct in_addr alias_addr,  /* is not found.           */
1428     u_short ip_id)
1429 {
1430         
1431         LIBALIAS_LOCK_ASSERT(la);
1432         return FindLinkIn(la, dst_addr, alias_addr,
1433             NO_DEST_PORT, ip_id,
1434             LINK_FRAGMENT_ID, 0);
1435 }
1436
1437
1438 struct alias_link *
1439 AddFragmentPtrLink(struct libalias *la, struct in_addr dst_addr,
1440     u_short ip_id)
1441 {
1442
1443         LIBALIAS_LOCK_ASSERT(la);
1444         return AddLink(la, la->nullAddress, dst_addr, la->nullAddress,
1445             NO_SRC_PORT, NO_DEST_PORT, ip_id,
1446             LINK_FRAGMENT_PTR);
1447 }
1448
1449
1450 struct alias_link *
1451 FindFragmentPtr(struct libalias *la, struct in_addr dst_addr,
1452     u_short ip_id)
1453 {
1454
1455         LIBALIAS_LOCK_ASSERT(la);
1456         return FindLinkIn(la, dst_addr, la->nullAddress,
1457             NO_DEST_PORT, ip_id,
1458             LINK_FRAGMENT_PTR, 0);
1459 }
1460
1461
1462 struct alias_link *
1463 FindProtoIn(struct libalias *la, struct in_addr dst_addr,
1464     struct in_addr alias_addr,
1465     u_char proto)
1466 {
1467         struct alias_link *lnk;
1468
1469         LIBALIAS_LOCK_ASSERT(la);
1470         lnk = FindLinkIn(la, dst_addr, alias_addr,
1471             NO_DEST_PORT, 0,
1472             proto, 1);
1473
1474         if (lnk == NULL && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1475                 struct in_addr target_addr;
1476
1477                 target_addr = FindOriginalAddress(la, alias_addr);
1478                 lnk = AddLink(la, target_addr, dst_addr, alias_addr,
1479                     NO_SRC_PORT, NO_DEST_PORT, 0,
1480                     proto);
1481         }
1482         return (lnk);
1483 }
1484
1485
1486 struct alias_link *
1487 FindProtoOut(struct libalias *la, struct in_addr src_addr,
1488     struct in_addr dst_addr,
1489     u_char proto)
1490 {
1491         struct alias_link *lnk;
1492
1493         LIBALIAS_LOCK_ASSERT(la);
1494         lnk = FindLinkOut(la, src_addr, dst_addr,
1495             NO_SRC_PORT, NO_DEST_PORT,
1496             proto, 1);
1497
1498         if (lnk == NULL) {
1499                 struct in_addr alias_addr;
1500
1501                 alias_addr = FindAliasAddress(la, src_addr);
1502                 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1503                     NO_SRC_PORT, NO_DEST_PORT, 0,
1504                     proto);
1505         }
1506         return (lnk);
1507 }
1508
1509
1510 struct alias_link *
1511 FindUdpTcpIn(struct libalias *la, struct in_addr dst_addr,
1512     struct in_addr alias_addr,
1513     u_short dst_port,
1514     u_short alias_port,
1515     u_char proto,
1516     int create)
1517 {
1518         int link_type;
1519         struct alias_link *lnk;
1520
1521         LIBALIAS_LOCK_ASSERT(la);
1522         switch (proto) {
1523         case IPPROTO_UDP:
1524                 link_type = LINK_UDP;
1525                 break;
1526         case IPPROTO_TCP:
1527                 link_type = LINK_TCP;
1528                 break;
1529         default:
1530                 return (NULL);
1531                 break;
1532         }
1533
1534         lnk = FindLinkIn(la, dst_addr, alias_addr,
1535             dst_port, alias_port,
1536             link_type, create);
1537
1538         if (lnk == NULL && create && !(la->packetAliasMode & PKT_ALIAS_DENY_INCOMING)) {
1539                 struct in_addr target_addr;
1540
1541                 target_addr = FindOriginalAddress(la, alias_addr);
1542                 lnk = AddLink(la, target_addr, dst_addr, alias_addr,
1543                     alias_port, dst_port, alias_port,
1544                     link_type);
1545         }
1546         return (lnk);
1547 }
1548
1549
1550 struct alias_link *
1551 FindUdpTcpOut(struct libalias *la, struct in_addr src_addr,
1552     struct in_addr dst_addr,
1553     u_short src_port,
1554     u_short dst_port,
1555     u_char proto,
1556     int create)
1557 {
1558         int link_type;
1559         struct alias_link *lnk;
1560
1561         LIBALIAS_LOCK_ASSERT(la);
1562         switch (proto) {
1563         case IPPROTO_UDP:
1564                 link_type = LINK_UDP;
1565                 break;
1566         case IPPROTO_TCP:
1567                 link_type = LINK_TCP;
1568                 break;
1569         default:
1570                 return (NULL);
1571                 break;
1572         }
1573
1574         lnk = FindLinkOut(la, src_addr, dst_addr, src_port, dst_port, link_type, create);
1575
1576         if (lnk == NULL && create) {
1577                 struct in_addr alias_addr;
1578
1579                 alias_addr = FindAliasAddress(la, src_addr);
1580                 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1581                     src_port, dst_port, GET_ALIAS_PORT,
1582                     link_type);
1583         }
1584         return (lnk);
1585 }
1586
1587
1588 struct alias_link *
1589 AddPptp(struct libalias *la, struct in_addr src_addr,
1590     struct in_addr dst_addr,
1591     struct in_addr alias_addr,
1592     u_int16_t src_call_id)
1593 {
1594         struct alias_link *lnk;
1595
1596         LIBALIAS_LOCK_ASSERT(la);
1597         lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1598             src_call_id, 0, GET_ALIAS_PORT,
1599             LINK_PPTP);
1600
1601         return (lnk);
1602 }
1603
1604
1605 struct alias_link *
1606 FindPptpOutByCallId(struct libalias *la, struct in_addr src_addr,
1607     struct in_addr dst_addr,
1608     u_int16_t src_call_id)
1609 {
1610         u_int i;
1611         struct alias_link *lnk;
1612
1613         LIBALIAS_LOCK_ASSERT(la);
1614         i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP);
1615         LIST_FOREACH(lnk, &la->linkTableOut[i], list_out)
1616             if (lnk->link_type == LINK_PPTP &&
1617             lnk->src_addr.s_addr == src_addr.s_addr &&
1618             lnk->dst_addr.s_addr == dst_addr.s_addr &&
1619             lnk->src_port == src_call_id)
1620                 break;
1621
1622         return (lnk);
1623 }
1624
1625
1626 struct alias_link *
1627 FindPptpOutByPeerCallId(struct libalias *la, struct in_addr src_addr,
1628     struct in_addr dst_addr,
1629     u_int16_t dst_call_id)
1630 {
1631         u_int i;
1632         struct alias_link *lnk;
1633
1634         LIBALIAS_LOCK_ASSERT(la);
1635         i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP);
1636         LIST_FOREACH(lnk, &la->linkTableOut[i], list_out)
1637             if (lnk->link_type == LINK_PPTP &&
1638             lnk->src_addr.s_addr == src_addr.s_addr &&
1639             lnk->dst_addr.s_addr == dst_addr.s_addr &&
1640             lnk->dst_port == dst_call_id)
1641                 break;
1642
1643         return (lnk);
1644 }
1645
1646
1647 struct alias_link *
1648 FindPptpInByCallId(struct libalias *la, struct in_addr dst_addr,
1649     struct in_addr alias_addr,
1650     u_int16_t dst_call_id)
1651 {
1652         u_int i;
1653         struct alias_link *lnk;
1654
1655         LIBALIAS_LOCK_ASSERT(la);
1656         i = StartPointIn(alias_addr, 0, LINK_PPTP);
1657         LIST_FOREACH(lnk, &la->linkTableIn[i], list_in)
1658             if (lnk->link_type == LINK_PPTP &&
1659             lnk->dst_addr.s_addr == dst_addr.s_addr &&
1660             lnk->alias_addr.s_addr == alias_addr.s_addr &&
1661             lnk->dst_port == dst_call_id)
1662                 break;
1663
1664         return (lnk);
1665 }
1666
1667
1668 struct alias_link *
1669 FindPptpInByPeerCallId(struct libalias *la, struct in_addr dst_addr,
1670     struct in_addr alias_addr,
1671     u_int16_t alias_call_id)
1672 {
1673         struct alias_link *lnk;
1674
1675         LIBALIAS_LOCK_ASSERT(la);
1676         lnk = FindLinkIn(la, dst_addr, alias_addr,
1677             0 /* any */ , alias_call_id,
1678             LINK_PPTP, 0);
1679
1680
1681         return (lnk);
1682 }
1683
1684
1685 struct alias_link *
1686 FindRtspOut(struct libalias *la, struct in_addr src_addr,
1687     struct in_addr dst_addr,
1688     u_short src_port,
1689     u_short alias_port,
1690     u_char proto)
1691 {
1692         int link_type;
1693         struct alias_link *lnk;
1694
1695         LIBALIAS_LOCK_ASSERT(la);
1696         switch (proto) {
1697         case IPPROTO_UDP:
1698                 link_type = LINK_UDP;
1699                 break;
1700         case IPPROTO_TCP:
1701                 link_type = LINK_TCP;
1702                 break;
1703         default:
1704                 return (NULL);
1705                 break;
1706         }
1707
1708         lnk = FindLinkOut(la, src_addr, dst_addr, src_port, 0, link_type, 1);
1709
1710         if (lnk == NULL) {
1711                 struct in_addr alias_addr;
1712
1713                 alias_addr = FindAliasAddress(la, src_addr);
1714                 lnk = AddLink(la, src_addr, dst_addr, alias_addr,
1715                     src_port, 0, alias_port,
1716                     link_type);
1717         }
1718         return (lnk);
1719 }
1720
1721
1722 struct in_addr
1723 FindOriginalAddress(struct libalias *la, struct in_addr alias_addr)
1724 {
1725         struct alias_link *lnk;
1726
1727         LIBALIAS_LOCK_ASSERT(la);
1728         lnk = FindLinkIn(la, la->nullAddress, alias_addr,
1729             0, 0, LINK_ADDR, 0);
1730         if (lnk == NULL) {
1731                 la->newDefaultLink = 1;
1732                 if (la->targetAddress.s_addr == INADDR_ANY)
1733                         return (alias_addr);
1734                 else if (la->targetAddress.s_addr == INADDR_NONE)
1735                         return (la->aliasAddress.s_addr != INADDR_ANY) ?
1736                             la->aliasAddress : alias_addr;
1737                 else
1738                         return (la->targetAddress);
1739         } else {
1740                 if (lnk->server != NULL) {      /* LSNAT link */
1741                         struct in_addr src_addr;
1742
1743                         src_addr = lnk->server->addr;
1744                         lnk->server = lnk->server->next;
1745                         return (src_addr);
1746                 } else if (lnk->src_addr.s_addr == INADDR_ANY)
1747                         return (la->aliasAddress.s_addr != INADDR_ANY) ?
1748                             la->aliasAddress : alias_addr;
1749                 else
1750                         return (lnk->src_addr);
1751         }
1752 }
1753
1754
1755 struct in_addr
1756 FindAliasAddress(struct libalias *la, struct in_addr original_addr)
1757 {
1758         struct alias_link *lnk;
1759
1760         LIBALIAS_LOCK_ASSERT(la);
1761         lnk = FindLinkOut(la, original_addr, la->nullAddress,
1762             0, 0, LINK_ADDR, 0);
1763         if (lnk == NULL) {
1764                 return (la->aliasAddress.s_addr != INADDR_ANY) ?
1765                     la->aliasAddress : original_addr;
1766         } else {
1767                 if (lnk->alias_addr.s_addr == INADDR_ANY)
1768                         return (la->aliasAddress.s_addr != INADDR_ANY) ?
1769                             la->aliasAddress : original_addr;
1770                 else
1771                         return (lnk->alias_addr);
1772         }
1773 }
1774
1775
1776 /* External routines for getting or changing link data
1777    (external to alias_db.c, but internal to alias*.c)
1778
1779     SetFragmentData(), GetFragmentData()
1780     SetFragmentPtr(), GetFragmentPtr()
1781     SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut()
1782     GetOriginalAddress(), GetDestAddress(), GetAliasAddress()
1783     GetOriginalPort(), GetAliasPort()
1784     SetAckModified(), GetAckModified()
1785     GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq()
1786     SetProtocolFlags(), GetProtocolFlags()
1787     SetDestCallId()
1788 */
1789
1790
1791 void
1792 SetFragmentAddr(struct alias_link *lnk, struct in_addr src_addr)
1793 {
1794         lnk->data.frag_addr = src_addr;
1795 }
1796
1797
1798 void
1799 GetFragmentAddr(struct alias_link *lnk, struct in_addr *src_addr)
1800 {
1801         *src_addr = lnk->data.frag_addr;
1802 }
1803
1804
1805 void
1806 SetFragmentPtr(struct alias_link *lnk, char *fptr)
1807 {
1808         lnk->data.frag_ptr = fptr;
1809 }
1810
1811
1812 void
1813 GetFragmentPtr(struct alias_link *lnk, char **fptr)
1814 {
1815         *fptr = lnk->data.frag_ptr;
1816 }
1817
1818
1819 void
1820 SetStateIn(struct alias_link *lnk, int state)
1821 {
1822         /* TCP input state */
1823         switch (state) {
1824                 case ALIAS_TCP_STATE_DISCONNECTED:
1825                 if (lnk->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED)
1826                         lnk->expire_time = TCP_EXPIRE_DEAD;
1827                 else
1828                         lnk->expire_time = TCP_EXPIRE_SINGLEDEAD;
1829                 break;
1830         case ALIAS_TCP_STATE_CONNECTED:
1831                 if (lnk->data.tcp->state.out == ALIAS_TCP_STATE_CONNECTED)
1832                         lnk->expire_time = TCP_EXPIRE_CONNECTED;
1833                 break;
1834         default:
1835 #ifdef  _KERNEL
1836                 panic("libalias:SetStateIn() unknown state");
1837 #else
1838                 abort();
1839 #endif
1840         }
1841         lnk->data.tcp->state.in = state;
1842 }
1843
1844
1845 void
1846 SetStateOut(struct alias_link *lnk, int state)
1847 {
1848         /* TCP output state */
1849         switch (state) {
1850                 case ALIAS_TCP_STATE_DISCONNECTED:
1851                 if (lnk->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED)
1852                         lnk->expire_time = TCP_EXPIRE_DEAD;
1853                 else
1854                         lnk->expire_time = TCP_EXPIRE_SINGLEDEAD;
1855                 break;
1856         case ALIAS_TCP_STATE_CONNECTED:
1857                 if (lnk->data.tcp->state.in == ALIAS_TCP_STATE_CONNECTED)
1858                         lnk->expire_time = TCP_EXPIRE_CONNECTED;
1859                 break;
1860         default:
1861 #ifdef  _KERNEL
1862                 panic("libalias:SetStateOut() unknown state");
1863 #else
1864                 abort();
1865 #endif
1866         }
1867         lnk->data.tcp->state.out = state;
1868 }
1869
1870
1871 int
1872 GetStateIn(struct alias_link *lnk)
1873 {
1874         /* TCP input state */
1875         return (lnk->data.tcp->state.in);
1876 }
1877
1878
1879 int
1880 GetStateOut(struct alias_link *lnk)
1881 {
1882         /* TCP output state */
1883         return (lnk->data.tcp->state.out);
1884 }
1885
1886
1887 struct in_addr
1888 GetOriginalAddress(struct alias_link *lnk)
1889 {
1890         if (lnk->src_addr.s_addr == INADDR_ANY)
1891                 return (lnk->la->aliasAddress);
1892         else
1893                 return (lnk->src_addr);
1894 }
1895
1896
1897 struct in_addr
1898 GetDestAddress(struct alias_link *lnk)
1899 {
1900         return (lnk->dst_addr);
1901 }
1902
1903
1904 struct in_addr
1905 GetAliasAddress(struct alias_link *lnk)
1906 {
1907         if (lnk->alias_addr.s_addr == INADDR_ANY)
1908                 return (lnk->la->aliasAddress);
1909         else
1910                 return (lnk->alias_addr);
1911 }
1912
1913
1914 struct in_addr
1915 GetDefaultAliasAddress(struct libalias *la)
1916 {
1917         
1918         LIBALIAS_LOCK_ASSERT(la);
1919         return (la->aliasAddress);
1920 }
1921
1922
1923 void
1924 SetDefaultAliasAddress(struct libalias *la, struct in_addr alias_addr)
1925 {
1926
1927         LIBALIAS_LOCK_ASSERT(la);
1928         la->aliasAddress = alias_addr;
1929 }
1930
1931
1932 u_short
1933 GetOriginalPort(struct alias_link *lnk)
1934 {
1935         return (lnk->src_port);
1936 }
1937
1938
1939 u_short
1940 GetAliasPort(struct alias_link *lnk)
1941 {
1942         return (lnk->alias_port);
1943 }
1944
1945 #ifndef NO_FW_PUNCH
1946 static          u_short
1947 GetDestPort(struct alias_link *lnk)
1948 {
1949         return (lnk->dst_port);
1950 }
1951
1952 #endif
1953
1954 void
1955 SetAckModified(struct alias_link *lnk)
1956 {
1957 /* Indicate that ACK numbers have been modified in a TCP connection */
1958         lnk->data.tcp->state.ack_modified = 1;
1959 }
1960
1961
1962 struct in_addr
1963 GetProxyAddress(struct alias_link *lnk)
1964 {
1965         return (lnk->proxy_addr);
1966 }
1967
1968
1969 void
1970 SetProxyAddress(struct alias_link *lnk, struct in_addr addr)
1971 {
1972         lnk->proxy_addr = addr;
1973 }
1974
1975
1976 u_short
1977 GetProxyPort(struct alias_link *lnk)
1978 {
1979         return (lnk->proxy_port);
1980 }
1981
1982
1983 void
1984 SetProxyPort(struct alias_link *lnk, u_short port)
1985 {
1986         lnk->proxy_port = port;
1987 }
1988
1989
1990 int
1991 GetAckModified(struct alias_link *lnk)
1992 {
1993 /* See if ACK numbers have been modified */
1994         return (lnk->data.tcp->state.ack_modified);
1995 }
1996
1997 // XXX ip free
1998 int
1999 GetDeltaAckIn(u_long ack, struct alias_link *lnk)
2000 {
2001 /*
2002 Find out how much the ACK number has been altered for an incoming
2003 TCP packet.  To do this, a circular list of ACK numbers where the TCP
2004 packet size was altered is searched.
2005 */
2006
2007         int i;
2008         int delta, ack_diff_min;
2009
2010         delta = 0;
2011         ack_diff_min = -1;
2012         for (i = 0; i < N_LINK_TCP_DATA; i++) {
2013                 struct ack_data_record x;
2014
2015                 x = lnk->data.tcp->ack[i];
2016                 if (x.active == 1) {
2017                         int ack_diff;
2018
2019                         ack_diff = SeqDiff(x.ack_new, ack);
2020                         if (ack_diff >= 0) {
2021                                 if (ack_diff_min >= 0) {
2022                                         if (ack_diff < ack_diff_min) {
2023                                                 delta = x.delta;
2024                                                 ack_diff_min = ack_diff;
2025                                         }
2026                                 } else {
2027                                         delta = x.delta;
2028                                         ack_diff_min = ack_diff;
2029                                 }
2030                         }
2031                 }
2032         }
2033         return (delta);
2034 }
2035
2036 // XXX ip free
2037 int
2038 GetDeltaSeqOut(u_long seq, struct alias_link *lnk)
2039 {
2040 /*
2041 Find out how much the sequence number has been altered for an outgoing
2042 TCP packet.  To do this, a circular list of ACK numbers where the TCP
2043 packet size was altered is searched.
2044 */
2045
2046         int i;
2047         int delta, seq_diff_min;
2048
2049         delta = 0;
2050         seq_diff_min = -1;
2051         for (i = 0; i < N_LINK_TCP_DATA; i++) {
2052                 struct ack_data_record x;
2053
2054                 x = lnk->data.tcp->ack[i];
2055                 if (x.active == 1) {
2056                         int seq_diff;
2057
2058                         seq_diff = SeqDiff(x.ack_old, seq);
2059                         if (seq_diff >= 0) {
2060                                 if (seq_diff_min >= 0) {
2061                                         if (seq_diff < seq_diff_min) {
2062                                                 delta = x.delta;
2063                                                 seq_diff_min = seq_diff;
2064                                         }
2065                                 } else {
2066                                         delta = x.delta;
2067                                         seq_diff_min = seq_diff;
2068                                 }
2069                         }
2070                 }
2071         }
2072         return (delta);
2073 }
2074
2075 // XXX ip free
2076 void
2077 AddSeq(struct alias_link *lnk, int delta, u_int ip_hl, u_short ip_len, 
2078     u_long th_seq, u_int th_off)
2079 {
2080 /*
2081 When a TCP packet has been altered in length, save this
2082 information in a circular list.  If enough packets have
2083 been altered, then this list will begin to overwrite itself.
2084 */
2085
2086         struct ack_data_record x;
2087         int hlen, tlen, dlen;
2088         int i;
2089
2090         hlen = (ip_hl + th_off) << 2;
2091         tlen = ntohs(ip_len);
2092         dlen = tlen - hlen;
2093
2094         x.ack_old = htonl(ntohl(th_seq) + dlen);
2095         x.ack_new = htonl(ntohl(th_seq) + dlen + delta);
2096         x.delta = delta;
2097         x.active = 1;
2098
2099         i = lnk->data.tcp->state.index;
2100         lnk->data.tcp->ack[i] = x;
2101
2102         i++;
2103         if (i == N_LINK_TCP_DATA)
2104                 lnk->data.tcp->state.index = 0;
2105         else
2106                 lnk->data.tcp->state.index = i;
2107 }
2108
2109 void
2110 SetExpire(struct alias_link *lnk, int expire)
2111 {
2112         if (expire == 0) {
2113                 lnk->flags &= ~LINK_PERMANENT;
2114                 DeleteLink(lnk);
2115         } else if (expire == -1) {
2116                 lnk->flags |= LINK_PERMANENT;
2117         } else if (expire > 0) {
2118                 lnk->expire_time = expire;
2119         } else {
2120 #ifdef LIBALIAS_DEBUG
2121                 fprintf(stderr, "PacketAlias/SetExpire(): ");
2122                 fprintf(stderr, "error in expire parameter\n");
2123 #endif
2124         }
2125 }
2126
2127 void
2128 ClearCheckNewLink(struct libalias *la)
2129 {
2130         
2131         LIBALIAS_LOCK_ASSERT(la);
2132         la->newDefaultLink = 0;
2133 }
2134
2135 void
2136 SetProtocolFlags(struct alias_link *lnk, int pflags)
2137 {
2138
2139         lnk->pflags = pflags;
2140 }
2141
2142 int
2143 GetProtocolFlags(struct alias_link *lnk)
2144 {
2145
2146         return (lnk->pflags);
2147 }
2148
2149 void
2150 SetDestCallId(struct alias_link *lnk, u_int16_t cid)
2151 {
2152         struct libalias *la = lnk->la;
2153
2154         LIBALIAS_LOCK_ASSERT(la);
2155         la->deleteAllLinks = 1;
2156         ReLink(lnk, lnk->src_addr, lnk->dst_addr, lnk->alias_addr,
2157             lnk->src_port, cid, lnk->alias_port, lnk->link_type);
2158         la->deleteAllLinks = 0;
2159 }
2160
2161
2162 /* Miscellaneous Functions
2163
2164     HouseKeeping()
2165     InitPacketAliasLog()
2166     UninitPacketAliasLog()
2167 */
2168
2169 /*
2170     Whenever an outgoing or incoming packet is handled, HouseKeeping()
2171     is called to find and remove timed-out aliasing links.  Logic exists
2172     to sweep through the entire table and linked list structure
2173     every 60 seconds.
2174
2175     (prototype in alias_local.h)
2176 */
2177
2178 void
2179 HouseKeeping(struct libalias *la)
2180 {
2181         int i, n;
2182 #ifndef _KERNEL
2183         struct timeval tv;
2184         struct timezone tz;
2185 #endif
2186
2187         LIBALIAS_LOCK_ASSERT(la);
2188         /*
2189          * Save system time (seconds) in global variable timeStamp for use
2190          * by other functions. This is done so as not to unnecessarily
2191          * waste timeline by making system calls.
2192          */
2193 #ifdef  _KERNEL
2194         la->timeStamp = time_uptime;
2195 #else
2196         gettimeofday(&tv, &tz);
2197         la->timeStamp = tv.tv_sec;
2198 #endif
2199
2200         /* Compute number of spokes (output table link chains) to cover */
2201         n = LINK_TABLE_OUT_SIZE * (la->timeStamp - la->lastCleanupTime);
2202         n /= ALIAS_CLEANUP_INTERVAL_SECS;
2203
2204         /* Handle different cases */
2205         if (n > 0) {
2206                 if (n > ALIAS_CLEANUP_MAX_SPOKES)
2207                         n = ALIAS_CLEANUP_MAX_SPOKES;
2208                 la->lastCleanupTime = la->timeStamp;
2209                 for (i = 0; i < n; i++)
2210                         IncrementalCleanup(la);
2211         } else if (n < 0) {
2212 #ifdef LIBALIAS_DEBUG
2213                 fprintf(stderr, "PacketAlias/HouseKeeping(): ");
2214                 fprintf(stderr, "something unexpected in time values\n");
2215 #endif
2216                 la->lastCleanupTime = la->timeStamp;
2217         }
2218 }
2219
2220 /* Init the log file and enable logging */
2221 static int
2222 InitPacketAliasLog(struct libalias *la)
2223 {
2224
2225         LIBALIAS_LOCK_ASSERT(la);
2226         if (~la->packetAliasMode & PKT_ALIAS_LOG) {
2227 #ifdef _KERNEL
2228                 if ((la->logDesc = malloc(LIBALIAS_BUF_SIZE)))
2229                         ;
2230 #else           
2231                 if ((la->logDesc = fopen("/var/log/alias.log", "w")))
2232                         fprintf(la->logDesc, "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n");               
2233 #endif
2234                 else 
2235                         return (ENOMEM); /* log initialization failed */
2236                 la->packetAliasMode |= PKT_ALIAS_LOG;
2237         }
2238
2239         return (1);
2240 }
2241
2242 /* Close the log-file and disable logging. */
2243 static void
2244 UninitPacketAliasLog(struct libalias *la)
2245 {
2246
2247         LIBALIAS_LOCK_ASSERT(la);
2248         if (la->logDesc) {
2249 #ifdef _KERNEL
2250                 free(la->logDesc);
2251 #else
2252                 fclose(la->logDesc);
2253 #endif
2254                 la->logDesc = NULL;
2255         }
2256         la->packetAliasMode &= ~PKT_ALIAS_LOG;
2257 }
2258
2259 /* Outside world interfaces
2260
2261 -- "outside world" means other than alias*.c routines --
2262
2263     PacketAliasRedirectPort()
2264     PacketAliasAddServer()
2265     PacketAliasRedirectProto()
2266     PacketAliasRedirectAddr()
2267     PacketAliasRedirectDynamic()
2268     PacketAliasRedirectDelete()
2269     PacketAliasSetAddress()
2270     PacketAliasInit()
2271     PacketAliasUninit()
2272     PacketAliasSetMode()
2273
2274 (prototypes in alias.h)
2275 */
2276
2277 /* Redirection from a specific public addr:port to a
2278    private addr:port */
2279 struct alias_link *
2280 LibAliasRedirectPort(struct libalias *la, struct in_addr src_addr, u_short src_port,
2281     struct in_addr dst_addr, u_short dst_port,
2282     struct in_addr alias_addr, u_short alias_port,
2283     u_char proto)
2284 {
2285         int link_type;
2286         struct alias_link *lnk;
2287
2288         LIBALIAS_LOCK(la);
2289         switch (proto) {
2290         case IPPROTO_UDP:
2291                 link_type = LINK_UDP;
2292                 break;
2293         case IPPROTO_TCP:
2294                 link_type = LINK_TCP;
2295                 break;
2296         case IPPROTO_SCTP:
2297                 link_type = LINK_SCTP;
2298                 break;
2299         default:
2300 #ifdef LIBALIAS_DEBUG
2301                 fprintf(stderr, "PacketAliasRedirectPort(): ");
2302                 fprintf(stderr, "only SCTP, TCP and UDP protocols allowed\n");
2303 #endif
2304                 lnk = NULL;
2305                 goto getout;
2306         }
2307
2308         lnk = AddLink(la, src_addr, dst_addr, alias_addr,
2309             src_port, dst_port, alias_port,
2310             link_type);
2311
2312         if (lnk != NULL) {
2313                 lnk->flags |= LINK_PERMANENT;
2314         }
2315 #ifdef LIBALIAS_DEBUG
2316         else {
2317                 fprintf(stderr, "PacketAliasRedirectPort(): "
2318                     "call to AddLink() failed\n");
2319         }
2320 #endif
2321
2322 getout:
2323         LIBALIAS_UNLOCK(la);
2324         return (lnk);
2325 }
2326
2327 /* Add server to the pool of servers */
2328 int
2329 LibAliasAddServer(struct libalias *la, struct alias_link *lnk, struct in_addr addr, u_short port)
2330 {
2331         struct server *server;
2332         int res;
2333
2334         LIBALIAS_LOCK(la);
2335         (void)la;
2336
2337         server = malloc(sizeof(struct server));
2338
2339         if (server != NULL) {
2340                 struct server *head;
2341
2342                 server->addr = addr;
2343                 server->port = port;
2344
2345                 head = lnk->server;
2346                 if (head == NULL)
2347                         server->next = server;
2348                 else {
2349                         struct server *s;
2350
2351                         for (s = head; s->next != head; s = s->next);
2352                         s->next = server;
2353                         server->next = head;
2354                 }
2355                 lnk->server = server;
2356                 res = 0;
2357         } else
2358                 res = -1;
2359
2360         LIBALIAS_UNLOCK(la);
2361         return (res);
2362 }
2363
2364 /* Redirect packets of a given IP protocol from a specific
2365    public address to a private address */
2366 struct alias_link *
2367 LibAliasRedirectProto(struct libalias *la, struct in_addr src_addr,
2368     struct in_addr dst_addr,
2369     struct in_addr alias_addr,
2370     u_char proto)
2371 {
2372         struct alias_link *lnk;
2373
2374         LIBALIAS_LOCK(la);
2375         lnk = AddLink(la, src_addr, dst_addr, alias_addr,
2376             NO_SRC_PORT, NO_DEST_PORT, 0,
2377             proto);
2378
2379         if (lnk != NULL) {
2380                 lnk->flags |= LINK_PERMANENT;
2381         }
2382 #ifdef LIBALIAS_DEBUG
2383         else {
2384                 fprintf(stderr, "PacketAliasRedirectProto(): "
2385                     "call to AddLink() failed\n");
2386         }
2387 #endif
2388
2389         LIBALIAS_UNLOCK(la);
2390         return (lnk);
2391 }
2392
2393 /* Static address translation */
2394 struct alias_link *
2395 LibAliasRedirectAddr(struct libalias *la, struct in_addr src_addr,
2396     struct in_addr alias_addr)
2397 {
2398         struct alias_link *lnk;
2399
2400         LIBALIAS_LOCK(la);
2401         lnk = AddLink(la, src_addr, la->nullAddress, alias_addr,
2402             0, 0, 0,
2403             LINK_ADDR);
2404
2405         if (lnk != NULL) {
2406                 lnk->flags |= LINK_PERMANENT;
2407         }
2408 #ifdef LIBALIAS_DEBUG
2409         else {
2410                 fprintf(stderr, "PacketAliasRedirectAddr(): "
2411                     "call to AddLink() failed\n");
2412         }
2413 #endif
2414
2415         LIBALIAS_UNLOCK(la);
2416         return (lnk);
2417 }
2418
2419
2420 /* Mark the aliasing link dynamic */
2421 int
2422 LibAliasRedirectDynamic(struct libalias *la, struct alias_link *lnk)
2423 {
2424         int res;
2425
2426         LIBALIAS_LOCK(la);
2427         (void)la;
2428
2429         if (lnk->flags & LINK_PARTIALLY_SPECIFIED)
2430                 res = -1;
2431         else {
2432                 lnk->flags &= ~LINK_PERMANENT;
2433                 res = 0;
2434         }
2435         LIBALIAS_UNLOCK(la);
2436         return (res);
2437 }
2438
2439
2440 void
2441 LibAliasRedirectDelete(struct libalias *la, struct alias_link *lnk)
2442 {
2443 /* This is a dangerous function to put in the API,
2444    because an invalid pointer can crash the program. */
2445
2446         LIBALIAS_LOCK(la);
2447         la->deleteAllLinks = 1;
2448         DeleteLink(lnk);
2449         la->deleteAllLinks = 0;
2450         LIBALIAS_UNLOCK(la);
2451 }
2452
2453
2454 void
2455 LibAliasSetAddress(struct libalias *la, struct in_addr addr)
2456 {
2457
2458         LIBALIAS_LOCK(la);
2459         if (la->packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE
2460             && la->aliasAddress.s_addr != addr.s_addr)
2461                 CleanupAliasData(la);
2462
2463         la->aliasAddress = addr;
2464         LIBALIAS_UNLOCK(la);
2465 }
2466
2467
2468 void
2469 LibAliasSetTarget(struct libalias *la, struct in_addr target_addr)
2470 {
2471
2472         LIBALIAS_LOCK(la);
2473         la->targetAddress = target_addr;
2474         LIBALIAS_UNLOCK(la);
2475 }
2476
2477 static void
2478 finishoff(void)
2479 {
2480
2481         while (!LIST_EMPTY(&instancehead))
2482                 LibAliasUninit(LIST_FIRST(&instancehead));
2483 }
2484
2485 struct libalias *
2486 LibAliasInit(struct libalias *la)
2487 {
2488         int i;
2489 #ifndef _KERNEL
2490         struct timeval tv;
2491         struct timezone tz;
2492 #endif
2493
2494         if (la == NULL) {
2495                 la = calloc(sizeof *la, 1);
2496                 if (la == NULL)
2497                         return (la);
2498
2499 #ifndef _KERNEL         /* kernel cleans up on module unload */
2500                 if (LIST_EMPTY(&instancehead))
2501                         atexit(finishoff);
2502 #endif
2503                 LIST_INSERT_HEAD(&instancehead, la, instancelist);
2504
2505 #ifdef  _KERNEL
2506                 la->timeStamp = time_uptime;
2507                 la->lastCleanupTime = time_uptime;
2508 #else
2509                 gettimeofday(&tv, &tz);
2510                 la->timeStamp = tv.tv_sec;
2511                 la->lastCleanupTime = tv.tv_sec;
2512 #endif
2513
2514                 for (i = 0; i < LINK_TABLE_OUT_SIZE; i++)
2515                         LIST_INIT(&la->linkTableOut[i]);
2516                 for (i = 0; i < LINK_TABLE_IN_SIZE; i++)
2517                         LIST_INIT(&la->linkTableIn[i]);
2518 #ifdef _KERNEL
2519                 AliasSctpInit(la);
2520 #endif
2521                 LIBALIAS_LOCK_INIT(la);
2522                 LIBALIAS_LOCK(la);
2523         } else {
2524                 LIBALIAS_LOCK(la);
2525                 la->deleteAllLinks = 1;
2526                 CleanupAliasData(la);
2527                 la->deleteAllLinks = 0;
2528 #ifdef _KERNEL
2529                 AliasSctpTerm(la);
2530                 AliasSctpInit(la);
2531 #endif
2532         }
2533
2534         la->aliasAddress.s_addr = INADDR_ANY;
2535         la->targetAddress.s_addr = INADDR_ANY;
2536
2537         la->icmpLinkCount = 0;
2538         la->udpLinkCount = 0;
2539         la->tcpLinkCount = 0;
2540         la->sctpLinkCount = 0;
2541         la->pptpLinkCount = 0;
2542         la->protoLinkCount = 0;
2543         la->fragmentIdLinkCount = 0;
2544         la->fragmentPtrLinkCount = 0;
2545         la->sockCount = 0;
2546
2547         la->cleanupIndex = 0;
2548
2549         la->packetAliasMode = PKT_ALIAS_SAME_PORTS
2550 #ifndef NO_USE_SOCKETS
2551             | PKT_ALIAS_USE_SOCKETS
2552 #endif
2553             | PKT_ALIAS_RESET_ON_ADDR_CHANGE;
2554 #ifndef NO_FW_PUNCH
2555         la->fireWallFD = -1;
2556 #endif
2557 #ifndef _KERNEL
2558         LibAliasRefreshModules();
2559 #endif
2560         LIBALIAS_UNLOCK(la);
2561         return (la);
2562 }
2563
2564 void
2565 LibAliasUninit(struct libalias *la)
2566 {
2567
2568         LIBALIAS_LOCK(la);
2569 #ifdef _KERNEL
2570         AliasSctpTerm(la);
2571 #endif
2572         la->deleteAllLinks = 1;
2573         CleanupAliasData(la);
2574         la->deleteAllLinks = 0;
2575         UninitPacketAliasLog(la);
2576 #ifndef NO_FW_PUNCH
2577         UninitPunchFW(la);
2578 #endif
2579         LIST_REMOVE(la, instancelist);
2580         LIBALIAS_UNLOCK(la);
2581         LIBALIAS_LOCK_DESTROY(la);
2582         free(la);
2583 }
2584
2585 /* Change mode for some operations */
2586 unsigned int
2587 LibAliasSetMode(
2588     struct libalias *la,
2589     unsigned int flags,         /* Which state to bring flags to */
2590     unsigned int mask           /* Mask of which flags to affect (use 0 to
2591                                  * do a probe for flag values) */
2592 )
2593 {
2594         int res = -1;
2595
2596         LIBALIAS_LOCK(la);
2597 /* Enable logging? */
2598         if (flags & mask & PKT_ALIAS_LOG) {
2599                 /* Do the enable */
2600                 if (InitPacketAliasLog(la) == ENOMEM)
2601                         goto getout;
2602         } else
2603 /* _Disable_ logging? */
2604         if (~flags & mask & PKT_ALIAS_LOG) {
2605                 UninitPacketAliasLog(la);
2606         }
2607 #ifndef NO_FW_PUNCH
2608 /* Start punching holes in the firewall? */
2609         if (flags & mask & PKT_ALIAS_PUNCH_FW) {
2610                 InitPunchFW(la);
2611         } else
2612 /* Stop punching holes in the firewall? */
2613         if (~flags & mask & PKT_ALIAS_PUNCH_FW) {
2614                 UninitPunchFW(la);
2615         }
2616 #endif
2617
2618 /* Other flags can be set/cleared without special action */
2619         la->packetAliasMode = (flags & mask) | (la->packetAliasMode & ~mask);
2620         res = la->packetAliasMode;
2621 getout:
2622         LIBALIAS_UNLOCK(la);
2623         return (res);
2624 }
2625
2626
2627 int
2628 LibAliasCheckNewLink(struct libalias *la)
2629 {
2630         int res;
2631
2632         LIBALIAS_LOCK(la);
2633         res = la->newDefaultLink;
2634         LIBALIAS_UNLOCK(la);
2635         return (res);
2636 }
2637
2638
2639 #ifndef NO_FW_PUNCH
2640
2641 /*****************
2642   Code to support firewall punching.  This shouldn't really be in this
2643   file, but making variables global is evil too.
2644   ****************/
2645
2646 /* Firewall include files */
2647 #include <net/if.h>
2648 #include <netinet/ip_fw.h>
2649 #include <string.h>
2650 #include <err.h>
2651
2652 /*
2653  * helper function, updates the pointer to cmd with the length
2654  * of the current command, and also cleans up the first word of
2655  * the new command in case it has been clobbered before.
2656  */
2657 static ipfw_insn *
2658 next_cmd(ipfw_insn * cmd)
2659 {
2660         cmd += F_LEN(cmd);
2661         bzero(cmd, sizeof(*cmd));
2662         return (cmd);
2663 }
2664
2665 /*
2666  * A function to fill simple commands of size 1.
2667  * Existing flags are preserved.
2668  */
2669 static ipfw_insn *
2670 fill_cmd(ipfw_insn * cmd, enum ipfw_opcodes opcode, int size,
2671     int flags, u_int16_t arg)
2672 {
2673         cmd->opcode = opcode;
2674         cmd->len = ((cmd->len | flags) & (F_NOT | F_OR)) | (size & F_LEN_MASK);
2675         cmd->arg1 = arg;
2676         return next_cmd(cmd);
2677 }
2678
2679 static ipfw_insn *
2680 fill_ip(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int32_t addr)
2681 {
2682         ipfw_insn_ip *cmd = (ipfw_insn_ip *) cmd1;
2683
2684         cmd->addr.s_addr = addr;
2685         return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u32), 0, 0);
2686 }
2687
2688 static ipfw_insn *
2689 fill_one_port(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int16_t port)
2690 {
2691         ipfw_insn_u16 *cmd = (ipfw_insn_u16 *) cmd1;
2692
2693         cmd->ports[0] = cmd->ports[1] = port;
2694         return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u16), 0, 0);
2695 }
2696
2697 static int
2698 fill_rule(void *buf, int bufsize, int rulenum,
2699     enum ipfw_opcodes action, int proto,
2700     struct in_addr sa, u_int16_t sp, struct in_addr da, u_int16_t dp)
2701 {
2702         struct ip_fw *rule = (struct ip_fw *)buf;
2703         ipfw_insn *cmd = (ipfw_insn *) rule->cmd;
2704
2705         bzero(buf, bufsize);
2706         rule->rulenum = rulenum;
2707
2708         cmd = fill_cmd(cmd, O_PROTO, F_INSN_SIZE(ipfw_insn), 0, proto);
2709         cmd = fill_ip(cmd, O_IP_SRC, sa.s_addr);
2710         cmd = fill_one_port(cmd, O_IP_SRCPORT, sp);
2711         cmd = fill_ip(cmd, O_IP_DST, da.s_addr);
2712         cmd = fill_one_port(cmd, O_IP_DSTPORT, dp);
2713
2714         rule->act_ofs = (u_int32_t *) cmd - (u_int32_t *) rule->cmd;
2715         cmd = fill_cmd(cmd, action, F_INSN_SIZE(ipfw_insn), 0, 0);
2716
2717         rule->cmd_len = (u_int32_t *) cmd - (u_int32_t *) rule->cmd;
2718
2719         return ((char *)cmd - (char *)buf);
2720 }
2721
2722 static void     ClearAllFWHoles(struct libalias *la);
2723
2724
2725 #define fw_setfield(la, field, num)                         \
2726 do {                                                    \
2727     (field)[(num) - la->fireWallBaseNum] = 1;               \
2728 } /*lint -save -e717 */ while(0)/* lint -restore */
2729
2730 #define fw_clrfield(la, field, num)                         \
2731 do {                                                    \
2732     (field)[(num) - la->fireWallBaseNum] = 0;               \
2733 } /*lint -save -e717 */ while(0)/* lint -restore */
2734
2735 #define fw_tstfield(la, field, num) ((field)[(num) - la->fireWallBaseNum])
2736
2737 static void
2738 InitPunchFW(struct libalias *la)
2739 {
2740
2741         LIBALIAS_LOCK_ASSERT(la);
2742         la->fireWallField = malloc(la->fireWallNumNums);
2743         if (la->fireWallField) {
2744                 memset(la->fireWallField, 0, la->fireWallNumNums);
2745                 if (la->fireWallFD < 0) {
2746                         la->fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
2747                 }
2748                 ClearAllFWHoles(la);
2749                 la->fireWallActiveNum = la->fireWallBaseNum;
2750         }
2751 }
2752
2753 static void
2754 UninitPunchFW(struct libalias *la)
2755 {
2756
2757         LIBALIAS_LOCK_ASSERT(la);
2758         ClearAllFWHoles(la);
2759         if (la->fireWallFD >= 0)
2760                 close(la->fireWallFD);
2761         la->fireWallFD = -1;
2762         if (la->fireWallField)
2763                 free(la->fireWallField);
2764         la->fireWallField = NULL;
2765         la->packetAliasMode &= ~PKT_ALIAS_PUNCH_FW;
2766 }
2767
2768 /* Make a certain link go through the firewall */
2769 void
2770 PunchFWHole(struct alias_link *lnk)
2771 {
2772         struct libalias *la;
2773         int r;                  /* Result code */
2774         struct ip_fw rule;      /* On-the-fly built rule */
2775         int fwhole;             /* Where to punch hole */
2776
2777         LIBALIAS_LOCK_ASSERT(la);
2778         la = lnk->la;
2779
2780 /* Don't do anything unless we are asked to */
2781         if (!(la->packetAliasMode & PKT_ALIAS_PUNCH_FW) ||
2782             la->fireWallFD < 0 ||
2783             lnk->link_type != LINK_TCP)
2784                 return;
2785
2786         memset(&rule, 0, sizeof rule);
2787
2788 /** Build rule **/
2789
2790         /* Find empty slot */
2791         for (fwhole = la->fireWallActiveNum;
2792             fwhole < la->fireWallBaseNum + la->fireWallNumNums &&
2793             fw_tstfield(la, la->fireWallField, fwhole);
2794             fwhole++);
2795         if (fwhole == la->fireWallBaseNum + la->fireWallNumNums) {
2796                 for (fwhole = la->fireWallBaseNum;
2797                     fwhole < la->fireWallActiveNum &&
2798                     fw_tstfield(la, la->fireWallField, fwhole);
2799                     fwhole++);
2800                 if (fwhole == la->fireWallActiveNum) {
2801                         /* No rule point empty - we can't punch more holes. */
2802                         la->fireWallActiveNum = la->fireWallBaseNum;
2803 #ifdef LIBALIAS_DEBUG
2804                         fprintf(stderr, "libalias: Unable to create firewall hole!\n");
2805 #endif
2806                         return;
2807                 }
2808         }
2809         /* Start next search at next position */
2810         la->fireWallActiveNum = fwhole + 1;
2811
2812         /*
2813          * generate two rules of the form
2814          *
2815          * add fwhole accept tcp from OAddr OPort to DAddr DPort add fwhole
2816          * accept tcp from DAddr DPort to OAddr OPort
2817          */
2818         if (GetOriginalPort(lnk) != 0 && GetDestPort(lnk) != 0) {
2819                 u_int32_t rulebuf[255];
2820                 int i;
2821
2822                 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
2823                     O_ACCEPT, IPPROTO_TCP,
2824                     GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk)),
2825                     GetDestAddress(lnk), ntohs(GetDestPort(lnk)));
2826                 r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
2827                 if (r)
2828                         err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)");
2829
2830                 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
2831                     O_ACCEPT, IPPROTO_TCP,
2832                     GetDestAddress(lnk), ntohs(GetDestPort(lnk)),
2833                     GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk)));
2834                 r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
2835                 if (r)
2836                         err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)");
2837         }
2838
2839 /* Indicate hole applied */
2840         lnk->data.tcp->fwhole = fwhole;
2841         fw_setfield(la, la->fireWallField, fwhole);
2842 }
2843
2844 /* Remove a hole in a firewall associated with a particular alias
2845    lnk.  Calling this too often is harmless. */
2846 static void
2847 ClearFWHole(struct alias_link *lnk)
2848 {
2849         struct libalias *la;
2850
2851         LIBALIAS_LOCK_ASSERT(la);
2852         la = lnk->la;
2853         if (lnk->link_type == LINK_TCP) {
2854                 int fwhole = lnk->data.tcp->fwhole;     /* Where is the firewall
2855                                                          * hole? */
2856                 struct ip_fw rule;
2857
2858                 if (fwhole < 0)
2859                         return;
2860
2861                 memset(&rule, 0, sizeof rule);  /* useless for ipfw2 */
2862                 while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL,
2863                     &fwhole, sizeof fwhole));
2864                 fw_clrfield(la, la->fireWallField, fwhole);
2865                 lnk->data.tcp->fwhole = -1;
2866         }
2867 }
2868
2869 /* Clear out the entire range dedicated to firewall holes. */
2870 static void
2871 ClearAllFWHoles(struct libalias *la)
2872 {
2873         struct ip_fw rule;      /* On-the-fly built rule */
2874         int i;
2875
2876         LIBALIAS_LOCK_ASSERT(la);
2877         if (la->fireWallFD < 0)
2878                 return;
2879
2880         memset(&rule, 0, sizeof rule);
2881         for (i = la->fireWallBaseNum; i < la->fireWallBaseNum + la->fireWallNumNums; i++) {
2882                 int r = i;
2883
2884                 while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL, &r, sizeof r));
2885         }
2886         /* XXX: third arg correct here ? /phk */
2887         memset(la->fireWallField, 0, la->fireWallNumNums);
2888 }
2889
2890 #endif
2891
2892 void
2893 LibAliasSetFWBase(struct libalias *la, unsigned int base, unsigned int num)
2894 {
2895
2896         LIBALIAS_LOCK(la);
2897 #ifndef NO_FW_PUNCH
2898         la->fireWallBaseNum = base;
2899         la->fireWallNumNums = num;
2900 #endif
2901         LIBALIAS_UNLOCK(la);
2902 }
2903
2904 void
2905 LibAliasSetSkinnyPort(struct libalias *la, unsigned int port)
2906 {
2907
2908         LIBALIAS_LOCK(la);
2909         la->skinnyPort = port;
2910         LIBALIAS_UNLOCK(la);
2911 }
2912
2913 /*
2914  * Find the address to redirect incoming packets
2915  */
2916 struct in_addr
2917 FindSctpRedirectAddress(struct libalias *la,  struct sctp_nat_msg *sm)
2918 {
2919         struct alias_link *lnk;
2920         struct in_addr redir;
2921
2922         LIBALIAS_LOCK_ASSERT(la);
2923         lnk = FindLinkIn(la, sm->ip_hdr->ip_src, sm->ip_hdr->ip_dst,
2924             sm->sctp_hdr->dest_port,sm->sctp_hdr->dest_port, LINK_SCTP, 1);
2925         if (lnk != NULL) {
2926                 return(lnk->src_addr); /* port redirect */
2927         } else {
2928                 redir = FindOriginalAddress(la,sm->ip_hdr->ip_dst);
2929                 if (redir.s_addr == la->aliasAddress.s_addr ||
2930                     redir.s_addr == la->targetAddress.s_addr) { /* No address found */
2931                         lnk = FindLinkIn(la, sm->ip_hdr->ip_src, sm->ip_hdr->ip_dst,
2932                             NO_DEST_PORT, 0, LINK_SCTP, 1);
2933                         if (lnk != NULL)
2934                                 return(lnk->src_addr); /* redirect proto */
2935                 }
2936                 return(redir); /* address redirect */
2937         }
2938 }