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