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