xref: /freebsd/sys/netinet/libalias/alias_db.c (revision 95d674824fe3a2e102b1463fec040433d86532a6)
1 /*  -*- mode: c; tab-width: 8; c-basic-indent: 4; -*- */
2 
3 /*-
4  * Copyright (c) 2001 Charles Mott <cmott@scientech.com>
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$
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 <errno.h>
149 #include <stdlib.h>
150 #include <stdio.h>
151 #include <unistd.h>
152 
153 #include <sys/queue.h>
154 #include <sys/socket.h>
155 #include <sys/time.h>
156 #include <sys/types.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     int pflags;                  /* protocol-specific flags */
308 
309 /* flag bits */
310 #define LINK_UNKNOWN_DEST_PORT     0x01
311 #define LINK_UNKNOWN_DEST_ADDR     0x02
312 #define LINK_PERMANENT             0x04
313 #define LINK_PARTIALLY_SPECIFIED   0x03 /* logical-or of first two bits */
314 #define LINK_UNFIREWALLED          0x08
315 
316     int timestamp;               /* Time link was last accessed         */
317     int expire_time;             /* Expire time for link                */
318 
319     int sockfd;                  /* socket descriptor                   */
320 
321     LIST_ENTRY(alias_link) list_out; /* Linked list of pointers for     */
322     LIST_ENTRY(alias_link) list_in;  /* input and output lookup tables  */
323 
324     union                        /* Auxiliary data                      */
325     {
326         char *frag_ptr;
327         struct in_addr frag_addr;
328         struct tcp_dat *tcp;
329     } data;
330 };
331 
332 
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 (0 != (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->pflags            = 0;
1020         link->timestamp         = timeStamp;
1021 
1022     /* Expiration time */
1023         switch (link_type)
1024         {
1025         case LINK_ICMP:
1026             link->expire_time = ICMP_EXPIRE_TIME;
1027             break;
1028         case LINK_UDP:
1029             link->expire_time = UDP_EXPIRE_TIME;
1030             break;
1031         case LINK_TCP:
1032             link->expire_time = TCP_EXPIRE_INITIAL;
1033             break;
1034         case LINK_PPTP:
1035             link->flags |= LINK_PERMANENT;	/* no timeout. */
1036             break;
1037         case LINK_FRAGMENT_ID:
1038             link->expire_time = FRAGMENT_ID_EXPIRE_TIME;
1039             break;
1040         case LINK_FRAGMENT_PTR:
1041             link->expire_time = FRAGMENT_PTR_EXPIRE_TIME;
1042             break;
1043 	case LINK_ADDR:
1044 	    break;
1045         default:
1046             link->expire_time = PROTO_EXPIRE_TIME;
1047             break;
1048         }
1049 
1050     /* Determine alias flags */
1051         if (dst_addr.s_addr == INADDR_ANY)
1052             link->flags |= LINK_UNKNOWN_DEST_ADDR;
1053         if (dst_port == 0)
1054             link->flags |= LINK_UNKNOWN_DEST_PORT;
1055 
1056     /* Determine alias port */
1057         if (GetNewPort(link, alias_port_param) != 0)
1058         {
1059             free(link);
1060             return(NULL);
1061         }
1062 
1063     /* Link-type dependent initialization */
1064         switch(link_type)
1065         {
1066             struct tcp_dat  *aux_tcp;
1067 
1068             case LINK_ICMP:
1069                 icmpLinkCount++;
1070                 break;
1071             case LINK_UDP:
1072                 udpLinkCount++;
1073                 break;
1074             case LINK_TCP:
1075                 aux_tcp = malloc(sizeof(struct tcp_dat));
1076                 if (aux_tcp != NULL)
1077                 {
1078                     int i;
1079 
1080                     tcpLinkCount++;
1081                     aux_tcp->state.in = ALIAS_TCP_STATE_NOT_CONNECTED;
1082                     aux_tcp->state.out = ALIAS_TCP_STATE_NOT_CONNECTED;
1083                     aux_tcp->state.index = 0;
1084                     aux_tcp->state.ack_modified = 0;
1085                     for (i=0; i<N_LINK_TCP_DATA; i++)
1086                         aux_tcp->ack[i].active = 0;
1087                     aux_tcp->fwhole = -1;
1088                     link->data.tcp = aux_tcp;
1089                 }
1090                 else
1091                 {
1092 #ifdef DEBUG
1093                     fprintf(stderr, "PacketAlias/AddLink: ");
1094                     fprintf(stderr, " cannot allocate auxiliary TCP data\n");
1095 #endif
1096 		    free(link);
1097 		    return (NULL);
1098                 }
1099                 break;
1100             case LINK_PPTP:
1101                 pptpLinkCount++;
1102                 break;
1103             case LINK_FRAGMENT_ID:
1104                 fragmentIdLinkCount++;
1105                 break;
1106             case LINK_FRAGMENT_PTR:
1107                 fragmentPtrLinkCount++;
1108                 break;
1109 	    case LINK_ADDR:
1110 		break;
1111             default:
1112                 protoLinkCount++;
1113                 break;
1114         }
1115 
1116     /* Set up pointers for output lookup table */
1117         start_point = StartPointOut(src_addr, dst_addr,
1118                                     src_port, dst_port, link_type);
1119         LIST_INSERT_HEAD(&linkTableOut[start_point], link, list_out);
1120 
1121     /* Set up pointers for input lookup table */
1122         start_point = StartPointIn(alias_addr, link->alias_port, link_type);
1123         LIST_INSERT_HEAD(&linkTableIn[start_point], link, list_in);
1124     }
1125     else
1126     {
1127 #ifdef DEBUG
1128         fprintf(stderr, "PacketAlias/AddLink(): ");
1129         fprintf(stderr, "malloc() call failed.\n");
1130 #endif
1131     }
1132 
1133     if (packetAliasMode & PKT_ALIAS_LOG)
1134     {
1135         ShowAliasStats();
1136     }
1137 
1138     return(link);
1139 }
1140 
1141 static struct alias_link *
1142 ReLink(struct alias_link *old_link,
1143        struct in_addr  src_addr,
1144        struct in_addr  dst_addr,
1145        struct in_addr  alias_addr,
1146        u_short         src_port,
1147        u_short         dst_port,
1148        int             alias_port_param,   /* if less than zero, alias   */
1149        int             link_type)          /* port will be automatically */
1150 {                                          /* chosen. If greater than    */
1151     struct alias_link *new_link;           /* zero, equal to alias port  */
1152 
1153     new_link = AddLink(src_addr, dst_addr, alias_addr,
1154                        src_port, dst_port, alias_port_param,
1155                        link_type);
1156 #ifndef NO_FW_PUNCH
1157     if (new_link != NULL &&
1158         old_link->link_type == LINK_TCP &&
1159         old_link->data.tcp->fwhole > 0) {
1160       PunchFWHole(new_link);
1161     }
1162 #endif
1163     DeleteLink(old_link);
1164     return new_link;
1165 }
1166 
1167 static struct alias_link *
1168 _FindLinkOut(struct in_addr src_addr,
1169             struct in_addr dst_addr,
1170             u_short src_port,
1171             u_short dst_port,
1172             int link_type,
1173             int replace_partial_links)
1174 {
1175     u_int i;
1176     struct alias_link *link;
1177 
1178     i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type);
1179     LIST_FOREACH(link, &linkTableOut[i], list_out)
1180     {
1181         if (link->src_addr.s_addr == src_addr.s_addr
1182          && link->server          == NULL
1183          && link->dst_addr.s_addr == dst_addr.s_addr
1184          && link->dst_port        == dst_port
1185          && link->src_port        == src_port
1186          && link->link_type       == link_type)
1187         {
1188             link->timestamp = timeStamp;
1189             break;
1190         }
1191     }
1192 
1193 /* Search for partially specified links. */
1194     if (link == NULL && replace_partial_links)
1195     {
1196         if (dst_port != 0 && dst_addr.s_addr != INADDR_ANY)
1197         {
1198             link = _FindLinkOut(src_addr, dst_addr, src_port, 0,
1199                                 link_type, 0);
1200             if (link == NULL)
1201                 link = _FindLinkOut(src_addr, nullAddress, src_port,
1202                                     dst_port, link_type, 0);
1203         }
1204         if (link == NULL &&
1205            (dst_port != 0 || dst_addr.s_addr != INADDR_ANY))
1206         {
1207             link = _FindLinkOut(src_addr, nullAddress, src_port, 0,
1208                                 link_type, 0);
1209         }
1210         if (link != NULL)
1211         {
1212             link = ReLink(link,
1213                           src_addr, dst_addr, link->alias_addr,
1214                           src_port, dst_port, link->alias_port,
1215                           link_type);
1216         }
1217     }
1218 
1219     return(link);
1220 }
1221 
1222 static struct alias_link *
1223 FindLinkOut(struct in_addr src_addr,
1224             struct in_addr dst_addr,
1225             u_short src_port,
1226             u_short dst_port,
1227             int link_type,
1228             int replace_partial_links)
1229 {
1230     struct alias_link *link;
1231 
1232     link = _FindLinkOut(src_addr, dst_addr, src_port, dst_port,
1233                         link_type, replace_partial_links);
1234 
1235     if (link == NULL)
1236     {
1237     /* The following allows permanent links to be
1238        specified as using the default source address
1239        (i.e. device interface address) without knowing
1240        in advance what that address is. */
1241         if (aliasAddress.s_addr != 0 &&
1242             src_addr.s_addr == aliasAddress.s_addr)
1243         {
1244             link = _FindLinkOut(nullAddress, dst_addr, src_port, dst_port,
1245                                link_type, replace_partial_links);
1246         }
1247     }
1248 
1249     return(link);
1250 }
1251 
1252 
1253 static struct alias_link *
1254 _FindLinkIn(struct in_addr dst_addr,
1255            struct in_addr  alias_addr,
1256            u_short         dst_port,
1257            u_short         alias_port,
1258            int             link_type,
1259            int             replace_partial_links)
1260 {
1261     int flags_in;
1262     u_int start_point;
1263     struct alias_link *link;
1264     struct alias_link *link_fully_specified;
1265     struct alias_link *link_unknown_all;
1266     struct alias_link *link_unknown_dst_addr;
1267     struct alias_link *link_unknown_dst_port;
1268 
1269 /* Initialize pointers */
1270     link_fully_specified  = NULL;
1271     link_unknown_all      = NULL;
1272     link_unknown_dst_addr = NULL;
1273     link_unknown_dst_port = NULL;
1274 
1275 /* If either the dest addr or port is unknown, the search
1276    loop will have to know about this. */
1277 
1278     flags_in = 0;
1279     if (dst_addr.s_addr == INADDR_ANY)
1280         flags_in |= LINK_UNKNOWN_DEST_ADDR;
1281     if (dst_port == 0)
1282         flags_in |= LINK_UNKNOWN_DEST_PORT;
1283 
1284 /* Search loop */
1285     start_point = StartPointIn(alias_addr, alias_port, link_type);
1286     LIST_FOREACH(link, &linkTableIn[start_point], list_in)
1287     {
1288         int flags;
1289 
1290         flags = flags_in | link->flags;
1291         if (!(flags & LINK_PARTIALLY_SPECIFIED))
1292         {
1293             if (link->alias_addr.s_addr == alias_addr.s_addr
1294              && link->alias_port        == alias_port
1295              && link->dst_addr.s_addr   == dst_addr.s_addr
1296              && link->dst_port          == dst_port
1297              && link->link_type         == link_type)
1298             {
1299                 link_fully_specified = link;
1300                 break;
1301             }
1302         }
1303         else if ((flags & LINK_UNKNOWN_DEST_ADDR)
1304               && (flags & LINK_UNKNOWN_DEST_PORT))
1305         {
1306             if (link->alias_addr.s_addr == alias_addr.s_addr
1307              && link->alias_port        == alias_port
1308              && link->link_type         == link_type)
1309             {
1310                 if (link_unknown_all == NULL)
1311                     link_unknown_all = link;
1312             }
1313         }
1314         else if (flags & LINK_UNKNOWN_DEST_ADDR)
1315         {
1316             if (link->alias_addr.s_addr == alias_addr.s_addr
1317              && link->alias_port        == alias_port
1318              && link->link_type         == link_type
1319              && link->dst_port          == dst_port)
1320             {
1321                 if (link_unknown_dst_addr == NULL)
1322                     link_unknown_dst_addr = link;
1323             }
1324         }
1325         else if (flags & LINK_UNKNOWN_DEST_PORT)
1326         {
1327             if (link->alias_addr.s_addr == alias_addr.s_addr
1328              && link->alias_port        == alias_port
1329              && link->link_type         == link_type
1330              && link->dst_addr.s_addr   == dst_addr.s_addr)
1331             {
1332                 if (link_unknown_dst_port == NULL)
1333                     link_unknown_dst_port = link;
1334             }
1335         }
1336     }
1337 
1338 
1339 
1340     if (link_fully_specified != NULL)
1341     {
1342         link_fully_specified->timestamp = timeStamp;
1343         link = link_fully_specified;
1344     }
1345     else if (link_unknown_dst_port != NULL)
1346 	link = link_unknown_dst_port;
1347     else if (link_unknown_dst_addr != NULL)
1348 	link = link_unknown_dst_addr;
1349     else if (link_unknown_all != NULL)
1350 	link = link_unknown_all;
1351     else
1352         return (NULL);
1353 
1354     if (replace_partial_links &&
1355 	(link->flags & LINK_PARTIALLY_SPECIFIED || link->server != NULL))
1356     {
1357 	struct in_addr src_addr;
1358 	u_short src_port;
1359 
1360 	if (link->server != NULL) {		/* LSNAT link */
1361 	    src_addr = link->server->addr;
1362 	    src_port = link->server->port;
1363 	    link->server = link->server->next;
1364 	} else {
1365 	    src_addr = link->src_addr;
1366 	    src_port = link->src_port;
1367 	}
1368 
1369 	link = ReLink(link,
1370 		      src_addr, dst_addr, alias_addr,
1371 		      src_port, dst_port, alias_port,
1372 		      link_type);
1373     }
1374 
1375     return (link);
1376 }
1377 
1378 static struct alias_link *
1379 FindLinkIn(struct in_addr dst_addr,
1380            struct in_addr alias_addr,
1381            u_short dst_port,
1382            u_short alias_port,
1383            int link_type,
1384            int replace_partial_links)
1385 {
1386     struct alias_link *link;
1387 
1388     link = _FindLinkIn(dst_addr, alias_addr, dst_port, alias_port,
1389                        link_type, replace_partial_links);
1390 
1391     if (link == NULL)
1392     {
1393     /* The following allows permanent links to be
1394        specified as using the default aliasing address
1395        (i.e. device interface address) without knowing
1396        in advance what that address is. */
1397         if (aliasAddress.s_addr != 0 &&
1398             alias_addr.s_addr == aliasAddress.s_addr)
1399         {
1400             link = _FindLinkIn(dst_addr, nullAddress, dst_port, alias_port,
1401                                link_type, replace_partial_links);
1402         }
1403     }
1404 
1405     return(link);
1406 }
1407 
1408 
1409 
1410 
1411 /* External routines for finding/adding links
1412 
1413 -- "external" means outside alias_db.c, but within alias*.c --
1414 
1415     FindIcmpIn(), FindIcmpOut()
1416     FindFragmentIn1(), FindFragmentIn2()
1417     AddFragmentPtrLink(), FindFragmentPtr()
1418     FindProtoIn(), FindProtoOut()
1419     FindUdpTcpIn(), FindUdpTcpOut()
1420     AddPptp(), FindPptpOutByCallId(), FindPptpInByCallId(),
1421     FindPptpOutByPeerCallId(), FindPptpInByPeerCallId()
1422     FindOriginalAddress(), FindAliasAddress()
1423 
1424 (prototypes in alias_local.h)
1425 */
1426 
1427 
1428 struct alias_link *
1429 FindIcmpIn(struct in_addr dst_addr,
1430            struct in_addr alias_addr,
1431            u_short id_alias,
1432            int create)
1433 {
1434     struct alias_link *link;
1435 
1436     link = FindLinkIn(dst_addr, alias_addr,
1437                       NO_DEST_PORT, id_alias,
1438                       LINK_ICMP, 0);
1439     if (link == NULL && create && !(packetAliasMode & PKT_ALIAS_DENY_INCOMING))
1440     {
1441         struct in_addr target_addr;
1442 
1443         target_addr = FindOriginalAddress(alias_addr);
1444         link = AddLink(target_addr, dst_addr, alias_addr,
1445                        id_alias, NO_DEST_PORT, id_alias,
1446                        LINK_ICMP);
1447     }
1448 
1449     return (link);
1450 }
1451 
1452 
1453 struct alias_link *
1454 FindIcmpOut(struct in_addr src_addr,
1455             struct in_addr dst_addr,
1456             u_short id,
1457             int create)
1458 {
1459     struct alias_link * link;
1460 
1461     link = FindLinkOut(src_addr, dst_addr,
1462                        id, NO_DEST_PORT,
1463                        LINK_ICMP, 0);
1464     if (link == NULL && create)
1465     {
1466         struct in_addr alias_addr;
1467 
1468         alias_addr = FindAliasAddress(src_addr);
1469         link = AddLink(src_addr, dst_addr, alias_addr,
1470                        id, NO_DEST_PORT, GET_ALIAS_ID,
1471                        LINK_ICMP);
1472     }
1473 
1474     return(link);
1475 }
1476 
1477 
1478 struct alias_link *
1479 FindFragmentIn1(struct in_addr dst_addr,
1480                 struct in_addr alias_addr,
1481                 u_short ip_id)
1482 {
1483     struct alias_link *link;
1484 
1485     link = FindLinkIn(dst_addr, alias_addr,
1486                       NO_DEST_PORT, ip_id,
1487                       LINK_FRAGMENT_ID, 0);
1488 
1489     if (link == NULL)
1490     {
1491         link = AddLink(nullAddress, dst_addr, alias_addr,
1492                        NO_SRC_PORT, NO_DEST_PORT, ip_id,
1493                        LINK_FRAGMENT_ID);
1494     }
1495 
1496     return(link);
1497 }
1498 
1499 
1500 struct alias_link *
1501 FindFragmentIn2(struct in_addr dst_addr,   /* Doesn't add a link if one */
1502                 struct in_addr alias_addr, /*   is not found.           */
1503                 u_short ip_id)
1504 {
1505     return FindLinkIn(dst_addr, alias_addr,
1506                       NO_DEST_PORT, ip_id,
1507                       LINK_FRAGMENT_ID, 0);
1508 }
1509 
1510 
1511 struct alias_link *
1512 AddFragmentPtrLink(struct in_addr dst_addr,
1513                    u_short ip_id)
1514 {
1515     return AddLink(nullAddress, dst_addr, nullAddress,
1516                    NO_SRC_PORT, NO_DEST_PORT, ip_id,
1517                    LINK_FRAGMENT_PTR);
1518 }
1519 
1520 
1521 struct alias_link *
1522 FindFragmentPtr(struct in_addr dst_addr,
1523                 u_short ip_id)
1524 {
1525     return FindLinkIn(dst_addr, nullAddress,
1526                       NO_DEST_PORT, ip_id,
1527                       LINK_FRAGMENT_PTR, 0);
1528 }
1529 
1530 
1531 struct alias_link *
1532 FindProtoIn(struct in_addr dst_addr,
1533             struct in_addr alias_addr,
1534 	    u_char proto)
1535 {
1536     struct alias_link *link;
1537 
1538     link = FindLinkIn(dst_addr, alias_addr,
1539                       NO_DEST_PORT, 0,
1540                       proto, 1);
1541 
1542     if (link == NULL && !(packetAliasMode & PKT_ALIAS_DENY_INCOMING))
1543     {
1544         struct in_addr target_addr;
1545 
1546         target_addr = FindOriginalAddress(alias_addr);
1547         link = AddLink(target_addr, dst_addr, alias_addr,
1548                        NO_SRC_PORT, NO_DEST_PORT, 0,
1549                        proto);
1550     }
1551 
1552     return (link);
1553 }
1554 
1555 
1556 struct alias_link *
1557 FindProtoOut(struct in_addr src_addr,
1558              struct in_addr dst_addr,
1559              u_char proto)
1560 {
1561     struct alias_link *link;
1562 
1563     link = FindLinkOut(src_addr, dst_addr,
1564                        NO_SRC_PORT, NO_DEST_PORT,
1565                        proto, 1);
1566 
1567     if (link == NULL)
1568     {
1569         struct in_addr alias_addr;
1570 
1571         alias_addr = FindAliasAddress(src_addr);
1572         link = AddLink(src_addr, dst_addr, alias_addr,
1573                        NO_SRC_PORT, NO_DEST_PORT, 0,
1574                        proto);
1575     }
1576 
1577     return (link);
1578 }
1579 
1580 
1581 struct alias_link *
1582 FindUdpTcpIn(struct in_addr dst_addr,
1583              struct in_addr alias_addr,
1584              u_short        dst_port,
1585              u_short        alias_port,
1586              u_char         proto,
1587              int            create)
1588 {
1589     int link_type;
1590     struct alias_link *link;
1591 
1592     switch (proto)
1593     {
1594     case IPPROTO_UDP:
1595         link_type = LINK_UDP;
1596         break;
1597     case IPPROTO_TCP:
1598         link_type = LINK_TCP;
1599         break;
1600     default:
1601         return NULL;
1602         break;
1603     }
1604 
1605     link = FindLinkIn(dst_addr, alias_addr,
1606                       dst_port, alias_port,
1607                       link_type, create);
1608 
1609     if (link == NULL && create && !(packetAliasMode & PKT_ALIAS_DENY_INCOMING))
1610     {
1611         struct in_addr target_addr;
1612 
1613         target_addr = FindOriginalAddress(alias_addr);
1614         link = AddLink(target_addr, dst_addr, alias_addr,
1615                        alias_port, dst_port, alias_port,
1616                        link_type);
1617     }
1618 
1619     return(link);
1620 }
1621 
1622 
1623 struct alias_link *
1624 FindUdpTcpOut(struct in_addr  src_addr,
1625               struct in_addr  dst_addr,
1626               u_short         src_port,
1627               u_short         dst_port,
1628               u_char          proto,
1629               int             create)
1630 {
1631     int link_type;
1632     struct alias_link *link;
1633 
1634     switch (proto)
1635     {
1636     case IPPROTO_UDP:
1637         link_type = LINK_UDP;
1638         break;
1639     case IPPROTO_TCP:
1640         link_type = LINK_TCP;
1641         break;
1642     default:
1643         return NULL;
1644         break;
1645     }
1646 
1647     link = FindLinkOut(src_addr, dst_addr, src_port, dst_port, link_type, create);
1648 
1649     if (link == NULL && create)
1650     {
1651         struct in_addr alias_addr;
1652 
1653         alias_addr = FindAliasAddress(src_addr);
1654         link = AddLink(src_addr, dst_addr, alias_addr,
1655                        src_port, dst_port, GET_ALIAS_PORT,
1656                        link_type);
1657     }
1658 
1659     return(link);
1660 }
1661 
1662 
1663 struct alias_link *
1664 AddPptp(struct in_addr  src_addr,
1665 	struct in_addr  dst_addr,
1666 	struct in_addr  alias_addr,
1667 	u_int16_t       src_call_id)
1668 {
1669     struct alias_link *link;
1670 
1671     link = AddLink(src_addr, dst_addr, alias_addr,
1672 		   src_call_id, 0, GET_ALIAS_PORT,
1673 		   LINK_PPTP);
1674 
1675     return (link);
1676 }
1677 
1678 
1679 struct alias_link *
1680 FindPptpOutByCallId(struct in_addr src_addr,
1681 		    struct in_addr dst_addr,
1682 		    u_int16_t      src_call_id)
1683 {
1684     u_int i;
1685     struct alias_link *link;
1686 
1687     i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP);
1688     LIST_FOREACH(link, &linkTableOut[i], list_out)
1689 	if (link->link_type == LINK_PPTP &&
1690 	    link->src_addr.s_addr == src_addr.s_addr &&
1691 	    link->dst_addr.s_addr == dst_addr.s_addr &&
1692 	    link->src_port == src_call_id)
1693 		break;
1694 
1695     return (link);
1696 }
1697 
1698 
1699 struct alias_link *
1700 FindPptpOutByPeerCallId(struct in_addr src_addr,
1701 			struct in_addr dst_addr,
1702 			u_int16_t      dst_call_id)
1703 {
1704     u_int i;
1705     struct alias_link *link;
1706 
1707     i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP);
1708     LIST_FOREACH(link, &linkTableOut[i], list_out)
1709 	if (link->link_type == LINK_PPTP &&
1710 	    link->src_addr.s_addr == src_addr.s_addr &&
1711 	    link->dst_addr.s_addr == dst_addr.s_addr &&
1712 	    link->dst_port == dst_call_id)
1713 		break;
1714 
1715     return (link);
1716 }
1717 
1718 
1719 struct alias_link *
1720 FindPptpInByCallId(struct in_addr dst_addr,
1721 		   struct in_addr alias_addr,
1722 		   u_int16_t      dst_call_id)
1723 {
1724     u_int i;
1725     struct alias_link *link;
1726 
1727     i = StartPointIn(alias_addr, 0, LINK_PPTP);
1728     LIST_FOREACH(link, &linkTableIn[i], list_in)
1729 	if (link->link_type == LINK_PPTP &&
1730 	    link->dst_addr.s_addr == dst_addr.s_addr &&
1731 	    link->alias_addr.s_addr == alias_addr.s_addr &&
1732 	    link->dst_port == dst_call_id)
1733 		break;
1734 
1735     return (link);
1736 }
1737 
1738 
1739 struct alias_link *
1740 FindPptpInByPeerCallId(struct in_addr dst_addr,
1741 		       struct in_addr alias_addr,
1742 		       u_int16_t      alias_call_id)
1743 {
1744     struct alias_link *link;
1745 
1746     link = FindLinkIn(dst_addr, alias_addr,
1747 		      0/* any */, alias_call_id,
1748 		      LINK_PPTP, 0);
1749 
1750 
1751     return (link);
1752 }
1753 
1754 
1755 struct alias_link *
1756 FindRtspOut(struct in_addr  src_addr,
1757             struct in_addr  dst_addr,
1758             u_short         src_port,
1759             u_short         alias_port,
1760             u_char          proto)
1761 {
1762     int link_type;
1763     struct alias_link *link;
1764 
1765     switch (proto)
1766     {
1767     case IPPROTO_UDP:
1768         link_type = LINK_UDP;
1769         break;
1770     case IPPROTO_TCP:
1771         link_type = LINK_TCP;
1772         break;
1773     default:
1774         return NULL;
1775         break;
1776     }
1777 
1778     link = FindLinkOut(src_addr, dst_addr, src_port, 0, link_type, 1);
1779 
1780     if (link == NULL)
1781     {
1782         struct in_addr alias_addr;
1783 
1784         alias_addr = FindAliasAddress(src_addr);
1785         link = AddLink(src_addr, dst_addr, alias_addr,
1786                        src_port, 0, alias_port,
1787                        link_type);
1788     }
1789 
1790     return(link);
1791 }
1792 
1793 
1794 struct in_addr
1795 FindOriginalAddress(struct in_addr alias_addr)
1796 {
1797     struct alias_link *link;
1798 
1799     link = FindLinkIn(nullAddress, alias_addr,
1800                       0, 0, LINK_ADDR, 0);
1801     if (link == NULL)
1802     {
1803         newDefaultLink = 1;
1804         if (targetAddress.s_addr == INADDR_ANY)
1805             return alias_addr;
1806         else if (targetAddress.s_addr == INADDR_NONE)
1807             return aliasAddress;
1808         else
1809             return targetAddress;
1810     }
1811     else
1812     {
1813 	if (link->server != NULL) {		/* LSNAT link */
1814 	    struct in_addr src_addr;
1815 
1816 	    src_addr = link->server->addr;
1817 	    link->server = link->server->next;
1818 	    return (src_addr);
1819         } else if (link->src_addr.s_addr == INADDR_ANY)
1820             return aliasAddress;
1821         else
1822             return link->src_addr;
1823     }
1824 }
1825 
1826 
1827 struct in_addr
1828 FindAliasAddress(struct in_addr original_addr)
1829 {
1830     struct alias_link *link;
1831 
1832     link = FindLinkOut(original_addr, nullAddress,
1833                        0, 0, LINK_ADDR, 0);
1834     if (link == NULL)
1835     {
1836         return aliasAddress;
1837     }
1838     else
1839     {
1840         if (link->alias_addr.s_addr == INADDR_ANY)
1841             return aliasAddress;
1842         else
1843             return link->alias_addr;
1844     }
1845 }
1846 
1847 
1848 /* External routines for getting or changing link data
1849    (external to alias_db.c, but internal to alias*.c)
1850 
1851     SetFragmentData(), GetFragmentData()
1852     SetFragmentPtr(), GetFragmentPtr()
1853     SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut()
1854     GetOriginalAddress(), GetDestAddress(), GetAliasAddress()
1855     GetOriginalPort(), GetAliasPort()
1856     SetAckModified(), GetAckModified()
1857     GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq()
1858     SetProtocolFlags(), GetProtocolFlags()
1859     SetDestCallId()
1860 */
1861 
1862 
1863 void
1864 SetFragmentAddr(struct alias_link *link, struct in_addr src_addr)
1865 {
1866     link->data.frag_addr = src_addr;
1867 }
1868 
1869 
1870 void
1871 GetFragmentAddr(struct alias_link *link, struct in_addr *src_addr)
1872 {
1873     *src_addr = link->data.frag_addr;
1874 }
1875 
1876 
1877 void
1878 SetFragmentPtr(struct alias_link *link, char *fptr)
1879 {
1880     link->data.frag_ptr = fptr;
1881 }
1882 
1883 
1884 void
1885 GetFragmentPtr(struct alias_link *link, char **fptr)
1886 {
1887    *fptr = link->data.frag_ptr;
1888 }
1889 
1890 
1891 void
1892 SetStateIn(struct alias_link *link, int state)
1893 {
1894     /* TCP input state */
1895     switch (state) {
1896     case ALIAS_TCP_STATE_DISCONNECTED:
1897         if (link->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED)
1898             link->expire_time = TCP_EXPIRE_DEAD;
1899         else
1900             link->expire_time = TCP_EXPIRE_SINGLEDEAD;
1901         break;
1902     case ALIAS_TCP_STATE_CONNECTED:
1903         if (link->data.tcp->state.out == ALIAS_TCP_STATE_CONNECTED)
1904             link->expire_time = TCP_EXPIRE_CONNECTED;
1905         break;
1906     default:
1907         abort();
1908     }
1909     link->data.tcp->state.in = state;
1910 }
1911 
1912 
1913 void
1914 SetStateOut(struct alias_link *link, int state)
1915 {
1916     /* TCP output state */
1917     switch (state) {
1918     case ALIAS_TCP_STATE_DISCONNECTED:
1919         if (link->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED)
1920             link->expire_time = TCP_EXPIRE_DEAD;
1921         else
1922             link->expire_time = TCP_EXPIRE_SINGLEDEAD;
1923         break;
1924     case ALIAS_TCP_STATE_CONNECTED:
1925         if (link->data.tcp->state.in == ALIAS_TCP_STATE_CONNECTED)
1926             link->expire_time = TCP_EXPIRE_CONNECTED;
1927         break;
1928     default:
1929         abort();
1930     }
1931     link->data.tcp->state.out = state;
1932 }
1933 
1934 
1935 int
1936 GetStateIn(struct alias_link *link)
1937 {
1938     /* TCP input state */
1939     return link->data.tcp->state.in;
1940 }
1941 
1942 
1943 int
1944 GetStateOut(struct alias_link *link)
1945 {
1946     /* TCP output state */
1947     return link->data.tcp->state.out;
1948 }
1949 
1950 
1951 struct in_addr
1952 GetOriginalAddress(struct alias_link *link)
1953 {
1954     if (link->src_addr.s_addr == INADDR_ANY)
1955         return aliasAddress;
1956     else
1957         return(link->src_addr);
1958 }
1959 
1960 
1961 struct in_addr
1962 GetDestAddress(struct alias_link *link)
1963 {
1964     return(link->dst_addr);
1965 }
1966 
1967 
1968 struct in_addr
1969 GetAliasAddress(struct alias_link *link)
1970 {
1971     if (link->alias_addr.s_addr == INADDR_ANY)
1972         return aliasAddress;
1973     else
1974         return link->alias_addr;
1975 }
1976 
1977 
1978 struct in_addr
1979 GetDefaultAliasAddress()
1980 {
1981     return aliasAddress;
1982 }
1983 
1984 
1985 void
1986 SetDefaultAliasAddress(struct in_addr alias_addr)
1987 {
1988     aliasAddress = alias_addr;
1989 }
1990 
1991 
1992 u_short
1993 GetOriginalPort(struct alias_link *link)
1994 {
1995     return(link->src_port);
1996 }
1997 
1998 
1999 u_short
2000 GetAliasPort(struct alias_link *link)
2001 {
2002     return(link->alias_port);
2003 }
2004 
2005 #ifndef NO_FW_PUNCH
2006 static u_short
2007 GetDestPort(struct alias_link *link)
2008 {
2009     return(link->dst_port);
2010 }
2011 #endif
2012 
2013 void
2014 SetAckModified(struct alias_link *link)
2015 {
2016 /* Indicate that ACK numbers have been modified in a TCP connection */
2017     link->data.tcp->state.ack_modified = 1;
2018 }
2019 
2020 
2021 struct in_addr
2022 GetProxyAddress(struct alias_link *link)
2023 {
2024     return link->proxy_addr;
2025 }
2026 
2027 
2028 void
2029 SetProxyAddress(struct alias_link *link, struct in_addr addr)
2030 {
2031     link->proxy_addr = addr;
2032 }
2033 
2034 
2035 u_short
2036 GetProxyPort(struct alias_link *link)
2037 {
2038     return link->proxy_port;
2039 }
2040 
2041 
2042 void
2043 SetProxyPort(struct alias_link *link, u_short port)
2044 {
2045     link->proxy_port = port;
2046 }
2047 
2048 
2049 int
2050 GetAckModified(struct alias_link *link)
2051 {
2052 /* See if ACK numbers have been modified */
2053     return link->data.tcp->state.ack_modified;
2054 }
2055 
2056 
2057 int
2058 GetDeltaAckIn(struct ip *pip, struct alias_link *link)
2059 {
2060 /*
2061 Find out how much the ACK number has been altered for an incoming
2062 TCP packet.  To do this, a circular list of ACK numbers where the TCP
2063 packet size was altered is searched.
2064 */
2065 
2066     int i;
2067     struct tcphdr *tc;
2068     int delta, ack_diff_min;
2069     u_long ack;
2070 
2071     tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
2072     ack      = tc->th_ack;
2073 
2074     delta = 0;
2075     ack_diff_min = -1;
2076     for (i=0; i<N_LINK_TCP_DATA; i++)
2077     {
2078         struct ack_data_record x;
2079 
2080         x = link->data.tcp->ack[i];
2081         if (x.active == 1)
2082         {
2083             int ack_diff;
2084 
2085             ack_diff = SeqDiff(x.ack_new, ack);
2086             if (ack_diff >= 0)
2087             {
2088                 if (ack_diff_min >= 0)
2089                 {
2090                     if (ack_diff < ack_diff_min)
2091                     {
2092                         delta = x.delta;
2093                         ack_diff_min = ack_diff;
2094                     }
2095                 }
2096                 else
2097                 {
2098                     delta = x.delta;
2099                     ack_diff_min = ack_diff;
2100                 }
2101             }
2102         }
2103     }
2104     return (delta);
2105 }
2106 
2107 
2108 int
2109 GetDeltaSeqOut(struct ip *pip, struct alias_link *link)
2110 {
2111 /*
2112 Find out how much the sequence number has been altered for an outgoing
2113 TCP packet.  To do this, a circular list of ACK numbers where the TCP
2114 packet size was altered is searched.
2115 */
2116 
2117     int i;
2118     struct tcphdr *tc;
2119     int delta, seq_diff_min;
2120     u_long seq;
2121 
2122     tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
2123     seq = tc->th_seq;
2124 
2125     delta = 0;
2126     seq_diff_min = -1;
2127     for (i=0; i<N_LINK_TCP_DATA; i++)
2128     {
2129         struct ack_data_record x;
2130 
2131         x = link->data.tcp->ack[i];
2132         if (x.active == 1)
2133         {
2134             int seq_diff;
2135 
2136             seq_diff = SeqDiff(x.ack_old, seq);
2137             if (seq_diff >= 0)
2138             {
2139                 if (seq_diff_min >= 0)
2140                 {
2141                     if (seq_diff < seq_diff_min)
2142                     {
2143                         delta = x.delta;
2144                         seq_diff_min = seq_diff;
2145                     }
2146                 }
2147                 else
2148                 {
2149                     delta = x.delta;
2150                     seq_diff_min = seq_diff;
2151                 }
2152             }
2153         }
2154     }
2155     return (delta);
2156 }
2157 
2158 
2159 void
2160 AddSeq(struct ip *pip, struct alias_link *link, int delta)
2161 {
2162 /*
2163 When a TCP packet has been altered in length, save this
2164 information in a circular list.  If enough packets have
2165 been altered, then this list will begin to overwrite itself.
2166 */
2167 
2168     struct tcphdr *tc;
2169     struct ack_data_record x;
2170     int hlen, tlen, dlen;
2171     int i;
2172 
2173     tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
2174 
2175     hlen = (pip->ip_hl + tc->th_off) << 2;
2176     tlen = ntohs(pip->ip_len);
2177     dlen = tlen - hlen;
2178 
2179     x.ack_old = htonl(ntohl(tc->th_seq) + dlen);
2180     x.ack_new = htonl(ntohl(tc->th_seq) + dlen + delta);
2181     x.delta = delta;
2182     x.active = 1;
2183 
2184     i = link->data.tcp->state.index;
2185     link->data.tcp->ack[i] = x;
2186 
2187     i++;
2188     if (i == N_LINK_TCP_DATA)
2189         link->data.tcp->state.index = 0;
2190     else
2191         link->data.tcp->state.index = i;
2192 }
2193 
2194 void
2195 SetExpire(struct alias_link *link, int expire)
2196 {
2197     if (expire == 0)
2198     {
2199         link->flags &= ~LINK_PERMANENT;
2200         DeleteLink(link);
2201     }
2202     else if (expire == -1)
2203     {
2204         link->flags |= LINK_PERMANENT;
2205     }
2206     else if (expire > 0)
2207     {
2208         link->expire_time = expire;
2209     }
2210     else
2211     {
2212 #ifdef DEBUG
2213         fprintf(stderr, "PacketAlias/SetExpire(): ");
2214         fprintf(stderr, "error in expire parameter\n");
2215 #endif
2216     }
2217 }
2218 
2219 void
2220 ClearCheckNewLink(void)
2221 {
2222     newDefaultLink = 0;
2223 }
2224 
2225 void
2226 SetProtocolFlags(struct alias_link *link, int pflags)
2227 {
2228 
2229     link->pflags = pflags;;
2230 }
2231 
2232 int
2233 GetProtocolFlags(struct alias_link *link)
2234 {
2235 
2236     return (link->pflags);
2237 }
2238 
2239 void
2240 SetDestCallId(struct alias_link *link, u_int16_t cid)
2241 {
2242 
2243     deleteAllLinks = 1;
2244     link = ReLink(link, link->src_addr, link->dst_addr, link->alias_addr,
2245 		  link->src_port, cid, link->alias_port, link->link_type);
2246     deleteAllLinks = 0;
2247 }
2248 
2249 
2250 /* Miscellaneous Functions
2251 
2252     HouseKeeping()
2253     InitPacketAliasLog()
2254     UninitPacketAliasLog()
2255 */
2256 
2257 /*
2258     Whenever an outgoing or incoming packet is handled, HouseKeeping()
2259     is called to find and remove timed-out aliasing links.  Logic exists
2260     to sweep through the entire table and linked list structure
2261     every 60 seconds.
2262 
2263     (prototype in alias_local.h)
2264 */
2265 
2266 void
2267 HouseKeeping(void)
2268 {
2269     int i, n, n100;
2270     struct timeval tv;
2271     struct timezone tz;
2272 
2273     /*
2274      * Save system time (seconds) in global variable timeStamp for
2275      * use by other functions. This is done so as not to unnecessarily
2276      * waste timeline by making system calls.
2277      */
2278     gettimeofday(&tv, &tz);
2279     timeStamp = tv.tv_sec;
2280 
2281     /* Compute number of spokes (output table link chains) to cover */
2282     n100  = LINK_TABLE_OUT_SIZE * 100 + houseKeepingResidual;
2283     n100 *= timeStamp - lastCleanupTime;
2284     n100 /= ALIAS_CLEANUP_INTERVAL_SECS;
2285 
2286     n = n100/100;
2287 
2288     /* Handle different cases */
2289     if (n > ALIAS_CLEANUP_MAX_SPOKES)
2290     {
2291         n = ALIAS_CLEANUP_MAX_SPOKES;
2292         lastCleanupTime = timeStamp;
2293         houseKeepingResidual = 0;
2294 
2295         for (i=0; i<n; i++)
2296             IncrementalCleanup();
2297     }
2298     else if (n > 0)
2299     {
2300         lastCleanupTime = timeStamp;
2301         houseKeepingResidual = n100 - 100*n;
2302 
2303         for (i=0; i<n; i++)
2304             IncrementalCleanup();
2305     }
2306     else if (n < 0)
2307     {
2308 #ifdef DEBUG
2309         fprintf(stderr, "PacketAlias/HouseKeeping(): ");
2310         fprintf(stderr, "something unexpected in time values\n");
2311 #endif
2312         lastCleanupTime = timeStamp;
2313         houseKeepingResidual = 0;
2314     }
2315 }
2316 
2317 
2318 /* Init the log file and enable logging */
2319 static void
2320 InitPacketAliasLog(void)
2321 {
2322    if ((~packetAliasMode & PKT_ALIAS_LOG)
2323     && (monitorFile = fopen("/var/log/alias.log", "w")))
2324    {
2325       packetAliasMode |= PKT_ALIAS_LOG;
2326       fprintf(monitorFile,
2327       "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n");
2328    }
2329 }
2330 
2331 
2332 /* Close the log-file and disable logging. */
2333 static void
2334 UninitPacketAliasLog(void)
2335 {
2336     if (monitorFile) {
2337         fclose(monitorFile);
2338         monitorFile = NULL;
2339     }
2340     packetAliasMode &= ~PKT_ALIAS_LOG;
2341 }
2342 
2343 
2344 
2345 
2346 
2347 
2348 /* Outside world interfaces
2349 
2350 -- "outside world" means other than alias*.c routines --
2351 
2352     PacketAliasRedirectPort()
2353     PacketAliasAddServer()
2354     PacketAliasRedirectProto()
2355     PacketAliasRedirectAddr()
2356     PacketAliasRedirectDelete()
2357     PacketAliasSetAddress()
2358     PacketAliasInit()
2359     PacketAliasUninit()
2360     PacketAliasSetMode()
2361 
2362 (prototypes in alias.h)
2363 */
2364 
2365 /* Redirection from a specific public addr:port to a
2366    private addr:port */
2367 struct alias_link *
2368 PacketAliasRedirectPort(struct in_addr src_addr,   u_short src_port,
2369                         struct in_addr dst_addr,   u_short dst_port,
2370                         struct in_addr alias_addr, u_short alias_port,
2371                         u_char proto)
2372 {
2373     int link_type;
2374     struct alias_link *link;
2375 
2376     switch(proto)
2377     {
2378     case IPPROTO_UDP:
2379         link_type = LINK_UDP;
2380         break;
2381     case IPPROTO_TCP:
2382         link_type = LINK_TCP;
2383         break;
2384     default:
2385 #ifdef DEBUG
2386         fprintf(stderr, "PacketAliasRedirectPort(): ");
2387         fprintf(stderr, "only TCP and UDP protocols allowed\n");
2388 #endif
2389         return NULL;
2390     }
2391 
2392     link = AddLink(src_addr, dst_addr, alias_addr,
2393                    src_port, dst_port, alias_port,
2394                    link_type);
2395 
2396     if (link != NULL)
2397     {
2398         link->flags |= LINK_PERMANENT;
2399     }
2400 #ifdef DEBUG
2401     else
2402     {
2403         fprintf(stderr, "PacketAliasRedirectPort(): "
2404                         "call to AddLink() failed\n");
2405     }
2406 #endif
2407 
2408     return link;
2409 }
2410 
2411 /* Add server to the pool of servers */
2412 int
2413 PacketAliasAddServer(struct alias_link *link, struct in_addr addr, u_short port)
2414 {
2415     struct server *server;
2416 
2417     server = malloc(sizeof(struct server));
2418 
2419     if (server != NULL) {
2420 	struct server *head;
2421 
2422 	server->addr = addr;
2423 	server->port = port;
2424 
2425 	head = link->server;
2426 	if (head == NULL)
2427 	    server->next = server;
2428 	else {
2429 	    struct server *s;
2430 
2431 	    for (s = head; s->next != head; s = s->next);
2432 	    s->next = server;
2433 	    server->next = head;
2434 	}
2435 	link->server = server;
2436 	return (0);
2437     } else
2438 	return (-1);
2439 }
2440 
2441 /* Redirect packets of a given IP protocol from a specific
2442    public address to a private address */
2443 struct alias_link *
2444 PacketAliasRedirectProto(struct in_addr src_addr,
2445                          struct in_addr dst_addr,
2446                          struct in_addr alias_addr,
2447                          u_char proto)
2448 {
2449     struct alias_link *link;
2450 
2451     link = AddLink(src_addr, dst_addr, alias_addr,
2452                    NO_SRC_PORT, NO_DEST_PORT, 0,
2453                    proto);
2454 
2455     if (link != NULL)
2456     {
2457         link->flags |= LINK_PERMANENT;
2458     }
2459 #ifdef DEBUG
2460     else
2461     {
2462         fprintf(stderr, "PacketAliasRedirectProto(): "
2463                         "call to AddLink() failed\n");
2464     }
2465 #endif
2466 
2467     return link;
2468 }
2469 
2470 /* Static address translation */
2471 struct alias_link *
2472 PacketAliasRedirectAddr(struct in_addr src_addr,
2473                         struct in_addr alias_addr)
2474 {
2475     struct alias_link *link;
2476 
2477     link = AddLink(src_addr, nullAddress, alias_addr,
2478                    0, 0, 0,
2479                    LINK_ADDR);
2480 
2481     if (link != NULL)
2482     {
2483         link->flags |= LINK_PERMANENT;
2484     }
2485 #ifdef DEBUG
2486     else
2487     {
2488         fprintf(stderr, "PacketAliasRedirectAddr(): "
2489                         "call to AddLink() failed\n");
2490     }
2491 #endif
2492 
2493     return link;
2494 }
2495 
2496 
2497 void
2498 PacketAliasRedirectDelete(struct alias_link *link)
2499 {
2500 /* This is a dangerous function to put in the API,
2501    because an invalid pointer can crash the program. */
2502 
2503     deleteAllLinks = 1;
2504     DeleteLink(link);
2505     deleteAllLinks = 0;
2506 }
2507 
2508 
2509 void
2510 PacketAliasSetAddress(struct in_addr addr)
2511 {
2512     if (packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE
2513      && aliasAddress.s_addr != addr.s_addr)
2514         CleanupAliasData();
2515 
2516     aliasAddress = addr;
2517 }
2518 
2519 
2520 void
2521 PacketAliasSetTarget(struct in_addr target_addr)
2522 {
2523     targetAddress = target_addr;
2524 }
2525 
2526 
2527 void
2528 PacketAliasInit(void)
2529 {
2530     int i;
2531     struct timeval tv;
2532     struct timezone tz;
2533     static int firstCall = 1;
2534 
2535     if (firstCall == 1)
2536     {
2537         gettimeofday(&tv, &tz);
2538         timeStamp = tv.tv_sec;
2539         lastCleanupTime = tv.tv_sec;
2540         houseKeepingResidual = 0;
2541 
2542         for (i=0; i<LINK_TABLE_OUT_SIZE; i++)
2543             LIST_INIT(&linkTableOut[i]);
2544         for (i=0; i<LINK_TABLE_IN_SIZE; i++)
2545             LIST_INIT(&linkTableIn[i]);
2546 
2547         atexit(PacketAliasUninit);
2548         firstCall = 0;
2549     }
2550     else
2551     {
2552         deleteAllLinks = 1;
2553         CleanupAliasData();
2554         deleteAllLinks = 0;
2555     }
2556 
2557     aliasAddress.s_addr = INADDR_ANY;
2558     targetAddress.s_addr = INADDR_ANY;
2559 
2560     icmpLinkCount = 0;
2561     udpLinkCount = 0;
2562     tcpLinkCount = 0;
2563     pptpLinkCount = 0;
2564     protoLinkCount = 0;
2565     fragmentIdLinkCount = 0;
2566     fragmentPtrLinkCount = 0;
2567     sockCount = 0;
2568 
2569     cleanupIndex =0;
2570 
2571     packetAliasMode = PKT_ALIAS_SAME_PORTS
2572                     | PKT_ALIAS_USE_SOCKETS
2573                     | PKT_ALIAS_RESET_ON_ADDR_CHANGE;
2574 }
2575 
2576 void
2577 PacketAliasUninit(void) {
2578     deleteAllLinks = 1;
2579     CleanupAliasData();
2580     deleteAllLinks = 0;
2581     UninitPacketAliasLog();
2582 #ifndef NO_FW_PUNCH
2583     UninitPunchFW();
2584 #endif
2585 }
2586 
2587 
2588 /* Change mode for some operations */
2589 unsigned int
2590 PacketAliasSetMode(
2591     unsigned int flags, /* Which state to bring flags to */
2592     unsigned int mask   /* Mask of which flags to affect (use 0 to do a
2593                            probe for flag values) */
2594 )
2595 {
2596 /* Enable logging? */
2597     if (flags & mask & PKT_ALIAS_LOG)
2598     {
2599         InitPacketAliasLog();     /* Do the enable */
2600     } else
2601 /* _Disable_ logging? */
2602     if (~flags & mask & PKT_ALIAS_LOG) {
2603         UninitPacketAliasLog();
2604     }
2605 
2606 #ifndef NO_FW_PUNCH
2607 /* Start punching holes in the firewall? */
2608     if (flags & mask & PKT_ALIAS_PUNCH_FW) {
2609         InitPunchFW();
2610     } else
2611 /* Stop punching holes in the firewall? */
2612     if (~flags & mask & PKT_ALIAS_PUNCH_FW) {
2613         UninitPunchFW();
2614     }
2615 #endif
2616 
2617 /* Other flags can be set/cleared without special action */
2618     packetAliasMode = (flags & mask) | (packetAliasMode & ~mask);
2619     return packetAliasMode;
2620 }
2621 
2622 
2623 int
2624 PacketAliasCheckNewLink(void)
2625 {
2626     return newDefaultLink;
2627 }
2628 
2629 
2630 #ifndef NO_FW_PUNCH
2631 
2632 /*****************
2633   Code to support firewall punching.  This shouldn't really be in this
2634   file, but making variables global is evil too.
2635   ****************/
2636 
2637 /* Firewall include files */
2638 #include <net/if.h>
2639 #include <netinet/ip_fw.h>
2640 #include <string.h>
2641 #include <err.h>
2642 
2643 static void ClearAllFWHoles(void);
2644 
2645 static int fireWallBaseNum;     /* The first firewall entry free for our use */
2646 static int fireWallNumNums;     /* How many entries can we use? */
2647 static int fireWallActiveNum;   /* Which entry did we last use? */
2648 static char *fireWallField;     /* bool array for entries */
2649 
2650 #define fw_setfield(field, num)                         \
2651 do {                                                    \
2652     (field)[(num) - fireWallBaseNum] = 1;               \
2653 } /*lint -save -e717 */ while(0) /*lint -restore */
2654 #define fw_clrfield(field, num)                         \
2655 do {                                                    \
2656     (field)[(num) - fireWallBaseNum] = 0;               \
2657 } /*lint -save -e717 */ while(0) /*lint -restore */
2658 #define fw_tstfield(field, num) ((field)[(num) - fireWallBaseNum])
2659 
2660 static void
2661 InitPunchFW(void) {
2662     fireWallField = malloc(fireWallNumNums);
2663     if (fireWallField) {
2664         memset(fireWallField, 0, fireWallNumNums);
2665         if (fireWallFD < 0) {
2666             fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
2667         }
2668         ClearAllFWHoles();
2669         fireWallActiveNum = fireWallBaseNum;
2670     }
2671 }
2672 
2673 static void
2674 UninitPunchFW(void) {
2675     ClearAllFWHoles();
2676     if (fireWallFD >= 0)
2677         close(fireWallFD);
2678     fireWallFD = -1;
2679     if (fireWallField)
2680         free(fireWallField);
2681     fireWallField = NULL;
2682     packetAliasMode &= ~PKT_ALIAS_PUNCH_FW;
2683 }
2684 
2685 /* Make a certain link go through the firewall */
2686 void
2687 PunchFWHole(struct alias_link *link) {
2688     int r;                      /* Result code */
2689     struct ip_fw rule;          /* On-the-fly built rule */
2690     int fwhole;                 /* Where to punch hole */
2691 
2692 /* Don't do anything unless we are asked to */
2693     if ( !(packetAliasMode & PKT_ALIAS_PUNCH_FW) ||
2694          fireWallFD < 0 ||
2695          link->link_type != LINK_TCP)
2696         return;
2697 
2698     memset(&rule, 0, sizeof rule);
2699 
2700 /** Build rule **/
2701 
2702     /* Find empty slot */
2703     for (fwhole = fireWallActiveNum;
2704          fwhole < fireWallBaseNum + fireWallNumNums &&
2705              fw_tstfield(fireWallField, fwhole);
2706          fwhole++)
2707         ;
2708     if (fwhole == fireWallBaseNum + fireWallNumNums) {
2709         for (fwhole = fireWallBaseNum;
2710              fwhole < fireWallActiveNum &&
2711                  fw_tstfield(fireWallField, fwhole);
2712              fwhole++)
2713             ;
2714         if (fwhole == fireWallActiveNum) {
2715             /* No rule point empty - we can't punch more holes. */
2716             fireWallActiveNum = fireWallBaseNum;
2717 #ifdef DEBUG
2718             fprintf(stderr, "libalias: Unable to create firewall hole!\n");
2719 #endif
2720             return;
2721         }
2722     }
2723     /* Start next search at next position */
2724     fireWallActiveNum = fwhole+1;
2725 
2726     /* Build generic part of the two rules */
2727     rule.fw_number = fwhole;
2728     IP_FW_SETNSRCP(&rule, 1);	/* Number of source ports. */
2729     IP_FW_SETNDSTP(&rule, 1);	/* Number of destination ports. */
2730     rule.fw_flg = IP_FW_F_ACCEPT | IP_FW_F_IN | IP_FW_F_OUT;
2731     rule.fw_prot = IPPROTO_TCP;
2732     rule.fw_smsk.s_addr = INADDR_BROADCAST;
2733     rule.fw_dmsk.s_addr = INADDR_BROADCAST;
2734 
2735     /* Build and apply specific part of the rules */
2736     rule.fw_src = GetOriginalAddress(link);
2737     rule.fw_dst = GetDestAddress(link);
2738     rule.fw_uar.fw_pts[0] = ntohs(GetOriginalPort(link));
2739     rule.fw_uar.fw_pts[1] = ntohs(GetDestPort(link));
2740 
2741     /* Skip non-bound links - XXX should not be strictly necessary,
2742        but seems to leave hole if not done.  Leak of non-bound links?
2743        (Code should be left even if the problem is fixed - it is a
2744        clear optimization) */
2745     if (rule.fw_uar.fw_pts[0] != 0 && rule.fw_uar.fw_pts[1] != 0) {
2746         r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule);
2747 #ifdef DEBUG
2748         if (r)
2749             err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)");
2750 #endif
2751         rule.fw_src = GetDestAddress(link);
2752         rule.fw_dst = GetOriginalAddress(link);
2753         rule.fw_uar.fw_pts[0] = ntohs(GetDestPort(link));
2754         rule.fw_uar.fw_pts[1] = ntohs(GetOriginalPort(link));
2755         r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule);
2756 #ifdef DEBUG
2757         if (r)
2758             err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)");
2759 #endif
2760     }
2761 /* Indicate hole applied */
2762     link->data.tcp->fwhole = fwhole;
2763     fw_setfield(fireWallField, fwhole);
2764 }
2765 
2766 /* Remove a hole in a firewall associated with a particular alias
2767    link.  Calling this too often is harmless. */
2768 static void
2769 ClearFWHole(struct alias_link *link) {
2770     if (link->link_type == LINK_TCP) {
2771         int fwhole =  link->data.tcp->fwhole; /* Where is the firewall hole? */
2772         struct ip_fw rule;
2773 
2774         if (fwhole < 0)
2775             return;
2776 
2777         memset(&rule, 0, sizeof rule);
2778         rule.fw_number = fwhole;
2779         while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule))
2780             ;
2781         fw_clrfield(fireWallField, fwhole);
2782         link->data.tcp->fwhole = -1;
2783     }
2784 }
2785 
2786 /* Clear out the entire range dedicated to firewall holes. */
2787 static void
2788 ClearAllFWHoles(void) {
2789     struct ip_fw rule;          /* On-the-fly built rule */
2790     int i;
2791 
2792     if (fireWallFD < 0)
2793         return;
2794 
2795     memset(&rule, 0, sizeof rule);
2796     for (i = fireWallBaseNum; i < fireWallBaseNum + fireWallNumNums; i++) {
2797         rule.fw_number = i;
2798         while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule))
2799             ;
2800     }
2801     memset(fireWallField, 0, fireWallNumNums);
2802 }
2803 #endif
2804 
2805 void
2806 PacketAliasSetFWBase(unsigned int base, unsigned int num) {
2807 #ifndef NO_FW_PUNCH
2808     fireWallBaseNum = base;
2809     fireWallNumNums = num;
2810 #endif
2811 }
2812