]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netinet/libalias/alias_db.c
Restore previous version of FindLinkIn().
[FreeBSD/FreeBSD.git] / sys / netinet / libalias / alias_db.c
1 /*  -*- mode: c; tab-width: 8; c-basic-indent: 4; -*-
2     Alias_db.c encapsulates all data structures used for storing
3     packet aliasing data.  Other parts of the aliasing software
4     access data through functions provided in this file.
5
6     Data storage is based on the notion of a "link", which is
7     established for ICMP echo/reply packets, UDP datagrams and
8     TCP stream connections.  A link stores the original source
9     and destination addresses.  For UDP and TCP, it also stores
10     source and destination port numbers, as well as an alias
11     port number.  Links are also used to store information about
12     fragments.
13
14     There is a facility for sweeping through and deleting old
15     links as new packets are sent through.  A simple timeout is
16     used for ICMP and UDP links.  TCP links are left alone unless
17     there is an incomplete connection, in which case the link
18     can be deleted after a certain amount of time.
19
20
21     This software is placed into the public domain with no restrictions
22     on its distribution.
23
24     Initial version: August, 1996  (cjm)
25
26     Version 1.4: September 16, 1996 (cjm)
27         Facility for handling incoming links added.
28
29     Version 1.6: September 18, 1996 (cjm)
30         ICMP data handling simplified.
31
32     Version 1.7: January 9, 1997 (cjm)
33         Fragment handling simplified.
34         Saves pointers for unresolved fragments.
35         Permits links for unspecied remote ports
36           or unspecified remote addresses.
37         Fixed bug which did not properly zero port
38           table entries after a link was deleted.
39         Cleaned up some obsolete comments.
40
41     Version 1.8: January 14, 1997 (cjm)
42         Fixed data type error in StartPoint().
43         (This error did not exist prior to v1.7
44         and was discovered and fixed by Ari Suutari)
45
46     Version 1.9: February 1, 1997
47         Optionally, connections initiated from packet aliasing host
48         machine will will not have their port number aliased unless it
49         conflicts with an aliasing port already being used. (cjm)
50
51         All options earlier being #ifdef'ed now are available through
52         a new interface, SetPacketAliasMode().  This allow run time
53         control (which is now available in PPP+pktAlias through the
54         'alias' keyword). (ee)
55
56         Added ability to create an alias port without
57         either destination address or port specified.
58         port type = ALIAS_PORT_UNKNOWN_DEST_ALL (ee)
59
60         Removed K&R style function headers
61         and general cleanup. (ee)
62
63         Added packetAliasMode to replace compiler #defines's (ee)
64
65         Allocates sockets for partially specified
66         ports if ALIAS_USE_SOCKETS defined. (cjm)
67
68     Version 2.0: March, 1997
69         SetAliasAddress() will now clean up alias links
70         if the aliasing address is changed. (cjm)
71
72         PacketAliasPermanentLink() function added to support permanent
73         links.  (J. Fortes suggested the need for this.)
74         Examples:
75
76         (192.168.0.1, port 23)  <-> alias port 6002, unknown dest addr/port
77
78         (192.168.0.2, port 21)  <-> alias port 3604, known dest addr
79                                                      unknown dest port
80
81         These permament links allow for incoming connections to
82         machines on the local network.  They can be given with a
83         user-chosen amount of specificity, with increasing specificity
84         meaning more security. (cjm)
85
86         Quite a bit of rework to the basic engine.  The portTable[]
87         array, which kept track of which ports were in use was replaced
88         by a table/linked list structure. (cjm)
89
90         SetExpire() function added. (cjm)
91
92         DeleteLink() no longer frees memory association with a pointer
93         to a fragment (this bug was first recognized by E. Eklund in
94         v1.9).
95
96     Version 2.1: May, 1997 (cjm)
97         Packet aliasing engine reworked so that it can handle
98         multiple external addresses rather than just a single
99         host address.
100
101         PacketAliasRedirectPort() and PacketAliasRedirectAddr()
102         added to the API.  The first function is a more generalized
103         version of PacketAliasPermanentLink().  The second function
104         implements static network address translation.
105
106     See HISTORY file for additional revisions.
107
108     $FreeBSD$
109 */
110
111
112 /* System include files */
113 #include <errno.h>
114 #include <stdlib.h>
115 #include <stdio.h>
116 #include <unistd.h>
117
118 #include <sys/socket.h>
119 #include <sys/time.h>
120 #include <sys/types.h>
121
122 /* BSD network include files */
123 #include <netinet/in_systm.h>
124 #include <netinet/in.h>
125 #include <netinet/ip.h>
126 #include <netinet/tcp.h>
127 #include <arpa/inet.h>
128
129 #include "alias.h"
130 #include "alias_local.h"
131
132
133
134 /*
135    Constants (note: constants are also defined
136               near relevant functions or structs)
137 */
138
139 /* Sizes of input and output link tables */
140 #define LINK_TABLE_OUT_SIZE         101
141 #define LINK_TABLE_IN_SIZE         4001
142
143 /* Parameters used for cleanup of expired links */
144 #define ALIAS_CLEANUP_INTERVAL_SECS  60
145 #define ALIAS_CLEANUP_MAX_SPOKES     30
146
147 /* Timeouts (in seconds) for different link types */
148 #define ICMP_EXPIRE_TIME             60
149 #define UDP_EXPIRE_TIME              60
150 #define FRAGMENT_ID_EXPIRE_TIME      10
151 #define FRAGMENT_PTR_EXPIRE_TIME     30
152
153 /* TCP link expire time for different cases */
154 /* When the link has been used and closed - minimal grace time to
155    allow ACKs and potential re-connect in FTP (XXX - is this allowed?)  */
156 #ifndef TCP_EXPIRE_DEAD
157 #   define TCP_EXPIRE_DEAD           10
158 #endif
159
160 /* When the link has been used and closed on one side - the other side
161    is allowed to still send data */
162 #ifndef TCP_EXPIRE_SINGLEDEAD
163 #   define TCP_EXPIRE_SINGLEDEAD     90
164 #endif
165
166 /* When the link isn't yet up */
167 #ifndef TCP_EXPIRE_INITIAL
168 #   define TCP_EXPIRE_INITIAL       300
169 #endif
170
171 /* When the link is up */
172 #ifndef TCP_EXPIRE_CONNECTED
173 #   define TCP_EXPIRE_CONNECTED   86400
174 #endif
175
176
177 /* Dummy port number codes used for FindLinkIn/Out() and AddLink().
178    These constants can be anything except zero, which indicates an
179    unknown port number. */
180
181 #define NO_DEST_PORT     1
182 #define NO_SRC_PORT      1
183
184
185
186 /* Data Structures
187
188     The fundamental data structure used in this program is
189     "struct alias_link".  Whenever a TCP connection is made,
190     a UDP datagram is sent out, or an ICMP echo request is made,
191     a link record is made (if it has not already been created).
192     The link record is identified by the source address/port
193     and the destination address/port. In the case of an ICMP
194     echo request, the source port is treated as being equivalent
195     with the 16-bit id number of the ICMP packet.
196
197     The link record also can store some auxiliary data.  For
198     TCP connections that have had sequence and acknowledgment
199     modifications, data space is available to track these changes.
200     A state field is used to keep track in changes to the tcp
201     connection state.  Id numbers of fragments can also be
202     stored in the auxiliary space.  Pointers to unresolved
203     framgents can also be stored.
204
205     The link records support two independent chainings.  Lookup
206     tables for input and out tables hold the initial pointers
207     the link chains.  On input, the lookup table indexes on alias
208     port and link type.  On output, the lookup table indexes on
209     source addreess, destination address, source port, destination
210     port and link type.
211 */
212
213 struct ack_data_record     /* used to save changes to ack/seq numbers */
214 {
215     u_long ack_old;
216     u_long ack_new;
217     int delta;
218     int active;
219 };
220
221 struct tcp_state           /* Information about tcp connection        */
222 {
223     int in;                /* State for outside -> inside             */
224     int out;               /* State for inside  -> outside            */
225     int index;             /* Index to ack data array                 */
226     int ack_modified;      /* Indicates whether ack and seq numbers   */
227                            /* been modified                           */
228 };
229
230 #define N_LINK_TCP_DATA   3 /* Number of distinct ack number changes
231                                saved for a modified TCP stream */
232 struct tcp_dat
233 {
234     struct tcp_state state;
235     struct ack_data_record ack[N_LINK_TCP_DATA];
236     int fwhole;             /* Which firewall record is used for this hole? */
237 };
238
239 struct alias_link                /* Main data structure */
240 {
241     struct in_addr src_addr;     /* Address and port information        */
242     struct in_addr dst_addr;
243     struct in_addr alias_addr;
244     struct in_addr proxy_addr;
245     u_short src_port;
246     u_short dst_port;
247     u_short alias_port;
248     u_short proxy_port;
249
250     int link_type;               /* Type of link: tcp, udp, icmp, frag  */
251
252 /* values for link_type */
253 #define LINK_ICMP                     1
254 #define LINK_UDP                      2
255 #define LINK_TCP                      3
256 #define LINK_FRAGMENT_ID              4
257 #define LINK_FRAGMENT_PTR             5
258 #define LINK_ADDR                     6
259
260     int flags;                   /* indicates special characteristics   */
261
262 /* flag bits */
263 #define LINK_UNKNOWN_DEST_PORT     0x01
264 #define LINK_UNKNOWN_DEST_ADDR     0x02
265 #define LINK_PERMANENT             0x04
266 #define LINK_PARTIALLY_SPECIFIED   0x03 /* logical-or of first two bits */
267 #define LINK_UNFIREWALLED          0x08
268
269     int timestamp;               /* Time link was last accessed         */
270     int expire_time;             /* Expire time for link                */
271
272     int sockfd;                  /* socket descriptor                   */
273
274     u_int start_point_out;       /* Index number in output lookup table */
275     u_int start_point_in;
276     struct alias_link *next_out; /* Linked list pointers for input and  */
277     struct alias_link *last_out; /* output tables                       */
278     struct alias_link *next_in;  /*  .                                  */
279     struct alias_link *last_in;  /*  .                                  */
280
281     union                        /* Auxiliary data                      */
282     {
283         char *frag_ptr;
284         struct in_addr frag_addr;
285         struct tcp_dat *tcp;
286     } data;
287 };
288
289
290
291
292
293 /* Global Variables 
294
295     The global variables listed here are only accessed from
296     within alias_db.c and so are prefixed with the static 
297     designation.
298 */
299
300 int packetAliasMode;                 /* Mode flags                      */ 
301                                      /*        - documented in alias.h  */
302
303 static struct in_addr aliasAddress;  /* Address written onto source     */
304                                      /*   field of IP packet.           */
305
306 static struct in_addr targetAddress; /* IP address incoming packets     */
307                                      /*   are sent to if no aliasing    */
308                                      /*   link already exists           */
309
310 static struct in_addr nullAddress;   /* Used as a dummy parameter for   */
311                                      /*   some function calls           */
312 static struct alias_link *
313 linkTableOut[LINK_TABLE_OUT_SIZE];   /* Lookup table of pointers to     */
314                                      /*   chains of link records. Each  */
315 static struct alias_link *           /*   link record is doubly indexed */
316 linkTableIn[LINK_TABLE_IN_SIZE];     /*   into input and output lookup  */
317                                      /*   tables.                       */
318
319 static int icmpLinkCount;            /* Link statistics                 */
320 static int udpLinkCount;
321 static int tcpLinkCount;
322 static int fragmentIdLinkCount;
323 static int fragmentPtrLinkCount;
324 static int sockCount;
325
326 static int cleanupIndex;             /* Index to chain of link table    */
327                                      /* being inspected for old links   */
328
329 static int timeStamp;                /* System time in seconds for      */
330                                      /* current packet                  */
331
332 static int lastCleanupTime;          /* Last time IncrementalCleanup()  */
333                                      /* was called                      */
334
335 static int houseKeepingResidual;     /* used by HouseKeeping()          */
336
337 static int deleteAllLinks;           /* If equal to zero, DeleteLink()  */
338                                      /* will not remove permanent links */
339
340 static FILE *monitorFile;            /* File descriptor for link        */
341                                      /* statistics monitoring file      */
342
343 static int newDefaultLink;           /* Indicates if a new aliasing     */
344                                      /* link has been created after a   */
345                                      /* call to PacketAliasIn/Out().    */
346              
347 #ifndef NO_FW_PUNCH
348 static int fireWallFD = -1;          /* File descriptor to be able to   */
349                                      /* control firewall.  Opened by    */
350                                      /* PacketAliasSetMode on first     */
351                                      /* setting the PKT_ALIAS_PUNCH_FW  */
352                                      /* flag.                           */
353 #endif
354
355 static int pptpAliasFlag;            /* Indicates if PPTP aliasing is   */
356                                      /* on or off                       */
357 static struct in_addr pptpAliasAddr; /* Address of source of PPTP       */
358                                      /* packets.                        */
359
360
361
362
363
364
365
366 /* Internal utility routines (used only in alias_db.c)
367
368 Lookup table starting points:
369     StartPointIn()           -- link table initial search point for
370                                 incoming packets
371     StartPointOut()          -- port table initial search point for
372                                 outgoing packets
373     
374 Miscellaneous:
375     SeqDiff()                -- difference between two TCP sequences
376     ShowAliasStats()         -- send alias statistics to a monitor file
377 */
378
379
380 /* Local prototypes */
381 static u_int StartPointIn(struct in_addr, u_short, int);
382
383 static u_int StartPointOut(struct in_addr, struct in_addr,
384                            u_short, u_short, int);
385
386 static int SeqDiff(u_long, u_long);
387
388 static void ShowAliasStats(void);
389
390 #ifndef NO_FW_PUNCH
391 /* Firewall control */
392 static void InitPunchFW(void);
393 static void UninitPunchFW(void);
394 static void ClearFWHole(struct alias_link *link);
395 #endif
396
397 /* Log file control */
398 static void InitPacketAliasLog(void);
399 static void UninitPacketAliasLog(void);
400
401 static u_int
402 StartPointIn(struct in_addr alias_addr,
403              u_short alias_port,
404              int link_type)
405 {
406     u_int n;
407
408     n  = alias_addr.s_addr;
409     n += alias_port;
410     n += link_type;
411     return(n % LINK_TABLE_IN_SIZE);
412 }
413
414
415 static u_int
416 StartPointOut(struct in_addr src_addr, struct in_addr dst_addr,
417               u_short src_port, u_short dst_port, int link_type)
418 {
419     u_int n;
420
421     n  = src_addr.s_addr;
422     n += dst_addr.s_addr;
423     n += src_port; 
424     n += dst_port;
425     n += link_type;
426
427     return(n % LINK_TABLE_OUT_SIZE);
428 }
429
430
431 static int
432 SeqDiff(u_long x, u_long y)
433 {
434 /* Return the difference between two TCP sequence numbers */
435
436 /*
437     This function is encapsulated in case there are any unusual
438     arithmetic conditions that need to be considered.
439 */
440
441     return (ntohl(y) - ntohl(x));
442 }
443
444
445 static void
446 ShowAliasStats(void)
447 {
448 /* Used for debugging */
449
450    if (monitorFile)
451    {
452       fprintf(monitorFile, "icmp=%d, udp=%d, tcp=%d, frag_id=%d frag_ptr=%d",
453               icmpLinkCount,
454               udpLinkCount,
455               tcpLinkCount,
456               fragmentIdLinkCount,
457               fragmentPtrLinkCount);
458
459       fprintf(monitorFile, " / tot=%d  (sock=%d)\n",
460               icmpLinkCount + udpLinkCount
461                             + tcpLinkCount
462                             + fragmentIdLinkCount
463                             + fragmentPtrLinkCount,
464               sockCount);
465
466       fflush(monitorFile);
467    }
468 }
469
470
471
472
473
474 /* Internal routines for finding, deleting and adding links
475
476 Port Allocation:
477     GetNewPort()             -- find and reserve new alias port number
478     GetSocket()              -- try to allocate a socket for a given port
479
480 Link creation and deletion:
481     CleanupAliasData()      - remove all link chains from lookup table
482     IncrementalCleanup()    - look for stale links in a single chain
483     DeleteLink()            - remove link
484     AddLink()               - add link 
485     ReLink()                - change link 
486
487 Link search:
488     FindLinkOut()           - find link for outgoing packets
489     FindLinkIn()            - find link for incoming packets
490 */
491
492 /* Local prototypes */
493 static int GetNewPort(struct alias_link *, int);
494
495 static u_short GetSocket(u_short, int *, int);
496
497 static void CleanupAliasData(void);
498
499 static void IncrementalCleanup(void);
500
501 static void DeleteLink(struct alias_link *);
502
503 static struct alias_link *
504 AddLink(struct in_addr, struct in_addr, struct in_addr,
505         u_short, u_short, int, int);
506
507 static struct alias_link *
508 ReLink(struct alias_link *,
509        struct in_addr, struct in_addr, struct in_addr,
510         u_short, u_short, int, int);
511
512 static struct alias_link *
513 FindLinkOut(struct in_addr, struct in_addr, u_short, u_short, int);
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 {
1039     u_int i;
1040     struct alias_link *link;
1041
1042     if (src_addr.s_addr == aliasAddress.s_addr)
1043         src_addr.s_addr = 0;
1044
1045     i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type);
1046     link = linkTableOut[i];
1047     while (link != NULL)
1048     {
1049         if (link->src_addr.s_addr == src_addr.s_addr
1050          && link->dst_addr.s_addr == dst_addr.s_addr
1051          && link->dst_port        == dst_port
1052          && link->src_port        == src_port
1053          && link->link_type       == link_type)
1054         {
1055             link->timestamp = timeStamp;
1056             break;
1057         }
1058         link = link->next_out;
1059     }
1060
1061 /* Search for partially specified links. */
1062     if (link == NULL)
1063     {
1064         if (dst_port != 0)
1065         {
1066             link = FindLinkOut(src_addr, dst_addr, src_port, 0, link_type);
1067         }
1068         else if (dst_addr.s_addr != 0)
1069         {
1070             link = FindLinkOut(src_addr, nullAddress, src_port, 0, link_type);
1071         }
1072     }
1073
1074     return(link);
1075 }
1076
1077
1078 struct alias_link *
1079 FindLinkIn(struct in_addr  dst_addr,
1080            struct in_addr  alias_addr,
1081            u_short         dst_port,
1082            u_short         alias_port,
1083            int             link_type,
1084            int             replace_partial_links)
1085 {
1086     int flags_in;
1087     u_int start_point;
1088     struct alias_link *link;
1089     struct alias_link *link_fully_specified;
1090     struct alias_link *link_unknown_all;
1091     struct alias_link *link_unknown_dst_addr;
1092     struct alias_link *link_unknown_dst_port;
1093
1094 /* Initialize pointers */
1095     link_fully_specified  = NULL;
1096     link_unknown_all      = NULL;
1097     link_unknown_dst_addr = NULL;
1098     link_unknown_dst_port = NULL;
1099
1100 /* If either the dest addr or port is unknown, the search
1101    loop will have to know about this. */
1102
1103     flags_in = 0;
1104     if (dst_addr.s_addr == 0)
1105         flags_in |= LINK_UNKNOWN_DEST_ADDR;
1106     if (dst_port == 0)
1107         flags_in |= LINK_UNKNOWN_DEST_PORT;
1108
1109 /* The following allows permanent links to be
1110    be specified as using the default aliasing address
1111    (i.e. device interface address) without knowing
1112    in advance what that address is. */
1113
1114     if (alias_addr.s_addr == aliasAddress.s_addr)
1115         alias_addr.s_addr = 0;
1116
1117 /* Search loop */
1118     start_point = StartPointIn(alias_addr, alias_port, link_type);
1119     link = linkTableIn[start_point];
1120     while (link != NULL)
1121     {
1122         int flags;
1123
1124         flags = flags_in | link->flags;
1125         if (!(flags & LINK_PARTIALLY_SPECIFIED))
1126         {
1127             if (link->alias_addr.s_addr == alias_addr.s_addr
1128              && link->alias_port        == alias_port 
1129              && link->dst_addr.s_addr   == dst_addr.s_addr
1130              && link->dst_port          == dst_port
1131              && link->link_type         == link_type)
1132             {
1133                 link_fully_specified = link;
1134                 break;
1135             }
1136         }
1137         else if ((flags & LINK_UNKNOWN_DEST_ADDR)
1138               && (flags & LINK_UNKNOWN_DEST_PORT))
1139         {
1140             if (link->alias_addr.s_addr == alias_addr.s_addr
1141              && link->alias_port        == alias_port
1142              && link->link_type         == link_type)
1143             {
1144                 if (link_unknown_all == NULL)
1145                     link_unknown_all = link;
1146             }
1147         }
1148         else if (flags & LINK_UNKNOWN_DEST_ADDR)
1149         {
1150             if (link->alias_addr.s_addr == alias_addr.s_addr
1151              && link->alias_port        == alias_port
1152              && link->link_type         == link_type
1153              && link->dst_port          == dst_port)
1154             {
1155                 if (link_unknown_dst_addr == NULL)
1156                     link_unknown_dst_addr = link;
1157             }
1158         }
1159         else if (flags & LINK_UNKNOWN_DEST_PORT)
1160         {
1161             if (link->alias_addr.s_addr == alias_addr.s_addr
1162              && link->alias_port        == alias_port
1163              && link->link_type         == link_type
1164              && link->dst_addr.s_addr   == dst_addr.s_addr)
1165             {
1166                 if (link_unknown_dst_port == NULL)
1167                     link_unknown_dst_port = link;
1168             }
1169         }
1170         link = link->next_in;
1171     }
1172
1173
1174
1175     if (link_fully_specified != NULL)
1176     {
1177         link_fully_specified->timestamp = timeStamp;
1178         return link_fully_specified;
1179     }
1180     else if (link_unknown_dst_port != NULL)
1181     {
1182         return replace_partial_links
1183           ? ReLink(link_unknown_dst_port,
1184                    link_unknown_dst_port->src_addr, dst_addr, alias_addr,
1185                    link_unknown_dst_port->src_port, dst_port, alias_port,
1186                    link_type)
1187           : link_unknown_dst_port;
1188     }
1189     else if (link_unknown_dst_addr != NULL)
1190     {
1191         return replace_partial_links
1192           ? ReLink(link_unknown_dst_addr,
1193                    link_unknown_dst_addr->src_addr, dst_addr, alias_addr,
1194                    link_unknown_dst_addr->src_port, dst_port, alias_port,
1195                    link_type)
1196           : link_unknown_dst_addr;
1197     }
1198     else if (link_unknown_all != NULL)
1199     {
1200         return replace_partial_links
1201           ? ReLink(link_unknown_all,
1202                    link_unknown_all->src_addr, dst_addr, alias_addr,
1203                    link_unknown_all->src_port, dst_port, alias_port,
1204                    link_type)
1205           : link_unknown_all;
1206     }
1207     else
1208     {
1209         return(NULL);
1210     }
1211 }
1212
1213
1214
1215
1216 /* External routines for finding/adding links
1217
1218 -- "external" means outside alias_db.c, but within alias*.c --
1219
1220     FindIcmpIn(), FindIcmpOut()
1221     FindFragmentIn1(), FindFragmentIn2()
1222     AddFragmentPtrLink(), FindFragmentPtr()
1223     FindUdpTcpIn(), FindUdpTcpOut()
1224     FindOriginalAddress(), FindAliasAddress()
1225
1226 (prototypes in alias_local.h)
1227 */
1228
1229
1230 struct alias_link *
1231 FindIcmpIn(struct in_addr dst_addr,
1232            struct in_addr alias_addr,
1233            u_short id_alias)
1234 {
1235     return FindLinkIn(dst_addr, alias_addr,
1236                       NO_DEST_PORT, id_alias,
1237                       LINK_ICMP, 0);
1238 }
1239
1240
1241 struct alias_link *
1242 FindIcmpOut(struct in_addr src_addr,
1243             struct in_addr dst_addr,
1244             u_short id)
1245 {
1246     struct alias_link * link;
1247
1248     link = FindLinkOut(src_addr, dst_addr,
1249                        id, NO_DEST_PORT,
1250                        LINK_ICMP);
1251     if (link == NULL)
1252     {
1253         struct in_addr alias_addr;
1254
1255         alias_addr = FindAliasAddress(src_addr);
1256         link = AddLink(src_addr, dst_addr, alias_addr,
1257                        id, NO_DEST_PORT, GET_ALIAS_ID,
1258                        LINK_ICMP);
1259     }
1260
1261     return(link);
1262 }
1263
1264
1265 struct alias_link *
1266 FindFragmentIn1(struct in_addr dst_addr,
1267                 struct in_addr alias_addr,
1268                 u_short ip_id)
1269 {
1270     struct alias_link *link;
1271
1272     link = FindLinkIn(dst_addr, alias_addr,
1273                       NO_DEST_PORT, ip_id,
1274                       LINK_FRAGMENT_ID, 0);
1275
1276     if (link == NULL)
1277     {
1278         link = AddLink(nullAddress, dst_addr, alias_addr,
1279                        NO_SRC_PORT, NO_DEST_PORT, ip_id,
1280                        LINK_FRAGMENT_ID);
1281     }
1282
1283     return(link);
1284 }
1285
1286
1287 struct alias_link *
1288 FindFragmentIn2(struct in_addr dst_addr,   /* Doesn't add a link if one */
1289                 struct in_addr alias_addr, /*   is not found.           */
1290                 u_short ip_id)
1291 {
1292     return FindLinkIn(dst_addr, alias_addr,
1293                       NO_DEST_PORT, ip_id,
1294                       LINK_FRAGMENT_ID, 0);
1295 }
1296
1297
1298 struct alias_link *
1299 AddFragmentPtrLink(struct in_addr dst_addr,
1300                    u_short ip_id)
1301 {
1302     return AddLink(nullAddress, dst_addr, nullAddress,
1303                    NO_SRC_PORT, NO_DEST_PORT, ip_id,
1304                    LINK_FRAGMENT_PTR);
1305 }
1306
1307
1308 struct alias_link *
1309 FindFragmentPtr(struct in_addr dst_addr,
1310                 u_short ip_id)
1311 {
1312     return FindLinkIn(dst_addr, nullAddress,
1313                       NO_DEST_PORT, ip_id,
1314                       LINK_FRAGMENT_PTR, 0);
1315 }
1316
1317
1318 struct alias_link *
1319 FindUdpTcpIn(struct in_addr dst_addr,
1320              struct in_addr alias_addr,
1321              u_short        dst_port,
1322              u_short        alias_port,
1323              u_char         proto)
1324 {
1325     int link_type;
1326     struct alias_link *link;
1327
1328     switch (proto)
1329     {
1330     case IPPROTO_UDP:
1331         link_type = LINK_UDP;
1332         break;
1333     case IPPROTO_TCP:
1334         link_type = LINK_TCP;
1335         break;
1336     default:
1337         return NULL;
1338         break;
1339     }
1340
1341     link = FindLinkIn(dst_addr, alias_addr,
1342                       dst_port, alias_port,
1343                       link_type, 1);
1344
1345     if (!(packetAliasMode & PKT_ALIAS_DENY_INCOMING)
1346      && !(packetAliasMode & PKT_ALIAS_PROXY_ONLY)
1347      && link == NULL)
1348     {
1349         struct in_addr target_addr;
1350
1351         target_addr = FindOriginalAddress(alias_addr);
1352         link = AddLink(target_addr, dst_addr, alias_addr,
1353                        alias_port, dst_port, alias_port,
1354                        link_type);
1355     }
1356
1357     return(link);
1358 }
1359
1360
1361 struct alias_link * 
1362 FindUdpTcpOut(struct in_addr  src_addr,
1363               struct in_addr  dst_addr,
1364               u_short         src_port,
1365               u_short         dst_port,
1366               u_char          proto)
1367 {
1368     int link_type;
1369     struct alias_link *link;
1370
1371     switch (proto)
1372     {
1373     case IPPROTO_UDP:
1374         link_type = LINK_UDP;
1375         break;
1376     case IPPROTO_TCP:
1377         link_type = LINK_TCP;
1378         break;
1379     default:
1380         return NULL;
1381         break;
1382     }
1383
1384     link = FindLinkOut(src_addr, dst_addr, src_port, dst_port, link_type);
1385
1386     if (link == NULL)
1387     {
1388         struct in_addr alias_addr;
1389
1390         alias_addr = FindAliasAddress(src_addr);
1391         link = AddLink(src_addr, dst_addr, alias_addr,
1392                        src_port, dst_port, GET_ALIAS_PORT,
1393                        link_type);
1394     }
1395
1396     return(link);
1397 }
1398
1399
1400 struct in_addr
1401 FindOriginalAddress(struct in_addr alias_addr)
1402 {
1403     struct alias_link *link;
1404     
1405     link = FindLinkIn(nullAddress, alias_addr,
1406                       0, 0, LINK_ADDR, 0);
1407     if (link == NULL)
1408     {
1409         newDefaultLink = 1;
1410         if (targetAddress.s_addr != 0)
1411             return targetAddress;
1412         else
1413             return alias_addr;
1414     }
1415     else
1416     {
1417         if (link->src_addr.s_addr == 0)
1418             return aliasAddress;
1419         else
1420             return link->src_addr;
1421     }
1422 }
1423
1424
1425 struct in_addr
1426 FindAliasAddress(struct in_addr original_addr)
1427 {
1428     struct alias_link *link;
1429     
1430     link = FindLinkOut(original_addr, nullAddress,
1431                        0, 0, LINK_ADDR);
1432     if (link == NULL)
1433     {
1434         return aliasAddress;
1435     }
1436     else
1437     {
1438         if (link->alias_addr.s_addr == 0)
1439             return aliasAddress;
1440         else
1441             return link->alias_addr;
1442     }
1443 }
1444
1445
1446 /* External routines for getting or changing link data
1447    (external to alias_db.c, but internal to alias*.c)
1448
1449     SetFragmentData(), GetFragmentData()
1450     SetFragmentPtr(), GetFragmentPtr()
1451     SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut()
1452     GetOriginalAddress(), GetDestAddress(), GetAliasAddress()
1453     GetOriginalPort(), GetAliasPort()
1454     SetAckModified(), GetAckModified()
1455     GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq()
1456 */
1457
1458
1459 void
1460 SetFragmentAddr(struct alias_link *link, struct in_addr src_addr)
1461 {
1462     link->data.frag_addr = src_addr;
1463 }
1464
1465
1466 void
1467 GetFragmentAddr(struct alias_link *link, struct in_addr *src_addr)
1468 {
1469     *src_addr = link->data.frag_addr;
1470 }
1471
1472
1473 void
1474 SetFragmentPtr(struct alias_link *link, char *fptr)
1475 {
1476     link->data.frag_ptr = fptr;
1477 }
1478
1479
1480 void
1481 GetFragmentPtr(struct alias_link *link, char **fptr)
1482 {
1483    *fptr = link->data.frag_ptr;
1484 }
1485
1486
1487 void
1488 SetStateIn(struct alias_link *link, int state)
1489 {
1490     /* TCP input state */
1491     switch (state) {
1492     case ALIAS_TCP_STATE_DISCONNECTED:
1493         if (link->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED) {
1494             link->expire_time = TCP_EXPIRE_DEAD;
1495         } else {
1496             link->expire_time = TCP_EXPIRE_SINGLEDEAD;
1497         }
1498         link->data.tcp->state.in = state;
1499         break;
1500     case ALIAS_TCP_STATE_CONNECTED:
1501         link->expire_time = TCP_EXPIRE_CONNECTED;
1502         /*FALLTHROUGH*/
1503     case ALIAS_TCP_STATE_NOT_CONNECTED:
1504         link->data.tcp->state.in = state;
1505         break;
1506     default:
1507         abort();
1508     }
1509 }
1510
1511
1512 void
1513 SetStateOut(struct alias_link *link, int state)
1514 {
1515     /* TCP output state */
1516     switch (state) {
1517     case ALIAS_TCP_STATE_DISCONNECTED:
1518         if (link->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED) {
1519             link->expire_time = TCP_EXPIRE_DEAD;
1520         } else {
1521             link->expire_time = TCP_EXPIRE_SINGLEDEAD;
1522         }
1523         link->data.tcp->state.out = state;
1524         break;
1525     case ALIAS_TCP_STATE_CONNECTED:
1526         link->expire_time = TCP_EXPIRE_CONNECTED;
1527         /*FALLTHROUGH*/
1528     case ALIAS_TCP_STATE_NOT_CONNECTED:
1529         link->data.tcp->state.out = state;
1530         break;
1531     default:
1532         abort();
1533     }
1534 }
1535
1536
1537 int
1538 GetStateIn(struct alias_link *link)
1539 {
1540     /* TCP input state */
1541     return link->data.tcp->state.in;
1542 }
1543
1544
1545 int
1546 GetStateOut(struct alias_link *link)
1547 {
1548     /* TCP output state */
1549     return link->data.tcp->state.out;
1550 }
1551
1552
1553 struct in_addr
1554 GetOriginalAddress(struct alias_link *link)
1555 {
1556     if (link->src_addr.s_addr == 0)
1557         return aliasAddress;
1558     else
1559         return(link->src_addr);
1560 }
1561
1562
1563 struct in_addr
1564 GetDestAddress(struct alias_link *link)
1565 {
1566     return(link->dst_addr);
1567 }
1568
1569
1570 struct in_addr
1571 GetAliasAddress(struct alias_link *link)
1572 {
1573     if (link->alias_addr.s_addr == 0)
1574         return aliasAddress;
1575     else
1576         return link->alias_addr;
1577 }
1578
1579
1580 struct in_addr
1581 GetDefaultAliasAddress()
1582 {
1583     return aliasAddress;
1584 }
1585
1586
1587 void
1588 SetDefaultAliasAddress(struct in_addr alias_addr)
1589 {
1590     aliasAddress = alias_addr;
1591 }
1592
1593
1594 u_short
1595 GetOriginalPort(struct alias_link *link)
1596 {
1597     return(link->src_port);
1598 }
1599
1600
1601 u_short
1602 GetAliasPort(struct alias_link *link)
1603 {
1604     return(link->alias_port);
1605 }
1606
1607 u_short
1608 GetDestPort(struct alias_link *link)
1609 {
1610     return(link->dst_port);
1611 }
1612
1613 void
1614 SetAckModified(struct alias_link *link)
1615 {
1616 /* Indicate that ack numbers have been modified in a TCP connection */
1617     link->data.tcp->state.ack_modified = 1;
1618 }
1619
1620
1621 struct in_addr
1622 GetProxyAddress(struct alias_link *link)
1623 {
1624     return link->proxy_addr;
1625 }
1626
1627
1628 void
1629 SetProxyAddress(struct alias_link *link, struct in_addr addr)
1630 {
1631     link->proxy_addr = addr;
1632 }
1633
1634
1635 u_short
1636 GetProxyPort(struct alias_link *link)
1637 {
1638     return link->proxy_port;
1639 }
1640
1641
1642 void
1643 SetProxyPort(struct alias_link *link, u_short port)
1644 {
1645     link->proxy_port = port;
1646 }
1647
1648
1649 int
1650 GetAckModified(struct alias_link *link)
1651 {
1652 /* See if ack numbers have been modified */
1653     return link->data.tcp->state.ack_modified;
1654 }
1655
1656
1657 int
1658 GetDeltaAckIn(struct ip *pip, struct alias_link *link)
1659 {
1660 /*
1661 Find out how much the ack number has been altered for an incoming
1662 TCP packet.  To do this, a circular list is ack numbers where the TCP
1663 packet size was altered is searched. 
1664 */
1665
1666     int i;
1667     struct tcphdr *tc;
1668     int delta, ack_diff_min;
1669     u_long ack;
1670
1671     tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
1672     ack      = tc->th_ack;
1673
1674     delta = 0;
1675     ack_diff_min = -1;
1676     for (i=0; i<N_LINK_TCP_DATA; i++)
1677     {
1678         struct ack_data_record x;
1679
1680         x = link->data.tcp->ack[i];
1681         if (x.active == 1)
1682         {
1683             int ack_diff;
1684
1685             ack_diff = SeqDiff(x.ack_new, ack);
1686             if (ack_diff >= 0)
1687             {
1688                 if (ack_diff_min >= 0)
1689                 {
1690                     if (ack_diff < ack_diff_min)
1691                     {
1692                         delta = x.delta;
1693                         ack_diff_min = ack_diff;
1694                     }
1695                 }
1696                 else
1697                 {
1698                     delta = x.delta;
1699                     ack_diff_min = ack_diff;
1700                 }
1701             }
1702         }
1703     }
1704     return (delta);
1705 }
1706
1707
1708 int
1709 GetDeltaSeqOut(struct ip *pip, struct alias_link *link)
1710 {
1711 /*
1712 Find out how much the seq number has been altered for an outgoing
1713 TCP packet.  To do this, a circular list is ack numbers where the TCP
1714 packet size was altered is searched. 
1715 */
1716
1717     int i;
1718     struct tcphdr *tc;
1719     int delta, seq_diff_min;
1720     u_long seq;
1721
1722     tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
1723     seq = tc->th_seq;
1724
1725     delta = 0;
1726     seq_diff_min = -1;
1727     for (i=0; i<N_LINK_TCP_DATA; i++)
1728     {
1729         struct ack_data_record x;
1730
1731         x = link->data.tcp->ack[i];
1732         if (x.active == 1)
1733         {
1734             int seq_diff;
1735
1736             seq_diff = SeqDiff(x.ack_old, seq);
1737             if (seq_diff >= 0)
1738             {
1739                 if (seq_diff_min >= 0)
1740                 {
1741                     if (seq_diff < seq_diff_min)
1742                     {
1743                         delta = x.delta;
1744                         seq_diff_min = seq_diff;
1745                     }
1746                 }
1747                 else
1748                 {
1749                     delta = x.delta;
1750                     seq_diff_min = seq_diff;
1751                 }
1752             }
1753         }
1754     }
1755     return (delta);
1756 }
1757
1758
1759 void
1760 AddSeq(struct ip *pip, struct alias_link *link, int delta)
1761 {
1762 /*
1763 When a TCP packet has been altered in length, save this
1764 information in a circular list.  If enough packets have
1765 been altered, then this list will begin to overwrite itself.
1766 */
1767
1768     struct tcphdr *tc;
1769     struct ack_data_record x;
1770     int hlen, tlen, dlen;
1771     int i;
1772
1773     tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
1774
1775     hlen = (pip->ip_hl + tc->th_off) << 2;
1776     tlen = ntohs(pip->ip_len);
1777     dlen = tlen - hlen;
1778
1779     x.ack_old = htonl(ntohl(tc->th_seq) + dlen);
1780     x.ack_new = htonl(ntohl(tc->th_seq) + dlen + delta);
1781     x.delta = delta;
1782     x.active = 1;
1783
1784     i = link->data.tcp->state.index;
1785     link->data.tcp->ack[i] = x;
1786
1787     i++;
1788     if (i == N_LINK_TCP_DATA)
1789         link->data.tcp->state.index = 0;
1790     else
1791         link->data.tcp->state.index = i;
1792 }
1793
1794 void
1795 SetExpire(struct alias_link *link, int expire)
1796 {
1797     if (expire == 0)
1798     {
1799         link->flags &= ~LINK_PERMANENT;
1800         DeleteLink(link);
1801     }
1802     else if (expire == -1)
1803     {
1804         link->flags |= LINK_PERMANENT;
1805     }
1806     else if (expire > 0)
1807     {
1808         link->expire_time = expire;
1809     }
1810     else
1811     {
1812 #ifdef DEBUG
1813         fprintf(stderr, "PacketAlias/SetExpire(): ");
1814         fprintf(stderr, "error in expire parameter\n");
1815 #endif
1816     }
1817 }
1818
1819 void
1820 ClearCheckNewLink(void)
1821 {
1822     newDefaultLink = 0;
1823 }
1824
1825
1826 /* Miscellaneous Functions
1827
1828     HouseKeeping()
1829     InitPacketAliasLog()
1830     UninitPacketAliasLog()
1831 */
1832
1833 /*
1834     Whenever an outgoing or incoming packet is handled, HouseKeeping()
1835     is called to find and remove timed-out aliasing links.  Logic exists
1836     to sweep through the entire table and linked list structure
1837     every 60 seconds.
1838
1839     (prototype in alias_local.h)
1840 */
1841
1842 void
1843 HouseKeeping(void)
1844 {
1845     int i, n, n100;
1846     struct timeval tv;
1847     struct timezone tz;
1848
1849     /*
1850      * Save system time (seconds) in global variable timeStamp for
1851      * use by other functions. This is done so as not to unnecessarily
1852      * waste timeline by making system calls.
1853      */
1854     gettimeofday(&tv, &tz);
1855     timeStamp = tv.tv_sec;
1856
1857     /* Compute number of spokes (output table link chains) to cover */
1858     n100  = LINK_TABLE_OUT_SIZE * 100 + houseKeepingResidual;
1859     n100 *= timeStamp - lastCleanupTime;
1860     n100 /= ALIAS_CLEANUP_INTERVAL_SECS;
1861
1862     n = n100/100;
1863
1864     /* Handle different cases */
1865     if (n > ALIAS_CLEANUP_MAX_SPOKES)
1866     {
1867         n = ALIAS_CLEANUP_MAX_SPOKES;
1868         lastCleanupTime = timeStamp;
1869         houseKeepingResidual = 0;
1870
1871         for (i=0; i<n; i++)
1872             IncrementalCleanup();
1873     }
1874     else if (n > 0)
1875     {
1876         lastCleanupTime = timeStamp;
1877         houseKeepingResidual = n100 - 100*n;
1878
1879         for (i=0; i<n; i++)
1880             IncrementalCleanup();
1881     }
1882     else if (n < 0)
1883     {
1884 #ifdef DEBUG
1885         fprintf(stderr, "PacketAlias/HouseKeeping(): ");
1886         fprintf(stderr, "something unexpected in time values\n");
1887 #endif
1888         lastCleanupTime = timeStamp;
1889         houseKeepingResidual = 0;
1890     }
1891 }
1892
1893
1894 /* Init the log file and enable logging */
1895 static void
1896 InitPacketAliasLog(void)
1897 {
1898    if ((~packetAliasMode & PKT_ALIAS_LOG)
1899     && (monitorFile = fopen("/var/log/alias.log", "w")))
1900    {
1901       packetAliasMode |= PKT_ALIAS_LOG;
1902       fprintf(monitorFile,
1903       "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n");
1904    }
1905 }
1906
1907
1908 /* Close the log-file and disable logging. */
1909 static void
1910 UninitPacketAliasLog(void)
1911 {
1912     if (monitorFile) {
1913         fclose(monitorFile);
1914         monitorFile = NULL;
1915     }
1916     packetAliasMode &= ~PKT_ALIAS_LOG;
1917 }
1918
1919
1920
1921
1922
1923
1924 /* Outside world interfaces
1925
1926 -- "outside world" means other than alias*.c routines --
1927
1928     PacketAliasRedirectPort()
1929     PacketAliasRedirectAddr()
1930     PacketAliasRedirectDelete()
1931     PacketAliasSetAddress()
1932     PacketAliasInit()
1933     PacketAliasUninit()
1934     PacketAliasSetMode()
1935
1936 (prototypes in alias.h)
1937 */
1938
1939 /* Redirection from a specific public addr:port to a
1940    a private addr:port */
1941 struct alias_link *
1942 PacketAliasRedirectPort(struct in_addr src_addr,   u_short src_port,
1943                         struct in_addr dst_addr,   u_short dst_port,
1944                         struct in_addr alias_addr, u_short alias_port,
1945                         u_char proto)
1946 {
1947     int link_type;
1948     struct alias_link *link;
1949
1950     switch(proto)
1951     {
1952     case IPPROTO_UDP:
1953         link_type = LINK_UDP;
1954         break;
1955     case IPPROTO_TCP:
1956         link_type = LINK_TCP;
1957         break;
1958     default:
1959 #ifdef DEBUG
1960         fprintf(stderr, "PacketAliasRedirectPort(): ");
1961         fprintf(stderr, "only TCP and UDP protocols allowed\n");
1962 #endif
1963         return NULL;
1964     }
1965
1966     link = AddLink(src_addr, dst_addr, alias_addr,
1967                    src_port, dst_port, alias_port,
1968                    link_type);
1969
1970     if (link != NULL)
1971     {
1972         link->flags |= LINK_PERMANENT;
1973     }
1974 #ifdef DEBUG
1975     else
1976     {
1977         fprintf(stderr, "PacketAliasRedirectPort(): " 
1978                         "call to AddLink() failed\n");
1979     }
1980 #endif
1981
1982     return link;
1983 }
1984
1985 /* Translate PPTP packets to a machine on the inside
1986  */
1987 int
1988 PacketAliasPptp(struct in_addr src_addr)
1989 {
1990
1991     pptpAliasAddr = src_addr;           /* Address of the inside PPTP machine */
1992     pptpAliasFlag = src_addr.s_addr != INADDR_NONE;
1993
1994     return 1;
1995 }
1996
1997 int GetPptpAlias (struct in_addr* alias_addr)
1998 {
1999     if (pptpAliasFlag)
2000         *alias_addr = pptpAliasAddr;
2001
2002     return pptpAliasFlag;
2003 }
2004
2005 /* Static address translation */
2006 struct alias_link *
2007 PacketAliasRedirectAddr(struct in_addr src_addr,
2008                         struct in_addr alias_addr)
2009 {
2010     struct alias_link *link;
2011
2012     link = AddLink(src_addr, nullAddress, alias_addr,
2013                    0, 0, 0,
2014                    LINK_ADDR);
2015
2016     if (link != NULL)
2017     {
2018         link->flags |= LINK_PERMANENT;
2019     }
2020 #ifdef DEBUG
2021     else
2022     {
2023         fprintf(stderr, "PacketAliasRedirectAddr(): " 
2024                         "call to AddLink() failed\n");
2025     }
2026 #endif
2027
2028     return link;
2029 }
2030
2031
2032 void
2033 PacketAliasRedirectDelete(struct alias_link *link)
2034 {
2035 /* This is a dangerous function to put in the API,
2036    because an invalid pointer can crash the program. */
2037
2038     deleteAllLinks = 1;
2039     DeleteLink(link);
2040     deleteAllLinks = 0;
2041 }
2042
2043
2044 void
2045 PacketAliasSetAddress(struct in_addr addr)
2046 {
2047     if (packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE
2048      && aliasAddress.s_addr != addr.s_addr)
2049         CleanupAliasData();
2050
2051     aliasAddress = addr;
2052 }
2053
2054
2055 void
2056 PacketAliasSetTarget(struct in_addr target_addr)
2057 {
2058     targetAddress = target_addr;
2059 }
2060
2061
2062 void
2063 PacketAliasInit(void)
2064 {
2065     int i;
2066     struct timeval tv;
2067     struct timezone tz;
2068     static int firstCall = 1;
2069
2070     if (firstCall == 1)
2071     {
2072         gettimeofday(&tv, &tz);
2073         timeStamp = tv.tv_sec;
2074         lastCleanupTime = tv.tv_sec;
2075         houseKeepingResidual = 0;
2076
2077         for (i=0; i<LINK_TABLE_OUT_SIZE; i++)
2078             linkTableOut[i] = NULL;
2079         for (i=0; i<LINK_TABLE_IN_SIZE; i++)
2080             linkTableIn[i] = NULL;
2081
2082         atexit(PacketAliasUninit);
2083         firstCall = 0;
2084     }
2085     else
2086     {
2087         deleteAllLinks = 1;
2088         CleanupAliasData();
2089         deleteAllLinks = 0;
2090     }
2091
2092     aliasAddress.s_addr = 0;
2093     targetAddress.s_addr = 0;
2094
2095     icmpLinkCount = 0;
2096     udpLinkCount = 0;
2097     tcpLinkCount = 0;
2098     fragmentIdLinkCount = 0;
2099     fragmentPtrLinkCount = 0;
2100     sockCount = 0;
2101
2102     cleanupIndex =0;
2103
2104     packetAliasMode = PKT_ALIAS_SAME_PORTS
2105                     | PKT_ALIAS_USE_SOCKETS
2106                     | PKT_ALIAS_RESET_ON_ADDR_CHANGE;
2107
2108     pptpAliasFlag = 0;
2109 }
2110
2111 void
2112 PacketAliasUninit(void) {
2113     deleteAllLinks = 1;
2114     CleanupAliasData();
2115     deleteAllLinks = 0;
2116     UninitPacketAliasLog();
2117 #ifndef NO_FW_PUNCH
2118     UninitPunchFW();
2119 #endif
2120 }
2121
2122
2123 /* Change mode for some operations */
2124 unsigned int
2125 PacketAliasSetMode(
2126     unsigned int flags, /* Which state to bring flags to */
2127     unsigned int mask   /* Mask of which flags to affect (use 0 to do a
2128                            probe for flag values) */
2129 )
2130 {
2131 /* Enable logging? */
2132     if (flags & mask & PKT_ALIAS_LOG)
2133     {
2134         InitPacketAliasLog();     /* Do the enable */
2135     } else
2136 /* _Disable_ logging? */
2137     if (~flags & mask & PKT_ALIAS_LOG) {
2138         UninitPacketAliasLog();
2139     }
2140
2141 #ifndef NO_FW_PUNCH
2142 /* Start punching holes in the firewall? */
2143     if (flags & mask & PKT_ALIAS_PUNCH_FW) {
2144         InitPunchFW();
2145     } else
2146 /* Stop punching holes in the firewall? */
2147     if (~flags & mask & PKT_ALIAS_PUNCH_FW) {
2148         UninitPunchFW();
2149     }
2150 #endif
2151
2152 /* Other flags can be set/cleared without special action */
2153     packetAliasMode = (flags & mask) | (packetAliasMode & ~mask);
2154     return packetAliasMode;
2155 }
2156
2157
2158 int
2159 PacketAliasCheckNewLink(void)
2160 {
2161     return newDefaultLink;
2162 }
2163
2164
2165 #ifndef NO_FW_PUNCH
2166
2167 /*****************
2168   Code to support firewall punching.  This shouldn't really be in this
2169   file, but making variables global is evil too.
2170   ****************/
2171
2172 /* Firewall include files */
2173 #include <sys/queue.h>
2174 #include <net/if.h>
2175 #include <netinet/ip_fw.h>
2176 #include <string.h>
2177 #include <err.h>
2178
2179 static void ClearAllFWHoles(void);
2180
2181 static int fireWallBaseNum;     /* The first firewall entry free for our use */
2182 static int fireWallNumNums;     /* How many entries can we use? */
2183 static int fireWallActiveNum;   /* Which entry did we last use? */
2184 static char *fireWallField;     /* bool array for entries */
2185
2186 #define fw_setfield(field, num)                         \
2187 do {                                                    \
2188     (field)[num] = 1;                                   \
2189 } /*lint -save -e717 */ while(0) /*lint -restore */
2190 #define fw_clrfield(field, num)                         \
2191 do {                                                    \
2192     (field)[num] = 0;                                   \
2193 } /*lint -save -e717 */ while(0) /*lint -restore */
2194 #define fw_tstfield(field, num) ((field)[num])
2195
2196 void
2197 PacketAliasSetFWBase(unsigned int base, unsigned int num) {
2198     fireWallBaseNum = base;
2199     fireWallNumNums = num;
2200 }
2201
2202 static void
2203 InitPunchFW(void) {
2204     fireWallField = malloc(fireWallNumNums);
2205     if (fireWallField) {
2206         memset(fireWallField, 0, fireWallNumNums);
2207         if (fireWallFD < 0) {
2208             fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
2209         }
2210         ClearAllFWHoles();
2211         fireWallActiveNum = fireWallBaseNum;
2212     }
2213 }
2214
2215 static void
2216 UninitPunchFW(void) {
2217     ClearAllFWHoles();
2218     if (fireWallFD >= 0)
2219         close(fireWallFD);
2220     fireWallFD = -1;
2221     if (fireWallField)
2222         free(fireWallField);
2223     fireWallField = NULL;
2224     packetAliasMode &= ~PKT_ALIAS_PUNCH_FW;
2225 }
2226
2227 /* Make a certain link go through the firewall */
2228 void
2229 PunchFWHole(struct alias_link *link) {
2230     int r;                      /* Result code */
2231     struct ip_fw rule;          /* On-the-fly built rule */
2232     int fwhole;                 /* Where to punch hole */
2233
2234 /* Don't do anything unless we are asked to */
2235     if ( !(packetAliasMode & PKT_ALIAS_PUNCH_FW) ||
2236          fireWallFD < 0 ||
2237          link->link_type != LINK_TCP ||
2238          !link->data.tcp)
2239         return;
2240
2241     memset(&rule, 0, sizeof rule);
2242
2243 /** Build rule **/
2244
2245     /* Find empty slot */
2246     for (fwhole = fireWallActiveNum;
2247          fwhole < fireWallBaseNum + fireWallNumNums &&
2248              fw_tstfield(fireWallField, fwhole);
2249          fwhole++)
2250         ;
2251     if (fwhole >= fireWallBaseNum + fireWallNumNums ||
2252         fw_tstfield(fireWallField, fwhole)) {
2253         for (fwhole = fireWallBaseNum;
2254              fwhole < fireWallActiveNum &&
2255                  fw_tstfield(fireWallField, fwhole);
2256              fwhole++)
2257             ;
2258         if (fwhole == fireWallActiveNum) {
2259             /* No rule point empty - we can't punch more holes. */
2260             fireWallActiveNum = fireWallBaseNum;
2261 #ifdef DEBUG
2262             fprintf(stderr, "libalias: Unable to create firewall hole!\n");
2263 #endif
2264             return;
2265         }
2266     }
2267     /* Start next search at next position */
2268     fireWallActiveNum = fwhole+1;
2269
2270     /* Build generic part of the two rules */
2271     rule.fw_number = fwhole;
2272     rule.fw_nports = 1;         /* Number of source ports; dest ports follow */
2273     rule.fw_flg = IP_FW_F_ACCEPT;
2274     rule.fw_prot = IPPROTO_TCP;
2275     rule.fw_smsk.s_addr = INADDR_BROADCAST;
2276     rule.fw_dmsk.s_addr = INADDR_BROADCAST;
2277
2278     /* Build and apply specific part of the rules */
2279     rule.fw_src = GetOriginalAddress(link);
2280     rule.fw_dst = GetDestAddress(link);
2281     rule.fw_uar.fw_pts[0] = ntohs(GetOriginalPort(link));
2282     rule.fw_uar.fw_pts[1] = ntohs(GetDestPort(link));
2283
2284     /* Skip non-bound links - XXX should not be strictly necessary,
2285        but seems to leave hole if not done.  Leak of non-bound links?
2286        (Code should be left even if the problem is fixed - it is a
2287        clear optimization) */
2288     if (rule.fw_uar.fw_pts[0] != 0 && rule.fw_uar.fw_pts[1] != 0) {
2289         r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule);
2290 #ifdef DEBUG
2291         if (r)
2292             err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)");
2293 #endif
2294         rule.fw_src = GetDestAddress(link);
2295         rule.fw_dst = GetOriginalAddress(link);
2296         rule.fw_uar.fw_pts[0] = ntohs(GetDestPort(link));
2297         rule.fw_uar.fw_pts[1] = ntohs(GetOriginalPort(link));
2298         r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, &rule, sizeof rule);
2299 #ifdef DEBUG
2300         if (r)
2301             err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)");
2302 #endif
2303     }
2304 /* Indicate hole applied */
2305     link->data.tcp->fwhole = fwhole;
2306     fw_setfield(fireWallField, fwhole);
2307 }
2308
2309 /* Remove a hole in a firewall associated with a particular alias
2310    link.  Calling this too often is harmless. */
2311 static void
2312 ClearFWHole(struct alias_link *link) {
2313     if (link->link_type == LINK_TCP && link->data.tcp) {
2314         int fwhole =  link->data.tcp->fwhole; /* Where is the firewall hole? */
2315         struct ip_fw rule;
2316
2317         if (fwhole < 0)
2318             return;
2319
2320         memset(&rule, 0, sizeof rule);
2321         rule.fw_number = fwhole;
2322         while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule))
2323             ;
2324         fw_clrfield(fireWallField, fwhole);
2325         link->data.tcp->fwhole = -1;
2326     }
2327 }
2328
2329 /* Clear out the entire range dedicated to firewall holes. */
2330 static void
2331 ClearAllFWHoles(void) {
2332     struct ip_fw rule;          /* On-the-fly built rule */
2333     int i;
2334     
2335     if (fireWallFD < 0)
2336         return;
2337
2338     memset(&rule, 0, sizeof rule);
2339     for (i = fireWallBaseNum; i < fireWallBaseNum + fireWallNumNums; i++) {
2340         rule.fw_number = i;
2341         while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &rule, sizeof rule))
2342             ;
2343     }
2344     memset(fireWallField, 0, fireWallNumNums);
2345 }
2346 #endif