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