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