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