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