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