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