]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/netinet/libalias/alias_db.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.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
1980 int
1981 GetDeltaAckIn(struct ip *pip, 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         struct tcphdr *tc;
1991         int delta, ack_diff_min;
1992         u_long ack;
1993
1994         tc = ip_next(pip);
1995         ack = tc->th_ack;
1996
1997         delta = 0;
1998         ack_diff_min = -1;
1999         for (i = 0; i < N_LINK_TCP_DATA; i++) {
2000                 struct ack_data_record x;
2001
2002                 x = lnk->data.tcp->ack[i];
2003                 if (x.active == 1) {
2004                         int ack_diff;
2005
2006                         ack_diff = SeqDiff(x.ack_new, ack);
2007                         if (ack_diff >= 0) {
2008                                 if (ack_diff_min >= 0) {
2009                                         if (ack_diff < ack_diff_min) {
2010                                                 delta = x.delta;
2011                                                 ack_diff_min = ack_diff;
2012                                         }
2013                                 } else {
2014                                         delta = x.delta;
2015                                         ack_diff_min = ack_diff;
2016                                 }
2017                         }
2018                 }
2019         }
2020         return (delta);
2021 }
2022
2023
2024 int
2025 GetDeltaSeqOut(struct ip *pip, struct alias_link *lnk)
2026 {
2027 /*
2028 Find out how much the sequence number has been altered for an outgoing
2029 TCP packet.  To do this, a circular list of ACK numbers where the TCP
2030 packet size was altered is searched.
2031 */
2032
2033         int i;
2034         struct tcphdr *tc;
2035         int delta, seq_diff_min;
2036         u_long seq;
2037
2038         tc = ip_next(pip);
2039         seq = tc->th_seq;
2040
2041         delta = 0;
2042         seq_diff_min = -1;
2043         for (i = 0; i < N_LINK_TCP_DATA; i++) {
2044                 struct ack_data_record x;
2045
2046                 x = lnk->data.tcp->ack[i];
2047                 if (x.active == 1) {
2048                         int seq_diff;
2049
2050                         seq_diff = SeqDiff(x.ack_old, seq);
2051                         if (seq_diff >= 0) {
2052                                 if (seq_diff_min >= 0) {
2053                                         if (seq_diff < seq_diff_min) {
2054                                                 delta = x.delta;
2055                                                 seq_diff_min = seq_diff;
2056                                         }
2057                                 } else {
2058                                         delta = x.delta;
2059                                         seq_diff_min = seq_diff;
2060                                 }
2061                         }
2062                 }
2063         }
2064         return (delta);
2065 }
2066
2067
2068 void
2069 AddSeq(struct ip *pip, struct alias_link *lnk, int delta)
2070 {
2071 /*
2072 When a TCP packet has been altered in length, save this
2073 information in a circular list.  If enough packets have
2074 been altered, then this list will begin to overwrite itself.
2075 */
2076
2077         struct tcphdr *tc;
2078         struct ack_data_record x;
2079         int hlen, tlen, dlen;
2080         int i;
2081
2082         tc = ip_next(pip);
2083
2084         hlen = (pip->ip_hl + tc->th_off) << 2;
2085         tlen = ntohs(pip->ip_len);
2086         dlen = tlen - hlen;
2087
2088         x.ack_old = htonl(ntohl(tc->th_seq) + dlen);
2089         x.ack_new = htonl(ntohl(tc->th_seq) + dlen + delta);
2090         x.delta = delta;
2091         x.active = 1;
2092
2093         i = lnk->data.tcp->state.index;
2094         lnk->data.tcp->ack[i] = x;
2095
2096         i++;
2097         if (i == N_LINK_TCP_DATA)
2098                 lnk->data.tcp->state.index = 0;
2099         else
2100                 lnk->data.tcp->state.index = i;
2101 }
2102
2103 void
2104 SetExpire(struct alias_link *lnk, int expire)
2105 {
2106         if (expire == 0) {
2107                 lnk->flags &= ~LINK_PERMANENT;
2108                 DeleteLink(lnk);
2109         } else if (expire == -1) {
2110                 lnk->flags |= LINK_PERMANENT;
2111         } else if (expire > 0) {
2112                 lnk->expire_time = expire;
2113         } else {
2114 #ifdef LIBALIAS_DEBUG
2115                 fprintf(stderr, "PacketAlias/SetExpire(): ");
2116                 fprintf(stderr, "error in expire parameter\n");
2117 #endif
2118         }
2119 }
2120
2121 void
2122 ClearCheckNewLink(struct libalias *la)
2123 {
2124         
2125         LIBALIAS_LOCK_ASSERT(la);
2126         la->newDefaultLink = 0;
2127 }
2128
2129 void
2130 SetProtocolFlags(struct alias_link *lnk, int pflags)
2131 {
2132
2133         lnk->pflags = pflags;;
2134 }
2135
2136 int
2137 GetProtocolFlags(struct alias_link *lnk)
2138 {
2139
2140         return (lnk->pflags);
2141 }
2142
2143 void
2144 SetDestCallId(struct alias_link *lnk, u_int16_t cid)
2145 {
2146         struct libalias *la = lnk->la;
2147
2148         LIBALIAS_LOCK_ASSERT(la);
2149         la->deleteAllLinks = 1;
2150         ReLink(lnk, lnk->src_addr, lnk->dst_addr, lnk->alias_addr,
2151             lnk->src_port, cid, lnk->alias_port, lnk->link_type);
2152         la->deleteAllLinks = 0;
2153 }
2154
2155
2156 /* Miscellaneous Functions
2157
2158     HouseKeeping()
2159     InitPacketAliasLog()
2160     UninitPacketAliasLog()
2161 */
2162
2163 /*
2164     Whenever an outgoing or incoming packet is handled, HouseKeeping()
2165     is called to find and remove timed-out aliasing links.  Logic exists
2166     to sweep through the entire table and linked list structure
2167     every 60 seconds.
2168
2169     (prototype in alias_local.h)
2170 */
2171
2172 void
2173 HouseKeeping(struct libalias *la)
2174 {
2175         int i, n;
2176 #ifndef _KERNEL
2177         struct timeval tv;
2178         struct timezone tz;
2179 #endif
2180
2181         LIBALIAS_LOCK_ASSERT(la);
2182         /*
2183          * Save system time (seconds) in global variable timeStamp for use
2184          * by other functions. This is done so as not to unnecessarily
2185          * waste timeline by making system calls.
2186          */
2187 #ifdef  _KERNEL
2188         la->timeStamp = time_uptime;
2189 #else
2190         gettimeofday(&tv, &tz);
2191         la->timeStamp = tv.tv_sec;
2192 #endif
2193
2194         /* Compute number of spokes (output table link chains) to cover */
2195         n = LINK_TABLE_OUT_SIZE * (la->timeStamp - la->lastCleanupTime);
2196         n /= ALIAS_CLEANUP_INTERVAL_SECS;
2197
2198         /* Handle different cases */
2199         if (n > 0) {
2200                 if (n > ALIAS_CLEANUP_MAX_SPOKES)
2201                         n = ALIAS_CLEANUP_MAX_SPOKES;
2202                 la->lastCleanupTime = la->timeStamp;
2203                 for (i = 0; i < n; i++)
2204                         IncrementalCleanup(la);
2205         } else if (n < 0) {
2206 #ifdef LIBALIAS_DEBUG
2207                 fprintf(stderr, "PacketAlias/HouseKeeping(): ");
2208                 fprintf(stderr, "something unexpected in time values\n");
2209 #endif
2210                 la->lastCleanupTime = la->timeStamp;
2211         }
2212 }
2213
2214 /* Init the log file and enable logging */
2215 static int
2216 InitPacketAliasLog(struct libalias *la)
2217 {
2218
2219         LIBALIAS_LOCK_ASSERT(la);
2220         if (~la->packetAliasMode & PKT_ALIAS_LOG) {
2221 #ifdef _KERNEL
2222                 if ((la->logDesc = malloc(LIBALIAS_BUF_SIZE)))
2223                         ;
2224 #else           
2225                 if ((la->logDesc = fopen("/var/log/alias.log", "w")))
2226                         fprintf(la->logDesc, "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n");               
2227 #endif
2228                 else 
2229                         return (ENOMEM); /* log initialization failed */
2230                 la->packetAliasMode |= PKT_ALIAS_LOG;
2231         }
2232
2233         return (1);
2234 }
2235
2236 /* Close the log-file and disable logging. */
2237 static void
2238 UninitPacketAliasLog(struct libalias *la)
2239 {
2240
2241         LIBALIAS_LOCK_ASSERT(la);
2242         if (la->logDesc) {
2243 #ifdef _KERNEL
2244                 free(la->logDesc);
2245 #else
2246                 fclose(la->logDesc);
2247 #endif
2248                 la->logDesc = NULL;
2249         }
2250         la->packetAliasMode &= ~PKT_ALIAS_LOG;
2251 }
2252
2253 /* Outside world interfaces
2254
2255 -- "outside world" means other than alias*.c routines --
2256
2257     PacketAliasRedirectPort()
2258     PacketAliasAddServer()
2259     PacketAliasRedirectProto()
2260     PacketAliasRedirectAddr()
2261     PacketAliasRedirectDynamic()
2262     PacketAliasRedirectDelete()
2263     PacketAliasSetAddress()
2264     PacketAliasInit()
2265     PacketAliasUninit()
2266     PacketAliasSetMode()
2267
2268 (prototypes in alias.h)
2269 */
2270
2271 /* Redirection from a specific public addr:port to a
2272    private addr:port */
2273 struct alias_link *
2274 LibAliasRedirectPort(struct libalias *la, struct in_addr src_addr, u_short src_port,
2275     struct in_addr dst_addr, u_short dst_port,
2276     struct in_addr alias_addr, u_short alias_port,
2277     u_char proto)
2278 {
2279         int link_type;
2280         struct alias_link *lnk;
2281
2282         LIBALIAS_LOCK(la);
2283         switch (proto) {
2284         case IPPROTO_UDP:
2285                 link_type = LINK_UDP;
2286                 break;
2287         case IPPROTO_TCP:
2288                 link_type = LINK_TCP;
2289                 break;
2290         default:
2291 #ifdef LIBALIAS_DEBUG
2292                 fprintf(stderr, "PacketAliasRedirectPort(): ");
2293                 fprintf(stderr, "only TCP and UDP protocols allowed\n");
2294 #endif
2295                 lnk = NULL;
2296                 goto getout;
2297         }
2298
2299         lnk = AddLink(la, src_addr, dst_addr, alias_addr,
2300             src_port, dst_port, alias_port,
2301             link_type);
2302
2303         if (lnk != NULL) {
2304                 lnk->flags |= LINK_PERMANENT;
2305         }
2306 #ifdef LIBALIAS_DEBUG
2307         else {
2308                 fprintf(stderr, "PacketAliasRedirectPort(): "
2309                     "call to AddLink() failed\n");
2310         }
2311 #endif
2312
2313 getout:
2314         LIBALIAS_UNLOCK(la);
2315         return (lnk);
2316 }
2317
2318 /* Add server to the pool of servers */
2319 int
2320 LibAliasAddServer(struct libalias *la, struct alias_link *lnk, struct in_addr addr, u_short port)
2321 {
2322         struct server *server;
2323         int res;
2324
2325         LIBALIAS_LOCK(la);
2326         (void)la;
2327
2328         server = malloc(sizeof(struct server));
2329
2330         if (server != NULL) {
2331                 struct server *head;
2332
2333                 server->addr = addr;
2334                 server->port = port;
2335
2336                 head = lnk->server;
2337                 if (head == NULL)
2338                         server->next = server;
2339                 else {
2340                         struct server *s;
2341
2342                         for (s = head; s->next != head; s = s->next);
2343                         s->next = server;
2344                         server->next = head;
2345                 }
2346                 lnk->server = server;
2347                 res = 0;
2348         } else
2349                 res = -1;
2350
2351         LIBALIAS_UNLOCK(la);
2352         return (res);
2353 }
2354
2355 /* Redirect packets of a given IP protocol from a specific
2356    public address to a private address */
2357 struct alias_link *
2358 LibAliasRedirectProto(struct libalias *la, struct in_addr src_addr,
2359     struct in_addr dst_addr,
2360     struct in_addr alias_addr,
2361     u_char proto)
2362 {
2363         struct alias_link *lnk;
2364
2365         LIBALIAS_LOCK(la);
2366         lnk = AddLink(la, src_addr, dst_addr, alias_addr,
2367             NO_SRC_PORT, NO_DEST_PORT, 0,
2368             proto);
2369
2370         if (lnk != NULL) {
2371                 lnk->flags |= LINK_PERMANENT;
2372         }
2373 #ifdef LIBALIAS_DEBUG
2374         else {
2375                 fprintf(stderr, "PacketAliasRedirectProto(): "
2376                     "call to AddLink() failed\n");
2377         }
2378 #endif
2379
2380         LIBALIAS_UNLOCK(la);
2381         return (lnk);
2382 }
2383
2384 /* Static address translation */
2385 struct alias_link *
2386 LibAliasRedirectAddr(struct libalias *la, struct in_addr src_addr,
2387     struct in_addr alias_addr)
2388 {
2389         struct alias_link *lnk;
2390
2391         LIBALIAS_LOCK(la);
2392         lnk = AddLink(la, src_addr, la->nullAddress, alias_addr,
2393             0, 0, 0,
2394             LINK_ADDR);
2395
2396         if (lnk != NULL) {
2397                 lnk->flags |= LINK_PERMANENT;
2398         }
2399 #ifdef LIBALIAS_DEBUG
2400         else {
2401                 fprintf(stderr, "PacketAliasRedirectAddr(): "
2402                     "call to AddLink() failed\n");
2403         }
2404 #endif
2405
2406         LIBALIAS_UNLOCK(la);
2407         return (lnk);
2408 }
2409
2410
2411 /* Mark the aliasing link dynamic */
2412 int
2413 LibAliasRedirectDynamic(struct libalias *la, struct alias_link *lnk)
2414 {
2415         int res;
2416
2417         LIBALIAS_LOCK(la);
2418         (void)la;
2419
2420         if (lnk->flags & LINK_PARTIALLY_SPECIFIED)
2421                 res = -1;
2422         else {
2423                 lnk->flags &= ~LINK_PERMANENT;
2424                 res = 0;
2425         }
2426         LIBALIAS_UNLOCK(la);
2427         return (res);
2428 }
2429
2430
2431 void
2432 LibAliasRedirectDelete(struct libalias *la, struct alias_link *lnk)
2433 {
2434 /* This is a dangerous function to put in the API,
2435    because an invalid pointer can crash the program. */
2436
2437         LIBALIAS_LOCK(la);
2438         la->deleteAllLinks = 1;
2439         DeleteLink(lnk);
2440         la->deleteAllLinks = 0;
2441         LIBALIAS_UNLOCK(la);
2442 }
2443
2444
2445 void
2446 LibAliasSetAddress(struct libalias *la, struct in_addr addr)
2447 {
2448
2449         LIBALIAS_LOCK(la);
2450         if (la->packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE
2451             && la->aliasAddress.s_addr != addr.s_addr)
2452                 CleanupAliasData(la);
2453
2454         la->aliasAddress = addr;
2455         LIBALIAS_UNLOCK(la);
2456 }
2457
2458
2459 void
2460 LibAliasSetTarget(struct libalias *la, struct in_addr target_addr)
2461 {
2462
2463         LIBALIAS_LOCK(la);
2464         la->targetAddress = target_addr;
2465         LIBALIAS_UNLOCK(la);
2466 }
2467
2468 static void
2469 finishoff(void)
2470 {
2471
2472         while (!LIST_EMPTY(&instancehead))
2473                 LibAliasUninit(LIST_FIRST(&instancehead));
2474 }
2475
2476 struct libalias *
2477 LibAliasInit(struct libalias *la)
2478 {
2479         int i;
2480 #ifndef _KERNEL
2481         struct timeval tv;
2482         struct timezone tz;
2483 #endif
2484
2485         if (la == NULL) {
2486                 la = calloc(sizeof *la, 1);
2487                 if (la == NULL)
2488                         return (la);
2489
2490 #ifndef _KERNEL         /* kernel cleans up on module unload */
2491                 if (LIST_EMPTY(&instancehead))
2492                         atexit(finishoff);
2493 #endif
2494                 LIST_INSERT_HEAD(&instancehead, la, instancelist);
2495
2496 #ifdef  _KERNEL
2497                 la->timeStamp = time_uptime;
2498                 la->lastCleanupTime = time_uptime;
2499 #else
2500                 gettimeofday(&tv, &tz);
2501                 la->timeStamp = tv.tv_sec;
2502                 la->lastCleanupTime = tv.tv_sec;
2503 #endif
2504
2505                 for (i = 0; i < LINK_TABLE_OUT_SIZE; i++)
2506                         LIST_INIT(&la->linkTableOut[i]);
2507                 for (i = 0; i < LINK_TABLE_IN_SIZE; i++)
2508                         LIST_INIT(&la->linkTableIn[i]);
2509                 LIBALIAS_LOCK_INIT(la);
2510                 LIBALIAS_LOCK(la);
2511         } else {
2512                 LIBALIAS_LOCK(la);
2513                 la->deleteAllLinks = 1;
2514                 CleanupAliasData(la);
2515                 la->deleteAllLinks = 0;
2516         }
2517
2518         la->aliasAddress.s_addr = INADDR_ANY;
2519         la->targetAddress.s_addr = INADDR_ANY;
2520
2521         la->icmpLinkCount = 0;
2522         la->udpLinkCount = 0;
2523         la->tcpLinkCount = 0;
2524         la->pptpLinkCount = 0;
2525         la->protoLinkCount = 0;
2526         la->fragmentIdLinkCount = 0;
2527         la->fragmentPtrLinkCount = 0;
2528         la->sockCount = 0;
2529
2530         la->cleanupIndex = 0;
2531
2532         la->packetAliasMode = PKT_ALIAS_SAME_PORTS
2533 #ifndef NO_USE_SOCKETS
2534             | PKT_ALIAS_USE_SOCKETS
2535 #endif
2536             | PKT_ALIAS_RESET_ON_ADDR_CHANGE;
2537 #ifndef NO_FW_PUNCH
2538         la->fireWallFD = -1;
2539 #endif
2540 #ifndef _KERNEL
2541         LibAliasRefreshModules();
2542 #endif
2543         LIBALIAS_UNLOCK(la);
2544         return (la);
2545 }
2546
2547 void
2548 LibAliasUninit(struct libalias *la)
2549 {
2550
2551         LIBALIAS_LOCK(la);
2552         la->deleteAllLinks = 1;
2553         CleanupAliasData(la);
2554         la->deleteAllLinks = 0;
2555         UninitPacketAliasLog(la);
2556 #ifndef NO_FW_PUNCH
2557         UninitPunchFW(la);
2558 #endif
2559         LIST_REMOVE(la, instancelist);
2560         LIBALIAS_UNLOCK(la);
2561         LIBALIAS_LOCK_DESTROY(la);
2562         free(la);
2563 }
2564
2565 /* Change mode for some operations */
2566 unsigned int
2567 LibAliasSetMode(
2568     struct libalias *la,
2569     unsigned int flags,         /* Which state to bring flags to */
2570     unsigned int mask           /* Mask of which flags to affect (use 0 to
2571                                  * do a probe for flag values) */
2572 )
2573 {
2574         int res = -1;
2575
2576         LIBALIAS_LOCK(la);
2577 /* Enable logging? */
2578         if (flags & mask & PKT_ALIAS_LOG) {
2579                 /* Do the enable */
2580                 if (InitPacketAliasLog(la) == ENOMEM)
2581                         goto getout;
2582         } else
2583 /* _Disable_ logging? */
2584         if (~flags & mask & PKT_ALIAS_LOG) {
2585                 UninitPacketAliasLog(la);
2586         }
2587 #ifndef NO_FW_PUNCH
2588 /* Start punching holes in the firewall? */
2589         if (flags & mask & PKT_ALIAS_PUNCH_FW) {
2590                 InitPunchFW(la);
2591         } else
2592 /* Stop punching holes in the firewall? */
2593         if (~flags & mask & PKT_ALIAS_PUNCH_FW) {
2594                 UninitPunchFW(la);
2595         }
2596 #endif
2597
2598 /* Other flags can be set/cleared without special action */
2599         la->packetAliasMode = (flags & mask) | (la->packetAliasMode & ~mask);
2600         res = la->packetAliasMode;
2601 getout:
2602         LIBALIAS_UNLOCK(la);
2603         return (res);
2604 }
2605
2606
2607 int
2608 LibAliasCheckNewLink(struct libalias *la)
2609 {
2610         int res;
2611
2612         LIBALIAS_LOCK(la);
2613         res = la->newDefaultLink;
2614         LIBALIAS_UNLOCK(la);
2615         return (res);
2616 }
2617
2618
2619 #ifndef NO_FW_PUNCH
2620
2621 /*****************
2622   Code to support firewall punching.  This shouldn't really be in this
2623   file, but making variables global is evil too.
2624   ****************/
2625
2626 /* Firewall include files */
2627 #include <net/if.h>
2628 #include <netinet/ip_fw.h>
2629 #include <string.h>
2630 #include <err.h>
2631
2632 /*
2633  * helper function, updates the pointer to cmd with the length
2634  * of the current command, and also cleans up the first word of
2635  * the new command in case it has been clobbered before.
2636  */
2637 static ipfw_insn *
2638 next_cmd(ipfw_insn * cmd)
2639 {
2640         cmd += F_LEN(cmd);
2641         bzero(cmd, sizeof(*cmd));
2642         return (cmd);
2643 }
2644
2645 /*
2646  * A function to fill simple commands of size 1.
2647  * Existing flags are preserved.
2648  */
2649 static ipfw_insn *
2650 fill_cmd(ipfw_insn * cmd, enum ipfw_opcodes opcode, int size,
2651     int flags, u_int16_t arg)
2652 {
2653         cmd->opcode = opcode;
2654         cmd->len = ((cmd->len | flags) & (F_NOT | F_OR)) | (size & F_LEN_MASK);
2655         cmd->arg1 = arg;
2656         return next_cmd(cmd);
2657 }
2658
2659 static ipfw_insn *
2660 fill_ip(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int32_t addr)
2661 {
2662         ipfw_insn_ip *cmd = (ipfw_insn_ip *) cmd1;
2663
2664         cmd->addr.s_addr = addr;
2665         return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u32), 0, 0);
2666 }
2667
2668 static ipfw_insn *
2669 fill_one_port(ipfw_insn * cmd1, enum ipfw_opcodes opcode, u_int16_t port)
2670 {
2671         ipfw_insn_u16 *cmd = (ipfw_insn_u16 *) cmd1;
2672
2673         cmd->ports[0] = cmd->ports[1] = port;
2674         return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u16), 0, 0);
2675 }
2676
2677 static int
2678 fill_rule(void *buf, int bufsize, int rulenum,
2679     enum ipfw_opcodes action, int proto,
2680     struct in_addr sa, u_int16_t sp, struct in_addr da, u_int16_t dp)
2681 {
2682         struct ip_fw *rule = (struct ip_fw *)buf;
2683         ipfw_insn *cmd = (ipfw_insn *) rule->cmd;
2684
2685         bzero(buf, bufsize);
2686         rule->rulenum = rulenum;
2687
2688         cmd = fill_cmd(cmd, O_PROTO, F_INSN_SIZE(ipfw_insn), 0, proto);
2689         cmd = fill_ip(cmd, O_IP_SRC, sa.s_addr);
2690         cmd = fill_one_port(cmd, O_IP_SRCPORT, sp);
2691         cmd = fill_ip(cmd, O_IP_DST, da.s_addr);
2692         cmd = fill_one_port(cmd, O_IP_DSTPORT, dp);
2693
2694         rule->act_ofs = (u_int32_t *) cmd - (u_int32_t *) rule->cmd;
2695         cmd = fill_cmd(cmd, action, F_INSN_SIZE(ipfw_insn), 0, 0);
2696
2697         rule->cmd_len = (u_int32_t *) cmd - (u_int32_t *) rule->cmd;
2698
2699         return ((char *)cmd - (char *)buf);
2700 }
2701
2702 static void     ClearAllFWHoles(struct libalias *la);
2703
2704
2705 #define fw_setfield(la, field, num)                         \
2706 do {                                                    \
2707     (field)[(num) - la->fireWallBaseNum] = 1;               \
2708 } /*lint -save -e717 */ while(0)/* lint -restore */
2709
2710 #define fw_clrfield(la, field, num)                         \
2711 do {                                                    \
2712     (field)[(num) - la->fireWallBaseNum] = 0;               \
2713 } /*lint -save -e717 */ while(0)/* lint -restore */
2714
2715 #define fw_tstfield(la, field, num) ((field)[(num) - la->fireWallBaseNum])
2716
2717 static void
2718 InitPunchFW(struct libalias *la)
2719 {
2720
2721         LIBALIAS_LOCK_ASSERT(la);
2722         la->fireWallField = malloc(la->fireWallNumNums);
2723         if (la->fireWallField) {
2724                 memset(la->fireWallField, 0, la->fireWallNumNums);
2725                 if (la->fireWallFD < 0) {
2726                         la->fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
2727                 }
2728                 ClearAllFWHoles(la);
2729                 la->fireWallActiveNum = la->fireWallBaseNum;
2730         }
2731 }
2732
2733 static void
2734 UninitPunchFW(struct libalias *la)
2735 {
2736
2737         LIBALIAS_LOCK_ASSERT(la);
2738         ClearAllFWHoles(la);
2739         if (la->fireWallFD >= 0)
2740                 close(la->fireWallFD);
2741         la->fireWallFD = -1;
2742         if (la->fireWallField)
2743                 free(la->fireWallField);
2744         la->fireWallField = NULL;
2745         la->packetAliasMode &= ~PKT_ALIAS_PUNCH_FW;
2746 }
2747
2748 /* Make a certain link go through the firewall */
2749 void
2750 PunchFWHole(struct alias_link *lnk)
2751 {
2752         struct libalias *la;
2753         int r;                  /* Result code */
2754         struct ip_fw rule;      /* On-the-fly built rule */
2755         int fwhole;             /* Where to punch hole */
2756
2757         LIBALIAS_LOCK_ASSERT(la);
2758         la = lnk->la;
2759
2760 /* Don't do anything unless we are asked to */
2761         if (!(la->packetAliasMode & PKT_ALIAS_PUNCH_FW) ||
2762             la->fireWallFD < 0 ||
2763             lnk->link_type != LINK_TCP)
2764                 return;
2765
2766         memset(&rule, 0, sizeof rule);
2767
2768 /** Build rule **/
2769
2770         /* Find empty slot */
2771         for (fwhole = la->fireWallActiveNum;
2772             fwhole < la->fireWallBaseNum + la->fireWallNumNums &&
2773             fw_tstfield(la, la->fireWallField, fwhole);
2774             fwhole++);
2775         if (fwhole == la->fireWallBaseNum + la->fireWallNumNums) {
2776                 for (fwhole = la->fireWallBaseNum;
2777                     fwhole < la->fireWallActiveNum &&
2778                     fw_tstfield(la, la->fireWallField, fwhole);
2779                     fwhole++);
2780                 if (fwhole == la->fireWallActiveNum) {
2781                         /* No rule point empty - we can't punch more holes. */
2782                         la->fireWallActiveNum = la->fireWallBaseNum;
2783 #ifdef LIBALIAS_DEBUG
2784                         fprintf(stderr, "libalias: Unable to create firewall hole!\n");
2785 #endif
2786                         return;
2787                 }
2788         }
2789         /* Start next search at next position */
2790         la->fireWallActiveNum = fwhole + 1;
2791
2792         /*
2793          * generate two rules of the form
2794          *
2795          * add fwhole accept tcp from OAddr OPort to DAddr DPort add fwhole
2796          * accept tcp from DAddr DPort to OAddr OPort
2797          */
2798         if (GetOriginalPort(lnk) != 0 && GetDestPort(lnk) != 0) {
2799                 u_int32_t rulebuf[255];
2800                 int i;
2801
2802                 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
2803                     O_ACCEPT, IPPROTO_TCP,
2804                     GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk)),
2805                     GetDestAddress(lnk), ntohs(GetDestPort(lnk)));
2806                 r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
2807                 if (r)
2808                         err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)");
2809
2810                 i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
2811                     O_ACCEPT, IPPROTO_TCP,
2812                     GetDestAddress(lnk), ntohs(GetDestPort(lnk)),
2813                     GetOriginalAddress(lnk), ntohs(GetOriginalPort(lnk)));
2814                 r = setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
2815                 if (r)
2816                         err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)");
2817         }
2818
2819 /* Indicate hole applied */
2820         lnk->data.tcp->fwhole = fwhole;
2821         fw_setfield(la, la->fireWallField, fwhole);
2822 }
2823
2824 /* Remove a hole in a firewall associated with a particular alias
2825    lnk.  Calling this too often is harmless. */
2826 static void
2827 ClearFWHole(struct alias_link *lnk)
2828 {
2829         struct libalias *la;
2830
2831         LIBALIAS_LOCK_ASSERT(la);
2832         la = lnk->la;
2833         if (lnk->link_type == LINK_TCP) {
2834                 int fwhole = lnk->data.tcp->fwhole;     /* Where is the firewall
2835                                                          * hole? */
2836                 struct ip_fw rule;
2837
2838                 if (fwhole < 0)
2839                         return;
2840
2841                 memset(&rule, 0, sizeof rule);  /* useless for ipfw2 */
2842                 while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL,
2843                     &fwhole, sizeof fwhole));
2844                 fw_clrfield(la, la->fireWallField, fwhole);
2845                 lnk->data.tcp->fwhole = -1;
2846         }
2847 }
2848
2849 /* Clear out the entire range dedicated to firewall holes. */
2850 static void
2851 ClearAllFWHoles(struct libalias *la)
2852 {
2853         struct ip_fw rule;      /* On-the-fly built rule */
2854         int i;
2855
2856         LIBALIAS_LOCK_ASSERT(la);
2857         if (la->fireWallFD < 0)
2858                 return;
2859
2860         memset(&rule, 0, sizeof rule);
2861         for (i = la->fireWallBaseNum; i < la->fireWallBaseNum + la->fireWallNumNums; i++) {
2862                 int r = i;
2863
2864                 while (!setsockopt(la->fireWallFD, IPPROTO_IP, IP_FW_DEL, &r, sizeof r));
2865         }
2866         /* XXX: third arg correct here ? /phk */
2867         memset(la->fireWallField, 0, la->fireWallNumNums);
2868 }
2869
2870 #endif
2871
2872 void
2873 LibAliasSetFWBase(struct libalias *la, unsigned int base, unsigned int num)
2874 {
2875
2876         LIBALIAS_LOCK(la);
2877 #ifndef NO_FW_PUNCH
2878         la->fireWallBaseNum = base;
2879         la->fireWallNumNums = num;
2880 #endif
2881         LIBALIAS_UNLOCK(la);
2882 }
2883
2884 void
2885 LibAliasSetSkinnyPort(struct libalias *la, unsigned int port)
2886 {
2887
2888         LIBALIAS_LOCK(la);
2889         la->skinnyPort = port;
2890         LIBALIAS_UNLOCK(la);
2891 }