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