xref: /freebsd/sys/netinet/libalias/alias_db.c (revision 807a5caa14df5ff04b331e24b45893f6a2f6bc1b)
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 = INADDR_ANY;
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 == INADDR_ANY)
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 static 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 == INADDR_ANY)
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 == INADDR_ANY)
1459             return alias_addr;
1460         else if (targetAddress.s_addr == INADDR_NONE)
1461             return aliasAddress;
1462         else
1463             return targetAddress;
1464     }
1465     else
1466     {
1467         if (link->src_addr.s_addr == INADDR_ANY)
1468             return aliasAddress;
1469         else
1470             return link->src_addr;
1471     }
1472 }
1473 
1474 
1475 struct in_addr
1476 FindAliasAddress(struct in_addr original_addr)
1477 {
1478     struct alias_link *link;
1479 
1480     link = FindLinkOut(original_addr, nullAddress,
1481                        0, 0, LINK_ADDR, 0);
1482     if (link == NULL)
1483     {
1484         return aliasAddress;
1485     }
1486     else
1487     {
1488         if (link->alias_addr.s_addr == INADDR_ANY)
1489             return aliasAddress;
1490         else
1491             return link->alias_addr;
1492     }
1493 }
1494 
1495 
1496 /* External routines for getting or changing link data
1497    (external to alias_db.c, but internal to alias*.c)
1498 
1499     SetFragmentData(), GetFragmentData()
1500     SetFragmentPtr(), GetFragmentPtr()
1501     SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut()
1502     GetOriginalAddress(), GetDestAddress(), GetAliasAddress()
1503     GetOriginalPort(), GetAliasPort()
1504     SetAckModified(), GetAckModified()
1505     GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq()
1506 */
1507 
1508 
1509 void
1510 SetFragmentAddr(struct alias_link *link, struct in_addr src_addr)
1511 {
1512     link->data.frag_addr = src_addr;
1513 }
1514 
1515 
1516 void
1517 GetFragmentAddr(struct alias_link *link, struct in_addr *src_addr)
1518 {
1519     *src_addr = link->data.frag_addr;
1520 }
1521 
1522 
1523 void
1524 SetFragmentPtr(struct alias_link *link, char *fptr)
1525 {
1526     link->data.frag_ptr = fptr;
1527 }
1528 
1529 
1530 void
1531 GetFragmentPtr(struct alias_link *link, char **fptr)
1532 {
1533    *fptr = link->data.frag_ptr;
1534 }
1535 
1536 
1537 void
1538 SetStateIn(struct alias_link *link, int state)
1539 {
1540     /* TCP input state */
1541     switch (state) {
1542     case ALIAS_TCP_STATE_DISCONNECTED:
1543         if (link->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED) {
1544             link->expire_time = TCP_EXPIRE_DEAD;
1545         } else {
1546             link->expire_time = TCP_EXPIRE_SINGLEDEAD;
1547         }
1548         link->data.tcp->state.in = state;
1549         break;
1550     case ALIAS_TCP_STATE_CONNECTED:
1551         link->expire_time = TCP_EXPIRE_CONNECTED;
1552         /*FALLTHROUGH*/
1553     case ALIAS_TCP_STATE_NOT_CONNECTED:
1554         link->data.tcp->state.in = state;
1555         break;
1556     default:
1557         abort();
1558     }
1559 }
1560 
1561 
1562 void
1563 SetStateOut(struct alias_link *link, int state)
1564 {
1565     /* TCP output state */
1566     switch (state) {
1567     case ALIAS_TCP_STATE_DISCONNECTED:
1568         if (link->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED) {
1569             link->expire_time = TCP_EXPIRE_DEAD;
1570         } else {
1571             link->expire_time = TCP_EXPIRE_SINGLEDEAD;
1572         }
1573         link->data.tcp->state.out = state;
1574         break;
1575     case ALIAS_TCP_STATE_CONNECTED:
1576         link->expire_time = TCP_EXPIRE_CONNECTED;
1577         /*FALLTHROUGH*/
1578     case ALIAS_TCP_STATE_NOT_CONNECTED:
1579         link->data.tcp->state.out = state;
1580         break;
1581     default:
1582         abort();
1583     }
1584 }
1585 
1586 
1587 int
1588 GetStateIn(struct alias_link *link)
1589 {
1590     /* TCP input state */
1591     return link->data.tcp->state.in;
1592 }
1593 
1594 
1595 int
1596 GetStateOut(struct alias_link *link)
1597 {
1598     /* TCP output state */
1599     return link->data.tcp->state.out;
1600 }
1601 
1602 
1603 struct in_addr
1604 GetOriginalAddress(struct alias_link *link)
1605 {
1606     if (link->src_addr.s_addr == INADDR_ANY)
1607         return aliasAddress;
1608     else
1609         return(link->src_addr);
1610 }
1611 
1612 
1613 struct in_addr
1614 GetDestAddress(struct alias_link *link)
1615 {
1616     return(link->dst_addr);
1617 }
1618 
1619 
1620 struct in_addr
1621 GetAliasAddress(struct alias_link *link)
1622 {
1623     if (link->alias_addr.s_addr == INADDR_ANY)
1624         return aliasAddress;
1625     else
1626         return link->alias_addr;
1627 }
1628 
1629 
1630 struct in_addr
1631 GetDefaultAliasAddress()
1632 {
1633     return aliasAddress;
1634 }
1635 
1636 
1637 void
1638 SetDefaultAliasAddress(struct in_addr alias_addr)
1639 {
1640     aliasAddress = alias_addr;
1641 }
1642 
1643 
1644 u_short
1645 GetOriginalPort(struct alias_link *link)
1646 {
1647     return(link->src_port);
1648 }
1649 
1650 
1651 u_short
1652 GetAliasPort(struct alias_link *link)
1653 {
1654     return(link->alias_port);
1655 }
1656 
1657 #ifndef NO_FW_PUNCH
1658 static u_short
1659 GetDestPort(struct alias_link *link)
1660 {
1661     return(link->dst_port);
1662 }
1663 #endif
1664 
1665 void
1666 SetAckModified(struct alias_link *link)
1667 {
1668 /* Indicate that ack numbers have been modified in a TCP connection */
1669     link->data.tcp->state.ack_modified = 1;
1670 }
1671 
1672 
1673 struct in_addr
1674 GetProxyAddress(struct alias_link *link)
1675 {
1676     return link->proxy_addr;
1677 }
1678 
1679 
1680 void
1681 SetProxyAddress(struct alias_link *link, struct in_addr addr)
1682 {
1683     link->proxy_addr = addr;
1684 }
1685 
1686 
1687 u_short
1688 GetProxyPort(struct alias_link *link)
1689 {
1690     return link->proxy_port;
1691 }
1692 
1693 
1694 void
1695 SetProxyPort(struct alias_link *link, u_short port)
1696 {
1697     link->proxy_port = port;
1698 }
1699 
1700 
1701 int
1702 GetAckModified(struct alias_link *link)
1703 {
1704 /* See if ack numbers have been modified */
1705     return link->data.tcp->state.ack_modified;
1706 }
1707 
1708 
1709 int
1710 GetDeltaAckIn(struct ip *pip, struct alias_link *link)
1711 {
1712 /*
1713 Find out how much the ack number has been altered for an incoming
1714 TCP packet.  To do this, a circular list is ack numbers where the TCP
1715 packet size was altered is searched.
1716 */
1717 
1718     int i;
1719     struct tcphdr *tc;
1720     int delta, ack_diff_min;
1721     u_long ack;
1722 
1723     tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
1724     ack      = tc->th_ack;
1725 
1726     delta = 0;
1727     ack_diff_min = -1;
1728     for (i=0; i<N_LINK_TCP_DATA; i++)
1729     {
1730         struct ack_data_record x;
1731 
1732         x = link->data.tcp->ack[i];
1733         if (x.active == 1)
1734         {
1735             int ack_diff;
1736 
1737             ack_diff = SeqDiff(x.ack_new, ack);
1738             if (ack_diff >= 0)
1739             {
1740                 if (ack_diff_min >= 0)
1741                 {
1742                     if (ack_diff < ack_diff_min)
1743                     {
1744                         delta = x.delta;
1745                         ack_diff_min = ack_diff;
1746                     }
1747                 }
1748                 else
1749                 {
1750                     delta = x.delta;
1751                     ack_diff_min = ack_diff;
1752                 }
1753             }
1754         }
1755     }
1756     return (delta);
1757 }
1758 
1759 
1760 int
1761 GetDeltaSeqOut(struct ip *pip, struct alias_link *link)
1762 {
1763 /*
1764 Find out how much the seq number has been altered for an outgoing
1765 TCP packet.  To do this, a circular list is ack numbers where the TCP
1766 packet size was altered is searched.
1767 */
1768 
1769     int i;
1770     struct tcphdr *tc;
1771     int delta, seq_diff_min;
1772     u_long seq;
1773 
1774     tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
1775     seq = tc->th_seq;
1776 
1777     delta = 0;
1778     seq_diff_min = -1;
1779     for (i=0; i<N_LINK_TCP_DATA; i++)
1780     {
1781         struct ack_data_record x;
1782 
1783         x = link->data.tcp->ack[i];
1784         if (x.active == 1)
1785         {
1786             int seq_diff;
1787 
1788             seq_diff = SeqDiff(x.ack_old, seq);
1789             if (seq_diff >= 0)
1790             {
1791                 if (seq_diff_min >= 0)
1792                 {
1793                     if (seq_diff < seq_diff_min)
1794                     {
1795                         delta = x.delta;
1796                         seq_diff_min = seq_diff;
1797                     }
1798                 }
1799                 else
1800                 {
1801                     delta = x.delta;
1802                     seq_diff_min = seq_diff;
1803                 }
1804             }
1805         }
1806     }
1807     return (delta);
1808 }
1809 
1810 
1811 void
1812 AddSeq(struct ip *pip, struct alias_link *link, int delta)
1813 {
1814 /*
1815 When a TCP packet has been altered in length, save this
1816 information in a circular list.  If enough packets have
1817 been altered, then this list will begin to overwrite itself.
1818 */
1819 
1820     struct tcphdr *tc;
1821     struct ack_data_record x;
1822     int hlen, tlen, dlen;
1823     int i;
1824 
1825     tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
1826 
1827     hlen = (pip->ip_hl + tc->th_off) << 2;
1828     tlen = ntohs(pip->ip_len);
1829     dlen = tlen - hlen;
1830 
1831     x.ack_old = htonl(ntohl(tc->th_seq) + dlen);
1832     x.ack_new = htonl(ntohl(tc->th_seq) + dlen + delta);
1833     x.delta = delta;
1834     x.active = 1;
1835 
1836     i = link->data.tcp->state.index;
1837     link->data.tcp->ack[i] = x;
1838 
1839     i++;
1840     if (i == N_LINK_TCP_DATA)
1841         link->data.tcp->state.index = 0;
1842     else
1843         link->data.tcp->state.index = i;
1844 }
1845 
1846 void
1847 SetExpire(struct alias_link *link, int expire)
1848 {
1849     if (expire == 0)
1850     {
1851         link->flags &= ~LINK_PERMANENT;
1852         DeleteLink(link);
1853     }
1854     else if (expire == -1)
1855     {
1856         link->flags |= LINK_PERMANENT;
1857     }
1858     else if (expire > 0)
1859     {
1860         link->expire_time = expire;
1861     }
1862     else
1863     {
1864 #ifdef DEBUG
1865         fprintf(stderr, "PacketAlias/SetExpire(): ");
1866         fprintf(stderr, "error in expire parameter\n");
1867 #endif
1868     }
1869 }
1870 
1871 void
1872 ClearCheckNewLink(void)
1873 {
1874     newDefaultLink = 0;
1875 }
1876 
1877 
1878 /* Miscellaneous Functions
1879 
1880     HouseKeeping()
1881     InitPacketAliasLog()
1882     UninitPacketAliasLog()
1883 */
1884 
1885 /*
1886     Whenever an outgoing or incoming packet is handled, HouseKeeping()
1887     is called to find and remove timed-out aliasing links.  Logic exists
1888     to sweep through the entire table and linked list structure
1889     every 60 seconds.
1890 
1891     (prototype in alias_local.h)
1892 */
1893 
1894 void
1895 HouseKeeping(void)
1896 {
1897     int i, n, n100;
1898     struct timeval tv;
1899     struct timezone tz;
1900 
1901     /*
1902      * Save system time (seconds) in global variable timeStamp for
1903      * use by other functions. This is done so as not to unnecessarily
1904      * waste timeline by making system calls.
1905      */
1906     gettimeofday(&tv, &tz);
1907     timeStamp = tv.tv_sec;
1908 
1909     /* Compute number of spokes (output table link chains) to cover */
1910     n100  = LINK_TABLE_OUT_SIZE * 100 + houseKeepingResidual;
1911     n100 *= timeStamp - lastCleanupTime;
1912     n100 /= ALIAS_CLEANUP_INTERVAL_SECS;
1913 
1914     n = n100/100;
1915 
1916     /* Handle different cases */
1917     if (n > ALIAS_CLEANUP_MAX_SPOKES)
1918     {
1919         n = ALIAS_CLEANUP_MAX_SPOKES;
1920         lastCleanupTime = timeStamp;
1921         houseKeepingResidual = 0;
1922 
1923         for (i=0; i<n; i++)
1924             IncrementalCleanup();
1925     }
1926     else if (n > 0)
1927     {
1928         lastCleanupTime = timeStamp;
1929         houseKeepingResidual = n100 - 100*n;
1930 
1931         for (i=0; i<n; i++)
1932             IncrementalCleanup();
1933     }
1934     else if (n < 0)
1935     {
1936 #ifdef DEBUG
1937         fprintf(stderr, "PacketAlias/HouseKeeping(): ");
1938         fprintf(stderr, "something unexpected in time values\n");
1939 #endif
1940         lastCleanupTime = timeStamp;
1941         houseKeepingResidual = 0;
1942     }
1943 }
1944 
1945 
1946 /* Init the log file and enable logging */
1947 static void
1948 InitPacketAliasLog(void)
1949 {
1950    if ((~packetAliasMode & PKT_ALIAS_LOG)
1951     && (monitorFile = fopen("/var/log/alias.log", "w")))
1952    {
1953       packetAliasMode |= PKT_ALIAS_LOG;
1954       fprintf(monitorFile,
1955       "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n");
1956    }
1957 }
1958 
1959 
1960 /* Close the log-file and disable logging. */
1961 static void
1962 UninitPacketAliasLog(void)
1963 {
1964     if (monitorFile) {
1965         fclose(monitorFile);
1966         monitorFile = NULL;
1967     }
1968     packetAliasMode &= ~PKT_ALIAS_LOG;
1969 }
1970 
1971 
1972 
1973 
1974 
1975 
1976 /* Outside world interfaces
1977 
1978 -- "outside world" means other than alias*.c routines --
1979 
1980     PacketAliasRedirectPort()
1981     PacketAliasRedirectAddr()
1982     PacketAliasRedirectDelete()
1983     PacketAliasSetAddress()
1984     PacketAliasInit()
1985     PacketAliasUninit()
1986     PacketAliasSetMode()
1987 
1988 (prototypes in alias.h)
1989 */
1990 
1991 /* Redirection from a specific public addr:port to a
1992    a private addr:port */
1993 struct alias_link *
1994 PacketAliasRedirectPort(struct in_addr src_addr,   u_short src_port,
1995                         struct in_addr dst_addr,   u_short dst_port,
1996                         struct in_addr alias_addr, u_short alias_port,
1997                         u_char proto)
1998 {
1999     int link_type;
2000     struct alias_link *link;
2001 
2002     switch(proto)
2003     {
2004     case IPPROTO_UDP:
2005         link_type = LINK_UDP;
2006         break;
2007     case IPPROTO_TCP:
2008         link_type = LINK_TCP;
2009         break;
2010     default:
2011 #ifdef DEBUG
2012         fprintf(stderr, "PacketAliasRedirectPort(): ");
2013         fprintf(stderr, "only TCP and UDP protocols allowed\n");
2014 #endif
2015         return NULL;
2016     }
2017 
2018     link = AddLink(src_addr, dst_addr, alias_addr,
2019                    src_port, dst_port, alias_port,
2020                    link_type);
2021 
2022     if (link != NULL)
2023     {
2024         link->flags |= LINK_PERMANENT;
2025     }
2026 #ifdef DEBUG
2027     else
2028     {
2029         fprintf(stderr, "PacketAliasRedirectPort(): "
2030                         "call to AddLink() failed\n");
2031     }
2032 #endif
2033 
2034     return link;
2035 }
2036 
2037 /* Translate PPTP packets to a machine on the inside
2038  */
2039 int
2040 PacketAliasPptp(struct in_addr src_addr)
2041 {
2042 
2043     pptpAliasAddr = src_addr; 		/* Address of the inside PPTP machine */
2044     pptpAliasFlag = src_addr.s_addr != INADDR_NONE;
2045 
2046     return 1;
2047 }
2048 
2049 int GetPptpAlias (struct in_addr* alias_addr)
2050 {
2051     if (pptpAliasFlag)
2052 	*alias_addr = pptpAliasAddr;
2053 
2054     return pptpAliasFlag;
2055 }
2056 
2057 /* Static address translation */
2058 struct alias_link *
2059 PacketAliasRedirectAddr(struct in_addr src_addr,
2060                         struct in_addr alias_addr)
2061 {
2062     struct alias_link *link;
2063 
2064     link = AddLink(src_addr, nullAddress, alias_addr,
2065                    0, 0, 0,
2066                    LINK_ADDR);
2067 
2068     if (link != NULL)
2069     {
2070         link->flags |= LINK_PERMANENT;
2071     }
2072 #ifdef DEBUG
2073     else
2074     {
2075         fprintf(stderr, "PacketAliasRedirectAddr(): "
2076                         "call to AddLink() failed\n");
2077     }
2078 #endif
2079 
2080     return link;
2081 }
2082 
2083 
2084 void
2085 PacketAliasRedirectDelete(struct alias_link *link)
2086 {
2087 /* This is a dangerous function to put in the API,
2088    because an invalid pointer can crash the program. */
2089 
2090     deleteAllLinks = 1;
2091     DeleteLink(link);
2092     deleteAllLinks = 0;
2093 }
2094 
2095 
2096 void
2097 PacketAliasSetAddress(struct in_addr addr)
2098 {
2099     if (packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE
2100      && aliasAddress.s_addr != addr.s_addr)
2101         CleanupAliasData();
2102 
2103     aliasAddress = addr;
2104 }
2105 
2106 
2107 void
2108 PacketAliasSetTarget(struct in_addr target_addr)
2109 {
2110     targetAddress = target_addr;
2111 }
2112 
2113 
2114 void
2115 PacketAliasInit(void)
2116 {
2117     int i;
2118     struct timeval tv;
2119     struct timezone tz;
2120     static int firstCall = 1;
2121 
2122     if (firstCall == 1)
2123     {
2124         gettimeofday(&tv, &tz);
2125         timeStamp = tv.tv_sec;
2126         lastCleanupTime = tv.tv_sec;
2127         houseKeepingResidual = 0;
2128 
2129         for (i=0; i<LINK_TABLE_OUT_SIZE; i++)
2130             linkTableOut[i] = NULL;
2131         for (i=0; i<LINK_TABLE_IN_SIZE; i++)
2132             linkTableIn[i] = NULL;
2133 
2134         atexit(PacketAliasUninit);
2135         firstCall = 0;
2136     }
2137     else
2138     {
2139         deleteAllLinks = 1;
2140         CleanupAliasData();
2141         deleteAllLinks = 0;
2142     }
2143 
2144     aliasAddress.s_addr = INADDR_ANY;
2145     targetAddress.s_addr = INADDR_NONE;
2146 
2147     icmpLinkCount = 0;
2148     udpLinkCount = 0;
2149     tcpLinkCount = 0;
2150     fragmentIdLinkCount = 0;
2151     fragmentPtrLinkCount = 0;
2152     sockCount = 0;
2153 
2154     cleanupIndex =0;
2155 
2156     packetAliasMode = PKT_ALIAS_SAME_PORTS
2157                     | PKT_ALIAS_USE_SOCKETS
2158                     | PKT_ALIAS_RESET_ON_ADDR_CHANGE;
2159 
2160     pptpAliasFlag = 0;
2161 }
2162 
2163 void
2164 PacketAliasUninit(void) {
2165     deleteAllLinks = 1;
2166     CleanupAliasData();
2167     deleteAllLinks = 0;
2168     UninitPacketAliasLog();
2169 #ifndef NO_FW_PUNCH
2170     UninitPunchFW();
2171 #endif
2172 }
2173 
2174 
2175 /* Change mode for some operations */
2176 unsigned int
2177 PacketAliasSetMode(
2178     unsigned int flags, /* Which state to bring flags to */
2179     unsigned int mask   /* Mask of which flags to affect (use 0 to do a
2180                            probe for flag values) */
2181 )
2182 {
2183 /* Enable logging? */
2184     if (flags & mask & PKT_ALIAS_LOG)
2185     {
2186         InitPacketAliasLog();     /* Do the enable */
2187     } else
2188 /* _Disable_ logging? */
2189     if (~flags & mask & PKT_ALIAS_LOG) {
2190         UninitPacketAliasLog();
2191     }
2192 
2193 #ifndef NO_FW_PUNCH
2194 /* Start punching holes in the firewall? */
2195     if (flags & mask & PKT_ALIAS_PUNCH_FW) {
2196         InitPunchFW();
2197     } else
2198 /* Stop punching holes in the firewall? */
2199     if (~flags & mask & PKT_ALIAS_PUNCH_FW) {
2200         UninitPunchFW();
2201     }
2202 #endif
2203 
2204 /* Other flags can be set/cleared without special action */
2205     packetAliasMode = (flags & mask) | (packetAliasMode & ~mask);
2206     return packetAliasMode;
2207 }
2208 
2209 
2210 int
2211 PacketAliasCheckNewLink(void)
2212 {
2213     return newDefaultLink;
2214 }
2215 
2216 
2217 #ifndef NO_FW_PUNCH
2218 
2219 /*****************
2220   Code to support firewall punching.  This shouldn't really be in this
2221   file, but making variables global is evil too.
2222   ****************/
2223 
2224 /* Firewall include files */
2225 #include <sys/queue.h>
2226 #include <net/if.h>
2227 #include <netinet/ip_fw.h>
2228 #include <string.h>
2229 #include <err.h>
2230 
2231 static void ClearAllFWHoles(void);
2232 
2233 static int fireWallBaseNum;     /* The first firewall entry free for our use */
2234 static int fireWallNumNums;     /* How many entries can we use? */
2235 static int fireWallActiveNum;   /* Which entry did we last use? */
2236 static char *fireWallField;     /* bool array for entries */
2237 
2238 #define fw_setfield(field, num)                         \
2239 do {                                                    \
2240     (field)[num] = 1;                                   \
2241 } /*lint -save -e717 */ while(0) /*lint -restore */
2242 #define fw_clrfield(field, num)                         \
2243 do {                                                    \
2244     (field)[num] = 0;                                   \
2245 } /*lint -save -e717 */ while(0) /*lint -restore */
2246 #define fw_tstfield(field, num) ((field)[num])
2247 
2248 void
2249 PacketAliasSetFWBase(unsigned int base, unsigned int num) {
2250     fireWallBaseNum = base;
2251     fireWallNumNums = num;
2252 }
2253 
2254 static void
2255 InitPunchFW(void) {
2256     fireWallField = malloc(fireWallNumNums);
2257     if (fireWallField) {
2258         memset(fireWallField, 0, fireWallNumNums);
2259         if (fireWallFD < 0) {
2260             fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
2261         }
2262         ClearAllFWHoles();
2263         fireWallActiveNum = fireWallBaseNum;
2264     }
2265 }
2266 
2267 static void
2268 UninitPunchFW(void) {
2269     ClearAllFWHoles();
2270     if (fireWallFD >= 0)
2271         close(fireWallFD);
2272     fireWallFD = -1;
2273     if (fireWallField)
2274         free(fireWallField);
2275     fireWallField = NULL;
2276     packetAliasMode &= ~PKT_ALIAS_PUNCH_FW;
2277 }
2278 
2279 /* Make a certain link go through the firewall */
2280 void
2281 PunchFWHole(struct alias_link *link) {
2282     int r;                      /* Result code */
2283     struct ip_fw rule;          /* On-the-fly built rule */
2284     int fwhole;                 /* Where to punch hole */
2285 
2286 /* Don't do anything unless we are asked to */
2287     if ( !(packetAliasMode & PKT_ALIAS_PUNCH_FW) ||
2288          fireWallFD < 0 ||
2289          link->link_type != LINK_TCP ||
2290          !link->data.tcp)
2291         return;
2292 
2293     memset(&rule, 0, sizeof rule);
2294 
2295 /** Build rule **/
2296 
2297     /* Find empty slot */
2298     for (fwhole = fireWallActiveNum;
2299          fwhole < fireWallBaseNum + fireWallNumNums &&
2300              fw_tstfield(fireWallField, fwhole);
2301          fwhole++)
2302         ;
2303     if (fwhole >= fireWallBaseNum + fireWallNumNums ||
2304         fw_tstfield(fireWallField, fwhole)) {
2305         for (fwhole = fireWallBaseNum;
2306              fwhole < fireWallActiveNum &&
2307                  fw_tstfield(fireWallField, fwhole);
2308              fwhole++)
2309             ;
2310         if (fwhole == fireWallActiveNum) {
2311             /* No rule point empty - we can't punch more holes. */
2312             fireWallActiveNum = fireWallBaseNum;
2313 #ifdef DEBUG
2314             fprintf(stderr, "libalias: Unable to create firewall hole!\n");
2315 #endif
2316             return;
2317         }
2318     }
2319     /* Start next search at next position */
2320     fireWallActiveNum = fwhole+1;
2321 
2322     /* Build generic part of the two rules */
2323     rule.fw_number = fwhole;
2324     rule.fw_nports = 1;         /* Number of source ports; dest ports follow */
2325     rule.fw_flg = IP_FW_F_ACCEPT;
2326     rule.fw_prot = IPPROTO_TCP;
2327     rule.fw_smsk.s_addr = INADDR_BROADCAST;
2328     rule.fw_dmsk.s_addr = INADDR_BROADCAST;
2329 
2330     /* Build and apply specific part of the rules */
2331     rule.fw_src = GetOriginalAddress(link);
2332     rule.fw_dst = GetDestAddress(link);
2333     rule.fw_uar.fw_pts[0] = ntohs(GetOriginalPort(link));
2334     rule.fw_uar.fw_pts[1] = ntohs(GetDestPort(link));
2335 
2336     /* Skip non-bound links - XXX should not be strictly necessary,
2337        but seems to leave hole if not done.  Leak of non-bound links?
2338        (Code should be left even if the problem is fixed - it is a
2339        clear optimization) */
2340     if (rule.fw_uar.fw_pts[0] != 0 && rule.fw_uar.fw_pts[1] != 0) {
2341         r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule);
2342 #ifdef DEBUG
2343         if (r)
2344             err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)");
2345 #endif
2346         rule.fw_src = GetDestAddress(link);
2347         rule.fw_dst = GetOriginalAddress(link);
2348         rule.fw_uar.fw_pts[0] = ntohs(GetDestPort(link));
2349         rule.fw_uar.fw_pts[1] = ntohs(GetOriginalPort(link));
2350         r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule);
2351 #ifdef DEBUG
2352         if (r)
2353             err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)");
2354 #endif
2355     }
2356 /* Indicate hole applied */
2357     link->data.tcp->fwhole = fwhole;
2358     fw_setfield(fireWallField, fwhole);
2359 }
2360 
2361 /* Remove a hole in a firewall associated with a particular alias
2362    link.  Calling this too often is harmless. */
2363 static void
2364 ClearFWHole(struct alias_link *link) {
2365     if (link->link_type == LINK_TCP && link->data.tcp) {
2366         int fwhole =  link->data.tcp->fwhole; /* Where is the firewall hole? */
2367         struct ip_fw rule;
2368 
2369         if (fwhole < 0)
2370             return;
2371 
2372         memset(&rule, 0, sizeof rule);
2373         rule.fw_number = fwhole;
2374         while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule))
2375             ;
2376         fw_clrfield(fireWallField, fwhole);
2377         link->data.tcp->fwhole = -1;
2378     }
2379 }
2380 
2381 /* Clear out the entire range dedicated to firewall holes. */
2382 static void
2383 ClearAllFWHoles(void) {
2384     struct ip_fw rule;          /* On-the-fly built rule */
2385     int i;
2386 
2387     if (fireWallFD < 0)
2388         return;
2389 
2390     memset(&rule, 0, sizeof rule);
2391     for (i = fireWallBaseNum; i < fireWallBaseNum + fireWallNumNums; i++) {
2392         rule.fw_number = i;
2393         while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule))
2394             ;
2395     }
2396     memset(fireWallField, 0, fireWallNumNums);
2397 }
2398 #endif
2399