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