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