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