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