Sweep-fix comparing pointers with 0 (and assigning 0 to pointers).
[games.git] / lib / libalias / alias_db.c
1 /*  -*- mode: c; tab-width: 8; c-basic-indent: 4; -*- */
2
3 /*-
4  * Copyright (c) 2001 Charles Mott <cm@linktel.net>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  * $FreeBSD: src/lib/libalias/alias_db.c,v 1.21.2.14 2002/07/24 03:21:24 luigi Exp $
29  */
30
31 /*
32     Alias_db.c encapsulates all data structures used for storing
33     packet aliasing data.  Other parts of the aliasing software
34     access data through functions provided in this file.
35
36     Data storage is based on the notion of a "link", which is
37     established for ICMP echo/reply packets, UDP datagrams and
38     TCP stream connections.  A link stores the original source
39     and destination addresses.  For UDP and TCP, it also stores
40     source and destination port numbers, as well as an alias
41     port number.  Links are also used to store information about
42     fragments.
43
44     There is a facility for sweeping through and deleting old
45     links as new packets are sent through.  A simple timeout is
46     used for ICMP and UDP links.  TCP links are left alone unless
47     there is an incomplete connection, in which case the link
48     can be deleted after a certain amount of time.
49
50
51     Initial version: August, 1996  (cjm)
52
53     Version 1.4: September 16, 1996 (cjm)
54         Facility for handling incoming links added.
55
56     Version 1.6: September 18, 1996 (cjm)
57         ICMP data handling simplified.
58
59     Version 1.7: January 9, 1997 (cjm)
60         Fragment handling simplified.
61         Saves pointers for unresolved fragments.
62         Permits links for unspecified remote ports
63           or unspecified remote addresses.
64         Fixed bug which did not properly zero port
65           table entries after a link was deleted.
66         Cleaned up some obsolete comments.
67
68     Version 1.8: January 14, 1997 (cjm)
69         Fixed data type error in StartPoint().
70         (This error did not exist prior to v1.7
71         and was discovered and fixed by Ari Suutari)
72
73     Version 1.9: February 1, 1997
74         Optionally, connections initiated from packet aliasing host
75         machine will will not have their port number aliased unless it
76         conflicts with an aliasing port already being used. (cjm)
77
78         All options earlier being #ifdef'ed are now available through
79         a new interface, SetPacketAliasMode().  This allows run time
80         control (which is now available in PPP+pktAlias through the
81         'alias' keyword). (ee)
82
83         Added ability to create an alias port without
84         either destination address or port specified.
85         port type = ALIAS_PORT_UNKNOWN_DEST_ALL (ee)
86
87         Removed K&R style function headers
88         and general cleanup. (ee)
89
90         Added packetAliasMode to replace compiler #defines's (ee)
91
92         Allocates sockets for partially specified
93         ports if ALIAS_USE_SOCKETS defined. (cjm)
94
95     Version 2.0: March, 1997
96         SetAliasAddress() will now clean up alias links
97         if the aliasing address is changed. (cjm)
98
99         PacketAliasPermanentLink() function added to support permanent
100         links.  (J. Fortes suggested the need for this.)
101         Examples:
102
103         (192.168.0.1, port 23)  <-> alias port 6002, unknown dest addr/port
104
105         (192.168.0.2, port 21)  <-> alias port 3604, known dest addr
106                                                      unknown dest port
107
108         These permanent links allow for incoming connections to
109         machines on the local network.  They can be given with a
110         user-chosen amount of specificity, with increasing specificity
111         meaning more security. (cjm)
112
113         Quite a bit of rework to the basic engine.  The portTable[]
114         array, which kept track of which ports were in use was replaced
115         by a table/linked list structure. (cjm)
116
117         SetExpire() function added. (cjm)
118
119         DeleteLink() no longer frees memory association with a pointer
120         to a fragment (this bug was first recognized by E. Eklund in
121         v1.9).
122
123     Version 2.1: May, 1997 (cjm)
124         Packet aliasing engine reworked so that it can handle
125         multiple external addresses rather than just a single
126         host address.
127
128         PacketAliasRedirectPort() and PacketAliasRedirectAddr()
129         added to the API.  The first function is a more generalized
130         version of PacketAliasPermanentLink().  The second function
131         implements static network address translation.
132
133     Version 3.2: July, 2000 (salander and satoh)
134         Added FindNewPortGroup to get contiguous range of port values.
135
136         Added QueryUdpTcpIn and QueryUdpTcpOut to look for an aliasing
137         link but not actually add one.
138
139         Added FindRtspOut, which is closely derived from FindUdpTcpOut,
140         except that the alias port (from FindNewPortGroup) is provided
141         as input.
142
143     See HISTORY file for additional revisions.
144 */
145
146
147 /* System include files */
148 #include <sys/param.h>
149 #include <sys/queue.h>
150 #include <sys/socket.h>
151 #include <sys/time.h>
152
153 #include <errno.h>
154 #include <stdlib.h>
155 #include <stdio.h>
156 #include <unistd.h>
157
158 /* BSD network include files */
159 #include <netinet/in_systm.h>
160 #include <netinet/in.h>
161 #include <netinet/ip.h>
162 #include <netinet/tcp.h>
163 #include <arpa/inet.h>
164
165 #include "alias.h"
166 #include "alias_local.h"
167
168
169
170 /*
171    Constants (note: constants are also defined
172               near relevant functions or structs)
173 */
174
175 /* Sizes of input and output link tables */
176 #define LINK_TABLE_OUT_SIZE         101
177 #define LINK_TABLE_IN_SIZE         4001
178
179 /* Parameters used for cleanup of expired links */
180 #define ALIAS_CLEANUP_INTERVAL_SECS  60
181 #define ALIAS_CLEANUP_MAX_SPOKES     30
182
183 /* Timeouts (in seconds) for different link types */
184 #define ICMP_EXPIRE_TIME             60
185 #define UDP_EXPIRE_TIME              60
186 #define PROTO_EXPIRE_TIME            60
187 #define FRAGMENT_ID_EXPIRE_TIME      10
188 #define FRAGMENT_PTR_EXPIRE_TIME     30
189
190 /* TCP link expire time for different cases */
191 /* When the link has been used and closed - minimal grace time to
192    allow ACKs and potential re-connect in FTP (XXX - is this allowed?)  */
193 #ifndef TCP_EXPIRE_DEAD
194 #   define TCP_EXPIRE_DEAD           10
195 #endif
196
197 /* When the link has been used and closed on one side - the other side
198    is allowed to still send data */
199 #ifndef TCP_EXPIRE_SINGLEDEAD
200 #   define TCP_EXPIRE_SINGLEDEAD     90
201 #endif
202
203 /* When the link isn't yet up */
204 #ifndef TCP_EXPIRE_INITIAL
205 #   define TCP_EXPIRE_INITIAL       300
206 #endif
207
208 /* When the link is up */
209 #ifndef TCP_EXPIRE_CONNECTED
210 #   define TCP_EXPIRE_CONNECTED   86400
211 #endif
212
213
214 /* Dummy port number codes used for FindLinkIn/Out() and AddLink().
215    These constants can be anything except zero, which indicates an
216    unknown port number. */
217
218 #define NO_DEST_PORT     1
219 #define NO_SRC_PORT      1
220
221
222
223 /* Data Structures
224
225     The fundamental data structure used in this program is
226     "struct alias_link".  Whenever a TCP connection is made,
227     a UDP datagram is sent out, or an ICMP echo request is made,
228     a link record is made (if it has not already been created).
229     The link record is identified by the source address/port
230     and the destination address/port. In the case of an ICMP
231     echo request, the source port is treated as being equivalent
232     with the 16-bit ID number of the ICMP packet.
233
234     The link record also can store some auxiliary data.  For
235     TCP connections that have had sequence and acknowledgment
236     modifications, data space is available to track these changes.
237     A state field is used to keep track in changes to the TCP
238     connection state.  ID numbers of fragments can also be
239     stored in the auxiliary space.  Pointers to unresolved
240     fragments can also be stored.
241
242     The link records support two independent chainings.  Lookup
243     tables for input and out tables hold the initial pointers
244     the link chains.  On input, the lookup table indexes on alias
245     port and link type.  On output, the lookup table indexes on
246     source address, destination address, source port, destination
247     port and link type.
248 */
249
250 struct ack_data_record     /* used to save changes to ACK/sequence numbers */
251 {
252     u_long ack_old;
253     u_long ack_new;
254     int delta;
255     int active;
256 };
257
258 struct tcp_state           /* Information about TCP connection        */
259 {
260     int in;                /* State for outside -> inside             */
261     int out;               /* State for inside  -> outside            */
262     int index;             /* Index to ACK data array                 */
263     int ack_modified;      /* Indicates whether ACK and sequence numbers */
264                            /* been modified                           */
265 };
266
267 #define N_LINK_TCP_DATA   3 /* Number of distinct ACK number changes
268                                saved for a modified TCP stream */
269 struct tcp_dat
270 {
271     struct tcp_state state;
272     struct ack_data_record ack[N_LINK_TCP_DATA];
273     int fwhole;             /* Which firewall record is used for this hole? */
274 };
275
276 struct server              /* LSNAT server pool (circular list) */
277 {
278     struct in_addr addr;
279     u_short port;
280     struct server *next;
281 };
282
283 struct alias_link                /* Main data structure */
284 {
285     struct in_addr src_addr;     /* Address and port information        */
286     struct in_addr dst_addr;
287     struct in_addr alias_addr;
288     struct in_addr proxy_addr;
289     u_short src_port;
290     u_short dst_port;
291     u_short alias_port;
292     u_short proxy_port;
293     struct server *server;
294
295     int link_type;               /* Type of link: TCP, UDP, ICMP, proto, frag */
296
297 /* values for link_type */
298 #define LINK_ICMP                     IPPROTO_ICMP
299 #define LINK_UDP                      IPPROTO_UDP
300 #define LINK_TCP                      IPPROTO_TCP
301 #define LINK_FRAGMENT_ID              (IPPROTO_MAX + 1)
302 #define LINK_FRAGMENT_PTR             (IPPROTO_MAX + 2)
303 #define LINK_ADDR                     (IPPROTO_MAX + 3)
304 #define LINK_PPTP                     (IPPROTO_MAX + 4)
305
306     int flags;                   /* indicates special characteristics   */
307
308 /* flag bits */
309 #define LINK_UNKNOWN_DEST_PORT     0x01
310 #define LINK_UNKNOWN_DEST_ADDR     0x02
311 #define LINK_PERMANENT             0x04
312 #define LINK_PARTIALLY_SPECIFIED   0x03 /* logical-or of first two bits */
313 #define LINK_UNFIREWALLED          0x08
314 #define LINK_LAST_LINE_CRLF_TERMED 0x10
315
316     int timestamp;               /* Time link was last accessed         */
317     int expire_time;             /* Expire time for link                */
318
319     int sockfd;                  /* socket descriptor                   */
320
321     LIST_ENTRY(alias_link) list_out; /* Linked list of pointers for     */
322     LIST_ENTRY(alias_link) list_in;  /* input and output lookup tables  */
323
324     union                        /* Auxiliary data                      */
325     {
326         char *frag_ptr;
327         struct in_addr frag_addr;
328         struct tcp_dat *tcp;
329     } data;
330 };
331
332
333
334
335
336 /* Global Variables
337
338     The global variables listed here are only accessed from
339     within alias_db.c and so are prefixed with the static
340     designation.
341 */
342
343 int packetAliasMode;                 /* Mode flags                      */
344                                      /*        - documented in alias.h  */
345
346 static struct in_addr aliasAddress;  /* Address written onto source     */
347                                      /*   field of IP packet.           */
348
349 static struct in_addr targetAddress; /* IP address incoming packets     */
350                                      /*   are sent to if no aliasing    */
351                                      /*   link already exists           */
352
353 static struct in_addr nullAddress;   /* Used as a dummy parameter for   */
354                                      /*   some function calls           */
355 static LIST_HEAD(, alias_link)
356 linkTableOut[LINK_TABLE_OUT_SIZE];   /* Lookup table of pointers to     */
357                                      /*   chains of link records. Each  */
358 static LIST_HEAD(, alias_link)       /*   link record is doubly indexed */
359 linkTableIn[LINK_TABLE_IN_SIZE];     /*   into input and output lookup  */
360                                      /*   tables.                       */
361
362 static int icmpLinkCount;            /* Link statistics                 */
363 static int udpLinkCount;
364 static int tcpLinkCount;
365 static int pptpLinkCount;
366 static int protoLinkCount;
367 static int fragmentIdLinkCount;
368 static int fragmentPtrLinkCount;
369 static int sockCount;
370
371 static int cleanupIndex;             /* Index to chain of link table    */
372                                      /* being inspected for old links   */
373
374 static int timeStamp;                /* System time in seconds for      */
375                                      /* current packet                  */
376
377 static int lastCleanupTime;          /* Last time IncrementalCleanup()  */
378                                      /* was called                      */
379
380 static int houseKeepingResidual;     /* used by HouseKeeping()          */
381
382 static int deleteAllLinks;           /* If equal to zero, DeleteLink()  */
383                                      /* will not remove permanent links */
384
385 static FILE *monitorFile;            /* File descriptor for link        */
386                                      /* statistics monitoring file      */
387
388 static int newDefaultLink;           /* Indicates if a new aliasing     */
389                                      /* link has been created after a   */
390                                      /* call to PacketAliasIn/Out().    */
391
392 #ifndef NO_FW_PUNCH
393 static int fireWallFD = -1;          /* File descriptor to be able to   */
394                                      /* control firewall.  Opened by    */
395                                      /* PacketAliasSetMode on first     */
396                                      /* setting the PKT_ALIAS_PUNCH_FW  */
397                                      /* flag.                           */
398 #endif
399
400
401
402
403
404
405
406 /* Internal utility routines (used only in alias_db.c)
407
408 Lookup table starting points:
409     StartPointIn()           -- link table initial search point for
410                                 incoming packets
411     StartPointOut()          -- link table initial search point for
412                                 outgoing packets
413
414 Miscellaneous:
415     SeqDiff()                -- difference between two TCP sequences
416     ShowAliasStats()         -- send alias statistics to a monitor file
417 */
418
419
420 /* Local prototypes */
421 static u_int StartPointIn(struct in_addr, u_short, int);
422
423 static u_int StartPointOut(struct in_addr, struct in_addr,
424                            u_short, u_short, int);
425
426 static int SeqDiff(u_long, u_long);
427
428 static void ShowAliasStats(void);
429
430 #ifndef NO_FW_PUNCH
431 /* Firewall control */
432 static void InitPunchFW(void);
433 static void UninitPunchFW(void);
434 static void ClearFWHole(struct alias_link *link);
435 #endif
436
437 /* Log file control */
438 static void InitPacketAliasLog(void);
439 static void UninitPacketAliasLog(void);
440
441 static u_int
442 StartPointIn(struct in_addr alias_addr,
443              u_short alias_port,
444              int link_type)
445 {
446     u_int n;
447
448     n  = alias_addr.s_addr;
449     if (link_type != LINK_PPTP)
450         n += alias_port;
451     n += link_type;
452     return(n % LINK_TABLE_IN_SIZE);
453 }
454
455
456 static u_int
457 StartPointOut(struct in_addr src_addr, struct in_addr dst_addr,
458               u_short src_port, u_short dst_port, int link_type)
459 {
460     u_int n;
461
462     n  = src_addr.s_addr;
463     n += dst_addr.s_addr;
464     if (link_type != LINK_PPTP) {
465         n += src_port;
466         n += dst_port;
467     }
468     n += link_type;
469
470     return(n % LINK_TABLE_OUT_SIZE);
471 }
472
473
474 static int
475 SeqDiff(u_long x, u_long y)
476 {
477 /* Return the difference between two TCP sequence numbers */
478
479 /*
480     This function is encapsulated in case there are any unusual
481     arithmetic conditions that need to be considered.
482 */
483
484     return (ntohl(y) - ntohl(x));
485 }
486
487
488 static void
489 ShowAliasStats(void)
490 {
491 /* Used for debugging */
492
493    if (monitorFile)
494    {
495       fprintf(monitorFile, "icmp=%d, udp=%d, tcp=%d, pptp=%d, proto=%d, frag_id=%d frag_ptr=%d",
496               icmpLinkCount,
497               udpLinkCount,
498               tcpLinkCount,
499               pptpLinkCount,
500               protoLinkCount,
501               fragmentIdLinkCount,
502               fragmentPtrLinkCount);
503
504       fprintf(monitorFile, " / tot=%d  (sock=%d)\n",
505               icmpLinkCount + udpLinkCount
506                             + tcpLinkCount
507                             + pptpLinkCount
508                             + protoLinkCount
509                             + fragmentIdLinkCount
510                             + fragmentPtrLinkCount,
511               sockCount);
512
513       fflush(monitorFile);
514    }
515 }
516
517
518
519
520
521 /* Internal routines for finding, deleting and adding links
522
523 Port Allocation:
524     GetNewPort()             -- find and reserve new alias port number
525     GetSocket()              -- try to allocate a socket for a given port
526
527 Link creation and deletion:
528     CleanupAliasData()      - remove all link chains from lookup table
529     IncrementalCleanup()    - look for stale links in a single chain
530     DeleteLink()            - remove link
531     AddLink()               - add link
532     ReLink()                - change link
533
534 Link search:
535     FindLinkOut()           - find link for outgoing packets
536     FindLinkIn()            - find link for incoming packets
537
538 Port search:
539     FindNewPortGroup()      - find an available group of ports
540 */
541
542 /* Local prototypes */
543 static int GetNewPort(struct alias_link *, int);
544
545 static u_short GetSocket(u_short, int *, int);
546
547 static void CleanupAliasData(void);
548
549 static void IncrementalCleanup(void);
550
551 static void DeleteLink(struct alias_link *);
552
553 static struct alias_link *
554 AddLink(struct in_addr, struct in_addr, struct in_addr,
555         u_short, u_short, int, int);
556
557 static struct alias_link *
558 ReLink(struct alias_link *,
559        struct in_addr, struct in_addr, struct in_addr,
560         u_short, u_short, int, int);
561
562 static struct alias_link *
563 FindLinkOut(struct in_addr, struct in_addr, u_short, u_short, int, int);
564
565 static struct alias_link *
566 FindLinkIn(struct in_addr, struct in_addr, u_short, u_short, int, int);
567
568
569 #define ALIAS_PORT_BASE            0x08000
570 #define ALIAS_PORT_MASK            0x07fff
571 #define ALIAS_PORT_MASK_EVEN       0x07ffe
572 #define GET_NEW_PORT_MAX_ATTEMPTS       20
573
574 #define GET_ALIAS_PORT                  -1
575 #define GET_ALIAS_ID        GET_ALIAS_PORT
576
577 #define FIND_EVEN_ALIAS_BASE             1
578
579 /* GetNewPort() allocates port numbers.  Note that if a port number
580    is already in use, that does not mean that it cannot be used by
581    another link concurrently.  This is because GetNewPort() looks for
582    unused triplets: (dest addr, dest port, alias port). */
583
584 static int
585 GetNewPort(struct alias_link *link, int alias_port_param)
586 {
587     int i;
588     int max_trials;
589     u_short port_sys;
590     u_short port_net;
591
592 /*
593    Description of alias_port_param for GetNewPort().  When
594    this parameter is zero or positive, it precisely specifies
595    the port number.  GetNewPort() will return this number
596    without check that it is in use.
597
598    When this parameter is GET_ALIAS_PORT, it indicates to get a randomly
599    selected port number.
600 */
601
602     if (alias_port_param == GET_ALIAS_PORT)
603     {
604         /*
605          * The aliasing port is automatically selected
606          * by one of two methods below:
607          */
608         max_trials = GET_NEW_PORT_MAX_ATTEMPTS;
609
610         if (packetAliasMode & PKT_ALIAS_SAME_PORTS)
611         {
612             /*
613              * When the PKT_ALIAS_SAME_PORTS option is
614              * chosen, the first try will be the
615              * actual source port. If this is already
616              * in use, the remainder of the trials
617              * will be random.
618              */
619             port_net = link->src_port;
620             port_sys = ntohs(port_net);
621         }
622         else
623         {
624             /* First trial and all subsequent are random. */
625             port_sys = random() & ALIAS_PORT_MASK;
626             port_sys += ALIAS_PORT_BASE;
627             port_net = htons(port_sys);
628         }
629     }
630     else if (alias_port_param >= 0 && alias_port_param < 0x10000)
631     {
632         link->alias_port = (u_short) alias_port_param;
633         return(0);
634     }
635     else
636     {
637 #ifdef DEBUG
638         fprintf(stderr, "PacketAlias/GetNewPort(): ");
639         fprintf(stderr, "input parameter error\n");
640 #endif
641         return(-1);
642     }
643
644
645 /* Port number search */
646     for (i=0; i<max_trials; i++)
647     {
648         int go_ahead;
649         struct alias_link *search_result;
650
651         search_result = FindLinkIn(link->dst_addr, link->alias_addr,
652                                    link->dst_port, port_net,
653                                    link->link_type, 0);
654
655         if (search_result == NULL)
656             go_ahead = 1;
657         else if (!(link->flags          & LINK_PARTIALLY_SPECIFIED)
658                && (search_result->flags & LINK_PARTIALLY_SPECIFIED))
659             go_ahead = 1;
660         else
661             go_ahead = 0;
662
663         if (go_ahead)
664         {
665             if ((packetAliasMode & PKT_ALIAS_USE_SOCKETS)
666              && (link->flags & LINK_PARTIALLY_SPECIFIED)
667              && ((link->link_type == LINK_TCP) ||
668                  (link->link_type == LINK_UDP)))
669             {
670                 if (GetSocket(port_net, &link->sockfd, link->link_type))
671                 {
672                     link->alias_port = port_net;
673                     return(0);
674                 }
675             }
676             else
677             {
678                 link->alias_port = port_net;
679                 return(0);
680             }
681         }
682
683         port_sys = random() & ALIAS_PORT_MASK;
684         port_sys += ALIAS_PORT_BASE;
685         port_net = htons(port_sys);
686     }
687
688 #ifdef DEBUG
689     fprintf(stderr, "PacketAlias/GetnewPort(): ");
690     fprintf(stderr, "could not find free port\n");
691 #endif
692
693     return(-1);
694 }
695
696
697 static u_short
698 GetSocket(u_short port_net, int *sockfd, int link_type)
699 {
700     int err;
701     int sock;
702     struct sockaddr_in sock_addr;
703
704     if (link_type == LINK_TCP)
705         sock = socket(AF_INET, SOCK_STREAM, 0);
706     else if (link_type == LINK_UDP)
707         sock = socket(AF_INET, SOCK_DGRAM, 0);
708     else
709     {
710 #ifdef DEBUG
711         fprintf(stderr, "PacketAlias/GetSocket(): ");
712         fprintf(stderr, "incorrect link type\n");
713 #endif
714         return(0);
715     }
716
717     if (sock < 0)
718     {
719 #ifdef DEBUG
720         fprintf(stderr, "PacketAlias/GetSocket(): ");
721         fprintf(stderr, "socket() error %d\n", *sockfd);
722 #endif
723         return(0);
724     }
725
726     sock_addr.sin_family = AF_INET;
727     sock_addr.sin_addr.s_addr = htonl(INADDR_ANY);
728     sock_addr.sin_port = port_net;
729
730     err = bind(sock,
731                (struct sockaddr *) &sock_addr,
732                sizeof(sock_addr));
733     if (err == 0)
734     {
735         sockCount++;
736         *sockfd = sock;
737         return(1);
738     }
739     else
740     {
741         close(sock);
742         return(0);
743     }
744 }
745
746
747 /* FindNewPortGroup() returns a base port number for an available
748    range of contiguous port numbers. Note that if a port number
749    is already in use, that does not mean that it cannot be used by
750    another link concurrently.  This is because FindNewPortGroup()
751    looks for unused triplets: (dest addr, dest port, alias port). */
752
753 int
754 FindNewPortGroup(struct in_addr  dst_addr,
755                  struct in_addr  alias_addr,
756                  u_short         src_port,
757                  u_short         dst_port,
758                  u_short         port_count,
759                  u_char          proto,
760                  u_char          align)
761 {
762     int     i, j;
763     int     max_trials;
764     u_short port_sys;
765     int     link_type;
766
767     /*
768      * Get link_type from protocol
769      */
770
771     switch (proto)
772     {
773     case IPPROTO_UDP:
774         link_type = LINK_UDP;
775         break;
776     case IPPROTO_TCP:
777         link_type = LINK_TCP;
778         break;
779     default:
780         return (0);
781         break;
782     }
783
784     /*
785      * The aliasing port is automatically selected
786      * by one of two methods below:
787      */
788     max_trials = GET_NEW_PORT_MAX_ATTEMPTS;
789
790     if (packetAliasMode & PKT_ALIAS_SAME_PORTS) {
791       /*
792        * When the ALIAS_SAME_PORTS option is
793        * chosen, the first try will be the
794        * actual source port. If this is already
795        * in use, the remainder of the trials
796        * will be random.
797        */
798       port_sys = ntohs(src_port);
799
800     } else {
801
802       /* First trial and all subsequent are random. */
803       if (align == FIND_EVEN_ALIAS_BASE)
804         port_sys = random() & ALIAS_PORT_MASK_EVEN;
805       else
806         port_sys = random() & ALIAS_PORT_MASK;
807
808       port_sys += ALIAS_PORT_BASE;
809     }
810
811 /* Port number search */
812     for (i = 0; i < max_trials; i++) {
813
814       struct alias_link *search_result;
815
816       for (j = 0; j < port_count; j++)
817         if (NULL != (search_result = FindLinkIn(dst_addr, alias_addr,
818                                         dst_port, htons(port_sys + j),
819                                         link_type, 0)))
820           break;
821
822       /* Found a good range, return base */
823       if (j == port_count)
824         return (htons(port_sys));
825
826       /* Find a new base to try */
827       if (align == FIND_EVEN_ALIAS_BASE)
828         port_sys = random() & ALIAS_PORT_MASK_EVEN;
829       else
830         port_sys = random() & ALIAS_PORT_MASK;
831
832       port_sys += ALIAS_PORT_BASE;
833     }
834
835 #ifdef DEBUG
836     fprintf(stderr, "PacketAlias/FindNewPortGroup(): ");
837     fprintf(stderr, "could not find free port(s)\n");
838 #endif
839
840     return(0);
841 }
842
843 static void
844 CleanupAliasData(void)
845 {
846     struct alias_link *link;
847     int i, icount;
848
849     icount = 0;
850     for (i=0; i<LINK_TABLE_OUT_SIZE; i++)
851     {
852         link = LIST_FIRST(&linkTableOut[i]);
853         while (link != NULL)
854         {
855             struct alias_link *link_next;
856             link_next = LIST_NEXT(link, list_out);
857             icount++;
858             DeleteLink(link);
859             link = link_next;
860         }
861     }
862
863     cleanupIndex =0;
864 }
865
866
867 static void
868 IncrementalCleanup(void)
869 {
870     int icount;
871     struct alias_link *link;
872
873     icount = 0;
874     link = LIST_FIRST(&linkTableOut[cleanupIndex++]);
875     while (link != NULL)
876     {
877         int idelta;
878         struct alias_link *link_next;
879
880         link_next = LIST_NEXT(link, list_out);
881         idelta = timeStamp - link->timestamp;
882         switch (link->link_type)
883         {
884             case LINK_TCP:
885                 if (idelta > link->expire_time)
886                 {
887                     struct tcp_dat *tcp_aux;
888
889                     tcp_aux = link->data.tcp;
890                     if (tcp_aux->state.in  != ALIAS_TCP_STATE_CONNECTED
891                      || tcp_aux->state.out != ALIAS_TCP_STATE_CONNECTED)
892                     {
893                         DeleteLink(link);
894                         icount++;
895                     }
896                 }
897                 break;
898             default:
899                 if (idelta > link->expire_time)
900                 {
901                     DeleteLink(link);
902                     icount++;
903                 }
904                 break;
905         }
906         link = link_next;
907     }
908
909     if (cleanupIndex == LINK_TABLE_OUT_SIZE)
910         cleanupIndex = 0;
911 }
912
913 static void
914 DeleteLink(struct alias_link *link)
915 {
916
917 /* Don't do anything if the link is marked permanent */
918     if (deleteAllLinks == 0 && link->flags & LINK_PERMANENT)
919         return;
920
921 #ifndef NO_FW_PUNCH
922 /* Delete associated firewall hole, if any */
923     ClearFWHole(link);
924 #endif
925
926 /* Free memory allocated for LSNAT server pool */
927     if (link->server != NULL) {
928         struct server *head, *curr, *next;
929
930         head = curr = link->server;
931         do {
932             next = curr->next;
933             free(curr);
934         } while ((curr = next) != head);
935     }
936
937 /* Adjust output table pointers */
938     LIST_REMOVE(link, list_out);
939
940 /* Adjust input table pointers */
941     LIST_REMOVE(link, list_in);
942
943 /* Close socket, if one has been allocated */
944     if (link->sockfd != -1)
945     {
946         sockCount--;
947         close(link->sockfd);
948     }
949
950 /* Link-type dependent cleanup */
951     switch(link->link_type)
952     {
953         case LINK_ICMP:
954             icmpLinkCount--;
955             break;
956         case LINK_UDP:
957             udpLinkCount--;
958             break;
959         case LINK_TCP:
960             tcpLinkCount--;
961             free(link->data.tcp);
962             break;
963         case LINK_PPTP:
964             pptpLinkCount--;
965             break;
966         case LINK_FRAGMENT_ID:
967             fragmentIdLinkCount--;
968             break;
969         case LINK_FRAGMENT_PTR:
970             fragmentPtrLinkCount--;
971             if (link->data.frag_ptr != NULL)
972                 free(link->data.frag_ptr);
973             break;
974         case LINK_ADDR:
975             break;
976         default:
977             protoLinkCount--;
978             break;
979     }
980
981 /* Free memory */
982     free(link);
983
984 /* Write statistics, if logging enabled */
985     if (packetAliasMode & PKT_ALIAS_LOG)
986     {
987         ShowAliasStats();
988     }
989 }
990
991
992 static struct alias_link *
993 AddLink(struct in_addr  src_addr,
994         struct in_addr  dst_addr,
995         struct in_addr  alias_addr,
996         u_short         src_port,
997         u_short         dst_port,
998         int             alias_port_param,  /* if less than zero, alias   */
999         int             link_type)         /* port will be automatically */
1000 {                                          /* chosen. If greater than    */
1001     u_int start_point;                     /* zero, equal to alias port  */
1002     struct alias_link *link;
1003
1004     link = malloc(sizeof(struct alias_link));
1005     if (link != NULL)
1006     {
1007     /* Basic initialization */
1008         link->src_addr          = src_addr;
1009         link->dst_addr          = dst_addr;
1010         link->alias_addr        = alias_addr;
1011         link->proxy_addr.s_addr = INADDR_ANY;
1012         link->src_port          = src_port;
1013         link->dst_port          = dst_port;
1014         link->proxy_port        = 0;
1015         link->server            = NULL;
1016         link->link_type         = link_type;
1017         link->sockfd            = -1;
1018         link->flags             = 0;
1019         link->timestamp         = timeStamp;
1020
1021     /* Expiration time */
1022         switch (link_type)
1023         {
1024         case LINK_ICMP:
1025             link->expire_time = ICMP_EXPIRE_TIME;
1026             break;
1027         case LINK_UDP:
1028             link->expire_time = UDP_EXPIRE_TIME;
1029             break;
1030         case LINK_TCP:
1031             link->expire_time = TCP_EXPIRE_INITIAL;
1032             break;
1033         case LINK_PPTP:
1034             link->flags |= LINK_PERMANENT;      /* no timeout. */
1035             break;
1036         case LINK_FRAGMENT_ID:
1037             link->expire_time = FRAGMENT_ID_EXPIRE_TIME;
1038             break;
1039         case LINK_FRAGMENT_PTR:
1040             link->expire_time = FRAGMENT_PTR_EXPIRE_TIME;
1041             break;
1042         case LINK_ADDR:
1043             break;
1044         default:
1045             link->expire_time = PROTO_EXPIRE_TIME;
1046             break;
1047         }
1048
1049     /* Determine alias flags */
1050         if (dst_addr.s_addr == INADDR_ANY)
1051             link->flags |= LINK_UNKNOWN_DEST_ADDR;
1052         if (dst_port == 0)
1053             link->flags |= LINK_UNKNOWN_DEST_PORT;
1054
1055     /* Determine alias port */
1056         if (GetNewPort(link, alias_port_param) != 0)
1057         {
1058             free(link);
1059             return(NULL);
1060         }
1061
1062     /* Link-type dependent initialization */
1063         switch(link_type)
1064         {
1065             struct tcp_dat  *aux_tcp;
1066
1067             case LINK_ICMP:
1068                 icmpLinkCount++;
1069                 break;
1070             case LINK_UDP:
1071                 udpLinkCount++;
1072                 break;
1073             case LINK_TCP:
1074                 aux_tcp = malloc(sizeof(struct tcp_dat));
1075                 if (aux_tcp != NULL)
1076                 {
1077                     int i;
1078
1079                     tcpLinkCount++;
1080                     aux_tcp->state.in = ALIAS_TCP_STATE_NOT_CONNECTED;
1081                     aux_tcp->state.out = ALIAS_TCP_STATE_NOT_CONNECTED;
1082                     aux_tcp->state.index = 0;
1083                     aux_tcp->state.ack_modified = 0;
1084                     for (i=0; i<N_LINK_TCP_DATA; i++)
1085                         aux_tcp->ack[i].active = 0;
1086                     aux_tcp->fwhole = -1;
1087                     link->data.tcp = aux_tcp;
1088                 }
1089                 else
1090                 {
1091 #ifdef DEBUG
1092                     fprintf(stderr, "PacketAlias/AddLink: ");
1093                     fprintf(stderr, " cannot allocate auxiliary TCP data\n");
1094 #endif
1095                     free(link);
1096                     return (NULL);
1097                 }
1098                 break;
1099             case LINK_PPTP:
1100                 pptpLinkCount++;
1101                 break;
1102             case LINK_FRAGMENT_ID:
1103                 fragmentIdLinkCount++;
1104                 break;
1105             case LINK_FRAGMENT_PTR:
1106                 fragmentPtrLinkCount++;
1107                 break;
1108             case LINK_ADDR:
1109                 break;
1110             default:
1111                 protoLinkCount++;
1112                 break;
1113         }
1114
1115     /* Set up pointers for output lookup table */
1116         start_point = StartPointOut(src_addr, dst_addr,
1117                                     src_port, dst_port, link_type);
1118         LIST_INSERT_HEAD(&linkTableOut[start_point], link, list_out);
1119
1120     /* Set up pointers for input lookup table */
1121         start_point = StartPointIn(alias_addr, link->alias_port, link_type);
1122         LIST_INSERT_HEAD(&linkTableIn[start_point], link, list_in);
1123     }
1124     else
1125     {
1126 #ifdef DEBUG
1127         fprintf(stderr, "PacketAlias/AddLink(): ");
1128         fprintf(stderr, "malloc() call failed.\n");
1129 #endif
1130     }
1131
1132     if (packetAliasMode & PKT_ALIAS_LOG)
1133     {
1134         ShowAliasStats();
1135     }
1136
1137     return(link);
1138 }
1139
1140 static struct alias_link *
1141 ReLink(struct alias_link *old_link,
1142        struct in_addr  src_addr,
1143        struct in_addr  dst_addr,
1144        struct in_addr  alias_addr,
1145        u_short         src_port,
1146        u_short         dst_port,
1147        int             alias_port_param,   /* if less than zero, alias   */
1148        int             link_type)          /* port will be automatically */
1149 {                                          /* chosen. If greater than    */
1150     struct alias_link *new_link;           /* zero, equal to alias port  */
1151
1152     new_link = AddLink(src_addr, dst_addr, alias_addr,
1153                        src_port, dst_port, alias_port_param,
1154                        link_type);
1155 #ifndef NO_FW_PUNCH
1156     if (new_link != NULL &&
1157         old_link->link_type == LINK_TCP &&
1158         old_link->data.tcp->fwhole > 0) {
1159       PunchFWHole(new_link);
1160     }
1161 #endif
1162     DeleteLink(old_link);
1163     return new_link;
1164 }
1165
1166 static struct alias_link *
1167 _FindLinkOut(struct in_addr src_addr,
1168             struct in_addr dst_addr,
1169             u_short src_port,
1170             u_short dst_port,
1171             int link_type,
1172             int replace_partial_links)
1173 {
1174     u_int i;
1175     struct alias_link *link;
1176
1177     i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type);
1178     LIST_FOREACH(link, &linkTableOut[i], list_out)
1179     {
1180         if (link->src_addr.s_addr == src_addr.s_addr
1181          && link->server          == NULL
1182          && link->dst_addr.s_addr == dst_addr.s_addr
1183          && link->dst_port        == dst_port
1184          && link->src_port        == src_port
1185          && link->link_type       == link_type)
1186         {
1187             link->timestamp = timeStamp;
1188             break;
1189         }
1190     }
1191
1192 /* Search for partially specified links. */
1193     if (link == NULL && replace_partial_links)
1194     {
1195         if (dst_port != 0 && dst_addr.s_addr != INADDR_ANY)
1196         {
1197             link = _FindLinkOut(src_addr, dst_addr, src_port, 0,
1198                                 link_type, 0);
1199             if (link == NULL)
1200                 link = _FindLinkOut(src_addr, nullAddress, src_port,
1201                                     dst_port, link_type, 0);
1202         }
1203         if (link == NULL &&
1204            (dst_port != 0 || dst_addr.s_addr != INADDR_ANY))
1205         {
1206             link = _FindLinkOut(src_addr, nullAddress, src_port, 0,
1207                                 link_type, 0);
1208         }
1209         if (link != NULL)
1210         {
1211             link = ReLink(link,
1212                           src_addr, dst_addr, link->alias_addr,
1213                           src_port, dst_port, link->alias_port,
1214                           link_type);
1215         }
1216     }
1217
1218     return(link);
1219 }
1220
1221 static struct alias_link *
1222 FindLinkOut(struct in_addr src_addr,
1223             struct in_addr dst_addr,
1224             u_short src_port,
1225             u_short dst_port,
1226             int link_type,
1227             int replace_partial_links)
1228 {
1229     struct alias_link *link;
1230
1231     link = _FindLinkOut(src_addr, dst_addr, src_port, dst_port,
1232                         link_type, replace_partial_links);
1233
1234     if (link == NULL)
1235     {
1236     /* The following allows permanent links to be
1237        specified as using the default source address
1238        (i.e. device interface address) without knowing
1239        in advance what that address is. */
1240         if (aliasAddress.s_addr != 0 &&
1241             src_addr.s_addr == aliasAddress.s_addr)
1242         {
1243             link = _FindLinkOut(nullAddress, dst_addr, src_port, dst_port,
1244                                link_type, replace_partial_links);
1245         }
1246     }
1247
1248     return(link);
1249 }
1250
1251
1252 static struct alias_link *
1253 _FindLinkIn(struct in_addr dst_addr,
1254            struct in_addr  alias_addr,
1255            u_short         dst_port,
1256            u_short         alias_port,
1257            int             link_type,
1258            int             replace_partial_links)
1259 {
1260     int flags_in;
1261     u_int start_point;
1262     struct alias_link *link;
1263     struct alias_link *link_fully_specified;
1264     struct alias_link *link_unknown_all;
1265     struct alias_link *link_unknown_dst_addr;
1266     struct alias_link *link_unknown_dst_port;
1267
1268 /* Initialize pointers */
1269     link_fully_specified  = NULL;
1270     link_unknown_all      = NULL;
1271     link_unknown_dst_addr = NULL;
1272     link_unknown_dst_port = NULL;
1273
1274 /* If either the dest addr or port is unknown, the search
1275    loop will have to know about this. */
1276
1277     flags_in = 0;
1278     if (dst_addr.s_addr == INADDR_ANY)
1279         flags_in |= LINK_UNKNOWN_DEST_ADDR;
1280     if (dst_port == 0)
1281         flags_in |= LINK_UNKNOWN_DEST_PORT;
1282
1283 /* Search loop */
1284     start_point = StartPointIn(alias_addr, alias_port, link_type);
1285     LIST_FOREACH(link, &linkTableIn[start_point], list_in)
1286     {
1287         int flags;
1288
1289         flags = flags_in | link->flags;
1290         if (!(flags & LINK_PARTIALLY_SPECIFIED))
1291         {
1292             if (link->alias_addr.s_addr == alias_addr.s_addr
1293              && link->alias_port        == alias_port
1294              && link->dst_addr.s_addr   == dst_addr.s_addr
1295              && link->dst_port          == dst_port
1296              && link->link_type         == link_type)
1297             {
1298                 link_fully_specified = link;
1299                 break;
1300             }
1301         }
1302         else if ((flags & LINK_UNKNOWN_DEST_ADDR)
1303               && (flags & LINK_UNKNOWN_DEST_PORT))
1304         {
1305             if (link->alias_addr.s_addr == alias_addr.s_addr
1306              && link->alias_port        == alias_port
1307              && link->link_type         == link_type)
1308             {
1309                 if (link_unknown_all == NULL)
1310                     link_unknown_all = link;
1311             }
1312         }
1313         else if (flags & LINK_UNKNOWN_DEST_ADDR)
1314         {
1315             if (link->alias_addr.s_addr == alias_addr.s_addr
1316              && link->alias_port        == alias_port
1317              && link->link_type         == link_type
1318              && link->dst_port          == dst_port)
1319             {
1320                 if (link_unknown_dst_addr == NULL)
1321                     link_unknown_dst_addr = link;
1322             }
1323         }
1324         else if (flags & LINK_UNKNOWN_DEST_PORT)
1325         {
1326             if (link->alias_addr.s_addr == alias_addr.s_addr
1327              && link->alias_port        == alias_port
1328              && link->link_type         == link_type
1329              && link->dst_addr.s_addr   == dst_addr.s_addr)
1330             {
1331                 if (link_unknown_dst_port == NULL)
1332                     link_unknown_dst_port = link;
1333             }
1334         }
1335     }
1336
1337
1338
1339     if (link_fully_specified != NULL)
1340     {
1341         link_fully_specified->timestamp = timeStamp;
1342         link = link_fully_specified;
1343     }
1344     else if (link_unknown_dst_port != NULL)
1345         link = link_unknown_dst_port;
1346     else if (link_unknown_dst_addr != NULL)
1347         link = link_unknown_dst_addr;
1348     else if (link_unknown_all != NULL)
1349         link = link_unknown_all;
1350     else
1351         return (NULL);
1352
1353     if (replace_partial_links &&
1354         (link->flags & LINK_PARTIALLY_SPECIFIED || link->server != NULL))
1355     {
1356         struct in_addr src_addr;
1357         u_short src_port;
1358
1359         if (link->server != NULL) {             /* LSNAT link */
1360             src_addr = link->server->addr;
1361             src_port = link->server->port;
1362             link->server = link->server->next;
1363         } else {
1364             src_addr = link->src_addr;
1365             src_port = link->src_port;
1366         }
1367
1368         link = ReLink(link,
1369                       src_addr, dst_addr, alias_addr,
1370                       src_port, dst_port, alias_port,
1371                       link_type);
1372     }
1373
1374     return (link);
1375 }
1376
1377 static struct alias_link *
1378 FindLinkIn(struct in_addr dst_addr,
1379            struct in_addr alias_addr,
1380            u_short dst_port,
1381            u_short alias_port,
1382            int link_type,
1383            int replace_partial_links)
1384 {
1385     struct alias_link *link;
1386
1387     link = _FindLinkIn(dst_addr, alias_addr, dst_port, alias_port,
1388                        link_type, replace_partial_links);
1389
1390     if (link == NULL)
1391     {
1392     /* The following allows permanent links to be
1393        specified as using the default aliasing address
1394        (i.e. device interface address) without knowing
1395        in advance what that address is. */
1396         if (aliasAddress.s_addr != 0 &&
1397             alias_addr.s_addr == aliasAddress.s_addr)
1398         {
1399             link = _FindLinkIn(dst_addr, nullAddress, dst_port, alias_port,
1400                                link_type, replace_partial_links);
1401         }
1402     }
1403
1404     return(link);
1405 }
1406
1407
1408
1409
1410 /* External routines for finding/adding links
1411
1412 -- "external" means outside alias_db.c, but within alias*.c --
1413
1414     FindIcmpIn(), FindIcmpOut()
1415     FindFragmentIn1(), FindFragmentIn2()
1416     AddFragmentPtrLink(), FindFragmentPtr()
1417     FindProtoIn(), FindProtoOut()
1418     FindUdpTcpIn(), FindUdpTcpOut()
1419     AddPptp(), FindPptpOutByCallId(), FindPptpInByCallId(),
1420     FindPptpOutByPeerCallId(), FindPptpInByPeerCallId()
1421     FindOriginalAddress(), FindAliasAddress()
1422
1423 (prototypes in alias_local.h)
1424 */
1425
1426
1427 struct alias_link *
1428 FindIcmpIn(struct in_addr dst_addr,
1429            struct in_addr alias_addr,
1430            u_short id_alias,
1431            int create)
1432 {
1433     struct alias_link *link;
1434
1435     link = FindLinkIn(dst_addr, alias_addr,
1436                       NO_DEST_PORT, id_alias,
1437                       LINK_ICMP, 0);
1438     if (link == NULL && create && !(packetAliasMode & PKT_ALIAS_DENY_INCOMING))
1439     {
1440         struct in_addr target_addr;
1441
1442         target_addr = FindOriginalAddress(alias_addr);
1443         link = AddLink(target_addr, dst_addr, alias_addr,
1444                        id_alias, NO_DEST_PORT, id_alias,
1445                        LINK_ICMP);
1446     }
1447
1448     return (link);
1449 }
1450
1451
1452 struct alias_link *
1453 FindIcmpOut(struct in_addr src_addr,
1454             struct in_addr dst_addr,
1455             u_short id,
1456             int create)
1457 {
1458     struct alias_link * link;
1459
1460     link = FindLinkOut(src_addr, dst_addr,
1461                        id, NO_DEST_PORT,
1462                        LINK_ICMP, 0);
1463     if (link == NULL && create)
1464     {
1465         struct in_addr alias_addr;
1466
1467         alias_addr = FindAliasAddress(src_addr);
1468         link = AddLink(src_addr, dst_addr, alias_addr,
1469                        id, NO_DEST_PORT, GET_ALIAS_ID,
1470                        LINK_ICMP);
1471     }
1472
1473     return(link);
1474 }
1475
1476
1477 struct alias_link *
1478 FindFragmentIn1(struct in_addr dst_addr,
1479                 struct in_addr alias_addr,
1480                 u_short ip_id)
1481 {
1482     struct alias_link *link;
1483
1484     link = FindLinkIn(dst_addr, alias_addr,
1485                       NO_DEST_PORT, ip_id,
1486                       LINK_FRAGMENT_ID, 0);
1487
1488     if (link == NULL)
1489     {
1490         link = AddLink(nullAddress, dst_addr, alias_addr,
1491                        NO_SRC_PORT, NO_DEST_PORT, ip_id,
1492                        LINK_FRAGMENT_ID);
1493     }
1494
1495     return(link);
1496 }
1497
1498
1499 struct alias_link *
1500 FindFragmentIn2(struct in_addr dst_addr,   /* Doesn't add a link if one */
1501                 struct in_addr alias_addr, /*   is not found.           */
1502                 u_short ip_id)
1503 {
1504     return FindLinkIn(dst_addr, alias_addr,
1505                       NO_DEST_PORT, ip_id,
1506                       LINK_FRAGMENT_ID, 0);
1507 }
1508
1509
1510 struct alias_link *
1511 AddFragmentPtrLink(struct in_addr dst_addr,
1512                    u_short ip_id)
1513 {
1514     return AddLink(nullAddress, dst_addr, nullAddress,
1515                    NO_SRC_PORT, NO_DEST_PORT, ip_id,
1516                    LINK_FRAGMENT_PTR);
1517 }
1518
1519
1520 struct alias_link *
1521 FindFragmentPtr(struct in_addr dst_addr,
1522                 u_short ip_id)
1523 {
1524     return FindLinkIn(dst_addr, nullAddress,
1525                       NO_DEST_PORT, ip_id,
1526                       LINK_FRAGMENT_PTR, 0);
1527 }
1528
1529
1530 struct alias_link *
1531 FindProtoIn(struct in_addr dst_addr,
1532             struct in_addr alias_addr,
1533             u_char proto)
1534 {
1535     struct alias_link *link;
1536
1537     link = FindLinkIn(dst_addr, alias_addr,
1538                       NO_DEST_PORT, 0,
1539                       proto, 1);
1540
1541     if (link == NULL && !(packetAliasMode & PKT_ALIAS_DENY_INCOMING))
1542     {
1543         struct in_addr target_addr;
1544
1545         target_addr = FindOriginalAddress(alias_addr);
1546         link = AddLink(target_addr, dst_addr, alias_addr,
1547                        NO_SRC_PORT, NO_DEST_PORT, 0,
1548                        proto);
1549     }
1550
1551     return (link);
1552 }
1553
1554
1555 struct alias_link *
1556 FindProtoOut(struct in_addr src_addr,
1557              struct in_addr dst_addr,
1558              u_char proto)
1559 {
1560     struct alias_link *link;
1561
1562     link = FindLinkOut(src_addr, dst_addr,
1563                        NO_SRC_PORT, NO_DEST_PORT,
1564                        proto, 1);
1565
1566     if (link == NULL)
1567     {
1568         struct in_addr alias_addr;
1569
1570         alias_addr = FindAliasAddress(src_addr);
1571         link = AddLink(src_addr, dst_addr, alias_addr,
1572                        NO_SRC_PORT, NO_DEST_PORT, 0,
1573                        proto);
1574     }
1575
1576     return (link);
1577 }
1578
1579
1580 struct alias_link *
1581 FindUdpTcpIn(struct in_addr dst_addr,
1582              struct in_addr alias_addr,
1583              u_short        dst_port,
1584              u_short        alias_port,
1585              u_char         proto,
1586              int            create)
1587 {
1588     int link_type;
1589     struct alias_link *link;
1590
1591     switch (proto)
1592     {
1593     case IPPROTO_UDP:
1594         link_type = LINK_UDP;
1595         break;
1596     case IPPROTO_TCP:
1597         link_type = LINK_TCP;
1598         break;
1599     default:
1600         return NULL;
1601         break;
1602     }
1603
1604     link = FindLinkIn(dst_addr, alias_addr,
1605                       dst_port, alias_port,
1606                       link_type, create);
1607
1608     if (link == NULL && create && !(packetAliasMode & PKT_ALIAS_DENY_INCOMING))
1609     {
1610         struct in_addr target_addr;
1611
1612         target_addr = FindOriginalAddress(alias_addr);
1613         link = AddLink(target_addr, dst_addr, alias_addr,
1614                        alias_port, dst_port, alias_port,
1615                        link_type);
1616     }
1617
1618     return(link);
1619 }
1620
1621
1622 struct alias_link *
1623 FindUdpTcpOut(struct in_addr  src_addr,
1624               struct in_addr  dst_addr,
1625               u_short         src_port,
1626               u_short         dst_port,
1627               u_char          proto,
1628               int             create)
1629 {
1630     int link_type;
1631     struct alias_link *link;
1632
1633     switch (proto)
1634     {
1635     case IPPROTO_UDP:
1636         link_type = LINK_UDP;
1637         break;
1638     case IPPROTO_TCP:
1639         link_type = LINK_TCP;
1640         break;
1641     default:
1642         return NULL;
1643         break;
1644     }
1645
1646     link = FindLinkOut(src_addr, dst_addr, src_port, dst_port, link_type, create);
1647
1648     if (link == NULL && create)
1649     {
1650         struct in_addr alias_addr;
1651
1652         alias_addr = FindAliasAddress(src_addr);
1653         link = AddLink(src_addr, dst_addr, alias_addr,
1654                        src_port, dst_port, GET_ALIAS_PORT,
1655                        link_type);
1656     }
1657
1658     return(link);
1659 }
1660
1661
1662 struct alias_link *
1663 AddPptp(struct in_addr  src_addr,
1664         struct in_addr  dst_addr,
1665         struct in_addr  alias_addr,
1666         u_int16_t       src_call_id)
1667 {
1668     struct alias_link *link;
1669
1670     link = AddLink(src_addr, dst_addr, alias_addr,
1671                    src_call_id, 0, GET_ALIAS_PORT,
1672                    LINK_PPTP);
1673
1674     return (link);
1675 }
1676
1677
1678 struct alias_link *
1679 FindPptpOutByCallId(struct in_addr src_addr,
1680                     struct in_addr dst_addr,
1681                     u_int16_t      src_call_id)
1682 {
1683     u_int i;
1684     struct alias_link *link;
1685
1686     i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP);
1687     LIST_FOREACH(link, &linkTableOut[i], list_out)
1688         if (link->link_type == LINK_PPTP &&
1689             link->src_addr.s_addr == src_addr.s_addr &&
1690             link->dst_addr.s_addr == dst_addr.s_addr &&
1691             link->src_port == src_call_id)
1692                 break;
1693
1694     return (link);
1695 }
1696
1697
1698 struct alias_link *
1699 FindPptpOutByPeerCallId(struct in_addr src_addr,
1700                         struct in_addr dst_addr,
1701                         u_int16_t      dst_call_id)
1702 {
1703     u_int i;
1704     struct alias_link *link;
1705
1706     i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP);
1707     LIST_FOREACH(link, &linkTableOut[i], list_out)
1708         if (link->link_type == LINK_PPTP &&
1709             link->src_addr.s_addr == src_addr.s_addr &&
1710             link->dst_addr.s_addr == dst_addr.s_addr &&
1711             link->dst_port == dst_call_id)
1712                 break;
1713
1714     return (link);
1715 }
1716
1717
1718 struct alias_link *
1719 FindPptpInByCallId(struct in_addr dst_addr,
1720                    struct in_addr alias_addr,
1721                    u_int16_t      dst_call_id)
1722 {
1723     u_int i;
1724     struct alias_link *link;
1725
1726     i = StartPointIn(alias_addr, 0, LINK_PPTP);
1727     LIST_FOREACH(link, &linkTableIn[i], list_in)
1728         if (link->link_type == LINK_PPTP &&
1729             link->dst_addr.s_addr == dst_addr.s_addr &&
1730             link->alias_addr.s_addr == alias_addr.s_addr &&
1731             link->dst_port == dst_call_id)
1732                 break;
1733
1734     return (link);
1735 }
1736
1737
1738 struct alias_link *
1739 FindPptpInByPeerCallId(struct in_addr dst_addr,
1740                        struct in_addr alias_addr,
1741                        u_int16_t      alias_call_id)
1742 {
1743     struct alias_link *link;
1744
1745     link = FindLinkIn(dst_addr, alias_addr,
1746                       0/* any */, alias_call_id,
1747                       LINK_PPTP, 0);
1748
1749
1750     return (link);
1751 }
1752
1753
1754 struct alias_link *
1755 FindRtspOut(struct in_addr  src_addr,
1756             struct in_addr  dst_addr,
1757             u_short         src_port,
1758             u_short         alias_port,
1759             u_char          proto)
1760 {
1761     int link_type;
1762     struct alias_link *link;
1763
1764     switch (proto)
1765     {
1766     case IPPROTO_UDP:
1767         link_type = LINK_UDP;
1768         break;
1769     case IPPROTO_TCP:
1770         link_type = LINK_TCP;
1771         break;
1772     default:
1773         return NULL;
1774         break;
1775     }
1776
1777     link = FindLinkOut(src_addr, dst_addr, src_port, 0, link_type, 1);
1778
1779     if (link == NULL)
1780     {
1781         struct in_addr alias_addr;
1782
1783         alias_addr = FindAliasAddress(src_addr);
1784         link = AddLink(src_addr, dst_addr, alias_addr,
1785                        src_port, 0, alias_port,
1786                        link_type);
1787     }
1788
1789     return(link);
1790 }
1791
1792
1793 struct in_addr
1794 FindOriginalAddress(struct in_addr alias_addr)
1795 {
1796     struct alias_link *link;
1797
1798     link = FindLinkIn(nullAddress, alias_addr,
1799                       0, 0, LINK_ADDR, 0);
1800     if (link == NULL)
1801     {
1802         newDefaultLink = 1;
1803         if (targetAddress.s_addr == INADDR_ANY)
1804             return alias_addr;
1805         else if (targetAddress.s_addr == INADDR_NONE)
1806             return aliasAddress;
1807         else
1808             return targetAddress;
1809     }
1810     else
1811     {
1812         if (link->server != NULL) {             /* LSNAT link */
1813             struct in_addr src_addr;
1814
1815             src_addr = link->server->addr;
1816             link->server = link->server->next;
1817             return (src_addr);
1818         } else if (link->src_addr.s_addr == INADDR_ANY)
1819             return aliasAddress;
1820         else
1821             return link->src_addr;
1822     }
1823 }
1824
1825
1826 struct in_addr
1827 FindAliasAddress(struct in_addr original_addr)
1828 {
1829     struct alias_link *link;
1830
1831     link = FindLinkOut(original_addr, nullAddress,
1832                        0, 0, LINK_ADDR, 0);
1833     if (link == NULL)
1834     {
1835         return aliasAddress;
1836     }
1837     else
1838     {
1839         if (link->alias_addr.s_addr == INADDR_ANY)
1840             return aliasAddress;
1841         else
1842             return link->alias_addr;
1843     }
1844 }
1845
1846
1847 /* External routines for getting or changing link data
1848    (external to alias_db.c, but internal to alias*.c)
1849
1850     SetFragmentData(), GetFragmentData()
1851     SetFragmentPtr(), GetFragmentPtr()
1852     SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut()
1853     GetOriginalAddress(), GetDestAddress(), GetAliasAddress()
1854     GetOriginalPort(), GetAliasPort()
1855     SetAckModified(), GetAckModified()
1856     GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq()
1857     SetLastLineCrlfTermed(), GetLastLineCrlfTermed()
1858     SetDestCallId()
1859 */
1860
1861
1862 void
1863 SetFragmentAddr(struct alias_link *link, struct in_addr src_addr)
1864 {
1865     link->data.frag_addr = src_addr;
1866 }
1867
1868
1869 void
1870 GetFragmentAddr(struct alias_link *link, struct in_addr *src_addr)
1871 {
1872     *src_addr = link->data.frag_addr;
1873 }
1874
1875
1876 void
1877 SetFragmentPtr(struct alias_link *link, char *fptr)
1878 {
1879     link->data.frag_ptr = fptr;
1880 }
1881
1882
1883 void
1884 GetFragmentPtr(struct alias_link *link, char **fptr)
1885 {
1886    *fptr = link->data.frag_ptr;
1887 }
1888
1889
1890 void
1891 SetStateIn(struct alias_link *link, int state)
1892 {
1893     /* TCP input state */
1894     switch (state) {
1895     case ALIAS_TCP_STATE_DISCONNECTED:
1896         if (link->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED)
1897             link->expire_time = TCP_EXPIRE_DEAD;
1898         else
1899             link->expire_time = TCP_EXPIRE_SINGLEDEAD;
1900         break;
1901     case ALIAS_TCP_STATE_CONNECTED:
1902         if (link->data.tcp->state.out == ALIAS_TCP_STATE_CONNECTED)
1903             link->expire_time = TCP_EXPIRE_CONNECTED;
1904         break;
1905     default:
1906         abort();
1907     }
1908     link->data.tcp->state.in = state;
1909 }
1910
1911
1912 void
1913 SetStateOut(struct alias_link *link, int state)
1914 {
1915     /* TCP output state */
1916     switch (state) {
1917     case ALIAS_TCP_STATE_DISCONNECTED:
1918         if (link->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED)
1919             link->expire_time = TCP_EXPIRE_DEAD;
1920         else
1921             link->expire_time = TCP_EXPIRE_SINGLEDEAD;
1922         break;
1923     case ALIAS_TCP_STATE_CONNECTED:
1924         if (link->data.tcp->state.in == ALIAS_TCP_STATE_CONNECTED)
1925             link->expire_time = TCP_EXPIRE_CONNECTED;
1926         break;
1927     default:
1928         abort();
1929     }
1930     link->data.tcp->state.out = state;
1931 }
1932
1933
1934 int
1935 GetStateIn(struct alias_link *link)
1936 {
1937     /* TCP input state */
1938     return link->data.tcp->state.in;
1939 }
1940
1941
1942 int
1943 GetStateOut(struct alias_link *link)
1944 {
1945     /* TCP output state */
1946     return link->data.tcp->state.out;
1947 }
1948
1949
1950 struct in_addr
1951 GetOriginalAddress(struct alias_link *link)
1952 {
1953     if (link->src_addr.s_addr == INADDR_ANY)
1954         return aliasAddress;
1955     else
1956         return(link->src_addr);
1957 }
1958
1959
1960 struct in_addr
1961 GetDestAddress(struct alias_link *link)
1962 {
1963     return(link->dst_addr);
1964 }
1965
1966
1967 struct in_addr
1968 GetAliasAddress(struct alias_link *link)
1969 {
1970     if (link->alias_addr.s_addr == INADDR_ANY)
1971         return aliasAddress;
1972     else
1973         return link->alias_addr;
1974 }
1975
1976
1977 struct in_addr
1978 GetDefaultAliasAddress(void)
1979 {
1980     return aliasAddress;
1981 }
1982
1983
1984 void
1985 SetDefaultAliasAddress(struct in_addr alias_addr)
1986 {
1987     aliasAddress = alias_addr;
1988 }
1989
1990
1991 u_short
1992 GetOriginalPort(struct alias_link *link)
1993 {
1994     return(link->src_port);
1995 }
1996
1997
1998 u_short
1999 GetAliasPort(struct alias_link *link)
2000 {
2001     return(link->alias_port);
2002 }
2003
2004 #ifndef NO_FW_PUNCH
2005 static u_short
2006 GetDestPort(struct alias_link *link)
2007 {
2008     return(link->dst_port);
2009 }
2010 #endif
2011
2012 void
2013 SetAckModified(struct alias_link *link)
2014 {
2015 /* Indicate that ACK numbers have been modified in a TCP connection */
2016     link->data.tcp->state.ack_modified = 1;
2017 }
2018
2019
2020 struct in_addr
2021 GetProxyAddress(struct alias_link *link)
2022 {
2023     return link->proxy_addr;
2024 }
2025
2026
2027 void
2028 SetProxyAddress(struct alias_link *link, struct in_addr addr)
2029 {
2030     link->proxy_addr = addr;
2031 }
2032
2033
2034 u_short
2035 GetProxyPort(struct alias_link *link)
2036 {
2037     return link->proxy_port;
2038 }
2039
2040
2041 void
2042 SetProxyPort(struct alias_link *link, u_short port)
2043 {
2044     link->proxy_port = port;
2045 }
2046
2047
2048 int
2049 GetAckModified(struct alias_link *link)
2050 {
2051 /* See if ACK numbers have been modified */
2052     return link->data.tcp->state.ack_modified;
2053 }
2054
2055
2056 int
2057 GetDeltaAckIn(struct ip *pip, struct alias_link *link)
2058 {
2059 /*
2060 Find out how much the ACK number has been altered for an incoming
2061 TCP packet.  To do this, a circular list of ACK numbers where the TCP
2062 packet size was altered is searched.
2063 */
2064
2065     int i;
2066     struct tcphdr *tc;
2067     int delta, ack_diff_min;
2068     u_long ack;
2069
2070     tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
2071     ack      = tc->th_ack;
2072
2073     delta = 0;
2074     ack_diff_min = -1;
2075     for (i=0; i<N_LINK_TCP_DATA; i++)
2076     {
2077         struct ack_data_record x;
2078
2079         x = link->data.tcp->ack[i];
2080         if (x.active == 1)
2081         {
2082             int ack_diff;
2083
2084             ack_diff = SeqDiff(x.ack_new, ack);
2085             if (ack_diff >= 0)
2086             {
2087                 if (ack_diff_min >= 0)
2088                 {
2089                     if (ack_diff < ack_diff_min)
2090                     {
2091                         delta = x.delta;
2092                         ack_diff_min = ack_diff;
2093                     }
2094                 }
2095                 else
2096                 {
2097                     delta = x.delta;
2098                     ack_diff_min = ack_diff;
2099                 }
2100             }
2101         }
2102     }
2103     return (delta);
2104 }
2105
2106
2107 int
2108 GetDeltaSeqOut(struct ip *pip, struct alias_link *link)
2109 {
2110 /*
2111 Find out how much the sequence number has been altered for an outgoing
2112 TCP packet.  To do this, a circular list of ACK numbers where the TCP
2113 packet size was altered is searched.
2114 */
2115
2116     int i;
2117     struct tcphdr *tc;
2118     int delta, seq_diff_min;
2119     u_long seq;
2120
2121     tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
2122     seq = tc->th_seq;
2123
2124     delta = 0;
2125     seq_diff_min = -1;
2126     for (i=0; i<N_LINK_TCP_DATA; i++)
2127     {
2128         struct ack_data_record x;
2129
2130         x = link->data.tcp->ack[i];
2131         if (x.active == 1)
2132         {
2133             int seq_diff;
2134
2135             seq_diff = SeqDiff(x.ack_old, seq);
2136             if (seq_diff >= 0)
2137             {
2138                 if (seq_diff_min >= 0)
2139                 {
2140                     if (seq_diff < seq_diff_min)
2141                     {
2142                         delta = x.delta;
2143                         seq_diff_min = seq_diff;
2144                     }
2145                 }
2146                 else
2147                 {
2148                     delta = x.delta;
2149                     seq_diff_min = seq_diff;
2150                 }
2151             }
2152         }
2153     }
2154     return (delta);
2155 }
2156
2157
2158 void
2159 AddSeq(struct ip *pip, struct alias_link *link, int delta)
2160 {
2161 /*
2162 When a TCP packet has been altered in length, save this
2163 information in a circular list.  If enough packets have
2164 been altered, then this list will begin to overwrite itself.
2165 */
2166
2167     struct tcphdr *tc;
2168     struct ack_data_record x;
2169     int hlen, tlen, dlen;
2170     int i;
2171
2172     tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
2173
2174     hlen = (pip->ip_hl + tc->th_off) << 2;
2175     tlen = ntohs(pip->ip_len);
2176     dlen = tlen - hlen;
2177
2178     x.ack_old = htonl(ntohl(tc->th_seq) + dlen);
2179     x.ack_new = htonl(ntohl(tc->th_seq) + dlen + delta);
2180     x.delta = delta;
2181     x.active = 1;
2182
2183     i = link->data.tcp->state.index;
2184     link->data.tcp->ack[i] = x;
2185
2186     i++;
2187     if (i == N_LINK_TCP_DATA)
2188         link->data.tcp->state.index = 0;
2189     else
2190         link->data.tcp->state.index = i;
2191 }
2192
2193 void
2194 SetExpire(struct alias_link *link, int expire)
2195 {
2196     if (expire == 0)
2197     {
2198         link->flags &= ~LINK_PERMANENT;
2199         DeleteLink(link);
2200     }
2201     else if (expire == -1)
2202     {
2203         link->flags |= LINK_PERMANENT;
2204     }
2205     else if (expire > 0)
2206     {
2207         link->expire_time = expire;
2208     }
2209     else
2210     {
2211 #ifdef DEBUG
2212         fprintf(stderr, "PacketAlias/SetExpire(): ");
2213         fprintf(stderr, "error in expire parameter\n");
2214 #endif
2215     }
2216 }
2217
2218 void
2219 ClearCheckNewLink(void)
2220 {
2221     newDefaultLink = 0;
2222 }
2223
2224 void
2225 SetLastLineCrlfTermed(struct alias_link *link, int yes)
2226 {
2227
2228     if (yes)
2229         link->flags |= LINK_LAST_LINE_CRLF_TERMED;
2230     else
2231         link->flags &= ~LINK_LAST_LINE_CRLF_TERMED;
2232 }
2233
2234 int
2235 GetLastLineCrlfTermed(struct alias_link *link)
2236 {
2237
2238     return (link->flags & LINK_LAST_LINE_CRLF_TERMED);
2239 }
2240
2241 void
2242 SetDestCallId(struct alias_link *link, u_int16_t cid)
2243 {
2244
2245     deleteAllLinks = 1;
2246     link = ReLink(link, link->src_addr, link->dst_addr, link->alias_addr,
2247                   link->src_port, cid, link->alias_port, link->link_type);
2248     deleteAllLinks = 0;
2249 }
2250
2251
2252 /* Miscellaneous Functions
2253
2254     HouseKeeping()
2255     InitPacketAliasLog()
2256     UninitPacketAliasLog()
2257 */
2258
2259 /*
2260     Whenever an outgoing or incoming packet is handled, HouseKeeping()
2261     is called to find and remove timed-out aliasing links.  Logic exists
2262     to sweep through the entire table and linked list structure
2263     every 60 seconds.
2264
2265     (prototype in alias_local.h)
2266 */
2267
2268 void
2269 HouseKeeping(void)
2270 {
2271     int i, n, n100;
2272     struct timeval tv;
2273     struct timezone tz;
2274
2275     /*
2276      * Save system time (seconds) in global variable timeStamp for
2277      * use by other functions. This is done so as not to unnecessarily
2278      * waste timeline by making system calls.
2279      */
2280     gettimeofday(&tv, &tz);
2281     timeStamp = tv.tv_sec;
2282
2283     /* Compute number of spokes (output table link chains) to cover */
2284     n100  = LINK_TABLE_OUT_SIZE * 100 + houseKeepingResidual;
2285     n100 *= timeStamp - lastCleanupTime;
2286     n100 /= ALIAS_CLEANUP_INTERVAL_SECS;
2287
2288     n = n100/100;
2289
2290     /* Handle different cases */
2291     if (n > ALIAS_CLEANUP_MAX_SPOKES)
2292     {
2293         n = ALIAS_CLEANUP_MAX_SPOKES;
2294         lastCleanupTime = timeStamp;
2295         houseKeepingResidual = 0;
2296
2297         for (i=0; i<n; i++)
2298             IncrementalCleanup();
2299     }
2300     else if (n > 0)
2301     {
2302         lastCleanupTime = timeStamp;
2303         houseKeepingResidual = n100 - 100*n;
2304
2305         for (i=0; i<n; i++)
2306             IncrementalCleanup();
2307     }
2308     else if (n < 0)
2309     {
2310 #ifdef DEBUG
2311         fprintf(stderr, "PacketAlias/HouseKeeping(): ");
2312         fprintf(stderr, "something unexpected in time values\n");
2313 #endif
2314         lastCleanupTime = timeStamp;
2315         houseKeepingResidual = 0;
2316     }
2317 }
2318
2319
2320 /* Init the log file and enable logging */
2321 static void
2322 InitPacketAliasLog(void)
2323 {
2324    if ((~packetAliasMode & PKT_ALIAS_LOG)
2325     && (monitorFile = fopen("/var/log/alias.log", "w")))
2326    {
2327       packetAliasMode |= PKT_ALIAS_LOG;
2328       fprintf(monitorFile,
2329       "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n");
2330    }
2331 }
2332
2333
2334 /* Close the log-file and disable logging. */
2335 static void
2336 UninitPacketAliasLog(void)
2337 {
2338     if (monitorFile) {
2339         fclose(monitorFile);
2340         monitorFile = NULL;
2341     }
2342     packetAliasMode &= ~PKT_ALIAS_LOG;
2343 }
2344
2345
2346
2347
2348
2349
2350 /* Outside world interfaces
2351
2352 -- "outside world" means other than alias*.c routines --
2353
2354     PacketAliasRedirectPort()
2355     PacketAliasAddServer()
2356     PacketAliasRedirectProto()
2357     PacketAliasRedirectAddr()
2358     PacketAliasRedirectDelete()
2359     PacketAliasSetAddress()
2360     PacketAliasInit()
2361     PacketAliasUninit()
2362     PacketAliasSetMode()
2363
2364 (prototypes in alias.h)
2365 */
2366
2367 /* Redirection from a specific public addr:port to a
2368    private addr:port */
2369 struct alias_link *
2370 PacketAliasRedirectPort(struct in_addr src_addr,   u_short src_port,
2371                         struct in_addr dst_addr,   u_short dst_port,
2372                         struct in_addr alias_addr, u_short alias_port,
2373                         u_char proto)
2374 {
2375     int link_type;
2376     struct alias_link *link;
2377
2378     switch(proto)
2379     {
2380     case IPPROTO_UDP:
2381         link_type = LINK_UDP;
2382         break;
2383     case IPPROTO_TCP:
2384         link_type = LINK_TCP;
2385         break;
2386     default:
2387 #ifdef DEBUG
2388         fprintf(stderr, "PacketAliasRedirectPort(): ");
2389         fprintf(stderr, "only TCP and UDP protocols allowed\n");
2390 #endif
2391         return NULL;
2392     }
2393
2394     link = AddLink(src_addr, dst_addr, alias_addr,
2395                    src_port, dst_port, alias_port,
2396                    link_type);
2397
2398     if (link != NULL)
2399     {
2400         link->flags |= LINK_PERMANENT;
2401     }
2402 #ifdef DEBUG
2403     else
2404     {
2405         fprintf(stderr, "PacketAliasRedirectPort(): "
2406                         "call to AddLink() failed\n");
2407     }
2408 #endif
2409
2410     return link;
2411 }
2412
2413 /* Add server to the pool of servers */
2414 int
2415 PacketAliasAddServer(struct alias_link *link, struct in_addr addr, u_short port)
2416 {
2417     struct server *server;
2418
2419     server = malloc(sizeof(struct server));
2420
2421     if (server != NULL) {
2422         struct server *head;
2423
2424         server->addr = addr;
2425         server->port = port;
2426
2427         head = link->server;
2428         if (head == NULL)
2429             server->next = server;
2430         else {
2431             struct server *s;
2432
2433             for (s = head; s->next != head; s = s->next);
2434             s->next = server;
2435             server->next = head;
2436         }
2437         link->server = server;
2438         return (0);
2439     } else
2440         return (-1);
2441 }
2442
2443 /* Redirect packets of a given IP protocol from a specific
2444    public address to a private address */
2445 struct alias_link *
2446 PacketAliasRedirectProto(struct in_addr src_addr,
2447                          struct in_addr dst_addr,
2448                          struct in_addr alias_addr,
2449                          u_char proto)
2450 {
2451     struct alias_link *link;
2452
2453     link = AddLink(src_addr, dst_addr, alias_addr,
2454                    NO_SRC_PORT, NO_DEST_PORT, 0,
2455                    proto);
2456
2457     if (link != NULL)
2458     {
2459         link->flags |= LINK_PERMANENT;
2460     }
2461 #ifdef DEBUG
2462     else
2463     {
2464         fprintf(stderr, "PacketAliasRedirectProto(): "
2465                         "call to AddLink() failed\n");
2466     }
2467 #endif
2468
2469     return link;
2470 }
2471
2472 /* Static address translation */
2473 struct alias_link *
2474 PacketAliasRedirectAddr(struct in_addr src_addr,
2475                         struct in_addr alias_addr)
2476 {
2477     struct alias_link *link;
2478
2479     link = AddLink(src_addr, nullAddress, alias_addr,
2480                    0, 0, 0,
2481                    LINK_ADDR);
2482
2483     if (link != NULL)
2484     {
2485         link->flags |= LINK_PERMANENT;
2486     }
2487 #ifdef DEBUG
2488     else
2489     {
2490         fprintf(stderr, "PacketAliasRedirectAddr(): "
2491                         "call to AddLink() failed\n");
2492     }
2493 #endif
2494
2495     return link;
2496 }
2497
2498
2499 void
2500 PacketAliasRedirectDelete(struct alias_link *link)
2501 {
2502 /* This is a dangerous function to put in the API,
2503    because an invalid pointer can crash the program. */
2504
2505     deleteAllLinks = 1;
2506     DeleteLink(link);
2507     deleteAllLinks = 0;
2508 }
2509
2510
2511 void
2512 PacketAliasSetAddress(struct in_addr addr)
2513 {
2514     if (packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE
2515      && aliasAddress.s_addr != addr.s_addr)
2516         CleanupAliasData();
2517
2518     aliasAddress = addr;
2519 }
2520
2521
2522 void
2523 PacketAliasSetTarget(struct in_addr target_addr)
2524 {
2525     targetAddress = target_addr;
2526 }
2527
2528
2529 void
2530 PacketAliasInit(void)
2531 {
2532     int i;
2533     struct timeval tv;
2534     struct timezone tz;
2535     static int firstCall = 1;
2536
2537     if (firstCall == 1)
2538     {
2539         gettimeofday(&tv, &tz);
2540         timeStamp = tv.tv_sec;
2541         lastCleanupTime = tv.tv_sec;
2542         houseKeepingResidual = 0;
2543
2544         for (i=0; i<LINK_TABLE_OUT_SIZE; i++)
2545             LIST_INIT(&linkTableOut[i]);
2546         for (i=0; i<LINK_TABLE_IN_SIZE; i++)
2547             LIST_INIT(&linkTableIn[i]);
2548
2549         atexit(PacketAliasUninit);
2550         firstCall = 0;
2551     }
2552     else
2553     {
2554         deleteAllLinks = 1;
2555         CleanupAliasData();
2556         deleteAllLinks = 0;
2557     }
2558
2559     aliasAddress.s_addr = INADDR_ANY;
2560     targetAddress.s_addr = INADDR_ANY;
2561
2562     icmpLinkCount = 0;
2563     udpLinkCount = 0;
2564     tcpLinkCount = 0;
2565     pptpLinkCount = 0;
2566     protoLinkCount = 0;
2567     fragmentIdLinkCount = 0;
2568     fragmentPtrLinkCount = 0;
2569     sockCount = 0;
2570
2571     cleanupIndex =0;
2572
2573     packetAliasMode = PKT_ALIAS_SAME_PORTS
2574                     | PKT_ALIAS_USE_SOCKETS
2575                     | PKT_ALIAS_RESET_ON_ADDR_CHANGE;
2576 }
2577
2578 void
2579 PacketAliasUninit(void) {
2580     deleteAllLinks = 1;
2581     CleanupAliasData();
2582     deleteAllLinks = 0;
2583     UninitPacketAliasLog();
2584 #ifndef NO_FW_PUNCH
2585     UninitPunchFW();
2586 #endif
2587 }
2588
2589
2590 /* Change mode for some operations */
2591 unsigned int
2592 PacketAliasSetMode(
2593     unsigned int flags, /* Which state to bring flags to */
2594     unsigned int mask   /* Mask of which flags to affect (use 0 to do a
2595                            probe for flag values) */
2596 )
2597 {
2598 /* Enable logging? */
2599     if (flags & mask & PKT_ALIAS_LOG)
2600     {
2601         InitPacketAliasLog();     /* Do the enable */
2602     } else
2603 /* _Disable_ logging? */
2604     if (~flags & mask & PKT_ALIAS_LOG) {
2605         UninitPacketAliasLog();
2606     }
2607
2608 #ifndef NO_FW_PUNCH
2609 /* Start punching holes in the firewall? */
2610     if (flags & mask & PKT_ALIAS_PUNCH_FW) {
2611         InitPunchFW();
2612     } else
2613 /* Stop punching holes in the firewall? */
2614     if (~flags & mask & PKT_ALIAS_PUNCH_FW) {
2615         UninitPunchFW();
2616     }
2617 #endif
2618
2619 /* Other flags can be set/cleared without special action */
2620     packetAliasMode = (flags & mask) | (packetAliasMode & ~mask);
2621     return packetAliasMode;
2622 }
2623
2624
2625 int
2626 PacketAliasCheckNewLink(void)
2627 {
2628     return newDefaultLink;
2629 }
2630
2631
2632 #ifndef NO_FW_PUNCH
2633
2634 /*****************
2635   Code to support firewall punching.  This shouldn't really be in this
2636   file, but making variables global is evil too.
2637   ****************/
2638
2639 /* Firewall include files */
2640 #include <net/if.h>
2641 #include <net/ipfw/ip_fw.h>
2642 #include <string.h>
2643 #include <err.h>
2644
2645 /*
2646  * helper function, updates the pointer to cmd with the length
2647  * of the current command, and also cleans up the first word of
2648  * the new command in case it has been clobbered before.
2649  */
2650 static ipfw_insn *
2651 next_cmd(ipfw_insn *cmd)
2652 {
2653     cmd += F_LEN(cmd);
2654     bzero(cmd, sizeof(*cmd));
2655     return cmd;
2656 }
2657
2658 /*
2659  * A function to fill simple commands of size 1.
2660  * Existing flags are preserved.
2661  */
2662 static ipfw_insn *
2663 fill_cmd(ipfw_insn *cmd, enum ipfw_opcodes opcode, int size,
2664          int flags, u_int16_t arg)
2665 {
2666     cmd->opcode = opcode;
2667     cmd->len =  ((cmd->len | flags) & (F_NOT | F_OR)) | (size & F_LEN_MASK);
2668     cmd->arg1 = arg;
2669     return next_cmd(cmd);
2670 }
2671
2672 static ipfw_insn *
2673 fill_ip(ipfw_insn *cmd1, enum ipfw_opcodes opcode, u_int32_t addr)
2674 {
2675     ipfw_insn_ip *cmd = (ipfw_insn_ip *)cmd1;
2676
2677     cmd->addr.s_addr = addr;
2678     return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u32), 0, 0);
2679 }
2680
2681 static ipfw_insn *
2682 fill_one_port(ipfw_insn *cmd1, enum ipfw_opcodes opcode, u_int16_t port)
2683 {
2684     ipfw_insn_u16 *cmd = (ipfw_insn_u16 *)cmd1;
2685
2686     cmd->ports[0] = cmd->ports[1] = port;
2687     return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u16), 0, 0);
2688 }
2689
2690 static int
2691 fill_rule(void *buf, int bufsize, int rulenum,
2692         enum ipfw_opcodes action, int proto,
2693         struct in_addr sa, u_int16_t sp, struct in_addr da, u_int16_t dp)
2694 {
2695     struct ipfw_ioc_rule *rule = buf;
2696     ipfw_insn *cmd = (ipfw_insn *)rule->cmd;
2697
2698     bzero(buf, bufsize);
2699     rule->rulenum = rulenum;
2700
2701     cmd = fill_cmd(cmd, O_PROTO, F_INSN_SIZE(ipfw_insn), 0, proto);
2702     cmd = fill_ip(cmd, O_IP_SRC, sa.s_addr);
2703     cmd = fill_one_port(cmd, O_IP_SRCPORT, sp);
2704     cmd = fill_ip(cmd, O_IP_DST, da.s_addr);
2705     cmd = fill_one_port(cmd, O_IP_DSTPORT, dp);
2706
2707     rule->act_ofs = (u_int32_t *)cmd - (u_int32_t *)rule->cmd;
2708     cmd = fill_cmd(cmd, action, F_INSN_SIZE(ipfw_insn), 0, 0);
2709
2710     rule->cmd_len = (u_int32_t *)cmd - (u_int32_t *)rule->cmd;
2711
2712     return ((void *)cmd - buf);
2713 }
2714
2715 static void ClearAllFWHoles(void);
2716
2717 static int fireWallBaseNum;     /* The first firewall entry free for our use */
2718 static int fireWallNumNums;     /* How many entries can we use? */
2719 static int fireWallActiveNum;   /* Which entry did we last use? */
2720 static char *fireWallField;     /* bool array for entries */
2721
2722 #define fw_setfield(field, num)                         \
2723 do {                                                    \
2724     (field)[(num) - fireWallBaseNum] = 1;               \
2725 } /*lint -save -e717 */ while(0) /*lint -restore */
2726 #define fw_clrfield(field, num)                         \
2727 do {                                                    \
2728     (field)[(num) - fireWallBaseNum] = 0;               \
2729 } /*lint -save -e717 */ while(0) /*lint -restore */
2730 #define fw_tstfield(field, num) ((field)[(num) - fireWallBaseNum])
2731
2732 static void
2733 InitPunchFW(void) {
2734     fireWallField = malloc(fireWallNumNums);
2735     if (fireWallField) {
2736         memset(fireWallField, 0, fireWallNumNums);
2737         if (fireWallFD < 0) {
2738             fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
2739         }
2740         ClearAllFWHoles();
2741         fireWallActiveNum = fireWallBaseNum;
2742     }
2743 }
2744
2745 static void
2746 UninitPunchFW(void) {
2747     ClearAllFWHoles();
2748     if (fireWallFD >= 0)
2749         close(fireWallFD);
2750     fireWallFD = -1;
2751     if (fireWallField)
2752         free(fireWallField);
2753     fireWallField = NULL;
2754     packetAliasMode &= ~PKT_ALIAS_PUNCH_FW;
2755 }
2756
2757 /* Make a certain link go through the firewall */
2758 void
2759 PunchFWHole(struct alias_link *link) {
2760     int r;                      /* Result code */
2761     int fwhole;                 /* Where to punch hole */
2762
2763 /* Don't do anything unless we are asked to */
2764     if ( !(packetAliasMode & PKT_ALIAS_PUNCH_FW) ||
2765          fireWallFD < 0 ||
2766          link->link_type != LINK_TCP)
2767         return;
2768
2769 /** Build rule **/
2770
2771     /* Find empty slot */
2772     for (fwhole = fireWallActiveNum;
2773          fwhole < fireWallBaseNum + fireWallNumNums &&
2774              fw_tstfield(fireWallField, fwhole);
2775          fwhole++)
2776         ;
2777     if (fwhole == fireWallBaseNum + fireWallNumNums) {
2778         for (fwhole = fireWallBaseNum;
2779              fwhole < fireWallActiveNum &&
2780                  fw_tstfield(fireWallField, fwhole);
2781              fwhole++)
2782             ;
2783         if (fwhole == fireWallActiveNum) {
2784             /* No rule point empty - we can't punch more holes. */
2785             fireWallActiveNum = fireWallBaseNum;
2786 #ifdef DEBUG
2787             fprintf(stderr, "libalias: Unable to create firewall hole!\n");
2788 #endif
2789             return;
2790         }
2791     }
2792     /* Start next search at next position */
2793     fireWallActiveNum = fwhole+1;
2794
2795     /*
2796      * generate two rules of the form
2797      *
2798      *  add fwhole accept tcp from OAddr OPort to DAddr DPort
2799      *  add fwhole accept tcp from DAddr DPort to OAddr OPort
2800      */
2801     if (GetOriginalPort(link) != 0 && GetDestPort(link) != 0) {
2802         u_int32_t rulebuf[IPFW_RULE_SIZE_MAX];
2803         int i;
2804
2805         i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
2806                 O_ACCEPT, IPPROTO_TCP,
2807                 GetOriginalAddress(link), ntohs(GetOriginalPort(link)),
2808                 GetDestAddress(link), ntohs(GetDestPort(link)) );
2809         r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
2810         if (r)
2811                 err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)");
2812
2813         i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
2814                 O_ACCEPT, IPPROTO_TCP,
2815                 GetDestAddress(link), ntohs(GetDestPort(link)),
2816                 GetOriginalAddress(link), ntohs(GetOriginalPort(link)) );
2817         r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
2818         if (r)
2819                 err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)");
2820     }
2821 /* Indicate hole applied */
2822     link->data.tcp->fwhole = fwhole;
2823     fw_setfield(fireWallField, fwhole);
2824 }
2825
2826 /* Remove a hole in a firewall associated with a particular alias
2827    link.  Calling this too often is harmless. */
2828 static void
2829 ClearFWHole(struct alias_link *link) {
2830     if (link->link_type == LINK_TCP) {
2831         int fwhole =  link->data.tcp->fwhole; /* Where is the firewall hole? */
2832
2833         if (fwhole < 0)
2834             return;
2835
2836         while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL,
2837                     &fwhole, sizeof fwhole))
2838             ;
2839         fw_clrfield(fireWallField, fwhole);
2840         link->data.tcp->fwhole = -1;
2841     }
2842 }
2843
2844 /* Clear out the entire range dedicated to firewall holes. */
2845 static void
2846 ClearAllFWHoles(void) {
2847     int i;
2848
2849     if (fireWallFD < 0)
2850         return;
2851
2852     for (i = fireWallBaseNum; i < fireWallBaseNum + fireWallNumNums; i++) {
2853         int r = i;
2854         while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &r, sizeof r))
2855             ;
2856     }
2857     memset(fireWallField, 0, fireWallNumNums);
2858 }
2859 #endif
2860
2861 void
2862 PacketAliasSetFWBase(unsigned int base, unsigned int num) {
2863 #ifndef NO_FW_PUNCH
2864     fireWallBaseNum = base;
2865     fireWallNumNums = num;
2866 #endif
2867 }