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