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