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