alias_db.c revision 28084
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
186struct 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
194struct 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 */
205struct tcp_dat
206{
207    struct tcp_state state;
208    struct ack_data_record ack[N_LINK_TCP_DATA];
209};
210
211struct 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        char *frag_ptr;
253        struct in_addr frag_addr;
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
269int packetAliasMode;                 /* Mode flags                      */
270                                     /*        - documented in alias.h  */
271
272static struct in_addr aliasAddress;  /* Address written onto source     */
273                                     /*   field of IP packet.           */
274
275static struct in_addr targetAddress; /* IP address incoming packets     */
276                                     /*   are sent to if no aliasing    */
277                                     /*   link already exists           */
278
279static struct in_addr nullAddress;   /* Used as a dummy parameter for   */
280                                     /*   some function calls           */
281static struct alias_link *
282linkTableOut[LINK_TABLE_OUT_SIZE];   /* Lookup table of pointers to     */
283                                     /*   chains of link records. Each  */
284static struct alias_link *           /*   link record is doubly indexed */
285linkTableIn[LINK_TABLE_IN_SIZE];     /*   into input and output lookup  */
286                                     /*   tables.                       */
287
288static int icmpLinkCount;            /* Link statistics                 */
289static int udpLinkCount;
290static int tcpLinkCount;
291static int fragmentIdLinkCount;
292static int fragmentPtrLinkCount;
293static int sockCount;
294
295static int cleanupIndex;             /* Index to chain of link table    */
296                                     /* being inspected for old links   */
297
298static int timeStamp;                /* System time in seconds for      */
299                                     /* current packet                  */
300
301static int lastCleanupTime;          /* Last time IncrementalCleanup()  */
302                                     /* was called                      */
303
304static int houseKeepingResidual;     /* used by HouseKeeping()          */
305
306static int deleteAllLinks;           /* If equal to zero, DeleteLink()  */
307                                     /* will not remove permanent links */
308
309static FILE *monitorFile;            /* File descriptor for link        */
310                                     /* statistics monitoring file      */
311
312static int firstCall = 1;            /* Needed by InitAlias()           */
313
314static 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
325Lookup 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
331Miscellaneous:
332    SeqDiff()                -- difference between two TCP sequences
333    ShowAliasStats()         -- send alias statistics to a monitor file
334*/
335
336
337/* Local prototypes */
338static u_int StartPointIn(struct in_addr, u_short, int);
339
340static u_int StartPointOut(struct in_addr, struct in_addr,
341                           u_short, u_short, int);
342
343static int SeqDiff(u_long, u_long);
344
345static void ShowAliasStats(void);
346
347
348static u_int
349StartPointIn(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
362static u_int
363StartPointOut(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
378static int
379SeqDiff(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
392static void
393ShowAliasStats(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
423Port Allocation:
424    GetNewPort()             -- find and reserve new alias port number
425    GetSocket()              -- try to allocate a socket for a given port
426
427Link 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
433Link search:
434    FindLinkOut()           - find link for outgoing packets
435    FindLinkIn()            - find link for incoming packets
436*/
437
438/* Local prototypes */
439static int GetNewPort(struct alias_link *, int);
440
441static u_short GetSocket(u_short, int *, int);
442
443static void CleanupAliasData(void);
444
445static void IncrementalCleanup(void);
446
447static void DeleteLink(struct alias_link *);
448
449static struct alias_link *
450AddLink(struct in_addr, struct in_addr, struct in_addr,
451        u_short, u_short, int, int);
452
453static struct alias_link *
454FindLinkOut(struct in_addr, struct in_addr, u_short, u_short, int);
455
456static struct alias_link *
457FindLinkIn(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
472static int
473GetNewPort(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
579static u_short
580GetSocket(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        close(sock);
620        return(0);
621    }
622}
623
624
625static void
626CleanupAliasData(void)
627{
628    struct alias_link *link;
629    int i, icount;
630
631    icount = 0;
632    for (i=0; i<LINK_TABLE_OUT_SIZE; i++)
633    {
634        link = linkTableOut[i];
635        linkTableOut[i] = NULL;
636        while (link != NULL)
637        {
638            struct alias_link *link_next;
639            link_next = link->next_out;
640            icount++;
641            DeleteLink(link);
642            link = link_next;
643        }
644    }
645
646    cleanupIndex =0;
647}
648
649
650static void
651IncrementalCleanup(void)
652{
653    int icount;
654    struct alias_link *link;
655
656    icount = 0;
657    link = linkTableOut[cleanupIndex++];
658    while (link != NULL)
659    {
660        int idelta;
661        struct alias_link *link_next;
662
663        link_next = link->next_out;
664        idelta = timeStamp - link->timestamp;
665        switch (link->link_type)
666        {
667            case LINK_ICMP:
668            case LINK_UDP:
669            case LINK_FRAGMENT_ID:
670            case LINK_FRAGMENT_PTR:
671                if (idelta > link->expire_time)
672                {
673                    DeleteLink(link);
674                    icount++;
675                }
676                break;
677            case LINK_TCP:
678                if (idelta > link->expire_time)
679                {
680                    struct tcp_dat *tcp_aux;
681
682                    tcp_aux = link->data.tcp;
683                    if (tcp_aux->state.in  != 1
684                     || tcp_aux->state.out != 1)
685                    {
686                        DeleteLink(link);
687                        icount++;
688                    }
689                }
690                break;
691        }
692        link = link_next;
693    }
694
695    if (cleanupIndex == LINK_TABLE_OUT_SIZE)
696        cleanupIndex = 0;
697}
698
699void
700DeleteLink(struct alias_link *link)
701{
702    struct alias_link *link_last;
703    struct alias_link *link_next;
704
705/* Don't do anything if the link is marked permanent */
706    if (deleteAllLinks == 0 && link->flags & LINK_PERMANENT)
707        return;
708
709/* Adjust output table pointers */
710    link_last = link->last_out;
711    link_next = link->next_out;
712
713    if (link_last != NULL)
714        link_last->next_out = link_next;
715    else
716        linkTableOut[link->start_point_out] = link_next;
717
718    if (link_next != NULL)
719        link_next->last_out = link_last;
720
721/* Adjust input table pointers */
722    link_last = link->last_in;
723    link_next = link->next_in;
724
725    if (link_last != NULL)
726        link_last->next_in = link_next;
727    else
728        linkTableIn[link->start_point_in] = link_next;
729
730    if (link_next != NULL)
731        link_next->last_in = link_last;
732
733/* Close socket, if one has been allocated */
734    if (link->sockfd != -1)
735    {
736        sockCount--;
737        close(link->sockfd);
738    }
739
740/* Link-type dependent cleanup */
741    switch(link->link_type)
742    {
743        case LINK_ICMP:
744            icmpLinkCount--;
745            break;
746        case LINK_UDP:
747            udpLinkCount--;
748            break;
749        case LINK_TCP:
750            tcpLinkCount--;
751            if (link->data.tcp != NULL)
752                free(link->data.tcp);
753            break;
754        case LINK_FRAGMENT_ID:
755            fragmentIdLinkCount--;
756            break;
757        case LINK_FRAGMENT_PTR:
758            fragmentPtrLinkCount--;
759            if (link->data.frag_ptr != NULL)
760                free(link->data.frag_ptr);
761            break;
762    }
763
764/* Free memory */
765    free(link);
766
767/* Write statistics, if logging enabled */
768    if (packetAliasMode & PKT_ALIAS_LOG)
769    {
770        ShowAliasStats();
771    }
772}
773
774
775static struct alias_link *
776AddLink(struct in_addr  src_addr,
777        struct in_addr  dst_addr,
778        struct in_addr  alias_addr,
779        u_short         src_port,
780        u_short         dst_port,
781        int             alias_port_param,  /* if less than zero, alias   */
782        int             link_type)         /* port will be automatically */
783{                                          /* chosen. If greater than    */
784    u_int start_point;                     /* zero, equal to alias port  */
785    struct alias_link *link;
786    struct alias_link *first_link;
787
788    link = malloc(sizeof(struct alias_link));
789    if (link != NULL)
790    {
791    /* If either the aliasing address or source address are
792       equal to the default device address (equal to the
793       global variable aliasAddress), then set the alias
794       address field of the link record to zero */
795
796        if (src_addr.s_addr == aliasAddress.s_addr)
797            src_addr.s_addr = 0;
798
799        if (alias_addr.s_addr == aliasAddress.s_addr)
800            alias_addr.s_addr = 0;
801
802    /* Basic initialization */
803        link->src_addr    = src_addr;
804        link->dst_addr    = dst_addr;
805        link->src_port    = src_port;
806        link->alias_addr  = alias_addr;
807        link->dst_port    = dst_port;
808        link->link_type   = link_type;
809        link->sockfd      = -1;
810        link->flags       = 0;
811        link->timestamp   = timeStamp;
812
813    /* Expiration time */
814        switch (link_type)
815        {
816        case LINK_ICMP:
817            link->expire_time = ICMP_EXPIRE_TIME;
818            break;
819        case LINK_UDP:
820            link->expire_time = UDP_EXPIRE_TIME;
821            break;
822        case LINK_TCP:
823            link->expire_time = TCP_EXPIRE_TIME;
824            break;
825        case LINK_FRAGMENT_ID:
826            link->expire_time = FRAGMENT_ID_EXPIRE_TIME;
827            break;
828        case LINK_FRAGMENT_PTR:
829            link->expire_time = FRAGMENT_PTR_EXPIRE_TIME;
830            break;
831        }
832
833    /* Determine alias flags */
834        if (dst_addr.s_addr == 0)
835            link->flags |= LINK_UNKNOWN_DEST_ADDR;
836        if (dst_port == 0)
837            link->flags |= LINK_UNKNOWN_DEST_PORT;
838
839    /* Determine alias port */
840        if (GetNewPort(link, alias_port_param) != 0)
841        {
842            free(link);
843            return(NULL);
844        }
845
846    /* Set up pointers for output lookup table */
847        start_point = StartPointOut(src_addr, dst_addr,
848                                    src_port, dst_port, link_type);
849        first_link = linkTableOut[start_point];
850
851        link->last_out        = NULL;
852        link->next_out        = first_link;
853        link->start_point_out = start_point;
854
855        if (first_link != NULL)
856            first_link->last_out = link;
857
858        linkTableOut[start_point] = link;
859
860    /* Set up pointers for input lookup table */
861        start_point = StartPointIn(alias_addr, link->alias_port, link_type);
862        first_link = linkTableIn[start_point];
863
864        link->last_in        = NULL;
865        link->next_in        = first_link;
866        link->start_point_in = start_point;
867
868        if (first_link != NULL)
869            first_link->last_in = link;
870
871        linkTableIn[start_point] = link;
872
873    /* Link-type dependent initialization */
874        switch(link_type)
875        {
876            struct tcp_dat  *aux_tcp;
877
878            case LINK_ICMP:
879                icmpLinkCount++;
880                break;
881            case LINK_UDP:
882                udpLinkCount++;
883                break;
884            case LINK_TCP:
885                aux_tcp = malloc(sizeof(struct tcp_dat));
886                link->data.tcp = aux_tcp;
887                if (aux_tcp != NULL)
888                {
889                    int i;
890
891                    tcpLinkCount++;
892                    aux_tcp->state.in = 0;
893                    aux_tcp->state.out = 0;
894                    aux_tcp->state.index = 0;
895                    aux_tcp->state.ack_modified = 0;
896                    for (i=0; i<N_LINK_TCP_DATA; i++)
897                        aux_tcp->ack[i].active = 0;
898                }
899                else
900                {
901                    fprintf(stderr, "PacketAlias/AddLink: ");
902                    fprintf(stderr, " cannot allocate auxiliary TCP data\n");
903                }
904                break;
905            case LINK_FRAGMENT_ID:
906                fragmentIdLinkCount++;
907                break;
908            case LINK_FRAGMENT_PTR:
909                fragmentPtrLinkCount++;
910                break;
911        }
912    }
913    else
914    {
915        fprintf(stderr, "PacketAlias/AddLink(): ");
916        fprintf(stderr, "malloc() call failed.\n");
917    }
918
919    if (packetAliasMode & PKT_ALIAS_LOG)
920    {
921        ShowAliasStats();
922    }
923
924    return(link);
925}
926
927
928static struct alias_link *
929FindLinkOut(struct in_addr src_addr,
930            struct in_addr dst_addr,
931            u_short src_port,
932            u_short dst_port,
933            int link_type)
934{
935    u_int i;
936    struct alias_link *link;
937
938    if (src_addr.s_addr == aliasAddress.s_addr)
939        src_addr.s_addr = 0;
940
941    i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type);
942    link = linkTableOut[i];
943    while (link != NULL)
944    {
945        if (link->src_addr.s_addr == src_addr.s_addr
946         && link->dst_addr.s_addr == dst_addr.s_addr
947         && link->dst_port        == dst_port
948         && link->src_port        == src_port
949         && link->link_type       == link_type)
950        {
951            link->timestamp = timeStamp;
952            break;
953        }
954        link = link->next_out;
955    }
956
957    return(link);
958}
959
960
961struct alias_link *
962FindLinkIn(struct in_addr  dst_addr,
963           struct in_addr  alias_addr,
964           u_short         dst_port,
965           u_short         alias_port,
966           int             link_type,
967           int             replace_partial_links)
968{
969    int flags_in;
970    u_int start_point;
971    struct alias_link *link;
972    struct alias_link *link_fully_specified;
973    struct alias_link *link_unknown_all;
974    struct alias_link *link_unknown_dst_addr;
975    struct alias_link *link_unknown_dst_port;
976
977/* Initialize pointers */
978    link_fully_specified  = NULL;
979    link_unknown_all      = NULL;
980    link_unknown_dst_addr = NULL;
981    link_unknown_dst_port = NULL;
982
983/* If either the dest addr or port is unknown, the search
984   loop will have to know about this. */
985
986    flags_in = 0;
987    if (dst_addr.s_addr == 0)
988        flags_in |= LINK_UNKNOWN_DEST_ADDR;
989    if (dst_port == 0)
990        flags_in |= LINK_UNKNOWN_DEST_PORT;
991
992/* The following allows permanent links to be
993   be specified as using the default aliasing address
994   (i.e. device interface address) without knowing
995   in advance what that address is. */
996
997    if (alias_addr.s_addr == aliasAddress.s_addr)
998        alias_addr.s_addr = 0;
999
1000/* Search loop */
1001    start_point = StartPointIn(alias_addr, alias_port, link_type);
1002    link = linkTableIn[start_point];
1003    while (link != NULL)
1004    {
1005        int flags;
1006
1007        flags = flags_in | link->flags;
1008        if (!(flags & LINK_PARTIALLY_SPECIFIED))
1009        {
1010            if (link->alias_addr.s_addr == alias_addr.s_addr
1011             && link->alias_port        == alias_port
1012             && link->dst_addr.s_addr   == dst_addr.s_addr
1013             && link->dst_port          == dst_port
1014             && link->link_type         == link_type)
1015            {
1016                link_fully_specified = link;
1017                break;
1018            }
1019        }
1020        else if ((flags & LINK_UNKNOWN_DEST_ADDR)
1021              && (flags & LINK_UNKNOWN_DEST_PORT))
1022        {
1023            if (link->alias_addr.s_addr == alias_addr.s_addr
1024             && link->alias_port        == alias_port
1025             && link->link_type         == link_type)
1026            {
1027                if (link_unknown_all == NULL)
1028                    link_unknown_all = link;
1029            }
1030        }
1031        else if (flags & LINK_UNKNOWN_DEST_ADDR)
1032        {
1033            if (link->alias_addr.s_addr == alias_addr.s_addr
1034             && link->alias_port        == alias_port
1035             && link->link_type         == link_type
1036             && link->dst_port          == dst_port)
1037            {
1038                if (link_unknown_dst_addr == NULL)
1039                    link_unknown_dst_addr = link;
1040            }
1041        }
1042        else if (flags & LINK_UNKNOWN_DEST_PORT)
1043        {
1044            if (link->alias_addr.s_addr == alias_addr.s_addr
1045             && link->alias_port        == alias_port
1046             && link->link_type         == link_type
1047             && link->dst_addr.s_addr   == dst_addr.s_addr)
1048            {
1049                if (link_unknown_dst_port == NULL)
1050                    link_unknown_dst_port = link;
1051            }
1052        }
1053        link = link->next_in;
1054    }
1055
1056
1057
1058    if (link_fully_specified != NULL)
1059    {
1060        return (link_fully_specified);
1061    }
1062    else if (link_unknown_dst_port != NULL)
1063    {
1064        if (replace_partial_links)
1065        {
1066            link = AddLink(link_unknown_dst_port->src_addr, dst_addr,
1067                           alias_addr,
1068                           link_unknown_dst_port->src_port, dst_port,
1069                           alias_port, link_type);
1070            DeleteLink(link_unknown_dst_port);
1071            return(link);
1072        }
1073        else
1074        {
1075            return(link_unknown_dst_port);
1076        }
1077    }
1078    else if (link_unknown_dst_addr != NULL)
1079    {
1080        if (replace_partial_links)
1081        {
1082            link = AddLink(link_unknown_dst_addr->src_addr, dst_addr,
1083                           alias_addr,
1084                           link_unknown_dst_addr->src_port, dst_port,
1085                           alias_port, link_type);
1086            DeleteLink(link_unknown_dst_addr);
1087            return(link);
1088        }
1089        else
1090        {
1091            return(link_unknown_dst_addr);
1092        }
1093    }
1094    else if (link_unknown_all != NULL)
1095    {
1096        if (replace_partial_links)
1097        {
1098            link = AddLink(link_unknown_all->src_addr, dst_addr,
1099                           alias_addr,
1100                           link_unknown_all->src_port, dst_port,
1101                           alias_port, link_type);
1102            DeleteLink(link_unknown_all);
1103            return(link);
1104        }
1105        else
1106        {
1107            return(link_unknown_all);
1108        }
1109    }
1110    else
1111    {
1112        return(NULL);
1113    }
1114}
1115
1116
1117
1118
1119/* External routines for finding/adding links
1120
1121-- "external" means outside alias_db.c, but within alias*.c --
1122
1123    FindIcmpIn(), FindIcmpOut()
1124    FindFragmentIn1(), FindFragmentIn2()
1125    AddFragmentPtrLink(), FindFragmentPtr()
1126    FindUdpTcpIn(), FindUdpTcpOut()
1127    FindOriginalAddress(), FindAliasAddress()
1128
1129(prototypes in alias_local.h)
1130*/
1131
1132
1133struct alias_link *
1134FindIcmpIn(struct in_addr dst_addr,
1135           struct in_addr alias_addr,
1136           u_short id_alias)
1137{
1138    return FindLinkIn(dst_addr, alias_addr,
1139                      NO_DEST_PORT, id_alias,
1140                      LINK_ICMP, 0);
1141}
1142
1143
1144struct alias_link *
1145FindIcmpOut(struct in_addr src_addr,
1146            struct in_addr dst_addr,
1147            u_short id)
1148{
1149    struct alias_link * link;
1150
1151    link = FindLinkOut(src_addr, dst_addr,
1152                       id, NO_DEST_PORT,
1153                       LINK_ICMP);
1154    if (link == NULL)
1155    {
1156        struct in_addr alias_addr;
1157
1158        alias_addr = FindAliasAddress(src_addr);
1159        link = AddLink(src_addr, dst_addr, alias_addr,
1160                       id, NO_DEST_PORT, GET_ALIAS_ID,
1161                       LINK_ICMP);
1162    }
1163
1164    return(link);
1165}
1166
1167
1168struct alias_link *
1169FindFragmentIn1(struct in_addr dst_addr,
1170                struct in_addr alias_addr,
1171                u_short ip_id)
1172{
1173    struct alias_link *link;
1174
1175    link = FindLinkIn(dst_addr, alias_addr,
1176                      NO_DEST_PORT, ip_id,
1177                      LINK_FRAGMENT_ID, 0);
1178
1179    if (link == NULL)
1180    {
1181        link = AddLink(nullAddress, dst_addr, alias_addr,
1182                       NO_SRC_PORT, NO_DEST_PORT, ip_id,
1183                       LINK_FRAGMENT_ID);
1184    }
1185
1186    return(link);
1187}
1188
1189
1190struct alias_link *
1191FindFragmentIn2(struct in_addr dst_addr,   /* Doesn't add a link if one */
1192                struct in_addr alias_addr, /*   is not found.           */
1193                u_short ip_id)
1194{
1195    return FindLinkIn(dst_addr, alias_addr,
1196                      NO_DEST_PORT, ip_id,
1197                      LINK_FRAGMENT_ID, 0);
1198}
1199
1200
1201struct alias_link *
1202AddFragmentPtrLink(struct in_addr dst_addr,
1203                   u_short ip_id)
1204{
1205    return AddLink(nullAddress, dst_addr, nullAddress,
1206                   NO_SRC_PORT, NO_DEST_PORT, ip_id,
1207                   LINK_FRAGMENT_PTR);
1208}
1209
1210
1211struct alias_link *
1212FindFragmentPtr(struct in_addr dst_addr,
1213                u_short ip_id)
1214{
1215    return FindLinkIn(dst_addr, nullAddress,
1216                      NO_DEST_PORT, ip_id,
1217                      LINK_FRAGMENT_PTR, 0);
1218}
1219
1220
1221struct alias_link *
1222FindUdpTcpIn(struct in_addr dst_addr,
1223             struct in_addr alias_addr,
1224             u_short        dst_port,
1225             u_short        alias_port,
1226             u_char         proto)
1227{
1228    int link_type;
1229    struct alias_link *link;
1230
1231    switch (proto)
1232    {
1233    case IPPROTO_UDP:
1234        link_type = LINK_UDP;
1235        break;
1236    case IPPROTO_TCP:
1237        link_type = LINK_TCP;
1238        break;
1239    default:
1240        return NULL;
1241        break;
1242    }
1243
1244    link = FindLinkIn(dst_addr, alias_addr,
1245                      dst_port, alias_port,
1246                      link_type, 1);
1247
1248    if ( !(packetAliasMode & PKT_ALIAS_DENY_INCOMING) && link == NULL)
1249    {
1250        struct in_addr target_addr;
1251
1252        target_addr = FindOriginalAddress(alias_addr);
1253        link = AddLink(target_addr, dst_addr, alias_addr,
1254                       alias_port, dst_port, alias_port,
1255                       link_type);
1256    }
1257
1258    return(link);
1259}
1260
1261
1262struct alias_link *
1263FindUdpTcpOut(struct in_addr  src_addr,
1264              struct in_addr  dst_addr,
1265              u_short         src_port,
1266              u_short         dst_port,
1267              u_char          proto)
1268{
1269    int link_type;
1270    struct alias_link *link;
1271
1272    switch (proto)
1273    {
1274    case IPPROTO_UDP:
1275        link_type = LINK_UDP;
1276        break;
1277    case IPPROTO_TCP:
1278        link_type = LINK_TCP;
1279        break;
1280    default:
1281        return NULL;
1282        break;
1283    }
1284
1285    link = FindLinkOut(src_addr, dst_addr, src_port, dst_port, link_type);
1286
1287    if (link == NULL)
1288    {
1289        struct in_addr alias_addr;
1290
1291        alias_addr = FindAliasAddress(src_addr);
1292        link = AddLink(src_addr, dst_addr, alias_addr,
1293                       src_port, dst_port, GET_ALIAS_PORT,
1294                       link_type);
1295    }
1296
1297    return(link);
1298}
1299
1300
1301struct in_addr
1302FindOriginalAddress(struct in_addr alias_addr)
1303{
1304    struct alias_link *link;
1305
1306    link = FindLinkIn(nullAddress, alias_addr,
1307                      0, 0, LINK_ADDR, 0);
1308    if (link == NULL)
1309    {
1310        newDefaultLink = 1;
1311        if (targetAddress.s_addr != 0)
1312            return targetAddress;
1313        else
1314            return alias_addr;
1315    }
1316    else
1317    {
1318        if (link->src_addr.s_addr == 0)
1319            return aliasAddress;
1320        else
1321            return link->src_addr;
1322    }
1323}
1324
1325
1326struct in_addr
1327FindAliasAddress(struct in_addr original_addr)
1328{
1329    struct alias_link *link;
1330
1331    link = FindLinkOut(original_addr, nullAddress,
1332                       0, 0, LINK_ADDR);
1333    if (link == NULL)
1334    {
1335        return aliasAddress;
1336    }
1337    else
1338    {
1339        if (link->alias_addr.s_addr == 0)
1340            return aliasAddress;
1341        else
1342            return link->alias_addr;
1343    }
1344}
1345
1346
1347/* External routines for getting or changing link data
1348   (external to alias_db.c, but internal to alias*.c)
1349
1350    SetFragmentData(), GetFragmentData()
1351    SetFragmentPtr(), GetFragmentPtr()
1352    SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut()
1353    GetOriginalAddress(), GetDestAddress(), GetAliasAddress()
1354    GetOriginalPort(), GetAliasPort()
1355    SetAckModified(), GetAckModified()
1356    GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq()
1357*/
1358
1359
1360void
1361SetFragmentAddr(struct alias_link *link, struct in_addr src_addr)
1362{
1363    link->data.frag_addr = src_addr;
1364}
1365
1366
1367void
1368GetFragmentAddr(struct alias_link *link, struct in_addr *src_addr)
1369{
1370    *src_addr = link->data.frag_addr;
1371}
1372
1373
1374void
1375SetFragmentPtr(struct alias_link *link, char *fptr)
1376{
1377    link->data.frag_ptr = fptr;
1378}
1379
1380
1381void
1382GetFragmentPtr(struct alias_link *link, char **fptr)
1383{
1384   *fptr = link->data.frag_ptr;
1385}
1386
1387
1388void
1389SetStateIn(struct alias_link *link, int state)
1390{
1391    /* TCP input state */
1392    (link->data.tcp)->state.in = state;
1393}
1394
1395
1396void
1397SetStateOut(struct alias_link *link, int state)
1398{
1399    /* TCP output state */
1400    (link->data.tcp)->state.out = state;
1401}
1402
1403
1404int
1405GetStateIn(struct alias_link *link)
1406{
1407    /* TCP input state */
1408    return( (link->data.tcp)->state.in);
1409}
1410
1411
1412int
1413GetStateOut(struct alias_link *link)
1414{
1415    /* TCP output state */
1416    return( (link->data.tcp)->state.out);
1417}
1418
1419
1420struct in_addr
1421GetOriginalAddress(struct alias_link *link)
1422{
1423    if (link->src_addr.s_addr == 0)
1424        return aliasAddress;
1425    else
1426        return(link->src_addr);
1427}
1428
1429
1430struct in_addr
1431GetDestAddress(struct alias_link *link)
1432{
1433    return(link->dst_addr);
1434}
1435
1436
1437struct in_addr
1438GetAliasAddress(struct alias_link *link)
1439{
1440    if (link->alias_addr.s_addr == 0)
1441        return aliasAddress;
1442    else
1443        return link->alias_addr;
1444}
1445
1446
1447struct in_addr
1448GetDefaultAliasAddress()
1449{
1450    return aliasAddress;
1451}
1452
1453
1454void
1455SetDefaultAliasAddress(struct in_addr alias_addr)
1456{
1457    aliasAddress = alias_addr;
1458}
1459
1460
1461u_short
1462GetOriginalPort(struct alias_link *link)
1463{
1464    return(link->src_port);
1465}
1466
1467
1468u_short
1469GetAliasPort(struct alias_link *link)
1470{
1471    return(link->alias_port);
1472}
1473
1474
1475void
1476SetAckModified(struct alias_link *link)
1477{
1478/* Indicate that ack numbers have been modified in a TCP connection */
1479    (link->data.tcp)->state.ack_modified = 1;
1480}
1481
1482
1483int
1484GetAckModified(struct alias_link *link)
1485{
1486/* See if ack numbers have been modified */
1487    return( (link->data.tcp)->state.ack_modified );
1488}
1489
1490
1491int
1492GetDeltaAckIn(struct ip *pip, struct alias_link *link)
1493{
1494/*
1495Find out how much the ack number has been altered for an incoming
1496TCP packet.  To do this, a circular list is ack numbers where the TCP
1497packet size was altered is searched.
1498*/
1499
1500    int i;
1501    struct tcphdr *tc;
1502    int delta, ack_diff_min;
1503    u_long ack;
1504
1505    tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
1506    ack      = tc->th_ack;
1507
1508    delta = 0;
1509    ack_diff_min = -1;
1510    for (i=0; i<N_LINK_TCP_DATA; i++)
1511    {
1512        struct ack_data_record x;
1513
1514        x = (link->data.tcp)->ack[i];
1515        if (x.active == 1)
1516        {
1517            int ack_diff;
1518
1519            ack_diff = SeqDiff(x.ack_new, ack);
1520            if (ack_diff >= 0)
1521            {
1522                if (ack_diff_min >= 0)
1523                {
1524                    if (ack_diff < ack_diff_min)
1525                    {
1526                        delta = x.delta;
1527                        ack_diff_min = ack_diff;
1528                    }
1529                }
1530                else
1531                {
1532                    delta = x.delta;
1533                    ack_diff_min = ack_diff;
1534                }
1535            }
1536        }
1537    }
1538    return (delta);
1539}
1540
1541
1542int
1543GetDeltaSeqOut(struct ip *pip, struct alias_link *link)
1544{
1545/*
1546Find out how much the seq number has been altered for an outgoing
1547TCP packet.  To do this, a circular list is ack numbers where the TCP
1548packet size was altered is searched.
1549*/
1550
1551    int i;
1552    struct tcphdr *tc;
1553    int delta, seq_diff_min;
1554    u_long seq;
1555
1556    tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
1557    seq = tc->th_seq;
1558
1559    delta = 0;
1560    seq_diff_min = -1;
1561    for (i=0; i<N_LINK_TCP_DATA; i++)
1562    {
1563        struct ack_data_record x;
1564
1565        x = (link->data.tcp)->ack[i];
1566        if (x.active == 1)
1567        {
1568            int seq_diff;
1569
1570            seq_diff = SeqDiff(x.ack_old, seq);
1571            if (seq_diff >= 0)
1572            {
1573                if (seq_diff_min >= 0)
1574                {
1575                    if (seq_diff < seq_diff_min)
1576                    {
1577                        delta = x.delta;
1578                        seq_diff_min = seq_diff;
1579                    }
1580                }
1581                else
1582                {
1583                    delta = x.delta;
1584                    seq_diff_min = seq_diff;
1585                }
1586            }
1587        }
1588    }
1589    return (delta);
1590}
1591
1592
1593void
1594AddSeq(struct ip *pip, struct alias_link *link, int delta)
1595{
1596/*
1597When a TCP packet has been altered in length, save this
1598information in a circular list.  If enough packets have
1599been altered, then this list will begin to overwrite itself.
1600*/
1601
1602    struct tcphdr *tc;
1603    struct ack_data_record x;
1604    int hlen, tlen, dlen;
1605    int i;
1606
1607    tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
1608
1609    hlen = (pip->ip_hl + tc->th_off) << 2;
1610    tlen = ntohs(pip->ip_len);
1611    dlen = tlen - hlen;
1612
1613    x.ack_old = htonl(ntohl(tc->th_seq) + dlen);
1614    x.ack_new = htonl(ntohl(tc->th_seq) + dlen + delta);
1615    x.delta = delta;
1616    x.active = 1;
1617
1618    i = (link->data.tcp)->state.index;
1619    (link->data.tcp)->ack[i] = x;
1620
1621    i++;
1622    if (i == N_LINK_TCP_DATA)
1623        (link->data.tcp)->state.index = 0;
1624    else
1625        (link->data.tcp)->state.index = i;
1626}
1627
1628void
1629SetExpire(struct alias_link *link, int expire)
1630{
1631    if (expire == 0)
1632    {
1633        link->flags &= ~LINK_PERMANENT;
1634        DeleteLink(link);
1635    }
1636    else if (expire == -1)
1637    {
1638        link->flags |= LINK_PERMANENT;
1639    }
1640    else if (expire > 0)
1641    {
1642        link->expire_time = expire;
1643    }
1644    else
1645    {
1646        fprintf(stderr, "PacketAlias/SetExpire(): ");
1647        fprintf(stderr, "error in expire parameter\n");
1648    }
1649}
1650
1651void
1652ClearCheckNewLink(void)
1653{
1654    newDefaultLink = 0;
1655}
1656
1657
1658/* Miscellaneous Functions
1659
1660    HouseKeeping()
1661    InitPacketAliasLog()
1662    UninitPacketAliasLog()
1663*/
1664
1665/*
1666    Whenever an outgoing or incoming packet is handled, HouseKeeping()
1667    is called to find and remove timed-out aliasing links.  Logic exists
1668    to sweep through the entire table and linked list structure
1669    every 60 seconds.
1670
1671    (prototype in alias_local.h)
1672*/
1673
1674void
1675HouseKeeping(void)
1676{
1677    int i, n, n100;
1678    struct timeval tv;
1679    struct timezone tz;
1680
1681    /*
1682     * Save system time (seconds) in global variable timeStamp for
1683     * use by other functions. This is done so as not to unnecessarily
1684     * waste timeline by making system calls.
1685     */
1686    gettimeofday(&tv, &tz);
1687    timeStamp = tv.tv_sec;
1688
1689    /* Compute number of spokes (output table link chains) to cover */
1690    n100  = LINK_TABLE_OUT_SIZE * 100 + houseKeepingResidual;
1691    n100 *= timeStamp - lastCleanupTime;
1692    n100 /= ALIAS_CLEANUP_INTERVAL_SECS;
1693
1694    n = n100/100;
1695
1696    /* Handle different cases */
1697    if (n > ALIAS_CLEANUP_MAX_SPOKES)
1698    {
1699        n = ALIAS_CLEANUP_MAX_SPOKES;
1700        lastCleanupTime = timeStamp;
1701        houseKeepingResidual = 0;
1702
1703        for (i=0; i<n; i++)
1704            IncrementalCleanup();
1705    }
1706    else if (n > 0)
1707    {
1708        lastCleanupTime = timeStamp;
1709        houseKeepingResidual = n100 - 100*n;
1710
1711        for (i=0; i<n; i++)
1712            IncrementalCleanup();
1713    }
1714    else if (n < 0)
1715    {
1716        fprintf(stderr, "PacketAlias/HouseKeeping(): ");
1717        fprintf(stderr, "something unexpected in time values\n");
1718        lastCleanupTime = timeStamp;
1719        houseKeepingResidual = 0;
1720    }
1721}
1722
1723
1724/* Init the log file and enable logging */
1725void
1726InitPacketAliasLog(void)
1727{
1728   if ((~packetAliasMode & PKT_ALIAS_LOG)
1729    && (monitorFile = fopen("/var/log/alias.log", "w")))
1730   {
1731      packetAliasMode |= PKT_ALIAS_LOG;
1732      fprintf(monitorFile,
1733      "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n");
1734   }
1735}
1736
1737
1738/* Close the log-file and disable logging. */
1739void
1740UninitPacketAliasLog(void)
1741{
1742    if( monitorFile )
1743        fclose(monitorFile);
1744    packetAliasMode &= ~PKT_ALIAS_LOG;
1745}
1746
1747
1748
1749
1750
1751
1752/* Outside world interfaces
1753
1754-- "outside world" means other than alias*.c routines --
1755
1756    PacketAliasRedirectPort()
1757    PacketAliasRedirectAddr()
1758    PacketAliasRedirectDelete()
1759    PacketAliasSetAddress()
1760    PacketAliasInit()
1761    PacketAliasSetMode()
1762
1763(prototypes in alias.h)
1764*/
1765
1766/* Redirection from a specific public addr:port to a
1767   a private addr:port */
1768struct alias_link *
1769PacketAliasRedirectPort(struct in_addr src_addr,   u_short src_port,
1770                        struct in_addr dst_addr,   u_short dst_port,
1771                        struct in_addr alias_addr, u_short alias_port,
1772                        u_char proto)
1773{
1774    int link_type;
1775    struct alias_link *link;
1776
1777    switch(proto)
1778    {
1779    case IPPROTO_UDP:
1780        link_type = LINK_UDP;
1781        break;
1782    case IPPROTO_TCP:
1783        link_type = LINK_TCP;
1784        break;
1785    default:
1786        fprintf(stderr, "PacketAliasRedirectPort(): ");
1787        fprintf(stderr, "only TCP and UDP protocols allowed\n");
1788        return NULL;
1789    }
1790
1791    link = AddLink(src_addr, dst_addr, alias_addr,
1792                   src_port, dst_port, alias_port,
1793                   link_type);
1794
1795    if (link != NULL)
1796    {
1797        link->flags |= LINK_PERMANENT;
1798    }
1799    else
1800    {
1801        fprintf(stderr, "PacketAliasRedirectPort(): "
1802                        "call to AddLink() failed\n");
1803    }
1804
1805    return link;
1806}
1807
1808
1809/* Static address translation */
1810struct alias_link *
1811PacketAliasRedirectAddr(struct in_addr src_addr,
1812                        struct in_addr alias_addr)
1813{
1814    struct alias_link *link;
1815
1816    link = AddLink(src_addr, nullAddress, alias_addr,
1817                   0, 0, 0,
1818                   LINK_ADDR);
1819
1820    if (link != NULL)
1821    {
1822        link->flags |= LINK_PERMANENT;
1823    }
1824    else
1825    {
1826        fprintf(stderr, "PacketAliasRedirectAddr(): "
1827                        "call to AddLink() failed\n");
1828    }
1829
1830    return link;
1831}
1832
1833
1834void
1835PacketAliasRedirectDelete(struct alias_link *link)
1836{
1837/* This is a dangerous function to put in the API,
1838   because an invalid pointer can crash the program. */
1839
1840    deleteAllLinks = 1;
1841    DeleteLink(link);
1842    deleteAllLinks = 0;
1843}
1844
1845
1846void
1847PacketAliasSetAddress(struct in_addr addr)
1848{
1849    if (packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE
1850     && aliasAddress.s_addr != addr.s_addr)
1851    {
1852        CleanupAliasData();
1853        aliasAddress = addr;
1854    }
1855}
1856
1857
1858void
1859PacketAliasSetTarget(struct in_addr target_addr)
1860{
1861    targetAddress = target_addr;
1862}
1863
1864
1865void
1866PacketAliasInit(void)
1867{
1868    int i;
1869    struct timeval tv;
1870    struct timezone tz;
1871
1872    if (firstCall == 1)
1873    {
1874        gettimeofday(&tv, &tz);
1875        timeStamp = tv.tv_sec;
1876        lastCleanupTime = tv.tv_sec;
1877        houseKeepingResidual = 0;
1878
1879        for (i=0; i<LINK_TABLE_OUT_SIZE; i++)
1880            linkTableOut[i] = NULL;
1881        for (i=0; i<LINK_TABLE_IN_SIZE; i++)
1882            linkTableIn[i] = NULL;
1883
1884        firstCall = 0;
1885    }
1886    else
1887    {
1888        deleteAllLinks = 1;
1889        CleanupAliasData();
1890        deleteAllLinks = 0;
1891    }
1892
1893    aliasAddress.s_addr = 0;
1894    targetAddress.s_addr = 0;
1895
1896    icmpLinkCount = 0;
1897    udpLinkCount = 0;
1898    tcpLinkCount = 0;
1899    fragmentIdLinkCount = 0;
1900    fragmentPtrLinkCount = 0;
1901    sockCount = 0;
1902
1903    cleanupIndex =0;
1904
1905    packetAliasMode = PKT_ALIAS_SAME_PORTS
1906                    | PKT_ALIAS_USE_SOCKETS
1907                    | PKT_ALIAS_RESET_ON_ADDR_CHANGE;
1908}
1909
1910
1911/* Change mode for some operations */
1912unsigned int
1913PacketAliasSetMode
1914(
1915    unsigned int flags, /* Which state to bring flags to */
1916    unsigned int mask   /* Mask of which flags to affect (use 0 to do a
1917                           probe for flag values) */
1918)
1919{
1920/* Enable logging? */
1921    if (flags & mask & PKT_ALIAS_LOG)
1922    {
1923        InitPacketAliasLog();     /* Do the enable */
1924    }
1925/* _Disable_ logging? */
1926    if (~flags & mask & PKT_ALIAS_LOG) {
1927        UninitPacketAliasLog();
1928    }
1929
1930/* Other flags can be set/cleared without special action */
1931    packetAliasMode = (flags & mask) | (packetAliasMode & ~mask);
1932    return packetAliasMode;
1933}
1934
1935
1936int
1937PacketAliasCheckNewLink(void)
1938{
1939    return newDefaultLink;
1940}
1941