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