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