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