xref: /freebsd/sys/netinet/libalias/alias_db.h (revision 5180fce1cf7ec7430ccf2adb88358602e5ccee1e)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2001 Charles Mott <cm@linktel.net>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 /*
30     Alias_db.c encapsulates all data structures used for storing
31     packet aliasing data.  Other parts of the aliasing software
32     access data through functions provided in this file.
33 
34     Data storage is based on the notion of a "link", which is
35     established for ICMP echo/reply packets, UDP datagrams and
36     TCP stream connections.  A link stores the original source
37     and destination addresses.  For UDP and TCP, it also stores
38     source and destination port numbers, as well as an alias
39     port number.  Links are also used to store information about
40     fragments.
41 
42     There is a facility for sweeping through and deleting old
43     links as new packets are sent through.  A simple timeout is
44     used for ICMP and UDP links.  TCP links are left alone unless
45     there is an incomplete connection, in which case the link
46     can be deleted after a certain amount of time.
47 
48     Initial version: August, 1996  (cjm)
49 
50     Version 1.4: September 16, 1996 (cjm)
51 	Facility for handling incoming links added.
52 
53     Version 1.6: September 18, 1996 (cjm)
54 	ICMP data handling simplified.
55 
56     Version 1.7: January 9, 1997 (cjm)
57 	Fragment handling simplified.
58 	Saves pointers for unresolved fragments.
59 	Permits links for unspecified remote ports
60 	  or unspecified remote addresses.
61 	Fixed bug which did not properly zero port
62 	  table entries after a link was deleted.
63 	Cleaned up some obsolete comments.
64 
65     Version 1.8: January 14, 1997 (cjm)
66 	Fixed data type error in StartPoint().
67 	(This error did not exist prior to v1.7
68 	and was discovered and fixed by Ari Suutari)
69 
70     Version 1.9: February 1, 1997
71 	Optionally, connections initiated from packet aliasing host
72 	machine will will not have their port number aliased unless it
73 	conflicts with an aliasing port already being used. (cjm)
74 
75 	All options earlier being #ifdef'ed are now available through
76 	a new interface, SetPacketAliasMode().  This allows run time
77 	control (which is now available in PPP+pktAlias through the
78 	'alias' keyword). (ee)
79 
80 	Added ability to create an alias port without
81 	either destination address or port specified.
82 	port type = ALIAS_PORT_UNKNOWN_DEST_ALL (ee)
83 
84 	Removed K&R style function headers
85 	and general cleanup. (ee)
86 
87 	Added packetAliasMode to replace compiler #defines's (ee)
88 
89 	Allocates sockets for partially specified
90 	ports if ALIAS_USE_SOCKETS defined. (cjm)
91 
92     Version 2.0: March, 1997
93 	SetAliasAddress() will now clean up alias links
94 	if the aliasing address is changed. (cjm)
95 
96 	PacketAliasPermanentLink() function added to support permanent
97 	links.  (J. Fortes suggested the need for this.)
98 	Examples:
99 
100 	(192.168.0.1, port 23)  <-> alias port 6002, unknown dest addr/port
101 
102 	(192.168.0.2, port 21)  <-> alias port 3604, known dest addr
103 						     unknown dest port
104 
105 	These permanent links allow for incoming connections to
106 	machines on the local network.  They can be given with a
107 	user-chosen amount of specificity, with increasing specificity
108 	meaning more security. (cjm)
109 
110 	Quite a bit of rework to the basic engine.  The portTable[]
111 	array, which kept track of which ports were in use was replaced
112 	by a table/linked list structure. (cjm)
113 
114 	SetExpire() function added. (cjm)
115 
116 	DeleteLink() no longer frees memory association with a pointer
117 	to a fragment (this bug was first recognized by E. Eklund in
118 	v1.9).
119 
120     Version 2.1: May, 1997 (cjm)
121 	Packet aliasing engine reworked so that it can handle
122 	multiple external addresses rather than just a single
123 	host address.
124 
125 	PacketAliasRedirectPort() and PacketAliasRedirectAddr()
126 	added to the API.  The first function is a more generalized
127 	version of PacketAliasPermanentLink().  The second function
128 	implements static network address translation.
129 
130     Version 3.2: July, 2000 (salander and satoh)
131 	Added FindNewPortGroup to get contiguous range of port values.
132 
133 	Added QueryUdpTcpIn and QueryUdpTcpOut to look for an aliasing
134 	link but not actually add one.
135 
136 	Added FindRtspOut, which is closely derived from FindUdpTcpOut,
137 	except that the alias port (from FindNewPortGroup) is provided
138 	as input.
139 
140     See HISTORY file for additional revisions.
141 */
142 
143 #ifndef _ALIAS_DB_H_
144 #define _ALIAS_DB_H_
145 
146 
147 /*
148    Constants (note: constants are also defined
149 	      near relevant functions or structs)
150 */
151 
152 /* Timeouts (in seconds) for different link types */
153 #define ICMP_EXPIRE_TIME             60
154 #define UDP_EXPIRE_TIME              60
155 #define PROTO_EXPIRE_TIME            60
156 #define FRAGMENT_ID_EXPIRE_TIME      10
157 #define FRAGMENT_PTR_EXPIRE_TIME     30
158 
159 /* TCP link expire time for different cases */
160 /* When the link has been used and closed - minimal grace time to
161    allow ACKs and potential re-connect in FTP (XXX - is this allowed?)  */
162 #ifndef TCP_EXPIRE_DEAD
163 #define TCP_EXPIRE_DEAD           10
164 #endif
165 
166 /* When the link has been used and closed on one side - the other side
167    is allowed to still send data */
168 #ifndef TCP_EXPIRE_SINGLEDEAD
169 #define TCP_EXPIRE_SINGLEDEAD     90
170 #endif
171 
172 /* When the link isn't yet up */
173 #ifndef TCP_EXPIRE_INITIAL
174 #define TCP_EXPIRE_INITIAL       300
175 #endif
176 
177 /* When the link is up */
178 #ifndef TCP_EXPIRE_CONNECTED
179 #define TCP_EXPIRE_CONNECTED   86400
180 #endif
181 
182 /* Dummy port number codes used for FindLinkIn/Out() and AddLink().
183    These constants can be anything except zero, which indicates an
184    unknown port number. */
185 
186 #define NO_DEST_PORT     1
187 #define NO_SRC_PORT      1
188 
189 /* Matches any/unknown address in FindLinkIn/Out() and AddLink(). */
190 static struct in_addr const ANY_ADDR = { INADDR_ANY };
191 
192 /* Data Structures
193 
194     The fundamental data structure used in this program is
195     "struct alias_link".  Whenever a TCP connection is made,
196     a UDP datagram is sent out, or an ICMP echo request is made,
197     a link record is made (if it has not already been created).
198     The link record is identified by the source address/port
199     and the destination address/port. In the case of an ICMP
200     echo request, the source port is treated as being equivalent
201     with the 16-bit ID number of the ICMP packet.
202 
203     The link record also can store some auxiliary data.  For
204     TCP connections that have had sequence and acknowledgment
205     modifications, data space is available to track these changes.
206     A state field is used to keep track in changes to the TCP
207     connection state.  ID numbers of fragments can also be
208     stored in the auxiliary space.  Pointers to unresolved
209     fragments can also be stored.
210 
211     The link records support several independent chainings.  Lookup
212     tables for input and out tables hold the initial pointers
213     the link chains.  On input, the lookup table indexes on alias
214     port and link type.  On output, the lookup table indexes on
215     source address, destination address, source port, destination
216     port and link type. A internal_endpoint table is used for
217     endpoint-independent mapping, and indexes on source address,
218     source port and link type.
219 */
220 
221 /* used to save changes to ACK/sequence numbers */
222 struct ack_data_record {
223 	u_long		ack_old;
224 	u_long		ack_new;
225 	int		delta;
226 	int		active;
227 };
228 
229 /* Information about TCP connection */
230 struct tcp_state {
231 	int		in;	/* State for outside -> inside */
232 	int		out;	/* State for inside  -> outside */
233 	int		index;	/* Index to ACK data array */
234 	/* Indicates whether ACK and sequence numbers been modified */
235 	int		ack_modified;
236 };
237 
238 /* Number of distinct ACK number changes
239  * saved for a modified TCP stream */
240 #define N_LINK_TCP_DATA   3
241 struct tcp_dat {
242 	struct tcp_state state;
243 	struct ack_data_record ack[N_LINK_TCP_DATA];
244 	/* Which firewall record is used for this hole? */
245 	int		fwhole;
246 };
247 
248 /* LSNAT server pool (circular list) */
249 struct server {
250 	struct in_addr	addr;
251 	u_short		port;
252 	struct server  *next;
253 };
254 
255 /* Main data structure */
256 struct alias_link {
257 	struct libalias *la;
258 	/* Address and port information */
259 	struct in_addr	src_addr;
260 	struct in_addr	dst_addr;
261 	struct in_addr	alias_addr;
262 	struct in_addr	proxy_addr;
263 	u_short		src_port;
264 	u_short		dst_port;
265 	u_short		alias_port;
266 	u_short		proxy_port;
267 	struct server  *server;
268 	/* Type of link: TCP, UDP, ICMP, proto, frag */
269 	int		link_type;
270 /* values for link_type */
271 #define LINK_ICMP                     IPPROTO_ICMP
272 #define LINK_UDP                      IPPROTO_UDP
273 #define LINK_TCP                      IPPROTO_TCP
274 #define LINK_FRAGMENT_ID              (IPPROTO_MAX + 1)
275 #define LINK_FRAGMENT_PTR             (IPPROTO_MAX + 2)
276 #define LINK_ADDR                     (IPPROTO_MAX + 3)
277 #define LINK_PPTP                     (IPPROTO_MAX + 4)
278 
279 	int		flags;	/* indicates special characteristics */
280 	int		pflags;	/* protocol-specific flags */
281 /* flag bits */
282 #define LINK_UNKNOWN_DEST_PORT     0x01
283 #define LINK_UNKNOWN_DEST_ADDR     0x02
284 #define LINK_PERMANENT             0x04
285 #define LINK_PARTIALLY_SPECIFIED   0x03	/* logical-or of first two bits */
286 #define LINK_UNFIREWALLED          0x08
287 
288 	int		timestamp;	/* Time link was last accessed */
289 	uint64_t	seq;		/* Insertion order within the instance */
290 #ifndef NO_USE_SOCKETS
291 	int		sockfd;		/* socket descriptor */
292 #endif
293 	/* Linked list of pointers for input and output lookup tables  */
294 	union {
295 		struct {
296 			SPLAY_ENTRY(alias_link) out;
297 			union {
298 				/* in grp->partial */
299 				LIST_ENTRY (alias_link) in;
300 				/* in grp->full */
301 				RB_ENTRY(alias_link) in_full;
302 			};
303 			SPLAY_ENTRY(alias_link) internal_endpoint;
304 		} all;
305 		struct {
306 			LIST_ENTRY (alias_link) list;
307 		} pptp;
308 	};
309 	struct {
310 		TAILQ_ENTRY(alias_link) list;
311 		int	time;	/* Expire time for link */
312 	} expire;
313 	/* Auxiliary data */
314 	union {
315 		char           *frag_ptr;
316 		struct in_addr	frag_addr;
317 		struct tcp_dat *tcp;
318 	} data;
319 };
320 
321 /* Clean up procedure. */
322 static void finishoff(void);
323 
324 /* Internal utility routines (used only in alias_db.c)
325 
326 Lookup table starting points:
327     StartPointIn()           -- link table initial search point for
328 				incoming packets
329     StartPointOut()          -- link table initial search point for
330 				outgoing packets
331 
332 Miscellaneous:
333     SeqDiff()                -- difference between two TCP sequences
334     ShowAliasStats()         -- send alias statistics to a monitor file
335 */
336 
337 /* Local prototypes */
338 static struct group_in *
339 StartPointIn(struct libalias *, struct in_addr, u_short, int, int);
340 static int	SeqDiff(u_long, u_long);
341 
342 #ifndef NO_FW_PUNCH
343 /* Firewall control */
344 static void	InitPunchFW(struct libalias *);
345 static void	UninitPunchFW(struct libalias *);
346 static void	ClearFWHole(struct alias_link *);
347 
348 #endif
349 
350 /* Log file control */
351 static void	ShowAliasStats(struct libalias *);
352 static int	InitPacketAliasLog(struct libalias *);
353 static void	UninitPacketAliasLog(struct libalias *);
354 
355 void		SctpShowAliasStats(struct libalias *la);
356 
357 
358 /* Splay handling */
359 static inline int
360 cmp_out(struct alias_link *a, struct alias_link *b) {
361 	int i = a->src_port - b->src_port;
362 	if (i != 0) return (i);
363 	if (a->src_addr.s_addr > b->src_addr.s_addr) return (1);
364 	if (a->src_addr.s_addr < b->src_addr.s_addr) return (-1);
365 	if (a->dst_addr.s_addr > b->dst_addr.s_addr) return (1);
366 	if (a->dst_addr.s_addr < b->dst_addr.s_addr) return (-1);
367 	i = a->dst_port - b->dst_port;
368 	if (i != 0) return (i);
369 	i = a->link_type - b->link_type;
370 	return (i);
371 }
372 SPLAY_PROTOTYPE(splay_out, alias_link, all.out, cmp_out);
373 
374 static inline int
375 cmp_in(struct group_in *a, struct group_in *b) {
376 	int i = a->alias_port - b->alias_port;
377 	if (i != 0) return (i);
378 	i = a->link_type - b->link_type;
379 	if (i != 0) return (i);
380 	if (a->alias_addr.s_addr > b->alias_addr.s_addr) return (1);
381 	if (a->alias_addr.s_addr < b->alias_addr.s_addr) return (-1);
382 	return (0);
383 }
384 SPLAY_PROTOTYPE(splay_in, group_in, in, cmp_in);
385 
386 static inline int
387 cmp_internal_endpoint(struct alias_link *a, struct alias_link *b) {
388 	int i = a->link_type - b->link_type;
389 	if (i != 0) return (i);
390 	if (a->src_addr.s_addr > b->src_addr.s_addr) return (1);
391 	if (a->src_addr.s_addr < b->src_addr.s_addr) return (-1);
392 	i = a->src_port - b->src_port;
393 	return (i);
394 }
395 SPLAY_PROTOTYPE(splay_internal_endpoint, alias_link, all.internal_endpoint,
396     cmp_internal_endpoint);
397 
398 /* Internal routines for finding, deleting and adding links
399 
400 Port Allocation:
401     GetNewPort()                 -- find and reserve new alias port number
402     GetSocket()                  -- try to allocate a socket for a given port
403 
404 Link creation and deletion:
405     CleanupAliasData()           - remove all link chains from lookup table
406     CleanupLink()                - look for a stale link
407     DeleteLink()                 - remove link
408     AddLink()                    - add link
409     ReLink()                     - change link
410 
411 Link search:
412     FindLinkOut()                - find link for outgoing packets
413     FindLinkIn()                 - find link for incoming packets
414     FindLinkByInternalEndpoint() - find link by a packet's internal endpoint
415 
416 Port search:
417     FindNewPortGroup()           - find an available group of ports
418 */
419 
420 /* Local prototypes */
421 static int	GetNewPort(struct libalias *, struct alias_link *, int);
422 #ifndef NO_USE_SOCKETS
423 static u_short	GetSocket(struct libalias *, u_short, int *, int);
424 #endif
425 static void	CleanupAliasData(struct libalias *, int);
426 static void	CleanupLink(struct libalias *, struct alias_link **, int);
427 static void	DeleteLink(struct alias_link **, int);
428 static struct alias_link *
429 UseLink(struct libalias *, struct alias_link *);
430 
431 static struct alias_link *
432 ReLink(struct alias_link *,
433     struct in_addr, struct in_addr, struct in_addr,
434     u_short, u_short, int, int, int);
435 
436 static struct alias_link *
437 FindLinkOut(struct libalias *, struct in_addr, struct in_addr, u_short, u_short, int, int);
438 
439 static struct alias_link *
440 FindLinkIn(struct libalias *, struct in_addr, struct in_addr, u_short, u_short, int, int);
441 
442 static struct alias_link *
443 FindLinkByInternalEndpoint(struct libalias *, struct in_addr, u_short, int);
444 
445 static u_short _RandomPort(struct libalias *la);
446 
447 #define GET_NEW_PORT_MAX_ATTEMPTS       20
448 
449 
450 #ifndef NO_FW_PUNCH
451 
452 static void ClearAllFWHoles(struct libalias *la);
453 
454 #define fw_setfield(la, field, num)			\
455 do {						\
456     (field)[(num) - la->fireWallBaseNum] = 1;		\
457 } /*lint -save -e717 */ while(0)/* lint -restore */
458 
459 #define fw_clrfield(la, field, num)			\
460 do {							\
461     (field)[(num) - la->fireWallBaseNum] = 0;		\
462 } /*lint -save -e717 */ while(0)/* lint -restore */
463 
464 #define fw_tstfield(la, field, num) ((field)[(num) - la->fireWallBaseNum])
465 
466 #endif /* !NO_FW_PUNCH */
467 
468 #endif /* _ALIAS_DB_H_ */
469