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