alias_db.c revision 51491
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 51491 1999-09-21 01:26:49Z brian $
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/* Timouts (in seconds) for different link types) */
148#define ICMP_EXPIRE_TIME             60
149#define UDP_EXPIRE_TIME              60
150#define FRAGMENT_ID_EXPIRE_TIME      10
151#define FRAGMENT_PTR_EXPIRE_TIME     30
152
153/* TCP link expire time for different cases */
154/* When the link has been used and closed - minimal grace time to
155   allow ACKs and potential re-connect in FTP (XXX - is this allowed?)  */
156#ifndef TCP_EXPIRE_DEAD
157#   define TCP_EXPIRE_DEAD           10
158#endif
159
160/* When the link has been used and closed on one side - the other side
161   is allowed to still send data */
162#ifndef TCP_EXPIRE_SINGLEDEAD
163#   define TCP_EXPIRE_SINGLEDEAD     90
164#endif
165
166/* When the link isn't yet up */
167#ifndef TCP_EXPIRE_INITIAL
168#   define TCP_EXPIRE_INITIAL       300
169#endif
170
171/* When the link is up */
172#ifndef TCP_EXPIRE_CONNECTED
173#   define TCP_EXPIRE_CONNECTED   86400
174#endif
175
176
177/* Dummy port number codes used for FindLinkIn/Out() and AddLink().
178   These constants can be anything except zero, which indicates an
179   unknown port number. */
180
181#define NO_DEST_PORT     1
182#define NO_SRC_PORT      1
183
184
185
186/* Data Structures
187
188    The fundamental data structure used in this program is
189    "struct alias_link".  Whenever a TCP connection is made,
190    a UDP datagram is sent out, or an ICMP echo request is made,
191    a link record is made (if it has not already been created).
192    The link record is identified by the source address/port
193    and the destination address/port. In the case of an ICMP
194    echo request, the source port is treated as being equivalent
195    with the 16-bit id number of the ICMP packet.
196
197    The link record also can store some auxiliary data.  For
198    TCP connections that have had sequence and acknowledgment
199    modifications, data space is available to track these changes.
200    A state field is used to keep track in changes to the tcp
201    connection state.  Id numbers of fragments can also be
202    stored in the auxiliary space.  Pointers to unresolved
203    framgents can also be stored.
204
205    The link records support two independent chainings.  Lookup
206    tables for input and out tables hold the initial pointers
207    the link chains.  On input, the lookup table indexes on alias
208    port and link type.  On output, the lookup table indexes on
209    source addreess, destination address, source port, destination
210    port and link type.
211*/
212
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                                outgoing packets
371    StartPointOut()          -- port table initial search point for
372                                incoming 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);
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    /* If either the aliasing address or source address are
863       equal to the default device address (equal to the
864       global variable aliasAddress), then set the alias
865       address field of the link record to zero */
866
867        if (src_addr.s_addr == aliasAddress.s_addr)
868            src_addr.s_addr = 0;
869
870        if (alias_addr.s_addr == aliasAddress.s_addr)
871            alias_addr.s_addr = 0;
872
873    /* Basic initialization */
874        link->src_addr          = src_addr;
875        link->dst_addr          = dst_addr;
876        link->alias_addr        = alias_addr;
877        link->proxy_addr.s_addr = 0;
878        link->src_port          = src_port;
879        link->dst_port          = dst_port;
880        link->proxy_port        = 0;
881        link->link_type         = link_type;
882        link->sockfd            = -1;
883        link->flags             = 0;
884        link->timestamp         = timeStamp;
885
886    /* Expiration time */
887        switch (link_type)
888        {
889        case LINK_ICMP:
890            link->expire_time = ICMP_EXPIRE_TIME;
891            break;
892        case LINK_UDP:
893            link->expire_time = UDP_EXPIRE_TIME;
894            break;
895        case LINK_TCP:
896            link->expire_time = TCP_EXPIRE_INITIAL;
897            break;
898        case LINK_FRAGMENT_ID:
899            link->expire_time = FRAGMENT_ID_EXPIRE_TIME;
900            break;
901        case LINK_FRAGMENT_PTR:
902            link->expire_time = FRAGMENT_PTR_EXPIRE_TIME;
903            break;
904        }
905
906    /* Determine alias flags */
907        if (dst_addr.s_addr == 0)
908            link->flags |= LINK_UNKNOWN_DEST_ADDR;
909        if (dst_port == 0)
910            link->flags |= LINK_UNKNOWN_DEST_PORT;
911
912    /* Determine alias port */
913        if (GetNewPort(link, alias_port_param) != 0)
914        {
915            free(link);
916            return(NULL);
917        }
918
919    /* Set up pointers for output lookup table */
920        start_point = StartPointOut(src_addr, dst_addr,
921                                    src_port, dst_port, link_type);
922        first_link = linkTableOut[start_point];
923
924        link->last_out        = NULL;
925        link->next_out        = first_link;
926        link->start_point_out = start_point;
927
928        if (first_link != NULL)
929            first_link->last_out = link;
930
931        linkTableOut[start_point] = link;
932
933    /* Set up pointers for input lookup table */
934        start_point = StartPointIn(alias_addr, link->alias_port, link_type);
935        first_link = linkTableIn[start_point];
936
937        link->last_in        = NULL;
938        link->next_in        = first_link;
939        link->start_point_in = start_point;
940
941        if (first_link != NULL)
942            first_link->last_in = link;
943
944        linkTableIn[start_point] = link;
945
946    /* Link-type dependent initialization */
947        switch(link_type)
948        {
949            struct tcp_dat  *aux_tcp;
950
951            case LINK_ICMP:
952                icmpLinkCount++;
953                break;
954            case LINK_UDP:
955                udpLinkCount++;
956                break;
957            case LINK_TCP:
958                aux_tcp = malloc(sizeof(struct tcp_dat));
959                link->data.tcp = aux_tcp;
960                if (aux_tcp != NULL)
961                {
962                    int i;
963
964                    tcpLinkCount++;
965                    aux_tcp->state.in = ALIAS_TCP_STATE_NOT_CONNECTED;
966                    aux_tcp->state.out = ALIAS_TCP_STATE_NOT_CONNECTED;
967                    aux_tcp->state.index = 0;
968                    aux_tcp->state.ack_modified = 0;
969                    for (i=0; i<N_LINK_TCP_DATA; i++)
970                        aux_tcp->ack[i].active = 0;
971                    aux_tcp->fwhole = -1;
972                }
973                else
974                {
975#ifdef DEBUG
976                    fprintf(stderr, "PacketAlias/AddLink: ");
977                    fprintf(stderr, " cannot allocate auxiliary TCP data\n");
978#endif
979                }
980                break;
981            case LINK_FRAGMENT_ID:
982                fragmentIdLinkCount++;
983                break;
984            case LINK_FRAGMENT_PTR:
985                fragmentPtrLinkCount++;
986                break;
987        }
988    }
989    else
990    {
991#ifdef DEBUG
992        fprintf(stderr, "PacketAlias/AddLink(): ");
993        fprintf(stderr, "malloc() call failed.\n");
994#endif
995    }
996
997    if (packetAliasMode & PKT_ALIAS_LOG)
998    {
999        ShowAliasStats();
1000    }
1001
1002    return(link);
1003}
1004
1005static struct alias_link *
1006ReLink(struct alias_link *old_link,
1007       struct in_addr  src_addr,
1008       struct in_addr  dst_addr,
1009       struct in_addr  alias_addr,
1010       u_short         src_port,
1011       u_short         dst_port,
1012       int             alias_port_param,   /* if less than zero, alias   */
1013       int             link_type)          /* port will be automatically */
1014{                                          /* chosen. If greater than    */
1015    struct alias_link *new_link;           /* zero, equal to alias port  */
1016
1017    new_link = AddLink(src_addr, dst_addr, alias_addr,
1018                       src_port, dst_port, alias_port_param,
1019                       link_type);
1020#ifndef NO_FW_PUNCH
1021    if (new_link != NULL &&
1022        old_link->link_type == LINK_TCP &&
1023        old_link->data.tcp &&
1024        old_link->data.tcp->fwhole > 0) {
1025      PunchFWHole(new_link);
1026    }
1027#endif
1028    DeleteLink(old_link);
1029    return new_link;
1030}
1031
1032static struct alias_link *
1033FindLinkOut(struct in_addr src_addr,
1034            struct in_addr dst_addr,
1035            u_short src_port,
1036            u_short dst_port,
1037            int link_type)
1038{
1039    u_int i;
1040    struct alias_link *link;
1041
1042    if (src_addr.s_addr == aliasAddress.s_addr)
1043        src_addr.s_addr = 0;
1044
1045    i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type);
1046    link = linkTableOut[i];
1047    while (link != NULL)
1048    {
1049        if (link->src_addr.s_addr == src_addr.s_addr
1050         && link->dst_addr.s_addr == dst_addr.s_addr
1051         && link->dst_port        == dst_port
1052         && link->src_port        == src_port
1053         && link->link_type       == link_type)
1054        {
1055            link->timestamp = timeStamp;
1056            break;
1057        }
1058        link = link->next_out;
1059    }
1060
1061    return(link);
1062}
1063
1064
1065struct alias_link *
1066FindLinkIn(struct in_addr  dst_addr,
1067           struct in_addr  alias_addr,
1068           u_short         dst_port,
1069           u_short         alias_port,
1070           int             link_type,
1071           int             replace_partial_links)
1072{
1073    int flags_in;
1074    u_int start_point;
1075    struct alias_link *link;
1076    struct alias_link *link_fully_specified;
1077    struct alias_link *link_unknown_all;
1078    struct alias_link *link_unknown_dst_addr;
1079    struct alias_link *link_unknown_dst_port;
1080
1081/* Initialize pointers */
1082    link_fully_specified  = NULL;
1083    link_unknown_all      = NULL;
1084    link_unknown_dst_addr = NULL;
1085    link_unknown_dst_port = NULL;
1086
1087/* If either the dest addr or port is unknown, the search
1088   loop will have to know about this. */
1089
1090    flags_in = 0;
1091    if (dst_addr.s_addr == 0)
1092        flags_in |= LINK_UNKNOWN_DEST_ADDR;
1093    if (dst_port == 0)
1094        flags_in |= LINK_UNKNOWN_DEST_PORT;
1095
1096/* The following allows permanent links to be
1097   be specified as using the default aliasing address
1098   (i.e. device interface address) without knowing
1099   in advance what that address is. */
1100
1101    if (alias_addr.s_addr == aliasAddress.s_addr)
1102        alias_addr.s_addr = 0;
1103
1104/* Search loop */
1105    start_point = StartPointIn(alias_addr, alias_port, link_type);
1106    link = linkTableIn[start_point];
1107    while (link != NULL)
1108    {
1109        int flags;
1110
1111        flags = flags_in | link->flags;
1112        if (!(flags & LINK_PARTIALLY_SPECIFIED))
1113        {
1114            if (link->alias_addr.s_addr == alias_addr.s_addr
1115             && link->alias_port        == alias_port
1116             && link->dst_addr.s_addr   == dst_addr.s_addr
1117             && link->dst_port          == dst_port
1118             && link->link_type         == link_type)
1119            {
1120                link_fully_specified = link;
1121                break;
1122            }
1123        }
1124        else if ((flags & LINK_UNKNOWN_DEST_ADDR)
1125              && (flags & LINK_UNKNOWN_DEST_PORT))
1126        {
1127            if (link->alias_addr.s_addr == alias_addr.s_addr
1128             && link->alias_port        == alias_port
1129             && link->link_type         == link_type)
1130            {
1131                if (link_unknown_all == NULL)
1132                    link_unknown_all = link;
1133            }
1134        }
1135        else if (flags & LINK_UNKNOWN_DEST_ADDR)
1136        {
1137            if (link->alias_addr.s_addr == alias_addr.s_addr
1138             && link->alias_port        == alias_port
1139             && link->link_type         == link_type
1140             && link->dst_port          == dst_port)
1141            {
1142                if (link_unknown_dst_addr == NULL)
1143                    link_unknown_dst_addr = link;
1144            }
1145        }
1146        else if (flags & LINK_UNKNOWN_DEST_PORT)
1147        {
1148            if (link->alias_addr.s_addr == alias_addr.s_addr
1149             && link->alias_port        == alias_port
1150             && link->link_type         == link_type
1151             && link->dst_addr.s_addr   == dst_addr.s_addr)
1152            {
1153                if (link_unknown_dst_port == NULL)
1154                    link_unknown_dst_port = link;
1155            }
1156        }
1157        link = link->next_in;
1158    }
1159
1160
1161
1162    if (link_fully_specified != NULL)
1163    {
1164        link_fully_specified->timestamp = timeStamp;
1165        return link_fully_specified;
1166    }
1167    else if (link_unknown_dst_port != NULL)
1168    {
1169        return replace_partial_links
1170          ? ReLink(link_unknown_dst_port,
1171                   link_unknown_dst_port->src_addr, dst_addr, alias_addr,
1172                   link_unknown_dst_port->src_port, dst_port, alias_port,
1173                   link_type)
1174          : link_unknown_dst_port;
1175    }
1176    else if (link_unknown_dst_addr != NULL)
1177    {
1178        return replace_partial_links
1179          ? ReLink(link_unknown_dst_addr,
1180                   link_unknown_dst_addr->src_addr, dst_addr, alias_addr,
1181                   link_unknown_dst_addr->src_port, dst_port, alias_port,
1182                   link_type)
1183          : link_unknown_dst_addr;
1184    }
1185    else if (link_unknown_all != NULL)
1186    {
1187        return replace_partial_links
1188          ? ReLink(link_unknown_all,
1189                   link_unknown_all->src_addr, dst_addr, alias_addr,
1190                   link_unknown_all->src_port, dst_port, alias_port,
1191                   link_type)
1192          : link_unknown_all;
1193    }
1194    else
1195    {
1196        return(NULL);
1197    }
1198}
1199
1200
1201
1202
1203/* External routines for finding/adding links
1204
1205-- "external" means outside alias_db.c, but within alias*.c --
1206
1207    FindIcmpIn(), FindIcmpOut()
1208    FindFragmentIn1(), FindFragmentIn2()
1209    AddFragmentPtrLink(), FindFragmentPtr()
1210    FindUdpTcpIn(), FindUdpTcpOut()
1211    FindOriginalAddress(), FindAliasAddress()
1212
1213(prototypes in alias_local.h)
1214*/
1215
1216
1217struct alias_link *
1218FindIcmpIn(struct in_addr dst_addr,
1219           struct in_addr alias_addr,
1220           u_short id_alias)
1221{
1222    return FindLinkIn(dst_addr, alias_addr,
1223                      NO_DEST_PORT, id_alias,
1224                      LINK_ICMP, 0);
1225}
1226
1227
1228struct alias_link *
1229FindIcmpOut(struct in_addr src_addr,
1230            struct in_addr dst_addr,
1231            u_short id)
1232{
1233    struct alias_link * link;
1234
1235    link = FindLinkOut(src_addr, dst_addr,
1236                       id, NO_DEST_PORT,
1237                       LINK_ICMP);
1238    if (link == NULL)
1239    {
1240        struct in_addr alias_addr;
1241
1242        alias_addr = FindAliasAddress(src_addr);
1243        link = AddLink(src_addr, dst_addr, alias_addr,
1244                       id, NO_DEST_PORT, GET_ALIAS_ID,
1245                       LINK_ICMP);
1246    }
1247
1248    return(link);
1249}
1250
1251
1252struct alias_link *
1253FindFragmentIn1(struct in_addr dst_addr,
1254                struct in_addr alias_addr,
1255                u_short ip_id)
1256{
1257    struct alias_link *link;
1258
1259    link = FindLinkIn(dst_addr, alias_addr,
1260                      NO_DEST_PORT, ip_id,
1261                      LINK_FRAGMENT_ID, 0);
1262
1263    if (link == NULL)
1264    {
1265        link = AddLink(nullAddress, dst_addr, alias_addr,
1266                       NO_SRC_PORT, NO_DEST_PORT, ip_id,
1267                       LINK_FRAGMENT_ID);
1268    }
1269
1270    return(link);
1271}
1272
1273
1274struct alias_link *
1275FindFragmentIn2(struct in_addr dst_addr,   /* Doesn't add a link if one */
1276                struct in_addr alias_addr, /*   is not found.           */
1277                u_short ip_id)
1278{
1279    return FindLinkIn(dst_addr, alias_addr,
1280                      NO_DEST_PORT, ip_id,
1281                      LINK_FRAGMENT_ID, 0);
1282}
1283
1284
1285struct alias_link *
1286AddFragmentPtrLink(struct in_addr dst_addr,
1287                   u_short ip_id)
1288{
1289    return AddLink(nullAddress, dst_addr, nullAddress,
1290                   NO_SRC_PORT, NO_DEST_PORT, ip_id,
1291                   LINK_FRAGMENT_PTR);
1292}
1293
1294
1295struct alias_link *
1296FindFragmentPtr(struct in_addr dst_addr,
1297                u_short ip_id)
1298{
1299    return FindLinkIn(dst_addr, nullAddress,
1300                      NO_DEST_PORT, ip_id,
1301                      LINK_FRAGMENT_PTR, 0);
1302}
1303
1304
1305struct alias_link *
1306FindUdpTcpIn(struct in_addr dst_addr,
1307             struct in_addr alias_addr,
1308             u_short        dst_port,
1309             u_short        alias_port,
1310             u_char         proto)
1311{
1312    int link_type;
1313    struct alias_link *link;
1314
1315    switch (proto)
1316    {
1317    case IPPROTO_UDP:
1318        link_type = LINK_UDP;
1319        break;
1320    case IPPROTO_TCP:
1321        link_type = LINK_TCP;
1322        break;
1323    default:
1324        return NULL;
1325        break;
1326    }
1327
1328    link = FindLinkIn(dst_addr, alias_addr,
1329                      dst_port, alias_port,
1330                      link_type, 1);
1331
1332    if (!(packetAliasMode & PKT_ALIAS_DENY_INCOMING)
1333     && !(packetAliasMode & PKT_ALIAS_PROXY_ONLY)
1334     && link == NULL)
1335    {
1336        struct in_addr target_addr;
1337
1338        target_addr = FindOriginalAddress(alias_addr);
1339        link = AddLink(target_addr, dst_addr, alias_addr,
1340                       alias_port, dst_port, alias_port,
1341                       link_type);
1342    }
1343
1344    return(link);
1345}
1346
1347
1348struct alias_link *
1349FindUdpTcpOut(struct in_addr  src_addr,
1350              struct in_addr  dst_addr,
1351              u_short         src_port,
1352              u_short         dst_port,
1353              u_char          proto)
1354{
1355    int link_type;
1356    struct alias_link *link;
1357
1358    switch (proto)
1359    {
1360    case IPPROTO_UDP:
1361        link_type = LINK_UDP;
1362        break;
1363    case IPPROTO_TCP:
1364        link_type = LINK_TCP;
1365        break;
1366    default:
1367        return NULL;
1368        break;
1369    }
1370
1371    link = FindLinkOut(src_addr, dst_addr, src_port, dst_port, link_type);
1372
1373    if (link == NULL)
1374    {
1375        struct in_addr alias_addr;
1376
1377        alias_addr = FindAliasAddress(src_addr);
1378        link = AddLink(src_addr, dst_addr, alias_addr,
1379                       src_port, dst_port, GET_ALIAS_PORT,
1380                       link_type);
1381    }
1382
1383    return(link);
1384}
1385
1386
1387struct in_addr
1388FindOriginalAddress(struct in_addr alias_addr)
1389{
1390    struct alias_link *link;
1391
1392    link = FindLinkIn(nullAddress, alias_addr,
1393                      0, 0, LINK_ADDR, 0);
1394    if (link == NULL)
1395    {
1396        newDefaultLink = 1;
1397        if (targetAddress.s_addr != 0)
1398            return targetAddress;
1399        else
1400            return alias_addr;
1401    }
1402    else
1403    {
1404        if (link->src_addr.s_addr == 0)
1405            return aliasAddress;
1406        else
1407            return link->src_addr;
1408    }
1409}
1410
1411
1412struct in_addr
1413FindAliasAddress(struct in_addr original_addr)
1414{
1415    struct alias_link *link;
1416
1417    link = FindLinkOut(original_addr, nullAddress,
1418                       0, 0, LINK_ADDR);
1419    if (link == NULL)
1420    {
1421        return aliasAddress;
1422    }
1423    else
1424    {
1425        if (link->alias_addr.s_addr == 0)
1426            return aliasAddress;
1427        else
1428            return link->alias_addr;
1429    }
1430}
1431
1432
1433/* External routines for getting or changing link data
1434   (external to alias_db.c, but internal to alias*.c)
1435
1436    SetFragmentData(), GetFragmentData()
1437    SetFragmentPtr(), GetFragmentPtr()
1438    SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut()
1439    GetOriginalAddress(), GetDestAddress(), GetAliasAddress()
1440    GetOriginalPort(), GetAliasPort()
1441    SetAckModified(), GetAckModified()
1442    GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq()
1443*/
1444
1445
1446void
1447SetFragmentAddr(struct alias_link *link, struct in_addr src_addr)
1448{
1449    link->data.frag_addr = src_addr;
1450}
1451
1452
1453void
1454GetFragmentAddr(struct alias_link *link, struct in_addr *src_addr)
1455{
1456    *src_addr = link->data.frag_addr;
1457}
1458
1459
1460void
1461SetFragmentPtr(struct alias_link *link, char *fptr)
1462{
1463    link->data.frag_ptr = fptr;
1464}
1465
1466
1467void
1468GetFragmentPtr(struct alias_link *link, char **fptr)
1469{
1470   *fptr = link->data.frag_ptr;
1471}
1472
1473
1474void
1475SetStateIn(struct alias_link *link, int state)
1476{
1477    /* TCP input state */
1478    switch (state) {
1479    case ALIAS_TCP_STATE_DISCONNECTED:
1480        if (link->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED) {
1481            link->expire_time = TCP_EXPIRE_DEAD;
1482        } else {
1483            link->expire_time = TCP_EXPIRE_SINGLEDEAD;
1484        }
1485        link->data.tcp->state.in = state;
1486        break;
1487    case ALIAS_TCP_STATE_CONNECTED:
1488        link->expire_time = TCP_EXPIRE_CONNECTED;
1489        /*FALLTHROUGH*/
1490    case ALIAS_TCP_STATE_NOT_CONNECTED:
1491        link->data.tcp->state.in = state;
1492        break;
1493    default:
1494        abort();
1495    }
1496}
1497
1498
1499void
1500SetStateOut(struct alias_link *link, int state)
1501{
1502    /* TCP output state */
1503    switch (state) {
1504    case ALIAS_TCP_STATE_DISCONNECTED:
1505        if (link->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED) {
1506            link->expire_time = TCP_EXPIRE_DEAD;
1507        } else {
1508            link->expire_time = TCP_EXPIRE_SINGLEDEAD;
1509        }
1510        link->data.tcp->state.out = state;
1511        break;
1512    case ALIAS_TCP_STATE_CONNECTED:
1513        link->expire_time = TCP_EXPIRE_CONNECTED;
1514        /*FALLTHROUGH*/
1515    case ALIAS_TCP_STATE_NOT_CONNECTED:
1516        link->data.tcp->state.out = state;
1517        break;
1518    default:
1519        abort();
1520    }
1521}
1522
1523
1524int
1525GetStateIn(struct alias_link *link)
1526{
1527    /* TCP input state */
1528    return link->data.tcp->state.in;
1529}
1530
1531
1532int
1533GetStateOut(struct alias_link *link)
1534{
1535    /* TCP output state */
1536    return link->data.tcp->state.out;
1537}
1538
1539
1540struct in_addr
1541GetOriginalAddress(struct alias_link *link)
1542{
1543    if (link->src_addr.s_addr == 0)
1544        return aliasAddress;
1545    else
1546        return(link->src_addr);
1547}
1548
1549
1550struct in_addr
1551GetDestAddress(struct alias_link *link)
1552{
1553    return(link->dst_addr);
1554}
1555
1556
1557struct in_addr
1558GetAliasAddress(struct alias_link *link)
1559{
1560    if (link->alias_addr.s_addr == 0)
1561        return aliasAddress;
1562    else
1563        return link->alias_addr;
1564}
1565
1566
1567struct in_addr
1568GetDefaultAliasAddress()
1569{
1570    return aliasAddress;
1571}
1572
1573
1574void
1575SetDefaultAliasAddress(struct in_addr alias_addr)
1576{
1577    aliasAddress = alias_addr;
1578}
1579
1580
1581u_short
1582GetOriginalPort(struct alias_link *link)
1583{
1584    return(link->src_port);
1585}
1586
1587
1588u_short
1589GetAliasPort(struct alias_link *link)
1590{
1591    return(link->alias_port);
1592}
1593
1594u_short
1595GetDestPort(struct alias_link *link)
1596{
1597    return(link->dst_port);
1598}
1599
1600void
1601SetAckModified(struct alias_link *link)
1602{
1603/* Indicate that ack numbers have been modified in a TCP connection */
1604    link->data.tcp->state.ack_modified = 1;
1605}
1606
1607
1608struct in_addr
1609GetProxyAddress(struct alias_link *link)
1610{
1611    return link->proxy_addr;
1612}
1613
1614
1615void
1616SetProxyAddress(struct alias_link *link, struct in_addr addr)
1617{
1618    link->proxy_addr = addr;
1619}
1620
1621
1622u_short
1623GetProxyPort(struct alias_link *link)
1624{
1625    return link->proxy_port;
1626}
1627
1628
1629void
1630SetProxyPort(struct alias_link *link, u_short port)
1631{
1632    link->proxy_port = port;
1633}
1634
1635
1636int
1637GetAckModified(struct alias_link *link)
1638{
1639/* See if ack numbers have been modified */
1640    return link->data.tcp->state.ack_modified;
1641}
1642
1643
1644int
1645GetDeltaAckIn(struct ip *pip, struct alias_link *link)
1646{
1647/*
1648Find out how much the ack number has been altered for an incoming
1649TCP packet.  To do this, a circular list is ack numbers where the TCP
1650packet size was altered is searched.
1651*/
1652
1653    int i;
1654    struct tcphdr *tc;
1655    int delta, ack_diff_min;
1656    u_long ack;
1657
1658    tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
1659    ack      = tc->th_ack;
1660
1661    delta = 0;
1662    ack_diff_min = -1;
1663    for (i=0; i<N_LINK_TCP_DATA; i++)
1664    {
1665        struct ack_data_record x;
1666
1667        x = link->data.tcp->ack[i];
1668        if (x.active == 1)
1669        {
1670            int ack_diff;
1671
1672            ack_diff = SeqDiff(x.ack_new, ack);
1673            if (ack_diff >= 0)
1674            {
1675                if (ack_diff_min >= 0)
1676                {
1677                    if (ack_diff < ack_diff_min)
1678                    {
1679                        delta = x.delta;
1680                        ack_diff_min = ack_diff;
1681                    }
1682                }
1683                else
1684                {
1685                    delta = x.delta;
1686                    ack_diff_min = ack_diff;
1687                }
1688            }
1689        }
1690    }
1691    return (delta);
1692}
1693
1694
1695int
1696GetDeltaSeqOut(struct ip *pip, struct alias_link *link)
1697{
1698/*
1699Find out how much the seq number has been altered for an outgoing
1700TCP packet.  To do this, a circular list is ack numbers where the TCP
1701packet size was altered is searched.
1702*/
1703
1704    int i;
1705    struct tcphdr *tc;
1706    int delta, seq_diff_min;
1707    u_long seq;
1708
1709    tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
1710    seq = tc->th_seq;
1711
1712    delta = 0;
1713    seq_diff_min = -1;
1714    for (i=0; i<N_LINK_TCP_DATA; i++)
1715    {
1716        struct ack_data_record x;
1717
1718        x = link->data.tcp->ack[i];
1719        if (x.active == 1)
1720        {
1721            int seq_diff;
1722
1723            seq_diff = SeqDiff(x.ack_old, seq);
1724            if (seq_diff >= 0)
1725            {
1726                if (seq_diff_min >= 0)
1727                {
1728                    if (seq_diff < seq_diff_min)
1729                    {
1730                        delta = x.delta;
1731                        seq_diff_min = seq_diff;
1732                    }
1733                }
1734                else
1735                {
1736                    delta = x.delta;
1737                    seq_diff_min = seq_diff;
1738                }
1739            }
1740        }
1741    }
1742    return (delta);
1743}
1744
1745
1746void
1747AddSeq(struct ip *pip, struct alias_link *link, int delta)
1748{
1749/*
1750When a TCP packet has been altered in length, save this
1751information in a circular list.  If enough packets have
1752been altered, then this list will begin to overwrite itself.
1753*/
1754
1755    struct tcphdr *tc;
1756    struct ack_data_record x;
1757    int hlen, tlen, dlen;
1758    int i;
1759
1760    tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
1761
1762    hlen = (pip->ip_hl + tc->th_off) << 2;
1763    tlen = ntohs(pip->ip_len);
1764    dlen = tlen - hlen;
1765
1766    x.ack_old = htonl(ntohl(tc->th_seq) + dlen);
1767    x.ack_new = htonl(ntohl(tc->th_seq) + dlen + delta);
1768    x.delta = delta;
1769    x.active = 1;
1770
1771    i = link->data.tcp->state.index;
1772    link->data.tcp->ack[i] = x;
1773
1774    i++;
1775    if (i == N_LINK_TCP_DATA)
1776        link->data.tcp->state.index = 0;
1777    else
1778        link->data.tcp->state.index = i;
1779}
1780
1781void
1782SetExpire(struct alias_link *link, int expire)
1783{
1784    if (expire == 0)
1785    {
1786        link->flags &= ~LINK_PERMANENT;
1787        DeleteLink(link);
1788    }
1789    else if (expire == -1)
1790    {
1791        link->flags |= LINK_PERMANENT;
1792    }
1793    else if (expire > 0)
1794    {
1795        link->expire_time = expire;
1796    }
1797    else
1798    {
1799#ifdef DEBUG
1800        fprintf(stderr, "PacketAlias/SetExpire(): ");
1801        fprintf(stderr, "error in expire parameter\n");
1802#endif
1803    }
1804}
1805
1806void
1807ClearCheckNewLink(void)
1808{
1809    newDefaultLink = 0;
1810}
1811
1812
1813/* Miscellaneous Functions
1814
1815    HouseKeeping()
1816    InitPacketAliasLog()
1817    UninitPacketAliasLog()
1818*/
1819
1820/*
1821    Whenever an outgoing or incoming packet is handled, HouseKeeping()
1822    is called to find and remove timed-out aliasing links.  Logic exists
1823    to sweep through the entire table and linked list structure
1824    every 60 seconds.
1825
1826    (prototype in alias_local.h)
1827*/
1828
1829void
1830HouseKeeping(void)
1831{
1832    int i, n, n100;
1833    struct timeval tv;
1834    struct timezone tz;
1835
1836    /*
1837     * Save system time (seconds) in global variable timeStamp for
1838     * use by other functions. This is done so as not to unnecessarily
1839     * waste timeline by making system calls.
1840     */
1841    gettimeofday(&tv, &tz);
1842    timeStamp = tv.tv_sec;
1843
1844    /* Compute number of spokes (output table link chains) to cover */
1845    n100  = LINK_TABLE_OUT_SIZE * 100 + houseKeepingResidual;
1846    n100 *= timeStamp - lastCleanupTime;
1847    n100 /= ALIAS_CLEANUP_INTERVAL_SECS;
1848
1849    n = n100/100;
1850
1851    /* Handle different cases */
1852    if (n > ALIAS_CLEANUP_MAX_SPOKES)
1853    {
1854        n = ALIAS_CLEANUP_MAX_SPOKES;
1855        lastCleanupTime = timeStamp;
1856        houseKeepingResidual = 0;
1857
1858        for (i=0; i<n; i++)
1859            IncrementalCleanup();
1860    }
1861    else if (n > 0)
1862    {
1863        lastCleanupTime = timeStamp;
1864        houseKeepingResidual = n100 - 100*n;
1865
1866        for (i=0; i<n; i++)
1867            IncrementalCleanup();
1868    }
1869    else if (n < 0)
1870    {
1871#ifdef DEBUG
1872        fprintf(stderr, "PacketAlias/HouseKeeping(): ");
1873        fprintf(stderr, "something unexpected in time values\n");
1874#endif
1875        lastCleanupTime = timeStamp;
1876        houseKeepingResidual = 0;
1877    }
1878}
1879
1880
1881/* Init the log file and enable logging */
1882static void
1883InitPacketAliasLog(void)
1884{
1885   if ((~packetAliasMode & PKT_ALIAS_LOG)
1886    && (monitorFile = fopen("/var/log/alias.log", "w")))
1887   {
1888      packetAliasMode |= PKT_ALIAS_LOG;
1889      fprintf(monitorFile,
1890      "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n");
1891   }
1892}
1893
1894
1895/* Close the log-file and disable logging. */
1896static void
1897UninitPacketAliasLog(void)
1898{
1899    if (monitorFile) {
1900        fclose(monitorFile);
1901        monitorFile = NULL;
1902    }
1903    packetAliasMode &= ~PKT_ALIAS_LOG;
1904}
1905
1906
1907
1908
1909
1910
1911/* Outside world interfaces
1912
1913-- "outside world" means other than alias*.c routines --
1914
1915    PacketAliasRedirectPort()
1916    PacketAliasRedirectAddr()
1917    PacketAliasRedirectDelete()
1918    PacketAliasSetAddress()
1919    PacketAliasInit()
1920    PacketAliasUninit()
1921    PacketAliasSetMode()
1922
1923(prototypes in alias.h)
1924*/
1925
1926/* Redirection from a specific public addr:port to a
1927   a private addr:port */
1928struct alias_link *
1929PacketAliasRedirectPort(struct in_addr src_addr,   u_short src_port,
1930                        struct in_addr dst_addr,   u_short dst_port,
1931                        struct in_addr alias_addr, u_short alias_port,
1932                        u_char proto)
1933{
1934    int link_type;
1935    struct alias_link *link;
1936
1937    switch(proto)
1938    {
1939    case IPPROTO_UDP:
1940        link_type = LINK_UDP;
1941        break;
1942    case IPPROTO_TCP:
1943        link_type = LINK_TCP;
1944        break;
1945    default:
1946#ifdef DEBUG
1947        fprintf(stderr, "PacketAliasRedirectPort(): ");
1948        fprintf(stderr, "only TCP and UDP protocols allowed\n");
1949#endif
1950        return NULL;
1951    }
1952
1953    link = AddLink(src_addr, dst_addr, alias_addr,
1954                   src_port, dst_port, alias_port,
1955                   link_type);
1956
1957    if (link != NULL)
1958    {
1959        link->flags |= LINK_PERMANENT;
1960    }
1961#ifdef DEBUG
1962    else
1963    {
1964        fprintf(stderr, "PacketAliasRedirectPort(): "
1965                        "call to AddLink() failed\n");
1966    }
1967#endif
1968
1969    return link;
1970}
1971
1972/* Translate PPTP packets to a machine on the inside
1973 */
1974int
1975PacketAliasPptp(struct in_addr src_addr)
1976{
1977
1978    pptpAliasAddr = src_addr; 		/* Address of the inside PPTP machine */
1979    pptpAliasFlag = src_addr.s_addr != INADDR_NONE;
1980
1981    return 1;
1982}
1983
1984int GetPptpAlias (struct in_addr* alias_addr)
1985{
1986    if (pptpAliasFlag)
1987	*alias_addr = pptpAliasAddr;
1988
1989    return pptpAliasFlag;
1990}
1991
1992/* Static address translation */
1993struct alias_link *
1994PacketAliasRedirectAddr(struct in_addr src_addr,
1995                        struct in_addr alias_addr)
1996{
1997    struct alias_link *link;
1998
1999    link = AddLink(src_addr, nullAddress, alias_addr,
2000                   0, 0, 0,
2001                   LINK_ADDR);
2002
2003    if (link != NULL)
2004    {
2005        link->flags |= LINK_PERMANENT;
2006    }
2007#ifdef DEBUG
2008    else
2009    {
2010        fprintf(stderr, "PacketAliasRedirectAddr(): "
2011                        "call to AddLink() failed\n");
2012    }
2013#endif
2014
2015    return link;
2016}
2017
2018
2019void
2020PacketAliasRedirectDelete(struct alias_link *link)
2021{
2022/* This is a dangerous function to put in the API,
2023   because an invalid pointer can crash the program. */
2024
2025    deleteAllLinks = 1;
2026    DeleteLink(link);
2027    deleteAllLinks = 0;
2028}
2029
2030
2031void
2032PacketAliasSetAddress(struct in_addr addr)
2033{
2034    if (packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE
2035     && aliasAddress.s_addr != addr.s_addr)
2036        CleanupAliasData();
2037
2038    aliasAddress = addr;
2039}
2040
2041
2042void
2043PacketAliasSetTarget(struct in_addr target_addr)
2044{
2045    targetAddress = target_addr;
2046}
2047
2048
2049void
2050PacketAliasInit(void)
2051{
2052    int i;
2053    struct timeval tv;
2054    struct timezone tz;
2055    static int firstCall = 1;
2056
2057    if (firstCall == 1)
2058    {
2059        gettimeofday(&tv, &tz);
2060        timeStamp = tv.tv_sec;
2061        lastCleanupTime = tv.tv_sec;
2062        houseKeepingResidual = 0;
2063
2064        for (i=0; i<LINK_TABLE_OUT_SIZE; i++)
2065            linkTableOut[i] = NULL;
2066        for (i=0; i<LINK_TABLE_IN_SIZE; i++)
2067            linkTableIn[i] = NULL;
2068
2069        atexit(PacketAliasUninit);
2070        firstCall = 0;
2071    }
2072    else
2073    {
2074        deleteAllLinks = 1;
2075        CleanupAliasData();
2076        deleteAllLinks = 0;
2077    }
2078
2079    aliasAddress.s_addr = 0;
2080    targetAddress.s_addr = 0;
2081
2082    icmpLinkCount = 0;
2083    udpLinkCount = 0;
2084    tcpLinkCount = 0;
2085    fragmentIdLinkCount = 0;
2086    fragmentPtrLinkCount = 0;
2087    sockCount = 0;
2088
2089    cleanupIndex =0;
2090
2091    packetAliasMode = PKT_ALIAS_SAME_PORTS
2092                    | PKT_ALIAS_USE_SOCKETS
2093                    | PKT_ALIAS_RESET_ON_ADDR_CHANGE;
2094
2095    pptpAliasFlag = 0;
2096}
2097
2098void
2099PacketAliasUninit(void) {
2100    deleteAllLinks = 1;
2101    CleanupAliasData();
2102    deleteAllLinks = 0;
2103    UninitPacketAliasLog();
2104#ifndef NO_FW_PUNCH
2105    UninitPunchFW();
2106#endif
2107}
2108
2109
2110/* Change mode for some operations */
2111unsigned int
2112PacketAliasSetMode(
2113    unsigned int flags, /* Which state to bring flags to */
2114    unsigned int mask   /* Mask of which flags to affect (use 0 to do a
2115                           probe for flag values) */
2116)
2117{
2118/* Enable logging? */
2119    if (flags & mask & PKT_ALIAS_LOG)
2120    {
2121        InitPacketAliasLog();     /* Do the enable */
2122    } else
2123/* _Disable_ logging? */
2124    if (~flags & mask & PKT_ALIAS_LOG) {
2125        UninitPacketAliasLog();
2126    }
2127
2128#ifndef NO_FW_PUNCH
2129/* Start punching holes in the firewall? */
2130    if (flags & mask & PKT_ALIAS_PUNCH_FW) {
2131        InitPunchFW();
2132    } else
2133/* Stop punching holes in the firewall? */
2134    if (~flags & mask & PKT_ALIAS_PUNCH_FW) {
2135        UninitPunchFW();
2136    }
2137#endif
2138
2139/* Other flags can be set/cleared without special action */
2140    packetAliasMode = (flags & mask) | (packetAliasMode & ~mask);
2141    return packetAliasMode;
2142}
2143
2144
2145int
2146PacketAliasCheckNewLink(void)
2147{
2148    return newDefaultLink;
2149}
2150
2151
2152#ifndef NO_FW_PUNCH
2153
2154/*****************
2155  Code to support firewall punching.  This shouldn't really be in this
2156  file, but making variables global is evil too.
2157  ****************/
2158
2159/* Firewall include files */
2160#include <sys/queue.h>
2161#include <net/if.h>
2162#include <netinet/ip_fw.h>
2163#include <string.h>
2164#include <err.h>
2165
2166static void ClearAllFWHoles(void);
2167
2168static int fireWallBaseNum;     /* The first firewall entry free for our use */
2169static int fireWallNumNums;     /* How many entries can we use? */
2170static int fireWallActiveNum;   /* Which entry did we last use? */
2171static char *fireWallField;     /* bool array for entries */
2172
2173#define fw_setfield(field, num)                         \
2174do {                                                    \
2175    (field)[num] = 1;                                   \
2176} /*lint -save -e717 */ while(0) /*lint -restore */
2177#define fw_clrfield(field, num)                         \
2178do {                                                    \
2179    (field)[num] = 0;                                   \
2180} /*lint -save -e717 */ while(0) /*lint -restore */
2181#define fw_tstfield(field, num) ((field)[num])
2182
2183void
2184PacketAliasSetFWBase(unsigned int base, unsigned int num) {
2185    fireWallBaseNum = base;
2186    fireWallNumNums = num;
2187}
2188
2189static void
2190InitPunchFW(void) {
2191    fireWallField = malloc(fireWallNumNums);
2192    if (fireWallField) {
2193        memset(fireWallField, 0, fireWallNumNums);
2194        if (fireWallFD < 0) {
2195            fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
2196        }
2197        ClearAllFWHoles();
2198        fireWallActiveNum = fireWallBaseNum;
2199    }
2200}
2201
2202static void
2203UninitPunchFW(void) {
2204    ClearAllFWHoles();
2205    if (fireWallFD >= 0)
2206        close(fireWallFD);
2207    fireWallFD = -1;
2208    if (fireWallField)
2209        free(fireWallField);
2210    fireWallField = NULL;
2211    packetAliasMode &= ~PKT_ALIAS_PUNCH_FW;
2212}
2213
2214/* Make a certain link go through the firewall */
2215void
2216PunchFWHole(struct alias_link *link) {
2217    int r;                      /* Result code */
2218    struct ip_fw rule;          /* On-the-fly built rule */
2219    int fwhole;                 /* Where to punch hole */
2220
2221/* Don't do anything unless we are asked to */
2222    if ( !(packetAliasMode & PKT_ALIAS_PUNCH_FW) ||
2223         fireWallFD < 0 ||
2224         link->link_type != LINK_TCP ||
2225         !link->data.tcp)
2226        return;
2227
2228    memset(&rule, 0, sizeof rule);
2229
2230/** Build rule **/
2231
2232    /* Find empty slot */
2233    for (fwhole = fireWallActiveNum;
2234         fwhole < fireWallBaseNum + fireWallNumNums &&
2235             fw_tstfield(fireWallField, fwhole);
2236         fwhole++)
2237        ;
2238    if (fwhole >= fireWallBaseNum + fireWallNumNums ||
2239        fw_tstfield(fireWallField, fwhole)) {
2240        for (fwhole = fireWallBaseNum;
2241             fwhole < fireWallActiveNum &&
2242                 fw_tstfield(fireWallField, fwhole);
2243             fwhole++)
2244            ;
2245        if (fwhole == fireWallActiveNum) {
2246            /* No rule point empty - we can't punch more holes. */
2247            fireWallActiveNum = fireWallBaseNum;
2248#ifdef DEBUG
2249            fprintf(stderr, "libalias: Unable to create firewall hole!\n");
2250#endif
2251            return;
2252        }
2253    }
2254    /* Start next search at next position */
2255    fireWallActiveNum = fwhole+1;
2256
2257    /* Build generic part of the two rules */
2258    rule.fw_number = fwhole;
2259    rule.fw_nports = 1;         /* Number of source ports; dest ports follow */
2260    rule.fw_flg = IP_FW_F_ACCEPT;
2261    rule.fw_prot = IPPROTO_TCP;
2262    rule.fw_smsk.s_addr = INADDR_BROADCAST;
2263    rule.fw_dmsk.s_addr = INADDR_BROADCAST;
2264
2265    /* Build and apply specific part of the rules */
2266    rule.fw_src = GetOriginalAddress(link);
2267    rule.fw_dst = GetDestAddress(link);
2268    rule.fw_uar.fw_pts[0] = ntohs(GetOriginalPort(link));
2269    rule.fw_uar.fw_pts[1] = ntohs(GetDestPort(link));
2270
2271    /* Skip non-bound links - XXX should not be strictly necessary,
2272       but seems to leave hole if not done.  Leak of non-bound links?
2273       (Code should be left even if the problem is fixed - it is a
2274       clear optimization) */
2275    if (rule.fw_uar.fw_pts[0] != 0 && rule.fw_uar.fw_pts[1] != 0) {
2276        r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule);
2277#ifdef DEBUG
2278        if (r)
2279            err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)");
2280#endif
2281        rule.fw_src = GetDestAddress(link);
2282        rule.fw_dst = GetOriginalAddress(link);
2283        rule.fw_uar.fw_pts[0] = ntohs(GetDestPort(link));
2284        rule.fw_uar.fw_pts[1] = ntohs(GetOriginalPort(link));
2285        r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule);
2286#ifdef DEBUG
2287        if (r)
2288            err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)");
2289#endif
2290    }
2291/* Indicate hole applied */
2292    link->data.tcp->fwhole = fwhole;
2293    fw_setfield(fireWallField, fwhole);
2294}
2295
2296/* Remove a hole in a firewall associated with a particular alias
2297   link.  Calling this too often is harmless. */
2298static void
2299ClearFWHole(struct alias_link *link) {
2300    if (link->link_type == LINK_TCP && link->data.tcp) {
2301        int fwhole =  link->data.tcp->fwhole; /* Where is the firewall hole? */
2302        struct ip_fw rule;
2303
2304        if (fwhole < 0)
2305            return;
2306
2307        memset(&rule, 0, sizeof rule);
2308        rule.fw_number = fwhole;
2309        while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule))
2310            ;
2311        fw_clrfield(fireWallField, fwhole);
2312        link->data.tcp->fwhole = -1;
2313    }
2314}
2315
2316/* Clear out the entire range dedicated to firewall holes. */
2317static void
2318ClearAllFWHoles(void) {
2319    struct ip_fw rule;          /* On-the-fly built rule */
2320    int i;
2321
2322    if (fireWallFD < 0)
2323        return;
2324
2325    memset(&rule, 0, sizeof rule);
2326    for (i = fireWallBaseNum; i < fireWallBaseNum + fireWallNumNums; i++) {
2327        rule.fw_number = i;
2328        while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule))
2329            ;
2330    }
2331    memset(fireWallField, 0, fireWallNumNums);
2332}
2333#endif
2334