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