xref: /dragonfly/lib/libalias/alias_db.c (revision d9f85b33)
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;
848 
849     for (i=0; i<LINK_TABLE_OUT_SIZE; i++)
850     {
851         link = LIST_FIRST(&linkTableOut[i]);
852         while (link != NULL)
853         {
854             struct alias_link *link_next;
855             link_next = LIST_NEXT(link, list_out);
856             DeleteLink(link);
857             link = link_next;
858         }
859     }
860 
861     cleanupIndex =0;
862 }
863 
864 
865 static void
866 IncrementalCleanup(void)
867 {
868     struct alias_link *link;
869 
870     link = LIST_FIRST(&linkTableOut[cleanupIndex++]);
871     while (link != NULL)
872     {
873         int idelta;
874         struct alias_link *link_next;
875 
876         link_next = LIST_NEXT(link, list_out);
877         idelta = timeStamp - link->timestamp;
878         switch (link->link_type)
879         {
880             case LINK_TCP:
881                 if (idelta > link->expire_time)
882                 {
883                     struct tcp_dat *tcp_aux;
884 
885                     tcp_aux = link->data.tcp;
886                     if (tcp_aux->state.in  != ALIAS_TCP_STATE_CONNECTED
887                      || tcp_aux->state.out != ALIAS_TCP_STATE_CONNECTED)
888                     {
889                         DeleteLink(link);
890                     }
891                 }
892                 break;
893             default:
894                 if (idelta > link->expire_time)
895                 {
896                     DeleteLink(link);
897                 }
898                 break;
899         }
900         link = link_next;
901     }
902 
903     if (cleanupIndex == LINK_TABLE_OUT_SIZE)
904         cleanupIndex = 0;
905 }
906 
907 static void
908 DeleteLink(struct alias_link *link)
909 {
910 
911 /* Don't do anything if the link is marked permanent */
912     if (deleteAllLinks == 0 && link->flags & LINK_PERMANENT)
913         return;
914 
915 #ifndef NO_FW_PUNCH
916 /* Delete associated firewall hole, if any */
917     ClearFWHole(link);
918 #endif
919 
920 /* Free memory allocated for LSNAT server pool */
921     if (link->server != NULL) {
922 	struct server *head, *curr, *next;
923 
924 	head = curr = link->server;
925 	do {
926 	    next = curr->next;
927 	    free(curr);
928 	} while ((curr = next) != head);
929     }
930 
931 /* Adjust output table pointers */
932     LIST_REMOVE(link, list_out);
933 
934 /* Adjust input table pointers */
935     LIST_REMOVE(link, list_in);
936 
937 /* Close socket, if one has been allocated */
938     if (link->sockfd != -1)
939     {
940         sockCount--;
941         close(link->sockfd);
942     }
943 
944 /* Link-type dependent cleanup */
945     switch(link->link_type)
946     {
947         case LINK_ICMP:
948             icmpLinkCount--;
949             break;
950         case LINK_UDP:
951             udpLinkCount--;
952             break;
953         case LINK_TCP:
954             tcpLinkCount--;
955             free(link->data.tcp);
956             break;
957         case LINK_PPTP:
958             pptpLinkCount--;
959             break;
960         case LINK_FRAGMENT_ID:
961             fragmentIdLinkCount--;
962             break;
963         case LINK_FRAGMENT_PTR:
964             fragmentPtrLinkCount--;
965             if (link->data.frag_ptr != NULL)
966                 free(link->data.frag_ptr);
967             break;
968 	case LINK_ADDR:
969 	    break;
970         default:
971             protoLinkCount--;
972             break;
973     }
974 
975 /* Free memory */
976     free(link);
977 
978 /* Write statistics, if logging enabled */
979     if (packetAliasMode & PKT_ALIAS_LOG)
980     {
981         ShowAliasStats();
982     }
983 }
984 
985 
986 static struct alias_link *
987 AddLink(struct in_addr  src_addr,
988         struct in_addr  dst_addr,
989         struct in_addr  alias_addr,
990         u_short         src_port,
991         u_short         dst_port,
992         int             alias_port_param,  /* if less than zero, alias   */
993         int             link_type)         /* port will be automatically */
994 {                                          /* chosen. If greater than    */
995     u_int start_point;                     /* zero, equal to alias port  */
996     struct alias_link *link;
997 
998     link = malloc(sizeof(struct alias_link));
999     if (link != NULL)
1000     {
1001     /* Basic initialization */
1002         link->src_addr          = src_addr;
1003         link->dst_addr          = dst_addr;
1004         link->alias_addr        = alias_addr;
1005         link->proxy_addr.s_addr = INADDR_ANY;
1006         link->src_port          = src_port;
1007         link->dst_port          = dst_port;
1008         link->proxy_port        = 0;
1009         link->server            = NULL;
1010         link->link_type         = link_type;
1011         link->sockfd            = -1;
1012         link->flags             = 0;
1013         link->timestamp         = timeStamp;
1014 
1015     /* Expiration time */
1016         switch (link_type)
1017         {
1018         case LINK_ICMP:
1019             link->expire_time = ICMP_EXPIRE_TIME;
1020             break;
1021         case LINK_UDP:
1022             link->expire_time = UDP_EXPIRE_TIME;
1023             break;
1024         case LINK_TCP:
1025             link->expire_time = TCP_EXPIRE_INITIAL;
1026             break;
1027         case LINK_PPTP:
1028             link->flags |= LINK_PERMANENT;	/* no timeout. */
1029             break;
1030         case LINK_FRAGMENT_ID:
1031             link->expire_time = FRAGMENT_ID_EXPIRE_TIME;
1032             break;
1033         case LINK_FRAGMENT_PTR:
1034             link->expire_time = FRAGMENT_PTR_EXPIRE_TIME;
1035             break;
1036 	case LINK_ADDR:
1037 	    break;
1038         default:
1039             link->expire_time = PROTO_EXPIRE_TIME;
1040             break;
1041         }
1042 
1043     /* Determine alias flags */
1044         if (dst_addr.s_addr == INADDR_ANY)
1045             link->flags |= LINK_UNKNOWN_DEST_ADDR;
1046         if (dst_port == 0)
1047             link->flags |= LINK_UNKNOWN_DEST_PORT;
1048 
1049     /* Determine alias port */
1050         if (GetNewPort(link, alias_port_param) != 0)
1051         {
1052             free(link);
1053             return(NULL);
1054         }
1055 
1056     /* Link-type dependent initialization */
1057         switch(link_type)
1058         {
1059             struct tcp_dat  *aux_tcp;
1060 
1061             case LINK_ICMP:
1062                 icmpLinkCount++;
1063                 break;
1064             case LINK_UDP:
1065                 udpLinkCount++;
1066                 break;
1067             case LINK_TCP:
1068                 aux_tcp = malloc(sizeof(struct tcp_dat));
1069                 if (aux_tcp != NULL)
1070                 {
1071                     int i;
1072 
1073                     tcpLinkCount++;
1074                     aux_tcp->state.in = ALIAS_TCP_STATE_NOT_CONNECTED;
1075                     aux_tcp->state.out = ALIAS_TCP_STATE_NOT_CONNECTED;
1076                     aux_tcp->state.index = 0;
1077                     aux_tcp->state.ack_modified = 0;
1078                     for (i=0; i<N_LINK_TCP_DATA; i++)
1079                         aux_tcp->ack[i].active = 0;
1080                     aux_tcp->fwhole = -1;
1081                     link->data.tcp = aux_tcp;
1082                 }
1083                 else
1084                 {
1085 #ifdef DEBUG
1086                     fprintf(stderr, "PacketAlias/AddLink: ");
1087                     fprintf(stderr, " cannot allocate auxiliary TCP data\n");
1088 #endif
1089 		    free(link);
1090 		    return (NULL);
1091                 }
1092                 break;
1093             case LINK_PPTP:
1094                 pptpLinkCount++;
1095                 break;
1096             case LINK_FRAGMENT_ID:
1097                 fragmentIdLinkCount++;
1098                 break;
1099             case LINK_FRAGMENT_PTR:
1100                 fragmentPtrLinkCount++;
1101                 break;
1102 	    case LINK_ADDR:
1103 		break;
1104             default:
1105                 protoLinkCount++;
1106                 break;
1107         }
1108 
1109     /* Set up pointers for output lookup table */
1110         start_point = StartPointOut(src_addr, dst_addr,
1111                                     src_port, dst_port, link_type);
1112         LIST_INSERT_HEAD(&linkTableOut[start_point], link, list_out);
1113 
1114     /* Set up pointers for input lookup table */
1115         start_point = StartPointIn(alias_addr, link->alias_port, link_type);
1116         LIST_INSERT_HEAD(&linkTableIn[start_point], link, list_in);
1117     }
1118     else
1119     {
1120 #ifdef DEBUG
1121         fprintf(stderr, "PacketAlias/AddLink(): ");
1122         fprintf(stderr, "malloc() call failed.\n");
1123 #endif
1124     }
1125 
1126     if (packetAliasMode & PKT_ALIAS_LOG)
1127     {
1128         ShowAliasStats();
1129     }
1130 
1131     return(link);
1132 }
1133 
1134 static struct alias_link *
1135 ReLink(struct alias_link *old_link,
1136        struct in_addr  src_addr,
1137        struct in_addr  dst_addr,
1138        struct in_addr  alias_addr,
1139        u_short         src_port,
1140        u_short         dst_port,
1141        int             alias_port_param,   /* if less than zero, alias   */
1142        int             link_type)          /* port will be automatically */
1143 {                                          /* chosen. If greater than    */
1144     struct alias_link *new_link;           /* zero, equal to alias port  */
1145 
1146     new_link = AddLink(src_addr, dst_addr, alias_addr,
1147                        src_port, dst_port, alias_port_param,
1148                        link_type);
1149 #ifndef NO_FW_PUNCH
1150     if (new_link != NULL &&
1151         old_link->link_type == LINK_TCP &&
1152         old_link->data.tcp->fwhole > 0) {
1153       PunchFWHole(new_link);
1154     }
1155 #endif
1156     DeleteLink(old_link);
1157     return new_link;
1158 }
1159 
1160 static struct alias_link *
1161 _FindLinkOut(struct in_addr src_addr,
1162             struct in_addr dst_addr,
1163             u_short src_port,
1164             u_short dst_port,
1165             int link_type,
1166             int replace_partial_links)
1167 {
1168     u_int i;
1169     struct alias_link *link;
1170 
1171     i = StartPointOut(src_addr, dst_addr, src_port, dst_port, link_type);
1172     LIST_FOREACH(link, &linkTableOut[i], list_out)
1173     {
1174         if (link->src_addr.s_addr == src_addr.s_addr
1175          && link->server          == NULL
1176          && link->dst_addr.s_addr == dst_addr.s_addr
1177          && link->dst_port        == dst_port
1178          && link->src_port        == src_port
1179          && link->link_type       == link_type)
1180         {
1181             link->timestamp = timeStamp;
1182             break;
1183         }
1184     }
1185 
1186 /* Search for partially specified links. */
1187     if (link == NULL && replace_partial_links)
1188     {
1189         if (dst_port != 0 && dst_addr.s_addr != INADDR_ANY)
1190         {
1191             link = _FindLinkOut(src_addr, dst_addr, src_port, 0,
1192                                 link_type, 0);
1193             if (link == NULL)
1194                 link = _FindLinkOut(src_addr, nullAddress, src_port,
1195                                     dst_port, link_type, 0);
1196         }
1197         if (link == NULL &&
1198            (dst_port != 0 || dst_addr.s_addr != INADDR_ANY))
1199         {
1200             link = _FindLinkOut(src_addr, nullAddress, src_port, 0,
1201                                 link_type, 0);
1202         }
1203         if (link != NULL)
1204         {
1205             link = ReLink(link,
1206                           src_addr, dst_addr, link->alias_addr,
1207                           src_port, dst_port, link->alias_port,
1208                           link_type);
1209         }
1210     }
1211 
1212     return(link);
1213 }
1214 
1215 static struct alias_link *
1216 FindLinkOut(struct in_addr src_addr,
1217             struct in_addr dst_addr,
1218             u_short src_port,
1219             u_short dst_port,
1220             int link_type,
1221             int replace_partial_links)
1222 {
1223     struct alias_link *link;
1224 
1225     link = _FindLinkOut(src_addr, dst_addr, src_port, dst_port,
1226                         link_type, replace_partial_links);
1227 
1228     if (link == NULL)
1229     {
1230     /* The following allows permanent links to be
1231        specified as using the default source address
1232        (i.e. device interface address) without knowing
1233        in advance what that address is. */
1234         if (aliasAddress.s_addr != 0 &&
1235             src_addr.s_addr == aliasAddress.s_addr)
1236         {
1237             link = _FindLinkOut(nullAddress, dst_addr, src_port, dst_port,
1238                                link_type, replace_partial_links);
1239         }
1240     }
1241 
1242     return(link);
1243 }
1244 
1245 
1246 static struct alias_link *
1247 _FindLinkIn(struct in_addr dst_addr,
1248            struct in_addr  alias_addr,
1249            u_short         dst_port,
1250            u_short         alias_port,
1251            int             link_type,
1252            int             replace_partial_links)
1253 {
1254     int flags_in;
1255     u_int start_point;
1256     struct alias_link *link;
1257     struct alias_link *link_fully_specified;
1258     struct alias_link *link_unknown_all;
1259     struct alias_link *link_unknown_dst_addr;
1260     struct alias_link *link_unknown_dst_port;
1261 
1262 /* Initialize pointers */
1263     link_fully_specified  = NULL;
1264     link_unknown_all      = NULL;
1265     link_unknown_dst_addr = NULL;
1266     link_unknown_dst_port = NULL;
1267 
1268 /* If either the dest addr or port is unknown, the search
1269    loop will have to know about this. */
1270 
1271     flags_in = 0;
1272     if (dst_addr.s_addr == INADDR_ANY)
1273         flags_in |= LINK_UNKNOWN_DEST_ADDR;
1274     if (dst_port == 0)
1275         flags_in |= LINK_UNKNOWN_DEST_PORT;
1276 
1277 /* Search loop */
1278     start_point = StartPointIn(alias_addr, alias_port, link_type);
1279     LIST_FOREACH(link, &linkTableIn[start_point], list_in)
1280     {
1281         int flags;
1282 
1283         flags = flags_in | link->flags;
1284         if (!(flags & LINK_PARTIALLY_SPECIFIED))
1285         {
1286             if (link->alias_addr.s_addr == alias_addr.s_addr
1287              && link->alias_port        == alias_port
1288              && link->dst_addr.s_addr   == dst_addr.s_addr
1289              && link->dst_port          == dst_port
1290              && link->link_type         == link_type)
1291             {
1292                 link_fully_specified = link;
1293                 break;
1294             }
1295         }
1296         else if ((flags & LINK_UNKNOWN_DEST_ADDR)
1297               && (flags & LINK_UNKNOWN_DEST_PORT))
1298         {
1299             if (link->alias_addr.s_addr == alias_addr.s_addr
1300              && link->alias_port        == alias_port
1301              && link->link_type         == link_type)
1302             {
1303                 if (link_unknown_all == NULL)
1304                     link_unknown_all = link;
1305             }
1306         }
1307         else if (flags & LINK_UNKNOWN_DEST_ADDR)
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              && link->dst_port          == dst_port)
1313             {
1314                 if (link_unknown_dst_addr == NULL)
1315                     link_unknown_dst_addr = link;
1316             }
1317         }
1318         else if (flags & LINK_UNKNOWN_DEST_PORT)
1319         {
1320             if (link->alias_addr.s_addr == alias_addr.s_addr
1321              && link->alias_port        == alias_port
1322              && link->link_type         == link_type
1323              && link->dst_addr.s_addr   == dst_addr.s_addr)
1324             {
1325                 if (link_unknown_dst_port == NULL)
1326                     link_unknown_dst_port = link;
1327             }
1328         }
1329     }
1330 
1331 
1332 
1333     if (link_fully_specified != NULL)
1334     {
1335         link_fully_specified->timestamp = timeStamp;
1336         link = link_fully_specified;
1337     }
1338     else if (link_unknown_dst_port != NULL)
1339 	link = link_unknown_dst_port;
1340     else if (link_unknown_dst_addr != NULL)
1341 	link = link_unknown_dst_addr;
1342     else if (link_unknown_all != NULL)
1343 	link = link_unknown_all;
1344     else
1345         return (NULL);
1346 
1347     if (replace_partial_links &&
1348 	(link->flags & LINK_PARTIALLY_SPECIFIED || link->server != NULL))
1349     {
1350 	struct in_addr src_addr;
1351 	u_short src_port;
1352 
1353 	if (link->server != NULL) {		/* LSNAT link */
1354 	    src_addr = link->server->addr;
1355 	    src_port = link->server->port;
1356 	    link->server = link->server->next;
1357 	} else {
1358 	    src_addr = link->src_addr;
1359 	    src_port = link->src_port;
1360 	}
1361 
1362 	link = ReLink(link,
1363 		      src_addr, dst_addr, alias_addr,
1364 		      src_port, dst_port, alias_port,
1365 		      link_type);
1366     }
1367 
1368     return (link);
1369 }
1370 
1371 static struct alias_link *
1372 FindLinkIn(struct in_addr dst_addr,
1373            struct in_addr alias_addr,
1374            u_short dst_port,
1375            u_short alias_port,
1376            int link_type,
1377            int replace_partial_links)
1378 {
1379     struct alias_link *link;
1380 
1381     link = _FindLinkIn(dst_addr, alias_addr, dst_port, alias_port,
1382                        link_type, replace_partial_links);
1383 
1384     if (link == NULL)
1385     {
1386     /* The following allows permanent links to be
1387        specified as using the default aliasing address
1388        (i.e. device interface address) without knowing
1389        in advance what that address is. */
1390         if (aliasAddress.s_addr != 0 &&
1391             alias_addr.s_addr == aliasAddress.s_addr)
1392         {
1393             link = _FindLinkIn(dst_addr, nullAddress, dst_port, alias_port,
1394                                link_type, replace_partial_links);
1395         }
1396     }
1397 
1398     return(link);
1399 }
1400 
1401 
1402 
1403 
1404 /* External routines for finding/adding links
1405 
1406 -- "external" means outside alias_db.c, but within alias*.c --
1407 
1408     FindIcmpIn(), FindIcmpOut()
1409     FindFragmentIn1(), FindFragmentIn2()
1410     AddFragmentPtrLink(), FindFragmentPtr()
1411     FindProtoIn(), FindProtoOut()
1412     FindUdpTcpIn(), FindUdpTcpOut()
1413     AddPptp(), FindPptpOutByCallId(), FindPptpInByCallId(),
1414     FindPptpOutByPeerCallId(), FindPptpInByPeerCallId()
1415     FindOriginalAddress(), FindAliasAddress()
1416 
1417 (prototypes in alias_local.h)
1418 */
1419 
1420 
1421 struct alias_link *
1422 FindIcmpIn(struct in_addr dst_addr,
1423            struct in_addr alias_addr,
1424            u_short id_alias,
1425            int create)
1426 {
1427     struct alias_link *link;
1428 
1429     link = FindLinkIn(dst_addr, alias_addr,
1430                       NO_DEST_PORT, id_alias,
1431                       LINK_ICMP, 0);
1432     if (link == NULL && create && !(packetAliasMode & PKT_ALIAS_DENY_INCOMING))
1433     {
1434         struct in_addr target_addr;
1435 
1436         target_addr = FindOriginalAddress(alias_addr);
1437         link = AddLink(target_addr, dst_addr, alias_addr,
1438                        id_alias, NO_DEST_PORT, id_alias,
1439                        LINK_ICMP);
1440     }
1441 
1442     return (link);
1443 }
1444 
1445 
1446 struct alias_link *
1447 FindIcmpOut(struct in_addr src_addr,
1448             struct in_addr dst_addr,
1449             u_short id,
1450             int create)
1451 {
1452     struct alias_link * link;
1453 
1454     link = FindLinkOut(src_addr, dst_addr,
1455                        id, NO_DEST_PORT,
1456                        LINK_ICMP, 0);
1457     if (link == NULL && create)
1458     {
1459         struct in_addr alias_addr;
1460 
1461         alias_addr = FindAliasAddress(src_addr);
1462         link = AddLink(src_addr, dst_addr, alias_addr,
1463                        id, NO_DEST_PORT, GET_ALIAS_ID,
1464                        LINK_ICMP);
1465     }
1466 
1467     return(link);
1468 }
1469 
1470 
1471 struct alias_link *
1472 FindFragmentIn1(struct in_addr dst_addr,
1473                 struct in_addr alias_addr,
1474                 u_short ip_id)
1475 {
1476     struct alias_link *link;
1477 
1478     link = FindLinkIn(dst_addr, alias_addr,
1479                       NO_DEST_PORT, ip_id,
1480                       LINK_FRAGMENT_ID, 0);
1481 
1482     if (link == NULL)
1483     {
1484         link = AddLink(nullAddress, dst_addr, alias_addr,
1485                        NO_SRC_PORT, NO_DEST_PORT, ip_id,
1486                        LINK_FRAGMENT_ID);
1487     }
1488 
1489     return(link);
1490 }
1491 
1492 
1493 struct alias_link *
1494 FindFragmentIn2(struct in_addr dst_addr,   /* Doesn't add a link if one */
1495                 struct in_addr alias_addr, /*   is not found.           */
1496                 u_short ip_id)
1497 {
1498     return FindLinkIn(dst_addr, alias_addr,
1499                       NO_DEST_PORT, ip_id,
1500                       LINK_FRAGMENT_ID, 0);
1501 }
1502 
1503 
1504 struct alias_link *
1505 AddFragmentPtrLink(struct in_addr dst_addr,
1506                    u_short ip_id)
1507 {
1508     return AddLink(nullAddress, dst_addr, nullAddress,
1509                    NO_SRC_PORT, NO_DEST_PORT, ip_id,
1510                    LINK_FRAGMENT_PTR);
1511 }
1512 
1513 
1514 struct alias_link *
1515 FindFragmentPtr(struct in_addr dst_addr,
1516                 u_short ip_id)
1517 {
1518     return FindLinkIn(dst_addr, nullAddress,
1519                       NO_DEST_PORT, ip_id,
1520                       LINK_FRAGMENT_PTR, 0);
1521 }
1522 
1523 
1524 struct alias_link *
1525 FindProtoIn(struct in_addr dst_addr,
1526             struct in_addr alias_addr,
1527 	    u_char proto)
1528 {
1529     struct alias_link *link;
1530 
1531     link = FindLinkIn(dst_addr, alias_addr,
1532                       NO_DEST_PORT, 0,
1533                       proto, 1);
1534 
1535     if (link == NULL && !(packetAliasMode & PKT_ALIAS_DENY_INCOMING))
1536     {
1537         struct in_addr target_addr;
1538 
1539         target_addr = FindOriginalAddress(alias_addr);
1540         link = AddLink(target_addr, dst_addr, alias_addr,
1541                        NO_SRC_PORT, NO_DEST_PORT, 0,
1542                        proto);
1543     }
1544 
1545     return (link);
1546 }
1547 
1548 
1549 struct alias_link *
1550 FindProtoOut(struct in_addr src_addr,
1551              struct in_addr dst_addr,
1552              u_char proto)
1553 {
1554     struct alias_link *link;
1555 
1556     link = FindLinkOut(src_addr, dst_addr,
1557                        NO_SRC_PORT, NO_DEST_PORT,
1558                        proto, 1);
1559 
1560     if (link == NULL)
1561     {
1562         struct in_addr alias_addr;
1563 
1564         alias_addr = FindAliasAddress(src_addr);
1565         link = AddLink(src_addr, dst_addr, alias_addr,
1566                        NO_SRC_PORT, NO_DEST_PORT, 0,
1567                        proto);
1568     }
1569 
1570     return (link);
1571 }
1572 
1573 
1574 struct alias_link *
1575 FindUdpTcpIn(struct in_addr dst_addr,
1576              struct in_addr alias_addr,
1577              u_short        dst_port,
1578              u_short        alias_port,
1579              u_char         proto,
1580              int            create)
1581 {
1582     int link_type;
1583     struct alias_link *link;
1584 
1585     switch (proto)
1586     {
1587     case IPPROTO_UDP:
1588         link_type = LINK_UDP;
1589         break;
1590     case IPPROTO_TCP:
1591         link_type = LINK_TCP;
1592         break;
1593     default:
1594         return NULL;
1595         break;
1596     }
1597 
1598     link = FindLinkIn(dst_addr, alias_addr,
1599                       dst_port, alias_port,
1600                       link_type, create);
1601 
1602     if (link == NULL && create && !(packetAliasMode & PKT_ALIAS_DENY_INCOMING))
1603     {
1604         struct in_addr target_addr;
1605 
1606         target_addr = FindOriginalAddress(alias_addr);
1607         link = AddLink(target_addr, dst_addr, alias_addr,
1608                        alias_port, dst_port, alias_port,
1609                        link_type);
1610     }
1611 
1612     return(link);
1613 }
1614 
1615 
1616 struct alias_link *
1617 FindUdpTcpOut(struct in_addr  src_addr,
1618               struct in_addr  dst_addr,
1619               u_short         src_port,
1620               u_short         dst_port,
1621               u_char          proto,
1622               int             create)
1623 {
1624     int link_type;
1625     struct alias_link *link;
1626 
1627     switch (proto)
1628     {
1629     case IPPROTO_UDP:
1630         link_type = LINK_UDP;
1631         break;
1632     case IPPROTO_TCP:
1633         link_type = LINK_TCP;
1634         break;
1635     default:
1636         return NULL;
1637         break;
1638     }
1639 
1640     link = FindLinkOut(src_addr, dst_addr, src_port, dst_port, link_type, create);
1641 
1642     if (link == NULL && create)
1643     {
1644         struct in_addr alias_addr;
1645 
1646         alias_addr = FindAliasAddress(src_addr);
1647         link = AddLink(src_addr, dst_addr, alias_addr,
1648                        src_port, dst_port, GET_ALIAS_PORT,
1649                        link_type);
1650     }
1651 
1652     return(link);
1653 }
1654 
1655 
1656 struct alias_link *
1657 AddPptp(struct in_addr  src_addr,
1658 	struct in_addr  dst_addr,
1659 	struct in_addr  alias_addr,
1660 	u_int16_t       src_call_id)
1661 {
1662     struct alias_link *link;
1663 
1664     link = AddLink(src_addr, dst_addr, alias_addr,
1665 		   src_call_id, 0, GET_ALIAS_PORT,
1666 		   LINK_PPTP);
1667 
1668     return (link);
1669 }
1670 
1671 
1672 struct alias_link *
1673 FindPptpOutByCallId(struct in_addr src_addr,
1674 		    struct in_addr dst_addr,
1675 		    u_int16_t      src_call_id)
1676 {
1677     u_int i;
1678     struct alias_link *link;
1679 
1680     i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP);
1681     LIST_FOREACH(link, &linkTableOut[i], list_out)
1682 	if (link->link_type == LINK_PPTP &&
1683 	    link->src_addr.s_addr == src_addr.s_addr &&
1684 	    link->dst_addr.s_addr == dst_addr.s_addr &&
1685 	    link->src_port == src_call_id)
1686 		break;
1687 
1688     return (link);
1689 }
1690 
1691 
1692 struct alias_link *
1693 FindPptpOutByPeerCallId(struct in_addr src_addr,
1694 			struct in_addr dst_addr,
1695 			u_int16_t      dst_call_id)
1696 {
1697     u_int i;
1698     struct alias_link *link;
1699 
1700     i = StartPointOut(src_addr, dst_addr, 0, 0, LINK_PPTP);
1701     LIST_FOREACH(link, &linkTableOut[i], list_out)
1702 	if (link->link_type == LINK_PPTP &&
1703 	    link->src_addr.s_addr == src_addr.s_addr &&
1704 	    link->dst_addr.s_addr == dst_addr.s_addr &&
1705 	    link->dst_port == dst_call_id)
1706 		break;
1707 
1708     return (link);
1709 }
1710 
1711 
1712 struct alias_link *
1713 FindPptpInByCallId(struct in_addr dst_addr,
1714 		   struct in_addr alias_addr,
1715 		   u_int16_t      dst_call_id)
1716 {
1717     u_int i;
1718     struct alias_link *link;
1719 
1720     i = StartPointIn(alias_addr, 0, LINK_PPTP);
1721     LIST_FOREACH(link, &linkTableIn[i], list_in)
1722 	if (link->link_type == LINK_PPTP &&
1723 	    link->dst_addr.s_addr == dst_addr.s_addr &&
1724 	    link->alias_addr.s_addr == alias_addr.s_addr &&
1725 	    link->dst_port == dst_call_id)
1726 		break;
1727 
1728     return (link);
1729 }
1730 
1731 
1732 struct alias_link *
1733 FindPptpInByPeerCallId(struct in_addr dst_addr,
1734 		       struct in_addr alias_addr,
1735 		       u_int16_t      alias_call_id)
1736 {
1737     struct alias_link *link;
1738 
1739     link = FindLinkIn(dst_addr, alias_addr,
1740 		      0/* any */, alias_call_id,
1741 		      LINK_PPTP, 0);
1742 
1743 
1744     return (link);
1745 }
1746 
1747 
1748 struct alias_link *
1749 FindRtspOut(struct in_addr  src_addr,
1750             struct in_addr  dst_addr,
1751             u_short         src_port,
1752             u_short         alias_port,
1753             u_char          proto)
1754 {
1755     int link_type;
1756     struct alias_link *link;
1757 
1758     switch (proto)
1759     {
1760     case IPPROTO_UDP:
1761         link_type = LINK_UDP;
1762         break;
1763     case IPPROTO_TCP:
1764         link_type = LINK_TCP;
1765         break;
1766     default:
1767         return NULL;
1768         break;
1769     }
1770 
1771     link = FindLinkOut(src_addr, dst_addr, src_port, 0, link_type, 1);
1772 
1773     if (link == NULL)
1774     {
1775         struct in_addr alias_addr;
1776 
1777         alias_addr = FindAliasAddress(src_addr);
1778         link = AddLink(src_addr, dst_addr, alias_addr,
1779                        src_port, 0, alias_port,
1780                        link_type);
1781     }
1782 
1783     return(link);
1784 }
1785 
1786 
1787 struct in_addr
1788 FindOriginalAddress(struct in_addr alias_addr)
1789 {
1790     struct alias_link *link;
1791 
1792     link = FindLinkIn(nullAddress, alias_addr,
1793                       0, 0, LINK_ADDR, 0);
1794     if (link == NULL)
1795     {
1796         newDefaultLink = 1;
1797         if (targetAddress.s_addr == INADDR_ANY)
1798             return alias_addr;
1799         else if (targetAddress.s_addr == INADDR_NONE)
1800             return aliasAddress;
1801         else
1802             return targetAddress;
1803     }
1804     else
1805     {
1806 	if (link->server != NULL) {		/* LSNAT link */
1807 	    struct in_addr src_addr;
1808 
1809 	    src_addr = link->server->addr;
1810 	    link->server = link->server->next;
1811 	    return (src_addr);
1812         } else if (link->src_addr.s_addr == INADDR_ANY)
1813             return aliasAddress;
1814         else
1815             return link->src_addr;
1816     }
1817 }
1818 
1819 
1820 struct in_addr
1821 FindAliasAddress(struct in_addr original_addr)
1822 {
1823     struct alias_link *link;
1824 
1825     link = FindLinkOut(original_addr, nullAddress,
1826                        0, 0, LINK_ADDR, 0);
1827     if (link == NULL)
1828     {
1829         return aliasAddress;
1830     }
1831     else
1832     {
1833         if (link->alias_addr.s_addr == INADDR_ANY)
1834             return aliasAddress;
1835         else
1836             return link->alias_addr;
1837     }
1838 }
1839 
1840 
1841 /* External routines for getting or changing link data
1842    (external to alias_db.c, but internal to alias*.c)
1843 
1844     SetFragmentData(), GetFragmentData()
1845     SetFragmentPtr(), GetFragmentPtr()
1846     SetStateIn(), SetStateOut(), GetStateIn(), GetStateOut()
1847     GetOriginalAddress(), GetDestAddress(), GetAliasAddress()
1848     GetOriginalPort(), GetAliasPort()
1849     SetAckModified(), GetAckModified()
1850     GetDeltaAckIn(), GetDeltaSeqOut(), AddSeq()
1851     SetLastLineCrlfTermed(), GetLastLineCrlfTermed()
1852     SetDestCallId()
1853 */
1854 
1855 
1856 void
1857 SetFragmentAddr(struct alias_link *link, struct in_addr src_addr)
1858 {
1859     link->data.frag_addr = src_addr;
1860 }
1861 
1862 
1863 void
1864 GetFragmentAddr(struct alias_link *link, struct in_addr *src_addr)
1865 {
1866     *src_addr = link->data.frag_addr;
1867 }
1868 
1869 
1870 void
1871 SetFragmentPtr(struct alias_link *link, char *fptr)
1872 {
1873     link->data.frag_ptr = fptr;
1874 }
1875 
1876 
1877 void
1878 GetFragmentPtr(struct alias_link *link, char **fptr)
1879 {
1880    *fptr = link->data.frag_ptr;
1881 }
1882 
1883 
1884 void
1885 SetStateIn(struct alias_link *link, int state)
1886 {
1887     /* TCP input state */
1888     switch (state) {
1889     case ALIAS_TCP_STATE_DISCONNECTED:
1890         if (link->data.tcp->state.out != ALIAS_TCP_STATE_CONNECTED)
1891             link->expire_time = TCP_EXPIRE_DEAD;
1892         else
1893             link->expire_time = TCP_EXPIRE_SINGLEDEAD;
1894         break;
1895     case ALIAS_TCP_STATE_CONNECTED:
1896         if (link->data.tcp->state.out == ALIAS_TCP_STATE_CONNECTED)
1897             link->expire_time = TCP_EXPIRE_CONNECTED;
1898         break;
1899     default:
1900         abort();
1901     }
1902     link->data.tcp->state.in = state;
1903 }
1904 
1905 
1906 void
1907 SetStateOut(struct alias_link *link, int state)
1908 {
1909     /* TCP output state */
1910     switch (state) {
1911     case ALIAS_TCP_STATE_DISCONNECTED:
1912         if (link->data.tcp->state.in != ALIAS_TCP_STATE_CONNECTED)
1913             link->expire_time = TCP_EXPIRE_DEAD;
1914         else
1915             link->expire_time = TCP_EXPIRE_SINGLEDEAD;
1916         break;
1917     case ALIAS_TCP_STATE_CONNECTED:
1918         if (link->data.tcp->state.in == ALIAS_TCP_STATE_CONNECTED)
1919             link->expire_time = TCP_EXPIRE_CONNECTED;
1920         break;
1921     default:
1922         abort();
1923     }
1924     link->data.tcp->state.out = state;
1925 }
1926 
1927 
1928 int
1929 GetStateIn(struct alias_link *link)
1930 {
1931     /* TCP input state */
1932     return link->data.tcp->state.in;
1933 }
1934 
1935 
1936 int
1937 GetStateOut(struct alias_link *link)
1938 {
1939     /* TCP output state */
1940     return link->data.tcp->state.out;
1941 }
1942 
1943 
1944 struct in_addr
1945 GetOriginalAddress(struct alias_link *link)
1946 {
1947     if (link->src_addr.s_addr == INADDR_ANY)
1948         return aliasAddress;
1949     else
1950         return(link->src_addr);
1951 }
1952 
1953 
1954 struct in_addr
1955 GetDestAddress(struct alias_link *link)
1956 {
1957     return(link->dst_addr);
1958 }
1959 
1960 
1961 struct in_addr
1962 GetAliasAddress(struct alias_link *link)
1963 {
1964     if (link->alias_addr.s_addr == INADDR_ANY)
1965         return aliasAddress;
1966     else
1967         return link->alias_addr;
1968 }
1969 
1970 
1971 struct in_addr
1972 GetDefaultAliasAddress(void)
1973 {
1974     return aliasAddress;
1975 }
1976 
1977 
1978 void
1979 SetDefaultAliasAddress(struct in_addr alias_addr)
1980 {
1981     aliasAddress = alias_addr;
1982 }
1983 
1984 
1985 u_short
1986 GetOriginalPort(struct alias_link *link)
1987 {
1988     return(link->src_port);
1989 }
1990 
1991 
1992 u_short
1993 GetAliasPort(struct alias_link *link)
1994 {
1995     return(link->alias_port);
1996 }
1997 
1998 #ifndef NO_FW_PUNCH
1999 static u_short
2000 GetDestPort(struct alias_link *link)
2001 {
2002     return(link->dst_port);
2003 }
2004 #endif
2005 
2006 void
2007 SetAckModified(struct alias_link *link)
2008 {
2009 /* Indicate that ACK numbers have been modified in a TCP connection */
2010     link->data.tcp->state.ack_modified = 1;
2011 }
2012 
2013 
2014 struct in_addr
2015 GetProxyAddress(struct alias_link *link)
2016 {
2017     return link->proxy_addr;
2018 }
2019 
2020 
2021 void
2022 SetProxyAddress(struct alias_link *link, struct in_addr addr)
2023 {
2024     link->proxy_addr = addr;
2025 }
2026 
2027 
2028 u_short
2029 GetProxyPort(struct alias_link *link)
2030 {
2031     return link->proxy_port;
2032 }
2033 
2034 
2035 void
2036 SetProxyPort(struct alias_link *link, u_short port)
2037 {
2038     link->proxy_port = port;
2039 }
2040 
2041 
2042 int
2043 GetAckModified(struct alias_link *link)
2044 {
2045 /* See if ACK numbers have been modified */
2046     return link->data.tcp->state.ack_modified;
2047 }
2048 
2049 
2050 int
2051 GetDeltaAckIn(struct ip *pip, struct alias_link *link)
2052 {
2053 /*
2054 Find out how much the ACK number has been altered for an incoming
2055 TCP packet.  To do this, a circular list of ACK numbers where the TCP
2056 packet size was altered is searched.
2057 */
2058 
2059     int i;
2060     struct tcphdr *tc;
2061     int delta, ack_diff_min;
2062     u_long ack;
2063 
2064     tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
2065     ack      = tc->th_ack;
2066 
2067     delta = 0;
2068     ack_diff_min = -1;
2069     for (i=0; i<N_LINK_TCP_DATA; i++)
2070     {
2071         struct ack_data_record x;
2072 
2073         x = link->data.tcp->ack[i];
2074         if (x.active == 1)
2075         {
2076             int ack_diff;
2077 
2078             ack_diff = SeqDiff(x.ack_new, ack);
2079             if (ack_diff >= 0)
2080             {
2081                 if (ack_diff_min >= 0)
2082                 {
2083                     if (ack_diff < ack_diff_min)
2084                     {
2085                         delta = x.delta;
2086                         ack_diff_min = ack_diff;
2087                     }
2088                 }
2089                 else
2090                 {
2091                     delta = x.delta;
2092                     ack_diff_min = ack_diff;
2093                 }
2094             }
2095         }
2096     }
2097     return (delta);
2098 }
2099 
2100 
2101 int
2102 GetDeltaSeqOut(struct ip *pip, struct alias_link *link)
2103 {
2104 /*
2105 Find out how much the sequence number has been altered for an outgoing
2106 TCP packet.  To do this, a circular list of ACK numbers where the TCP
2107 packet size was altered is searched.
2108 */
2109 
2110     int i;
2111     struct tcphdr *tc;
2112     int delta, seq_diff_min;
2113     u_long seq;
2114 
2115     tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
2116     seq = tc->th_seq;
2117 
2118     delta = 0;
2119     seq_diff_min = -1;
2120     for (i=0; i<N_LINK_TCP_DATA; i++)
2121     {
2122         struct ack_data_record x;
2123 
2124         x = link->data.tcp->ack[i];
2125         if (x.active == 1)
2126         {
2127             int seq_diff;
2128 
2129             seq_diff = SeqDiff(x.ack_old, seq);
2130             if (seq_diff >= 0)
2131             {
2132                 if (seq_diff_min >= 0)
2133                 {
2134                     if (seq_diff < seq_diff_min)
2135                     {
2136                         delta = x.delta;
2137                         seq_diff_min = seq_diff;
2138                     }
2139                 }
2140                 else
2141                 {
2142                     delta = x.delta;
2143                     seq_diff_min = seq_diff;
2144                 }
2145             }
2146         }
2147     }
2148     return (delta);
2149 }
2150 
2151 
2152 void
2153 AddSeq(struct ip *pip, struct alias_link *link, int delta)
2154 {
2155 /*
2156 When a TCP packet has been altered in length, save this
2157 information in a circular list.  If enough packets have
2158 been altered, then this list will begin to overwrite itself.
2159 */
2160 
2161     struct tcphdr *tc;
2162     struct ack_data_record x;
2163     int hlen, tlen, dlen;
2164     int i;
2165 
2166     tc = (struct tcphdr *) ((char *) pip + (pip->ip_hl << 2));
2167 
2168     hlen = (pip->ip_hl + tc->th_off) << 2;
2169     tlen = ntohs(pip->ip_len);
2170     dlen = tlen - hlen;
2171 
2172     x.ack_old = htonl(ntohl(tc->th_seq) + dlen);
2173     x.ack_new = htonl(ntohl(tc->th_seq) + dlen + delta);
2174     x.delta = delta;
2175     x.active = 1;
2176 
2177     i = link->data.tcp->state.index;
2178     link->data.tcp->ack[i] = x;
2179 
2180     i++;
2181     if (i == N_LINK_TCP_DATA)
2182         link->data.tcp->state.index = 0;
2183     else
2184         link->data.tcp->state.index = i;
2185 }
2186 
2187 void
2188 SetExpire(struct alias_link *link, int expire)
2189 {
2190     if (expire == 0)
2191     {
2192         link->flags &= ~LINK_PERMANENT;
2193         DeleteLink(link);
2194     }
2195     else if (expire == -1)
2196     {
2197         link->flags |= LINK_PERMANENT;
2198     }
2199     else if (expire > 0)
2200     {
2201         link->expire_time = expire;
2202     }
2203     else
2204     {
2205 #ifdef DEBUG
2206         fprintf(stderr, "PacketAlias/SetExpire(): ");
2207         fprintf(stderr, "error in expire parameter\n");
2208 #endif
2209     }
2210 }
2211 
2212 void
2213 ClearCheckNewLink(void)
2214 {
2215     newDefaultLink = 0;
2216 }
2217 
2218 void
2219 SetLastLineCrlfTermed(struct alias_link *link, int yes)
2220 {
2221 
2222     if (yes)
2223 	link->flags |= LINK_LAST_LINE_CRLF_TERMED;
2224     else
2225 	link->flags &= ~LINK_LAST_LINE_CRLF_TERMED;
2226 }
2227 
2228 int
2229 GetLastLineCrlfTermed(struct alias_link *link)
2230 {
2231 
2232     return (link->flags & LINK_LAST_LINE_CRLF_TERMED);
2233 }
2234 
2235 void
2236 SetDestCallId(struct alias_link *link, u_int16_t cid)
2237 {
2238 
2239     deleteAllLinks = 1;
2240     link = ReLink(link, link->src_addr, link->dst_addr, link->alias_addr,
2241 		  link->src_port, cid, link->alias_port, link->link_type);
2242     deleteAllLinks = 0;
2243 }
2244 
2245 
2246 /* Miscellaneous Functions
2247 
2248     HouseKeeping()
2249     InitPacketAliasLog()
2250     UninitPacketAliasLog()
2251 */
2252 
2253 /*
2254     Whenever an outgoing or incoming packet is handled, HouseKeeping()
2255     is called to find and remove timed-out aliasing links.  Logic exists
2256     to sweep through the entire table and linked list structure
2257     every 60 seconds.
2258 
2259     (prototype in alias_local.h)
2260 */
2261 
2262 void
2263 HouseKeeping(void)
2264 {
2265     int i, n, n100;
2266     struct timeval tv;
2267     struct timezone tz;
2268 
2269     /*
2270      * Save system time (seconds) in global variable timeStamp for
2271      * use by other functions. This is done so as not to unnecessarily
2272      * waste timeline by making system calls.
2273      */
2274     gettimeofday(&tv, &tz);
2275     timeStamp = tv.tv_sec;
2276 
2277     /* Compute number of spokes (output table link chains) to cover */
2278     n100  = LINK_TABLE_OUT_SIZE * 100 + houseKeepingResidual;
2279     n100 *= timeStamp - lastCleanupTime;
2280     n100 /= ALIAS_CLEANUP_INTERVAL_SECS;
2281 
2282     n = n100/100;
2283 
2284     /* Handle different cases */
2285     if (n > ALIAS_CLEANUP_MAX_SPOKES)
2286     {
2287         n = ALIAS_CLEANUP_MAX_SPOKES;
2288         lastCleanupTime = timeStamp;
2289         houseKeepingResidual = 0;
2290 
2291         for (i=0; i<n; i++)
2292             IncrementalCleanup();
2293     }
2294     else if (n > 0)
2295     {
2296         lastCleanupTime = timeStamp;
2297         houseKeepingResidual = n100 - 100*n;
2298 
2299         for (i=0; i<n; i++)
2300             IncrementalCleanup();
2301     }
2302     else if (n < 0)
2303     {
2304 #ifdef DEBUG
2305         fprintf(stderr, "PacketAlias/HouseKeeping(): ");
2306         fprintf(stderr, "something unexpected in time values\n");
2307 #endif
2308         lastCleanupTime = timeStamp;
2309         houseKeepingResidual = 0;
2310     }
2311 }
2312 
2313 
2314 /* Init the log file and enable logging */
2315 static void
2316 InitPacketAliasLog(void)
2317 {
2318    if ((~packetAliasMode & PKT_ALIAS_LOG)
2319     && (monitorFile = fopen("/var/log/alias.log", "w")))
2320    {
2321       packetAliasMode |= PKT_ALIAS_LOG;
2322       fprintf(monitorFile,
2323       "PacketAlias/InitPacketAliasLog: Packet alias logging enabled.\n");
2324    }
2325 }
2326 
2327 
2328 /* Close the log-file and disable logging. */
2329 static void
2330 UninitPacketAliasLog(void)
2331 {
2332     if (monitorFile) {
2333         fclose(monitorFile);
2334         monitorFile = NULL;
2335     }
2336     packetAliasMode &= ~PKT_ALIAS_LOG;
2337 }
2338 
2339 
2340 
2341 
2342 
2343 
2344 /* Outside world interfaces
2345 
2346 -- "outside world" means other than alias*.c routines --
2347 
2348     PacketAliasRedirectPort()
2349     PacketAliasAddServer()
2350     PacketAliasRedirectProto()
2351     PacketAliasRedirectAddr()
2352     PacketAliasRedirectDelete()
2353     PacketAliasSetAddress()
2354     PacketAliasInit()
2355     PacketAliasUninit()
2356     PacketAliasSetMode()
2357 
2358 (prototypes in alias.h)
2359 */
2360 
2361 /* Redirection from a specific public addr:port to a
2362    private addr:port */
2363 struct alias_link *
2364 PacketAliasRedirectPort(struct in_addr src_addr,   u_short src_port,
2365                         struct in_addr dst_addr,   u_short dst_port,
2366                         struct in_addr alias_addr, u_short alias_port,
2367                         u_char proto)
2368 {
2369     int link_type;
2370     struct alias_link *link;
2371 
2372     switch(proto)
2373     {
2374     case IPPROTO_UDP:
2375         link_type = LINK_UDP;
2376         break;
2377     case IPPROTO_TCP:
2378         link_type = LINK_TCP;
2379         break;
2380     default:
2381 #ifdef DEBUG
2382         fprintf(stderr, "PacketAliasRedirectPort(): ");
2383         fprintf(stderr, "only TCP and UDP protocols allowed\n");
2384 #endif
2385         return NULL;
2386     }
2387 
2388     link = AddLink(src_addr, dst_addr, alias_addr,
2389                    src_port, dst_port, alias_port,
2390                    link_type);
2391 
2392     if (link != NULL)
2393     {
2394         link->flags |= LINK_PERMANENT;
2395     }
2396 #ifdef DEBUG
2397     else
2398     {
2399         fprintf(stderr, "PacketAliasRedirectPort(): "
2400                         "call to AddLink() failed\n");
2401     }
2402 #endif
2403 
2404     return link;
2405 }
2406 
2407 /* Add server to the pool of servers */
2408 int
2409 PacketAliasAddServer(struct alias_link *link, struct in_addr addr, u_short port)
2410 {
2411     struct server *server;
2412 
2413     server = malloc(sizeof(struct server));
2414 
2415     if (server != NULL) {
2416 	struct server *head;
2417 
2418 	server->addr = addr;
2419 	server->port = port;
2420 
2421 	head = link->server;
2422 	if (head == NULL)
2423 	    server->next = server;
2424 	else {
2425 	    struct server *s;
2426 
2427 	    for (s = head; s->next != head; s = s->next);
2428 	    s->next = server;
2429 	    server->next = head;
2430 	}
2431 	link->server = server;
2432 	return (0);
2433     } else
2434 	return (-1);
2435 }
2436 
2437 /* Redirect packets of a given IP protocol from a specific
2438    public address to a private address */
2439 struct alias_link *
2440 PacketAliasRedirectProto(struct in_addr src_addr,
2441                          struct in_addr dst_addr,
2442                          struct in_addr alias_addr,
2443                          u_char proto)
2444 {
2445     struct alias_link *link;
2446 
2447     link = AddLink(src_addr, dst_addr, alias_addr,
2448                    NO_SRC_PORT, NO_DEST_PORT, 0,
2449                    proto);
2450 
2451     if (link != NULL)
2452     {
2453         link->flags |= LINK_PERMANENT;
2454     }
2455 #ifdef DEBUG
2456     else
2457     {
2458         fprintf(stderr, "PacketAliasRedirectProto(): "
2459                         "call to AddLink() failed\n");
2460     }
2461 #endif
2462 
2463     return link;
2464 }
2465 
2466 /* Static address translation */
2467 struct alias_link *
2468 PacketAliasRedirectAddr(struct in_addr src_addr,
2469                         struct in_addr alias_addr)
2470 {
2471     struct alias_link *link;
2472 
2473     link = AddLink(src_addr, nullAddress, alias_addr,
2474                    0, 0, 0,
2475                    LINK_ADDR);
2476 
2477     if (link != NULL)
2478     {
2479         link->flags |= LINK_PERMANENT;
2480     }
2481 #ifdef DEBUG
2482     else
2483     {
2484         fprintf(stderr, "PacketAliasRedirectAddr(): "
2485                         "call to AddLink() failed\n");
2486     }
2487 #endif
2488 
2489     return link;
2490 }
2491 
2492 
2493 void
2494 PacketAliasRedirectDelete(struct alias_link *link)
2495 {
2496 /* This is a dangerous function to put in the API,
2497    because an invalid pointer can crash the program. */
2498 
2499     deleteAllLinks = 1;
2500     DeleteLink(link);
2501     deleteAllLinks = 0;
2502 }
2503 
2504 
2505 void
2506 PacketAliasSetAddress(struct in_addr addr)
2507 {
2508     if (packetAliasMode & PKT_ALIAS_RESET_ON_ADDR_CHANGE
2509      && aliasAddress.s_addr != addr.s_addr)
2510         CleanupAliasData();
2511 
2512     aliasAddress = addr;
2513 }
2514 
2515 
2516 void
2517 PacketAliasSetTarget(struct in_addr target_addr)
2518 {
2519     targetAddress = target_addr;
2520 }
2521 
2522 
2523 void
2524 PacketAliasInit(void)
2525 {
2526     int i;
2527     struct timeval tv;
2528     struct timezone tz;
2529     static int firstCall = 1;
2530 
2531     if (firstCall == 1)
2532     {
2533         gettimeofday(&tv, &tz);
2534         timeStamp = tv.tv_sec;
2535         lastCleanupTime = tv.tv_sec;
2536         houseKeepingResidual = 0;
2537 
2538         for (i=0; i<LINK_TABLE_OUT_SIZE; i++)
2539             LIST_INIT(&linkTableOut[i]);
2540         for (i=0; i<LINK_TABLE_IN_SIZE; i++)
2541             LIST_INIT(&linkTableIn[i]);
2542 
2543         atexit(PacketAliasUninit);
2544         firstCall = 0;
2545     }
2546     else
2547     {
2548         deleteAllLinks = 1;
2549         CleanupAliasData();
2550         deleteAllLinks = 0;
2551     }
2552 
2553     aliasAddress.s_addr = INADDR_ANY;
2554     targetAddress.s_addr = INADDR_ANY;
2555 
2556     icmpLinkCount = 0;
2557     udpLinkCount = 0;
2558     tcpLinkCount = 0;
2559     pptpLinkCount = 0;
2560     protoLinkCount = 0;
2561     fragmentIdLinkCount = 0;
2562     fragmentPtrLinkCount = 0;
2563     sockCount = 0;
2564 
2565     cleanupIndex =0;
2566 
2567     packetAliasMode = PKT_ALIAS_SAME_PORTS
2568                     | PKT_ALIAS_USE_SOCKETS
2569                     | PKT_ALIAS_RESET_ON_ADDR_CHANGE;
2570 }
2571 
2572 void
2573 PacketAliasUninit(void) {
2574     deleteAllLinks = 1;
2575     CleanupAliasData();
2576     deleteAllLinks = 0;
2577     UninitPacketAliasLog();
2578 #ifndef NO_FW_PUNCH
2579     UninitPunchFW();
2580 #endif
2581 }
2582 
2583 
2584 /* Change mode for some operations */
2585 unsigned int
2586 PacketAliasSetMode(
2587     unsigned int flags, /* Which state to bring flags to */
2588     unsigned int mask   /* Mask of which flags to affect (use 0 to do a
2589                            probe for flag values) */
2590 )
2591 {
2592 /* Enable logging? */
2593     if (flags & mask & PKT_ALIAS_LOG)
2594     {
2595         InitPacketAliasLog();     /* Do the enable */
2596     } else
2597 /* _Disable_ logging? */
2598     if (~flags & mask & PKT_ALIAS_LOG) {
2599         UninitPacketAliasLog();
2600     }
2601 
2602 #ifndef NO_FW_PUNCH
2603 /* Start punching holes in the firewall? */
2604     if (flags & mask & PKT_ALIAS_PUNCH_FW) {
2605         InitPunchFW();
2606     } else
2607 /* Stop punching holes in the firewall? */
2608     if (~flags & mask & PKT_ALIAS_PUNCH_FW) {
2609         UninitPunchFW();
2610     }
2611 #endif
2612 
2613 /* Other flags can be set/cleared without special action */
2614     packetAliasMode = (flags & mask) | (packetAliasMode & ~mask);
2615     return packetAliasMode;
2616 }
2617 
2618 
2619 int
2620 PacketAliasCheckNewLink(void)
2621 {
2622     return newDefaultLink;
2623 }
2624 
2625 
2626 #ifndef NO_FW_PUNCH
2627 
2628 /*****************
2629   Code to support firewall punching.  This shouldn't really be in this
2630   file, but making variables global is evil too.
2631   ****************/
2632 
2633 /* Firewall include files */
2634 #include <net/if.h>
2635 #include <net/ipfw/ip_fw.h>
2636 #include <string.h>
2637 #include <err.h>
2638 
2639 /*
2640  * helper function, updates the pointer to cmd with the length
2641  * of the current command, and also cleans up the first word of
2642  * the new command in case it has been clobbered before.
2643  */
2644 static ipfw_insn *
2645 next_cmd(ipfw_insn *cmd)
2646 {
2647     cmd += F_LEN(cmd);
2648     bzero(cmd, sizeof(*cmd));
2649     return cmd;
2650 }
2651 
2652 /*
2653  * A function to fill simple commands of size 1.
2654  * Existing flags are preserved.
2655  */
2656 static ipfw_insn *
2657 fill_cmd(ipfw_insn *cmd, enum ipfw_opcodes opcode, int size,
2658 	 int flags, u_int16_t arg)
2659 {
2660     cmd->opcode = opcode;
2661     cmd->len =  ((cmd->len | flags) & (F_NOT | F_OR)) | (size & F_LEN_MASK);
2662     cmd->arg1 = arg;
2663     return next_cmd(cmd);
2664 }
2665 
2666 static ipfw_insn *
2667 fill_ip(ipfw_insn *cmd1, enum ipfw_opcodes opcode, u_int32_t addr)
2668 {
2669     ipfw_insn_ip *cmd = (ipfw_insn_ip *)cmd1;
2670 
2671     cmd->addr.s_addr = addr;
2672     return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u32), 0, 0);
2673 }
2674 
2675 static ipfw_insn *
2676 fill_one_port(ipfw_insn *cmd1, enum ipfw_opcodes opcode, u_int16_t port)
2677 {
2678     ipfw_insn_u16 *cmd = (ipfw_insn_u16 *)cmd1;
2679 
2680     cmd->ports[0] = cmd->ports[1] = port;
2681     return fill_cmd(cmd1, opcode, F_INSN_SIZE(ipfw_insn_u16), 0, 0);
2682 }
2683 
2684 static int
2685 fill_rule(void *buf, int bufsize, int rulenum,
2686 	enum ipfw_opcodes action, int proto,
2687 	struct in_addr sa, u_int16_t sp, struct in_addr da, u_int16_t dp)
2688 {
2689     struct ipfw_ioc_rule *rule = buf;
2690     ipfw_insn *cmd = (ipfw_insn *)rule->cmd;
2691 
2692     bzero(buf, bufsize);
2693     rule->rulenum = rulenum;
2694 
2695     cmd = fill_cmd(cmd, O_PROTO, F_INSN_SIZE(ipfw_insn), 0, proto);
2696     cmd = fill_ip(cmd, O_IP_SRC, sa.s_addr);
2697     cmd = fill_one_port(cmd, O_IP_SRCPORT, sp);
2698     cmd = fill_ip(cmd, O_IP_DST, da.s_addr);
2699     cmd = fill_one_port(cmd, O_IP_DSTPORT, dp);
2700 
2701     rule->act_ofs = (u_int32_t *)cmd - (u_int32_t *)rule->cmd;
2702     cmd = fill_cmd(cmd, action, F_INSN_SIZE(ipfw_insn), 0, 0);
2703 
2704     rule->cmd_len = (u_int32_t *)cmd - (u_int32_t *)rule->cmd;
2705 
2706     return ((void *)cmd - buf);
2707 }
2708 
2709 static void ClearAllFWHoles(void);
2710 
2711 static int fireWallBaseNum;     /* The first firewall entry free for our use */
2712 static int fireWallNumNums;     /* How many entries can we use? */
2713 static int fireWallActiveNum;   /* Which entry did we last use? */
2714 static char *fireWallField;     /* bool array for entries */
2715 
2716 #define fw_setfield(field, num)                         \
2717 do {                                                    \
2718     (field)[(num) - fireWallBaseNum] = 1;               \
2719 } /*lint -save -e717 */ while(0) /*lint -restore */
2720 #define fw_clrfield(field, num)                         \
2721 do {                                                    \
2722     (field)[(num) - fireWallBaseNum] = 0;               \
2723 } /*lint -save -e717 */ while(0) /*lint -restore */
2724 #define fw_tstfield(field, num) ((field)[(num) - fireWallBaseNum])
2725 
2726 static void
2727 InitPunchFW(void) {
2728     fireWallField = malloc(fireWallNumNums);
2729     if (fireWallField) {
2730         memset(fireWallField, 0, fireWallNumNums);
2731         if (fireWallFD < 0) {
2732             fireWallFD = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
2733         }
2734         ClearAllFWHoles();
2735         fireWallActiveNum = fireWallBaseNum;
2736     }
2737 }
2738 
2739 static void
2740 UninitPunchFW(void) {
2741     ClearAllFWHoles();
2742     if (fireWallFD >= 0)
2743         close(fireWallFD);
2744     fireWallFD = -1;
2745     if (fireWallField)
2746         free(fireWallField);
2747     fireWallField = NULL;
2748     packetAliasMode &= ~PKT_ALIAS_PUNCH_FW;
2749 }
2750 
2751 /* Make a certain link go through the firewall */
2752 void
2753 PunchFWHole(struct alias_link *link) {
2754     int r;                      /* Result code */
2755     int fwhole;                 /* Where to punch hole */
2756 
2757 /* Don't do anything unless we are asked to */
2758     if ( !(packetAliasMode & PKT_ALIAS_PUNCH_FW) ||
2759          fireWallFD < 0 ||
2760          link->link_type != LINK_TCP)
2761         return;
2762 
2763 /** Build rule **/
2764 
2765     /* Find empty slot */
2766     for (fwhole = fireWallActiveNum;
2767          fwhole < fireWallBaseNum + fireWallNumNums &&
2768              fw_tstfield(fireWallField, fwhole);
2769          fwhole++)
2770         ;
2771     if (fwhole == fireWallBaseNum + fireWallNumNums) {
2772         for (fwhole = fireWallBaseNum;
2773              fwhole < fireWallActiveNum &&
2774                  fw_tstfield(fireWallField, fwhole);
2775              fwhole++)
2776             ;
2777         if (fwhole == fireWallActiveNum) {
2778             /* No rule point empty - we can't punch more holes. */
2779             fireWallActiveNum = fireWallBaseNum;
2780 #ifdef DEBUG
2781             fprintf(stderr, "libalias: Unable to create firewall hole!\n");
2782 #endif
2783             return;
2784         }
2785     }
2786     /* Start next search at next position */
2787     fireWallActiveNum = fwhole+1;
2788 
2789     /*
2790      * generate two rules of the form
2791      *
2792      *	add fwhole accept tcp from OAddr OPort to DAddr DPort
2793      *	add fwhole accept tcp from DAddr DPort to OAddr OPort
2794      */
2795     if (GetOriginalPort(link) != 0 && GetDestPort(link) != 0) {
2796 	u_int32_t rulebuf[IPFW_RULE_SIZE_MAX];
2797 	int i;
2798 
2799 	i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
2800 		O_ACCEPT, IPPROTO_TCP,
2801 		GetOriginalAddress(link), ntohs(GetOriginalPort(link)),
2802 		GetDestAddress(link), ntohs(GetDestPort(link)) );
2803 	r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
2804 	if (r)
2805 		err(1, "alias punch inbound(1) setsockopt(IP_FW_ADD)");
2806 
2807 	i = fill_rule(rulebuf, sizeof(rulebuf), fwhole,
2808 		O_ACCEPT, IPPROTO_TCP,
2809 		GetDestAddress(link), ntohs(GetDestPort(link)),
2810 		GetOriginalAddress(link), ntohs(GetOriginalPort(link)) );
2811 	r = setsockopt(fireWallFD, IPPROTO_IP, IP_FW_ADD, rulebuf, i);
2812 	if (r)
2813 		err(1, "alias punch inbound(2) setsockopt(IP_FW_ADD)");
2814     }
2815 /* Indicate hole applied */
2816     link->data.tcp->fwhole = fwhole;
2817     fw_setfield(fireWallField, fwhole);
2818 }
2819 
2820 /* Remove a hole in a firewall associated with a particular alias
2821    link.  Calling this too often is harmless. */
2822 static void
2823 ClearFWHole(struct alias_link *link) {
2824     if (link->link_type == LINK_TCP) {
2825         int fwhole =  link->data.tcp->fwhole; /* Where is the firewall hole? */
2826 
2827 	if (fwhole < 0)
2828 	    return;
2829 
2830 	while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL,
2831 		    &fwhole, sizeof fwhole))
2832 	    ;
2833         fw_clrfield(fireWallField, fwhole);
2834         link->data.tcp->fwhole = -1;
2835     }
2836 }
2837 
2838 /* Clear out the entire range dedicated to firewall holes. */
2839 static void
2840 ClearAllFWHoles(void) {
2841     int i;
2842 
2843     if (fireWallFD < 0)
2844         return;
2845 
2846     for (i = fireWallBaseNum; i < fireWallBaseNum + fireWallNumNums; i++) {
2847 	int r = i;
2848 	while (!setsockopt(fireWallFD, IPPROTO_IP, IP_FW_DEL, &r, sizeof r))
2849 	    ;
2850     }
2851     memset(fireWallField, 0, fireWallNumNums);
2852 }
2853 #endif
2854 
2855 void
2856 PacketAliasSetFWBase(unsigned int base, unsigned int num) {
2857 #ifndef NO_FW_PUNCH
2858     fireWallBaseNum = base;
2859     fireWallNumNums = num;
2860 #endif
2861 }
2862