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