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