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