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