alias_db.c revision 59356
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 unspecified 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 are now available through
52        a new interface, SetPacketAliasMode().  This allows 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 permanent 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 59356 2000-04-18 10:18:21Z 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 PPTP_EXPIRE_TIME             60
151#define FRAGMENT_ID_EXPIRE_TIME      10
152#define FRAGMENT_PTR_EXPIRE_TIME     30
153
154/* TCP link expire time for different cases */
155/* When the link has been used and closed - minimal grace time to
156   allow ACKs and potential re-connect in FTP (XXX - is this allowed?)  */
157#ifndef TCP_EXPIRE_DEAD
158#   define TCP_EXPIRE_DEAD           10
159#endif
160
161/* When the link has been used and closed on one side - the other side
162   is allowed to still send data */
163#ifndef TCP_EXPIRE_SINGLEDEAD
164#   define TCP_EXPIRE_SINGLEDEAD     90
165#endif
166
167/* When the link isn't yet up */
168#ifndef TCP_EXPIRE_INITIAL
169#   define TCP_EXPIRE_INITIAL       300
170#endif
171
172/* When the link is up */
173#ifndef TCP_EXPIRE_CONNECTED
174#   define TCP_EXPIRE_CONNECTED   86400
175#endif
176
177
178/* Dummy port number codes used for FindLinkIn/Out() and AddLink().
179   These constants can be anything except zero, which indicates an
180   unknown port number. */
181
182#define NO_DEST_PORT     1
183#define NO_SRC_PORT      1
184
185
186
187/* Data Structures
188
189    The fundamental data structure used in this program is
190    "struct alias_link".  Whenever a TCP connection is made,
191    a UDP datagram is sent out, or an ICMP echo request is made,
192    a link record is made (if it has not already been created).
193    The link record is identified by the source address/port
194    and the destination address/port. In the case of an ICMP
195    echo request, the source port is treated as being equivalent
196    with the 16-bit ID number of the ICMP packet.
197
198    The link record also can store some auxiliary data.  For
199    TCP connections that have had sequence and acknowledgment
200    modifications, data space is available to track these changes.
201    A state field is used to keep track in changes to the TCP
202    connection state.  ID numbers of fragments can also be
203    stored in the auxiliary space.  Pointers to unresolved
204    fragments can also be stored.
205
206    The link records support two independent chainings.  Lookup
207    tables for input and out tables hold the initial pointers
208    the link chains.  On input, the lookup table indexes on alias
209    port and link type.  On output, the lookup table indexes on
210    source address, destination address, source port, destination
211    port and link type.
212*/
213
214struct ack_data_record     /* used to save changes to ACK/sequence numbers */
215{
216    u_long ack_old;
217    u_long ack_new;
218    int delta;
219    int active;
220};
221
222struct tcp_state           /* Information about TCP connection        */
223{
224    int in;                /* State for outside -> inside             */
225    int out;               /* State for inside  -> outside            */
226    int index;             /* Index to ACK data array                 */
227    int ack_modified;      /* Indicates whether ACK and sequence numbers */
228                           /* been modified                           */
229};
230
231#define N_LINK_TCP_DATA   3 /* Number of distinct ACK number changes
232                               saved for a modified TCP stream */
233struct tcp_dat
234{
235    struct tcp_state state;
236    struct ack_data_record ack[N_LINK_TCP_DATA];
237    int fwhole;             /* Which firewall record is used for this hole? */
238};
239
240struct alias_link                /* Main data structure */
241{
242    struct in_addr src_addr;     /* Address and port information        */
243    struct in_addr dst_addr;
244    struct in_addr alias_addr;
245    struct in_addr proxy_addr;
246    u_short src_port;
247    u_short dst_port;
248    u_short alias_port;
249    u_short proxy_port;
250
251    int link_type;               /* Type of link: TCP, UDP, ICMP, PPTP, frag */
252
253/* values for link_type */
254#define LINK_ICMP                     1
255#define LINK_UDP                      2
256#define LINK_TCP                      3
257#define LINK_FRAGMENT_ID              4
258#define LINK_FRAGMENT_PTR             5
259#define LINK_ADDR                     6
260#define LINK_PPTP                     7
261
262    int flags;                   /* indicates special characteristics   */
263
264/* flag bits */
265#define LINK_UNKNOWN_DEST_PORT     0x01
266#define LINK_UNKNOWN_DEST_ADDR     0x02
267#define LINK_PERMANENT             0x04
268#define LINK_PARTIALLY_SPECIFIED   0x03 /* logical-or of first two bits */
269#define LINK_UNFIREWALLED          0x08
270
271    int timestamp;               /* Time link was last accessed         */
272    int expire_time;             /* Expire time for link                */
273
274    int sockfd;                  /* socket descriptor                   */
275
276    u_int start_point_out;       /* Index number in output lookup table */
277    u_int start_point_in;
278    struct alias_link *next_out; /* Linked list pointers for input and  */
279    struct alias_link *last_out; /* output tables                       */
280    struct alias_link *next_in;  /*  .                                  */
281    struct alias_link *last_in;  /*  .                                  */
282
283    union                        /* Auxiliary data                      */
284    {
285        char *frag_ptr;
286        struct in_addr frag_addr;
287        struct tcp_dat *tcp;
288    } data;
289};
290
291
292
293
294
295/* Global Variables
296
297    The global variables listed here are only accessed from
298    within alias_db.c and so are prefixed with the static
299    designation.
300*/
301
302int packetAliasMode;                 /* Mode flags                      */
303                                     /*        - documented in alias.h  */
304
305static struct in_addr aliasAddress;  /* Address written onto source     */
306                                     /*   field of IP packet.           */
307
308static struct in_addr targetAddress; /* IP address incoming packets     */
309                                     /*   are sent to if no aliasing    */
310                                     /*   link already exists           */
311
312static struct in_addr nullAddress;   /* Used as a dummy parameter for   */
313                                     /*   some function calls           */
314static struct alias_link *
315linkTableOut[LINK_TABLE_OUT_SIZE];   /* Lookup table of pointers to     */
316                                     /*   chains of link records. Each  */
317static struct alias_link *           /*   link record is doubly indexed */
318linkTableIn[LINK_TABLE_IN_SIZE];     /*   into input and output lookup  */
319                                     /*   tables.                       */
320
321static int icmpLinkCount;            /* Link statistics                 */
322static int udpLinkCount;
323static int tcpLinkCount;
324static int pptpLinkCount;
325static int fragmentIdLinkCount;
326static int fragmentPtrLinkCount;
327static int sockCount;
328
329static int cleanupIndex;             /* Index to chain of link table    */
330                                     /* being inspected for old links   */
331
332static int timeStamp;                /* System time in seconds for      */
333                                     /* current packet                  */
334
335static int lastCleanupTime;          /* Last time IncrementalCleanup()  */
336                                     /* was called                      */
337
338static int houseKeepingResidual;     /* used by HouseKeeping()          */
339
340static int deleteAllLinks;           /* If equal to zero, DeleteLink()  */
341                                     /* will not remove permanent links */
342
343static FILE *monitorFile;            /* File descriptor for link        */
344                                     /* statistics monitoring file      */
345
346static int newDefaultLink;           /* Indicates if a new aliasing     */
347                                     /* link has been created after a   */
348                                     /* call to PacketAliasIn/Out().    */
349
350#ifndef NO_FW_PUNCH
351static int fireWallFD = -1;          /* File descriptor to be able to   */
352                                     /* control firewall.  Opened by    */
353                                     /* PacketAliasSetMode on first     */
354                                     /* setting the PKT_ALIAS_PUNCH_FW  */
355                                     /* flag.                           */
356#endif
357
358
359
360
361
362
363
364/* Internal utility routines (used only in alias_db.c)
365
366Lookup table starting points:
367    StartPointIn()           -- link table initial search point for
368                                incoming packets
369    StartPointOut()          -- link table initial search point for
370                                outgoing packets
371
372Miscellaneous:
373    SeqDiff()                -- difference between two TCP sequences
374    ShowAliasStats()         -- send alias statistics to a monitor file
375*/
376
377
378/* Local prototypes */
379static u_int StartPointIn(struct in_addr, u_short, int);
380
381static u_int StartPointOut(struct in_addr, struct in_addr,
382                           u_short, u_short, int);
383
384static int SeqDiff(u_long, u_long);
385
386static void ShowAliasStats(void);
387
388#ifndef NO_FW_PUNCH
389/* Firewall control */
390static void InitPunchFW(void);
391static void UninitPunchFW(void);
392static void ClearFWHole(struct alias_link *link);
393#endif
394
395/* Log file control */
396static void InitPacketAliasLog(void);
397static void UninitPacketAliasLog(void);
398
399static u_int
400StartPointIn(struct in_addr alias_addr,
401             u_short alias_port,
402             int link_type)
403{
404    u_int n;
405
406    n  = alias_addr.s_addr;
407    n += alias_port;
408    n += link_type;
409    return(n % LINK_TABLE_IN_SIZE);
410}
411
412
413static u_int
414StartPointOut(struct in_addr src_addr, struct in_addr dst_addr,
415              u_short src_port, u_short dst_port, int link_type)
416{
417    u_int n;
418
419    n  = src_addr.s_addr;
420    n += dst_addr.s_addr;
421    n += src_port;
422    n += dst_port;
423    n += link_type;
424
425    return(n % LINK_TABLE_OUT_SIZE);
426}
427
428
429static int
430SeqDiff(u_long x, u_long y)
431{
432/* Return the difference between two TCP sequence numbers */
433
434/*
435    This function is encapsulated in case there are any unusual
436    arithmetic conditions that need to be considered.
437*/
438
439    return (ntohl(y) - ntohl(x));
440}
441
442
443static void
444ShowAliasStats(void)
445{
446/* Used for debugging */
447
448   if (monitorFile)
449   {
450      fprintf(monitorFile, "icmp=%d, udp=%d, tcp=%d, pptp=%d, frag_id=%d frag_ptr=%d",
451              icmpLinkCount,
452              udpLinkCount,
453              tcpLinkCount,
454              pptpLinkCount,
455              fragmentIdLinkCount,
456              fragmentPtrLinkCount);
457
458      fprintf(monitorFile, " / tot=%d  (sock=%d)\n",
459              icmpLinkCount + udpLinkCount
460                            + tcpLinkCount
461                            + pptpLinkCount
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   When 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 PKT_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            case LINK_PPTP:
738                if (idelta > link->expire_time)
739                {
740                    DeleteLink(link);
741                    icount++;
742                }
743                break;
744            case LINK_TCP:
745                if (idelta > link->expire_time)
746                {
747                    struct tcp_dat *tcp_aux;
748
749                    tcp_aux = link->data.tcp;
750                    if (tcp_aux->state.in  != ALIAS_TCP_STATE_CONNECTED
751                     || tcp_aux->state.out != ALIAS_TCP_STATE_CONNECTED)
752                    {
753                        DeleteLink(link);
754                        icount++;
755                    }
756                }
757                break;
758        }
759        link = link_next;
760    }
761
762    if (cleanupIndex == LINK_TABLE_OUT_SIZE)
763        cleanupIndex = 0;
764}
765
766void
767DeleteLink(struct alias_link *link)
768{
769    struct alias_link *link_last;
770    struct alias_link *link_next;
771
772/* Don't do anything if the link is marked permanent */
773    if (deleteAllLinks == 0 && link->flags & LINK_PERMANENT)
774        return;
775
776#ifndef NO_FW_PUNCH
777/* Delete associated firewall hole, if any */
778    ClearFWHole(link);
779#endif
780
781/* Adjust output table pointers */
782    link_last = link->last_out;
783    link_next = link->next_out;
784
785    if (link_last != NULL)
786        link_last->next_out = link_next;
787    else
788        linkTableOut[link->start_point_out] = link_next;
789
790    if (link_next != NULL)
791        link_next->last_out = link_last;
792
793/* Adjust input table pointers */
794    link_last = link->last_in;
795    link_next = link->next_in;
796
797    if (link_last != NULL)
798        link_last->next_in = link_next;
799    else
800        linkTableIn[link->start_point_in] = link_next;
801
802    if (link_next != NULL)
803        link_next->last_in = link_last;
804
805/* Close socket, if one has been allocated */
806    if (link->sockfd != -1)
807    {
808        sockCount--;
809        close(link->sockfd);
810    }
811
812/* Link-type dependent cleanup */
813    switch(link->link_type)
814    {
815        case LINK_ICMP:
816            icmpLinkCount--;
817            break;
818        case LINK_UDP:
819            udpLinkCount--;
820            break;
821        case LINK_TCP:
822            tcpLinkCount--;
823            if (link->data.tcp != NULL)
824                free(link->data.tcp);
825            break;
826        case LINK_PPTP:
827            pptpLinkCount--;
828            break;
829        case LINK_FRAGMENT_ID:
830            fragmentIdLinkCount--;
831            break;
832        case LINK_FRAGMENT_PTR:
833            fragmentPtrLinkCount--;
834            if (link->data.frag_ptr != NULL)
835                free(link->data.frag_ptr);
836            break;
837    }
838
839/* Free memory */
840    free(link);
841
842/* Write statistics, if logging enabled */
843    if (packetAliasMode & PKT_ALIAS_LOG)
844    {
845        ShowAliasStats();
846    }
847}
848
849
850static struct alias_link *
851AddLink(struct in_addr  src_addr,
852        struct in_addr  dst_addr,
853        struct in_addr  alias_addr,
854        u_short         src_port,
855        u_short         dst_port,
856        int             alias_port_param,  /* if less than zero, alias   */
857        int             link_type)         /* port will be automatically */
858{                                          /* chosen. If greater than    */
859    u_int start_point;                     /* zero, equal to alias port  */
860    struct alias_link *link;
861    struct alias_link *first_link;
862
863    link = malloc(sizeof(struct alias_link));
864    if (link != NULL)
865    {
866    /* Basic initialization */
867        link->src_addr          = src_addr;
868        link->dst_addr          = dst_addr;
869        link->alias_addr        = alias_addr;
870        link->proxy_addr.s_addr = INADDR_ANY;
871        link->src_port          = src_port;
872        link->dst_port          = dst_port;
873        link->proxy_port        = 0;
874        link->link_type         = link_type;
875        link->sockfd            = -1;
876        link->flags             = 0;
877        link->timestamp         = timeStamp;
878
879    /* Expiration time */
880        switch (link_type)
881        {
882        case LINK_ICMP:
883            link->expire_time = ICMP_EXPIRE_TIME;
884            break;
885        case LINK_UDP:
886            link->expire_time = UDP_EXPIRE_TIME;
887            break;
888        case LINK_TCP:
889            link->expire_time = TCP_EXPIRE_INITIAL;
890            break;
891        case LINK_PPTP:
892            link->expire_time = PPTP_EXPIRE_TIME;
893            break;
894        case LINK_FRAGMENT_ID:
895            link->expire_time = FRAGMENT_ID_EXPIRE_TIME;
896            break;
897        case LINK_FRAGMENT_PTR:
898            link->expire_time = FRAGMENT_PTR_EXPIRE_TIME;
899            break;
900        }
901
902    /* Determine alias flags */
903        if (dst_addr.s_addr == INADDR_ANY)
904            link->flags |= LINK_UNKNOWN_DEST_ADDR;
905        if (dst_port == 0)
906            link->flags |= LINK_UNKNOWN_DEST_PORT;
907
908    /* Determine alias port */
909        if (GetNewPort(link, alias_port_param) != 0)
910        {
911            free(link);
912            return(NULL);
913        }
914
915    /* Set up pointers for output lookup table */
916        start_point = StartPointOut(src_addr, dst_addr,
917                                    src_port, dst_port, link_type);
918        first_link = linkTableOut[start_point];
919
920        link->last_out        = NULL;
921        link->next_out        = first_link;
922        link->start_point_out = start_point;
923
924        if (first_link != NULL)
925            first_link->last_out = link;
926
927        linkTableOut[start_point] = link;
928
929    /* Set up pointers for input lookup table */
930        start_point = StartPointIn(alias_addr, link->alias_port, link_type);
931        first_link = linkTableIn[start_point];
932
933        link->last_in        = NULL;
934        link->next_in        = first_link;
935        link->start_point_in = start_point;
936
937        if (first_link != NULL)
938            first_link->last_in = link;
939
940        linkTableIn[start_point] = link;
941
942    /* Link-type dependent initialization */
943        switch(link_type)
944        {
945            struct tcp_dat  *aux_tcp;
946
947            case LINK_ICMP:
948                icmpLinkCount++;
949                break;
950            case LINK_UDP:
951                udpLinkCount++;
952                break;
953            case LINK_TCP:
954                aux_tcp = malloc(sizeof(struct tcp_dat));
955                link->data.tcp = aux_tcp;
956                if (aux_tcp != NULL)
957                {
958                    int i;
959
960                    tcpLinkCount++;
961                    aux_tcp->state.in = ALIAS_TCP_STATE_NOT_CONNECTED;
962                    aux_tcp->state.out = ALIAS_TCP_STATE_NOT_CONNECTED;
963                    aux_tcp->state.index = 0;
964                    aux_tcp->state.ack_modified = 0;
965                    for (i=0; i<N_LINK_TCP_DATA; i++)
966                        aux_tcp->ack[i].active = 0;
967                    aux_tcp->fwhole = -1;
968                }
969                else
970                {
971#ifdef DEBUG
972                    fprintf(stderr, "PacketAlias/AddLink: ");
973                    fprintf(stderr, " cannot allocate auxiliary TCP data\n");
974#endif
975                }
976                break;
977            case LINK_PPTP:
978                pptpLinkCount++;
979                break;
980            case LINK_FRAGMENT_ID:
981                fragmentIdLinkCount++;
982                break;
983            case LINK_FRAGMENT_PTR:
984                fragmentPtrLinkCount++;
985                break;
986        }
987    }
988    else
989    {
990#ifdef DEBUG
991        fprintf(stderr, "PacketAlias/AddLink(): ");
992        fprintf(stderr, "malloc() call failed.\n");
993#endif
994    }
995
996    if (packetAliasMode & PKT_ALIAS_LOG)
997    {
998        ShowAliasStats();
999    }
1000
1001    return(link);
1002}
1003
1004static struct alias_link *
1005ReLink(struct alias_link *old_link,
1006       struct in_addr  src_addr,
1007       struct in_addr  dst_addr,
1008       struct in_addr  alias_addr,
1009       u_short         src_port,
1010       u_short         dst_port,
1011       int             alias_port_param,   /* if less than zero, alias   */
1012       int             link_type)          /* port will be automatically */
1013{                                          /* chosen. If greater than    */
1014    struct alias_link *new_link;           /* zero, equal to alias port  */
1015
1016    new_link = AddLink(src_addr, dst_addr, alias_addr,
1017                       src_port, dst_port, alias_port_param,
1018                       link_type);
1019#ifndef NO_FW_PUNCH
1020    if (new_link != NULL &&
1021        old_link->link_type == LINK_TCP &&
1022        old_link->data.tcp &&
1023        old_link->data.tcp->fwhole > 0) {
1024      PunchFWHole(new_link);
1025    }
1026#endif
1027    DeleteLink(old_link);
1028    return new_link;
1029}
1030
1031static struct alias_link *
1032_FindLinkOut(struct in_addr src_addr,
1033            struct in_addr dst_addr,
1034            u_short src_port,
1035            u_short dst_port,
1036            int link_type,
1037            int replace_partial_links)
1038{
1039    u_int i;
1040    struct alias_link *link;
1041
1042    i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type);
1043    link = linkTableOut[i];
1044    while (link != NULL)
1045    {
1046        if (link->src_addr.s_addr == src_addr.s_addr
1047         && link->dst_addr.s_addr == dst_addr.s_addr
1048         && link->dst_port        == dst_port
1049         && link->src_port        == src_port
1050         && link->link_type       == link_type)
1051        {
1052            link->timestamp = timeStamp;
1053            break;
1054        }
1055        link = link->next_out;
1056    }
1057
1058/* Search for partially specified links. */
1059    if (link == NULL && replace_partial_links)
1060    {
1061        if (dst_port != 0 && dst_addr.s_addr != INADDR_ANY)
1062        {
1063            link = _FindLinkOut(src_addr, dst_addr, src_port, 0,
1064                                link_type, 0);
1065            if (link == NULL)
1066                link = _FindLinkOut(src_addr, nullAddress, src_port,
1067                                    dst_port, link_type, 0);
1068        }
1069        if (link == NULL &&
1070           (dst_port != 0 || dst_addr.s_addr != INADDR_ANY))
1071        {
1072            link = _FindLinkOut(src_addr, nullAddress, src_port, 0,
1073                                link_type, 0);
1074        }
1075        if (link != NULL)
1076        {
1077            link = ReLink(link,
1078                          src_addr, dst_addr, link->alias_addr,
1079                          src_port, dst_port, link->alias_port,
1080                          link_type);
1081        }
1082    }
1083
1084    return(link);
1085}
1086
1087static struct alias_link *
1088FindLinkOut(struct in_addr src_addr,
1089            struct in_addr dst_addr,
1090            u_short src_port,
1091            u_short dst_port,
1092            int link_type,
1093            int replace_partial_links)
1094{
1095    struct alias_link *link;
1096
1097    link = _FindLinkOut(src_addr, dst_addr, src_port, dst_port,
1098                        link_type, replace_partial_links);
1099
1100    if (link == NULL)
1101    {
1102    /* The following allows permanent links to be
1103       specified as using the default source address
1104       (i.e. device interface address) without knowing
1105       in advance what that address is. */
1106        if (aliasAddress.s_addr != 0 &&
1107            src_addr.s_addr == aliasAddress.s_addr)
1108        {
1109            link = _FindLinkOut(nullAddress, dst_addr, src_port, dst_port,
1110                               link_type, replace_partial_links);
1111        }
1112    }
1113
1114    return(link);
1115}
1116
1117
1118static struct alias_link *
1119_FindLinkIn(struct in_addr dst_addr,
1120           struct in_addr  alias_addr,
1121           u_short         dst_port,
1122           u_short         alias_port,
1123           int             link_type,
1124           int             replace_partial_links)
1125{
1126    int flags_in;
1127    u_int start_point;
1128    struct alias_link *link;
1129    struct alias_link *link_fully_specified;
1130    struct alias_link *link_unknown_all;
1131    struct alias_link *link_unknown_dst_addr;
1132    struct alias_link *link_unknown_dst_port;
1133
1134/* Initialize pointers */
1135    link_fully_specified  = NULL;
1136    link_unknown_all      = NULL;
1137    link_unknown_dst_addr = NULL;
1138    link_unknown_dst_port = NULL;
1139
1140/* If either the dest addr or port is unknown, the search
1141   loop will have to know about this. */
1142
1143    flags_in = 0;
1144    if (dst_addr.s_addr == INADDR_ANY)
1145        flags_in |= LINK_UNKNOWN_DEST_ADDR;
1146    if (dst_port == 0)
1147        flags_in |= LINK_UNKNOWN_DEST_PORT;
1148
1149/* Search loop */
1150    start_point = StartPointIn(alias_addr, alias_port, link_type);
1151    link = linkTableIn[start_point];
1152    while (link != NULL)
1153    {
1154        int flags;
1155
1156        flags = flags_in | link->flags;
1157        if (!(flags & LINK_PARTIALLY_SPECIFIED))
1158        {
1159            if (link->alias_addr.s_addr == alias_addr.s_addr
1160             && link->alias_port        == alias_port
1161             && link->dst_addr.s_addr   == dst_addr.s_addr
1162             && link->dst_port          == dst_port
1163             && link->link_type         == link_type)
1164            {
1165                link_fully_specified = link;
1166                break;
1167            }
1168        }
1169        else if ((flags & LINK_UNKNOWN_DEST_ADDR)
1170              && (flags & LINK_UNKNOWN_DEST_PORT))
1171        {
1172            if (link->alias_addr.s_addr == alias_addr.s_addr
1173             && link->alias_port        == alias_port
1174             && link->link_type         == link_type)
1175            {
1176                if (link_unknown_all == NULL)
1177                    link_unknown_all = link;
1178            }
1179        }
1180        else if (flags & LINK_UNKNOWN_DEST_ADDR)
1181        {
1182            if (link->alias_addr.s_addr == alias_addr.s_addr
1183             && link->alias_port        == alias_port
1184             && link->link_type         == link_type
1185             && link->dst_port          == dst_port)
1186            {
1187                if (link_unknown_dst_addr == NULL)
1188                    link_unknown_dst_addr = link;
1189            }
1190        }
1191        else if (flags & LINK_UNKNOWN_DEST_PORT)
1192        {
1193            if (link->alias_addr.s_addr == alias_addr.s_addr
1194             && link->alias_port        == alias_port
1195             && link->link_type         == link_type
1196             && link->dst_addr.s_addr   == dst_addr.s_addr)
1197            {
1198                if (link_unknown_dst_port == NULL)
1199                    link_unknown_dst_port = link;
1200            }
1201        }
1202        link = link->next_in;
1203    }
1204
1205
1206
1207    if (link_fully_specified != NULL)
1208    {
1209        link_fully_specified->timestamp = timeStamp;
1210        return link_fully_specified;
1211    }
1212    else if (link_unknown_dst_port != NULL)
1213    {
1214        return replace_partial_links
1215          ? ReLink(link_unknown_dst_port,
1216                   link_unknown_dst_port->src_addr, dst_addr, alias_addr,
1217                   link_unknown_dst_port->src_port, dst_port, alias_port,
1218                   link_type)
1219          : link_unknown_dst_port;
1220    }
1221    else if (link_unknown_dst_addr != NULL)
1222    {
1223        return replace_partial_links
1224          ? ReLink(link_unknown_dst_addr,
1225                   link_unknown_dst_addr->src_addr, dst_addr, alias_addr,
1226                   link_unknown_dst_addr->src_port, dst_port, alias_port,
1227                   link_type)
1228          : link_unknown_dst_addr;
1229    }
1230    else if (link_unknown_all != NULL)
1231    {
1232        return replace_partial_links
1233          ? ReLink(link_unknown_all,
1234                   link_unknown_all->src_addr, dst_addr, alias_addr,
1235                   link_unknown_all->src_port, dst_port, alias_port,
1236                   link_type)
1237          : link_unknown_all;
1238    }
1239    else
1240    {
1241        return(NULL);
1242    }
1243}
1244
1245static struct alias_link *
1246FindLinkIn(struct in_addr dst_addr,
1247           struct in_addr alias_addr,
1248           u_short dst_port,
1249           u_short alias_port,
1250           int link_type,
1251           int replace_partial_links)
1252{
1253    struct alias_link *link;
1254
1255    link = _FindLinkIn(dst_addr, alias_addr, dst_port, alias_port,
1256                       link_type, replace_partial_links);
1257
1258    if (link == NULL)
1259    {
1260    /* The following allows permanent links to be
1261       specified as using the default aliasing address
1262       (i.e. device interface address) without knowing
1263       in advance what that address is. */
1264        if (aliasAddress.s_addr != 0 &&
1265            alias_addr.s_addr == aliasAddress.s_addr)
1266        {
1267            link = _FindLinkIn(dst_addr, nullAddress, dst_port, alias_port,
1268                               link_type, replace_partial_links);
1269        }
1270    }
1271
1272    return(link);
1273}
1274
1275
1276
1277
1278/* External routines for finding/adding links
1279
1280-- "external" means outside alias_db.c, but within alias*.c --
1281
1282    FindIcmpIn(), FindIcmpOut()
1283    FindFragmentIn1(), FindFragmentIn2()
1284    AddFragmentPtrLink(), FindFragmentPtr()
1285    FindPptpIn(), FindPptpOut()
1286    FindUdpTcpIn(), FindUdpTcpOut()
1287    FindOriginalAddress(), FindAliasAddress()
1288
1289(prototypes in alias_local.h)
1290*/
1291
1292
1293struct alias_link *
1294FindIcmpIn(struct in_addr dst_addr,
1295           struct in_addr alias_addr,
1296           u_short id_alias)
1297{
1298    return FindLinkIn(dst_addr, alias_addr,
1299                      NO_DEST_PORT, id_alias,
1300                      LINK_ICMP, 0);
1301}
1302
1303
1304struct alias_link *
1305FindIcmpOut(struct in_addr src_addr,
1306            struct in_addr dst_addr,
1307            u_short id)
1308{
1309    struct alias_link * link;
1310
1311    link = FindLinkOut(src_addr, dst_addr,
1312                       id, NO_DEST_PORT,
1313                       LINK_ICMP, 0);
1314    if (link == NULL)
1315    {
1316        struct in_addr alias_addr;
1317
1318        alias_addr = FindAliasAddress(src_addr);
1319        link = AddLink(src_addr, dst_addr, alias_addr,
1320                       id, NO_DEST_PORT, GET_ALIAS_ID,
1321                       LINK_ICMP);
1322    }
1323
1324    return(link);
1325}
1326
1327
1328struct alias_link *
1329FindFragmentIn1(struct in_addr dst_addr,
1330                struct in_addr alias_addr,
1331                u_short ip_id)
1332{
1333    struct alias_link *link;
1334
1335    link = FindLinkIn(dst_addr, alias_addr,
1336                      NO_DEST_PORT, ip_id,
1337                      LINK_FRAGMENT_ID, 0);
1338
1339    if (link == NULL)
1340    {
1341        link = AddLink(nullAddress, dst_addr, alias_addr,
1342                       NO_SRC_PORT, NO_DEST_PORT, ip_id,
1343                       LINK_FRAGMENT_ID);
1344    }
1345
1346    return(link);
1347}
1348
1349
1350struct alias_link *
1351FindFragmentIn2(struct in_addr dst_addr,   /* Doesn't add a link if one */
1352                struct in_addr alias_addr, /*   is not found.           */
1353                u_short ip_id)
1354{
1355    return FindLinkIn(dst_addr, alias_addr,
1356                      NO_DEST_PORT, ip_id,
1357                      LINK_FRAGMENT_ID, 0);
1358}
1359
1360
1361struct alias_link *
1362AddFragmentPtrLink(struct in_addr dst_addr,
1363                   u_short ip_id)
1364{
1365    return AddLink(nullAddress, dst_addr, nullAddress,
1366                   NO_SRC_PORT, NO_DEST_PORT, ip_id,
1367                   LINK_FRAGMENT_PTR);
1368}
1369
1370
1371struct alias_link *
1372FindFragmentPtr(struct in_addr dst_addr,
1373                u_short ip_id)
1374{
1375    return FindLinkIn(dst_addr, nullAddress,
1376                      NO_DEST_PORT, ip_id,
1377                      LINK_FRAGMENT_PTR, 0);
1378}
1379
1380
1381struct alias_link *
1382FindPptpIn(struct in_addr dst_addr,
1383           struct in_addr alias_addr)
1384{
1385    struct alias_link *link;
1386
1387    link = FindLinkIn(dst_addr, alias_addr,
1388                      NO_DEST_PORT, 0,
1389                      LINK_PPTP, 1);
1390
1391    if (link == NULL && !(packetAliasMode & PKT_ALIAS_DENY_INCOMING))
1392    {
1393        struct in_addr target_addr;
1394
1395        target_addr = FindOriginalAddress(alias_addr);
1396        link = AddLink(target_addr, dst_addr, alias_addr,
1397                       NO_SRC_PORT, NO_DEST_PORT, 0,
1398                       LINK_PPTP);
1399    }
1400
1401    return (link);
1402}
1403
1404
1405struct alias_link *
1406FindPptpOut(struct in_addr src_addr,
1407            struct in_addr dst_addr)
1408{
1409    struct alias_link *link;
1410
1411    link = FindLinkOut(src_addr, dst_addr,
1412                       NO_SRC_PORT, NO_DEST_PORT,
1413                       LINK_PPTP, 1);
1414
1415    if (link == NULL)
1416    {
1417        struct in_addr alias_addr;
1418
1419        alias_addr = FindAliasAddress(src_addr);
1420        link = AddLink(src_addr, dst_addr, alias_addr,
1421                       NO_SRC_PORT, NO_DEST_PORT, 0,
1422                       LINK_PPTP);
1423    }
1424
1425    return (link);
1426}
1427
1428
1429struct alias_link *
1430FindUdpTcpIn(struct in_addr dst_addr,
1431             struct in_addr alias_addr,
1432             u_short        dst_port,
1433             u_short        alias_port,
1434             u_char         proto)
1435{
1436    int link_type;
1437    struct alias_link *link;
1438
1439    switch (proto)
1440    {
1441    case IPPROTO_UDP:
1442        link_type = LINK_UDP;
1443        break;
1444    case IPPROTO_TCP:
1445        link_type = LINK_TCP;
1446        break;
1447    default:
1448        return NULL;
1449        break;
1450    }
1451
1452    link = FindLinkIn(dst_addr, alias_addr,
1453                      dst_port, alias_port,
1454                      link_type, 1);
1455
1456    if (!(packetAliasMode & PKT_ALIAS_DENY_INCOMING)
1457     && !(packetAliasMode & PKT_ALIAS_PROXY_ONLY)
1458     && link == NULL)
1459    {
1460        struct in_addr target_addr;
1461
1462        target_addr = FindOriginalAddress(alias_addr);
1463        link = AddLink(target_addr, dst_addr, alias_addr,
1464                       alias_port, dst_port, alias_port,
1465                       link_type);
1466    }
1467
1468    return(link);
1469}
1470
1471
1472struct alias_link *
1473FindUdpTcpOut(struct in_addr  src_addr,
1474              struct in_addr  dst_addr,
1475              u_short         src_port,
1476              u_short         dst_port,
1477              u_char          proto)
1478{
1479    int link_type;
1480    struct alias_link *link;
1481
1482    switch (proto)
1483    {
1484    case IPPROTO_UDP:
1485        link_type = LINK_UDP;
1486        break;
1487    case IPPROTO_TCP:
1488        link_type = LINK_TCP;
1489        break;
1490    default:
1491        return NULL;
1492        break;
1493    }
1494
1495    link = FindLinkOut(src_addr, dst_addr, src_port, dst_port, link_type, 1);
1496
1497    if (link == NULL)
1498    {
1499        struct in_addr alias_addr;
1500
1501        alias_addr = FindAliasAddress(src_addr);
1502        link = AddLink(src_addr, dst_addr, alias_addr,
1503                       src_port, dst_port, GET_ALIAS_PORT,
1504                       link_type);
1505    }
1506
1507    return(link);
1508}
1509
1510
1511struct in_addr
1512FindOriginalAddress(struct in_addr alias_addr)
1513{
1514    struct alias_link *link;
1515
1516    link = FindLinkIn(nullAddress, alias_addr,
1517                      0, 0, LINK_ADDR, 0);
1518    if (link == NULL)
1519    {
1520        newDefaultLink = 1;
1521        if (targetAddress.s_addr == INADDR_ANY)
1522            return alias_addr;
1523        else if (targetAddress.s_addr == INADDR_NONE)
1524            return aliasAddress;
1525        else
1526            return targetAddress;
1527    }
1528    else
1529    {
1530        if (link->src_addr.s_addr == INADDR_ANY)
1531            return aliasAddress;
1532        else
1533            return link->src_addr;
1534    }
1535}
1536
1537
1538struct in_addr
1539FindAliasAddress(struct in_addr original_addr)
1540{
1541    struct alias_link *link;
1542
1543    link = FindLinkOut(original_addr, nullAddress,
1544                       0, 0, LINK_ADDR, 0);
1545    if (link == NULL)
1546    {
1547        return aliasAddress;
1548    }
1549    else
1550    {
1551        if (link->alias_addr.s_addr == INADDR_ANY)
1552            return aliasAddress;
1553        else
1554            return link->alias_addr;
1555    }
1556}
1557
1558
1559/* External routines for getting or changing link data
1560   (external to alias_db.c, but internal to alias*.c)
1561
1562    SetFragmentData(), GetFragmentData()
1563    SetFragmentPtr(), GetFragmentPtr()
1564    SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut()
1565    GetOriginalAddress(), GetDestAddress(), GetAliasAddress()
1566    GetOriginalPort(), GetAliasPort()
1567    SetAckModified(), GetAckModified()
1568    GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq()
1569*/
1570
1571
1572void
1573SetFragmentAddr(struct alias_link *link, struct in_addr src_addr)
1574{
1575    link->data.frag_addr = src_addr;
1576}
1577
1578
1579void
1580GetFragmentAddr(struct alias_link *link, struct in_addr *src_addr)
1581{
1582    *src_addr = link->data.frag_addr;
1583}
1584
1585
1586void
1587SetFragmentPtr(struct alias_link *link, char *fptr)
1588{
1589    link->data.frag_ptr = fptr;
1590}
1591
1592
1593void
1594GetFragmentPtr(struct alias_link *link, char **fptr)
1595{
1596   *fptr = link->data.frag_ptr;
1597}
1598
1599
1600void
1601SetStateIn(struct alias_link *link, int state)
1602{
1603    /* TCP input state */
1604    switch (state) {
1605    case ALIAS_TCP_STATE_DISCONNECTED:
1606        if (link->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED)
1607            link->expire_time = TCP_EXPIRE_DEAD;
1608        else
1609            link->expire_time = TCP_EXPIRE_SINGLEDEAD;
1610        break;
1611    case ALIAS_TCP_STATE_CONNECTED:
1612        if (link->data.tcp->state.out == ALIAS_TCP_STATE_CONNECTED)
1613            link->expire_time = TCP_EXPIRE_CONNECTED;
1614        break;
1615    default:
1616        abort();
1617    }
1618    link->data.tcp->state.in = state;
1619}
1620
1621
1622void
1623SetStateOut(struct alias_link *link, int state)
1624{
1625    /* TCP output state */
1626    switch (state) {
1627    case ALIAS_TCP_STATE_DISCONNECTED:
1628        if (link->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED)
1629            link->expire_time = TCP_EXPIRE_DEAD;
1630        else
1631            link->expire_time = TCP_EXPIRE_SINGLEDEAD;
1632        break;
1633    case ALIAS_TCP_STATE_CONNECTED:
1634        if (link->data.tcp->state.in == ALIAS_TCP_STATE_CONNECTED)
1635            link->expire_time = TCP_EXPIRE_CONNECTED;
1636        break;
1637    default:
1638        abort();
1639    }
1640    link->data.tcp->state.out = state;
1641}
1642
1643
1644int
1645GetStateIn(struct alias_link *link)
1646{
1647    /* TCP input state */
1648    return link->data.tcp->state.in;
1649}
1650
1651
1652int
1653GetStateOut(struct alias_link *link)
1654{
1655    /* TCP output state */
1656    return link->data.tcp->state.out;
1657}
1658
1659
1660struct in_addr
1661GetOriginalAddress(struct alias_link *link)
1662{
1663    if (link->src_addr.s_addr == INADDR_ANY)
1664        return aliasAddress;
1665    else
1666        return(link->src_addr);
1667}
1668
1669
1670struct in_addr
1671GetDestAddress(struct alias_link *link)
1672{
1673    return(link->dst_addr);
1674}
1675
1676
1677struct in_addr
1678GetAliasAddress(struct alias_link *link)
1679{
1680    if (link->alias_addr.s_addr == INADDR_ANY)
1681        return aliasAddress;
1682    else
1683        return link->alias_addr;
1684}
1685
1686
1687struct in_addr
1688GetDefaultAliasAddress()
1689{
1690    return aliasAddress;
1691}
1692
1693
1694void
1695SetDefaultAliasAddress(struct in_addr alias_addr)
1696{
1697    aliasAddress = alias_addr;
1698}
1699
1700
1701u_short
1702GetOriginalPort(struct alias_link *link)
1703{
1704    return(link->src_port);
1705}
1706
1707
1708u_short
1709GetAliasPort(struct alias_link *link)
1710{
1711    return(link->alias_port);
1712}
1713
1714#ifndef NO_FW_PUNCH
1715static u_short
1716GetDestPort(struct alias_link *link)
1717{
1718    return(link->dst_port);
1719}
1720#endif
1721
1722void
1723SetAckModified(struct alias_link *link)
1724{
1725/* Indicate that ACK numbers have been modified in a TCP connection */
1726    link->data.tcp->state.ack_modified = 1;
1727}
1728
1729
1730struct in_addr
1731GetProxyAddress(struct alias_link *link)
1732{
1733    return link->proxy_addr;
1734}
1735
1736
1737void
1738SetProxyAddress(struct alias_link *link, struct in_addr addr)
1739{
1740    link->proxy_addr = addr;
1741}
1742
1743
1744u_short
1745GetProxyPort(struct alias_link *link)
1746{
1747    return link->proxy_port;
1748}
1749
1750
1751void
1752SetProxyPort(struct alias_link *link, u_short port)
1753{
1754    link->proxy_port = port;
1755}
1756
1757
1758int
1759GetAckModified(struct alias_link *link)
1760{
1761/* See if ACK numbers have been modified */
1762    return link->data.tcp->state.ack_modified;
1763}
1764
1765
1766int
1767GetDeltaAckIn(struct ip *pip, struct alias_link *link)
1768{
1769/*
1770Find out how much the ACK number has been altered for an incoming
1771TCP packet.  To do this, a circular list of ACK numbers where the TCP
1772packet size was altered is searched.
1773*/
1774
1775    int i;
1776    struct tcphdr *tc;
1777    int delta, ack_diff_min;
1778    u_long ack;
1779
1780    tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
1781    ack      = tc->th_ack;
1782
1783    delta = 0;
1784    ack_diff_min = -1;
1785    for (i=0; i<N_LINK_TCP_DATA; i++)
1786    {
1787        struct ack_data_record x;
1788
1789        x = link->data.tcp->ack[i];
1790        if (x.active == 1)
1791        {
1792            int ack_diff;
1793
1794            ack_diff = SeqDiff(x.ack_new, ack);
1795            if (ack_diff >= 0)
1796            {
1797                if (ack_diff_min >= 0)
1798                {
1799                    if (ack_diff < ack_diff_min)
1800                    {
1801                        delta = x.delta;
1802                        ack_diff_min = ack_diff;
1803                    }
1804                }
1805                else
1806                {
1807                    delta = x.delta;
1808                    ack_diff_min = ack_diff;
1809                }
1810            }
1811        }
1812    }
1813    return (delta);
1814}
1815
1816
1817int
1818GetDeltaSeqOut(struct ip *pip, struct alias_link *link)
1819{
1820/*
1821Find out how much the sequence number has been altered for an outgoing
1822TCP packet.  To do this, a circular list of ACK numbers where the TCP
1823packet size was altered is searched.
1824*/
1825
1826    int i;
1827    struct tcphdr *tc;
1828    int delta, seq_diff_min;
1829    u_long seq;
1830
1831    tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
1832    seq = tc->th_seq;
1833
1834    delta = 0;
1835    seq_diff_min = -1;
1836    for (i=0; i<N_LINK_TCP_DATA; i++)
1837    {
1838        struct ack_data_record x;
1839
1840        x = link->data.tcp->ack[i];
1841        if (x.active == 1)
1842        {
1843            int seq_diff;
1844
1845            seq_diff = SeqDiff(x.ack_old, seq);
1846            if (seq_diff >= 0)
1847            {
1848                if (seq_diff_min >= 0)
1849                {
1850                    if (seq_diff < seq_diff_min)
1851                    {
1852                        delta = x.delta;
1853                        seq_diff_min = seq_diff;
1854                    }
1855                }
1856                else
1857                {
1858                    delta = x.delta;
1859                    seq_diff_min = seq_diff;
1860                }
1861            }
1862        }
1863    }
1864    return (delta);
1865}
1866
1867
1868void
1869AddSeq(struct ip *pip, struct alias_link *link, int delta)
1870{
1871/*
1872When a TCP packet has been altered in length, save this
1873information in a circular list.  If enough packets have
1874been altered, then this list will begin to overwrite itself.
1875*/
1876
1877    struct tcphdr *tc;
1878    struct ack_data_record x;
1879    int hlen, tlen, dlen;
1880    int i;
1881
1882    tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
1883
1884    hlen = (pip->ip_hl + tc->th_off) << 2;
1885    tlen = ntohs(pip->ip_len);
1886    dlen = tlen - hlen;
1887
1888    x.ack_old = htonl(ntohl(tc->th_seq) + dlen);
1889    x.ack_new = htonl(ntohl(tc->th_seq) + dlen + delta);
1890    x.delta = delta;
1891    x.active = 1;
1892
1893    i = link->data.tcp->state.index;
1894    link->data.tcp->ack[i] = x;
1895
1896    i++;
1897    if (i == N_LINK_TCP_DATA)
1898        link->data.tcp->state.index = 0;
1899    else
1900        link->data.tcp->state.index = i;
1901}
1902
1903void
1904SetExpire(struct alias_link *link, int expire)
1905{
1906    if (expire == 0)
1907    {
1908        link->flags &= ~LINK_PERMANENT;
1909        DeleteLink(link);
1910    }
1911    else if (expire == -1)
1912    {
1913        link->flags |= LINK_PERMANENT;
1914    }
1915    else if (expire > 0)
1916    {
1917        link->expire_time = expire;
1918    }
1919    else
1920    {
1921#ifdef DEBUG
1922        fprintf(stderr, "PacketAlias/SetExpire(): ");
1923        fprintf(stderr, "error in expire parameter\n");
1924#endif
1925    }
1926}
1927
1928void
1929ClearCheckNewLink(void)
1930{
1931    newDefaultLink = 0;
1932}
1933
1934
1935/* Miscellaneous Functions
1936
1937    HouseKeeping()
1938    InitPacketAliasLog()
1939    UninitPacketAliasLog()
1940*/
1941
1942/*
1943    Whenever an outgoing or incoming packet is handled, HouseKeeping()
1944    is called to find and remove timed-out aliasing links.  Logic exists
1945    to sweep through the entire table and linked list structure
1946    every 60 seconds.
1947
1948    (prototype in alias_local.h)
1949*/
1950
1951void
1952HouseKeeping(void)
1953{
1954    int i, n, n100;
1955    struct timeval tv;
1956    struct timezone tz;
1957
1958    /*
1959     * Save system time (seconds) in global variable timeStamp for
1960     * use by other functions. This is done so as not to unnecessarily
1961     * waste timeline by making system calls.
1962     */
1963    gettimeofday(&tv, &tz);
1964    timeStamp = tv.tv_sec;
1965
1966    /* Compute number of spokes (output table link chains) to cover */
1967    n100  = LINK_TABLE_OUT_SIZE * 100 + houseKeepingResidual;
1968    n100 *= timeStamp - lastCleanupTime;
1969    n100 /= ALIAS_CLEANUP_INTERVAL_SECS;
1970
1971    n = n100/100;
1972
1973    /* Handle different cases */
1974    if (n > ALIAS_CLEANUP_MAX_SPOKES)
1975    {
1976        n = ALIAS_CLEANUP_MAX_SPOKES;
1977        lastCleanupTime = timeStamp;
1978        houseKeepingResidual = 0;
1979
1980        for (i=0; i<n; i++)
1981            IncrementalCleanup();
1982    }
1983    else if (n > 0)
1984    {
1985        lastCleanupTime = timeStamp;
1986        houseKeepingResidual = n100 - 100*n;
1987
1988        for (i=0; i<n; i++)
1989            IncrementalCleanup();
1990    }
1991    else if (n < 0)
1992    {
1993#ifdef DEBUG
1994        fprintf(stderr, "PacketAlias/HouseKeeping(): ");
1995        fprintf(stderr, "something unexpected in time values\n");
1996#endif
1997        lastCleanupTime = timeStamp;
1998        houseKeepingResidual = 0;
1999    }
2000}
2001
2002
2003/* Init the log file and enable logging */
2004static void
2005InitPacketAliasLog(void)
2006{
2007   if ((~packetAliasMode & PKT_ALIAS_LOG)
2008    && (monitorFile = fopen("/var/log/alias.log", "w")))
2009   {
2010      packetAliasMode |= PKT_ALIAS_LOG;
2011      fprintf(monitorFile,
2012      "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n");
2013   }
2014}
2015
2016
2017/* Close the log-file and disable logging. */
2018static void
2019UninitPacketAliasLog(void)
2020{
2021    if (monitorFile) {
2022        fclose(monitorFile);
2023        monitorFile = NULL;
2024    }
2025    packetAliasMode &= ~PKT_ALIAS_LOG;
2026}
2027
2028
2029
2030
2031
2032
2033/* Outside world interfaces
2034
2035-- "outside world" means other than alias*.c routines --
2036
2037    PacketAliasRedirectPort()
2038    PacketAliasRedirectPptp()
2039    PacketAliasRedirectAddr()
2040    PacketAliasRedirectDelete()
2041    PacketAliasSetAddress()
2042    PacketAliasInit()
2043    PacketAliasUninit()
2044    PacketAliasSetMode()
2045
2046(prototypes in alias.h)
2047*/
2048
2049/* Redirection from a specific public addr:port to a
2050   private addr:port */
2051struct alias_link *
2052PacketAliasRedirectPort(struct in_addr src_addr,   u_short src_port,
2053                        struct in_addr dst_addr,   u_short dst_port,
2054                        struct in_addr alias_addr, u_short alias_port,
2055                        u_char proto)
2056{
2057    int link_type;
2058    struct alias_link *link;
2059
2060    switch(proto)
2061    {
2062    case IPPROTO_UDP:
2063        link_type = LINK_UDP;
2064        break;
2065    case IPPROTO_TCP:
2066        link_type = LINK_TCP;
2067        break;
2068    default:
2069#ifdef DEBUG
2070        fprintf(stderr, "PacketAliasRedirectPort(): ");
2071        fprintf(stderr, "only TCP and UDP protocols allowed\n");
2072#endif
2073        return NULL;
2074    }
2075
2076    link = AddLink(src_addr, dst_addr, alias_addr,
2077                   src_port, dst_port, alias_port,
2078                   link_type);
2079
2080    if (link != NULL)
2081    {
2082        link->flags |= LINK_PERMANENT;
2083    }
2084#ifdef DEBUG
2085    else
2086    {
2087        fprintf(stderr, "PacketAliasRedirectPort(): "
2088                        "call to AddLink() failed\n");
2089    }
2090#endif
2091
2092    return link;
2093}
2094
2095/* Translate PPTP packets to a machine on the inside
2096 * XXX This function is made obsolete by PacketAliasRedirectPptp().
2097 */
2098int
2099PacketAliasPptp(struct in_addr src_addr)
2100{
2101
2102    if (src_addr.s_addr == INADDR_NONE)
2103	packetAliasMode |= PKT_ALIAS_DENY_PPTP;
2104    else
2105	(void)PacketAliasRedirectPptp(src_addr, nullAddress, nullAddress);
2106
2107    return 1;
2108}
2109
2110/* Redirect PPTP packets from a specific
2111   public address to a private address */
2112struct alias_link *
2113PacketAliasRedirectPptp(struct in_addr src_addr,
2114                        struct in_addr dst_addr,
2115                        struct in_addr alias_addr)
2116{
2117    struct alias_link *link;
2118
2119    link = AddLink(src_addr, dst_addr, alias_addr,
2120                   NO_SRC_PORT, NO_DEST_PORT, 0,
2121                   LINK_PPTP);
2122
2123    if (link != NULL)
2124    {
2125        link->flags |= LINK_PERMANENT;
2126    }
2127#ifdef DEBUG
2128    else
2129    {
2130        fprintf(stderr, "PacketAliasRedirectPptp(): "
2131                        "call to AddLink() failed\n");
2132    }
2133#endif
2134
2135    return link;
2136}
2137
2138/* Static address translation */
2139struct alias_link *
2140PacketAliasRedirectAddr(struct in_addr src_addr,
2141                        struct in_addr alias_addr)
2142{
2143    struct alias_link *link;
2144
2145    link = AddLink(src_addr, nullAddress, alias_addr,
2146                   0, 0, 0,
2147                   LINK_ADDR);
2148
2149    if (link != NULL)
2150    {
2151        link->flags |= LINK_PERMANENT;
2152    }
2153#ifdef DEBUG
2154    else
2155    {
2156        fprintf(stderr, "PacketAliasRedirectAddr(): "
2157                        "call to AddLink() failed\n");
2158    }
2159#endif
2160
2161    return link;
2162}
2163
2164
2165void
2166PacketAliasRedirectDelete(struct alias_link *link)
2167{
2168/* This is a dangerous function to put in the API,
2169   because an invalid pointer can crash the program. */
2170
2171    deleteAllLinks = 1;
2172    DeleteLink(link);
2173    deleteAllLinks = 0;
2174}
2175
2176
2177void
2178PacketAliasSetAddress(struct in_addr addr)
2179{
2180    if (packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE
2181     && aliasAddress.s_addr != addr.s_addr)
2182        CleanupAliasData();
2183
2184    aliasAddress = addr;
2185}
2186
2187
2188void
2189PacketAliasSetTarget(struct in_addr target_addr)
2190{
2191    targetAddress = target_addr;
2192}
2193
2194
2195void
2196PacketAliasInit(void)
2197{
2198    int i;
2199    struct timeval tv;
2200    struct timezone tz;
2201    static int firstCall = 1;
2202
2203    if (firstCall == 1)
2204    {
2205        gettimeofday(&tv, &tz);
2206        timeStamp = tv.tv_sec;
2207        lastCleanupTime = tv.tv_sec;
2208        houseKeepingResidual = 0;
2209
2210        for (i=0; i<LINK_TABLE_OUT_SIZE; i++)
2211            linkTableOut[i] = NULL;
2212        for (i=0; i<LINK_TABLE_IN_SIZE; i++)
2213            linkTableIn[i] = NULL;
2214
2215        atexit(PacketAliasUninit);
2216        firstCall = 0;
2217    }
2218    else
2219    {
2220        deleteAllLinks = 1;
2221        CleanupAliasData();
2222        deleteAllLinks = 0;
2223    }
2224
2225    aliasAddress.s_addr = INADDR_ANY;
2226    targetAddress.s_addr = INADDR_NONE;
2227
2228    icmpLinkCount = 0;
2229    udpLinkCount = 0;
2230    tcpLinkCount = 0;
2231    pptpLinkCount = 0;
2232    fragmentIdLinkCount = 0;
2233    fragmentPtrLinkCount = 0;
2234    sockCount = 0;
2235
2236    cleanupIndex =0;
2237
2238    packetAliasMode = PKT_ALIAS_SAME_PORTS
2239                    | PKT_ALIAS_USE_SOCKETS
2240                    | PKT_ALIAS_RESET_ON_ADDR_CHANGE;
2241}
2242
2243void
2244PacketAliasUninit(void) {
2245    deleteAllLinks = 1;
2246    CleanupAliasData();
2247    deleteAllLinks = 0;
2248    UninitPacketAliasLog();
2249#ifndef NO_FW_PUNCH
2250    UninitPunchFW();
2251#endif
2252}
2253
2254
2255/* Change mode for some operations */
2256unsigned int
2257PacketAliasSetMode(
2258    unsigned int flags, /* Which state to bring flags to */
2259    unsigned int mask   /* Mask of which flags to affect (use 0 to do a
2260                           probe for flag values) */
2261)
2262{
2263/* Enable logging? */
2264    if (flags & mask & PKT_ALIAS_LOG)
2265    {
2266        InitPacketAliasLog();     /* Do the enable */
2267    } else
2268/* _Disable_ logging? */
2269    if (~flags & mask & PKT_ALIAS_LOG) {
2270        UninitPacketAliasLog();
2271    }
2272
2273#ifndef NO_FW_PUNCH
2274/* Start punching holes in the firewall? */
2275    if (flags & mask & PKT_ALIAS_PUNCH_FW) {
2276        InitPunchFW();
2277    } else
2278/* Stop punching holes in the firewall? */
2279    if (~flags & mask & PKT_ALIAS_PUNCH_FW) {
2280        UninitPunchFW();
2281    }
2282#endif
2283
2284/* Other flags can be set/cleared without special action */
2285    packetAliasMode = (flags & mask) | (packetAliasMode & ~mask);
2286    return packetAliasMode;
2287}
2288
2289
2290int
2291PacketAliasCheckNewLink(void)
2292{
2293    return newDefaultLink;
2294}
2295
2296
2297#ifndef NO_FW_PUNCH
2298
2299/*****************
2300  Code to support firewall punching.  This shouldn't really be in this
2301  file, but making variables global is evil too.
2302  ****************/
2303
2304/* Firewall include files */
2305#include <sys/queue.h>
2306#include <net/if.h>
2307#include <netinet/ip_fw.h>
2308#include <string.h>
2309#include <err.h>
2310
2311static void ClearAllFWHoles(void);
2312
2313static int fireWallBaseNum;     /* The first firewall entry free for our use */
2314static int fireWallNumNums;     /* How many entries can we use? */
2315static int fireWallActiveNum;   /* Which entry did we last use? */
2316static char *fireWallField;     /* bool array for entries */
2317
2318#define fw_setfield(field, num)                         \
2319do {                                                    \
2320    (field)[num] = 1;                                   \
2321} /*lint -save -e717 */ while(0) /*lint -restore */
2322#define fw_clrfield(field, num)                         \
2323do {                                                    \
2324    (field)[num] = 0;                                   \
2325} /*lint -save -e717 */ while(0) /*lint -restore */
2326#define fw_tstfield(field, num) ((field)[num])
2327
2328void
2329PacketAliasSetFWBase(unsigned int base, unsigned int num) {
2330    fireWallBaseNum = base;
2331    fireWallNumNums = num;
2332}
2333
2334static void
2335InitPunchFW(void) {
2336    fireWallField = malloc(fireWallNumNums);
2337    if (fireWallField) {
2338        memset(fireWallField, 0, fireWallNumNums);
2339        if (fireWallFD < 0) {
2340            fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
2341        }
2342        ClearAllFWHoles();
2343        fireWallActiveNum = fireWallBaseNum;
2344    }
2345}
2346
2347static void
2348UninitPunchFW(void) {
2349    ClearAllFWHoles();
2350    if (fireWallFD >= 0)
2351        close(fireWallFD);
2352    fireWallFD = -1;
2353    if (fireWallField)
2354        free(fireWallField);
2355    fireWallField = NULL;
2356    packetAliasMode &= ~PKT_ALIAS_PUNCH_FW;
2357}
2358
2359/* Make a certain link go through the firewall */
2360void
2361PunchFWHole(struct alias_link *link) {
2362    int r;                      /* Result code */
2363    struct ip_fw rule;          /* On-the-fly built rule */
2364    int fwhole;                 /* Where to punch hole */
2365
2366/* Don't do anything unless we are asked to */
2367    if ( !(packetAliasMode & PKT_ALIAS_PUNCH_FW) ||
2368         fireWallFD < 0 ||
2369         link->link_type != LINK_TCP ||
2370         !link->data.tcp)
2371        return;
2372
2373    memset(&rule, 0, sizeof rule);
2374
2375/** Build rule **/
2376
2377    /* Find empty slot */
2378    for (fwhole = fireWallActiveNum;
2379         fwhole < fireWallBaseNum + fireWallNumNums &&
2380             fw_tstfield(fireWallField, fwhole);
2381         fwhole++)
2382        ;
2383    if (fwhole >= fireWallBaseNum + fireWallNumNums ||
2384        fw_tstfield(fireWallField, fwhole)) {
2385        for (fwhole = fireWallBaseNum;
2386             fwhole < fireWallActiveNum &&
2387                 fw_tstfield(fireWallField, fwhole);
2388             fwhole++)
2389            ;
2390        if (fwhole == fireWallActiveNum) {
2391            /* No rule point empty - we can't punch more holes. */
2392            fireWallActiveNum = fireWallBaseNum;
2393#ifdef DEBUG
2394            fprintf(stderr, "libalias: Unable to create firewall hole!\n");
2395#endif
2396            return;
2397        }
2398    }
2399    /* Start next search at next position */
2400    fireWallActiveNum = fwhole+1;
2401
2402    /* Build generic part of the two rules */
2403    rule.fw_number = fwhole;
2404    rule.fw_nports = 1;         /* Number of source ports; dest ports follow */
2405    rule.fw_flg = IP_FW_F_ACCEPT;
2406    rule.fw_prot = IPPROTO_TCP;
2407    rule.fw_smsk.s_addr = INADDR_BROADCAST;
2408    rule.fw_dmsk.s_addr = INADDR_BROADCAST;
2409
2410    /* Build and apply specific part of the rules */
2411    rule.fw_src = GetOriginalAddress(link);
2412    rule.fw_dst = GetDestAddress(link);
2413    rule.fw_uar.fw_pts[0] = ntohs(GetOriginalPort(link));
2414    rule.fw_uar.fw_pts[1] = ntohs(GetDestPort(link));
2415
2416    /* Skip non-bound links - XXX should not be strictly necessary,
2417       but seems to leave hole if not done.  Leak of non-bound links?
2418       (Code should be left even if the problem is fixed - it is a
2419       clear optimization) */
2420    if (rule.fw_uar.fw_pts[0] != 0 && rule.fw_uar.fw_pts[1] != 0) {
2421        r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule);
2422#ifdef DEBUG
2423        if (r)
2424            err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)");
2425#endif
2426        rule.fw_src = GetDestAddress(link);
2427        rule.fw_dst = GetOriginalAddress(link);
2428        rule.fw_uar.fw_pts[0] = ntohs(GetDestPort(link));
2429        rule.fw_uar.fw_pts[1] = ntohs(GetOriginalPort(link));
2430        r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule);
2431#ifdef DEBUG
2432        if (r)
2433            err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)");
2434#endif
2435    }
2436/* Indicate hole applied */
2437    link->data.tcp->fwhole = fwhole;
2438    fw_setfield(fireWallField, fwhole);
2439}
2440
2441/* Remove a hole in a firewall associated with a particular alias
2442   link.  Calling this too often is harmless. */
2443static void
2444ClearFWHole(struct alias_link *link) {
2445    if (link->link_type == LINK_TCP && link->data.tcp) {
2446        int fwhole =  link->data.tcp->fwhole; /* Where is the firewall hole? */
2447        struct ip_fw rule;
2448
2449        if (fwhole < 0)
2450            return;
2451
2452        memset(&rule, 0, sizeof rule);
2453        rule.fw_number = fwhole;
2454        while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule))
2455            ;
2456        fw_clrfield(fireWallField, fwhole);
2457        link->data.tcp->fwhole = -1;
2458    }
2459}
2460
2461/* Clear out the entire range dedicated to firewall holes. */
2462static void
2463ClearAllFWHoles(void) {
2464    struct ip_fw rule;          /* On-the-fly built rule */
2465    int i;
2466
2467    if (fireWallFD < 0)
2468        return;
2469
2470    memset(&rule, 0, sizeof rule);
2471    for (i = fireWallBaseNum; i < fireWallBaseNum + fireWallNumNums; i++) {
2472        rule.fw_number = i;
2473        while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule))
2474            ;
2475    }
2476    memset(fireWallField, 0, fireWallNumNums);
2477}
2478#endif
2479