1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
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 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD: stable/12/sys/netinet/libalias/alias.c 371477 2022-01-09 23:06:52Z emaste $");
31 
32 /*
33     Alias.c provides supervisory control for the functions of the
34     packet aliasing software.  It consists of routines to monitor
35     TCP connection state, protocol-specific aliasing routines,
36     fragment handling and the following outside world functional
37     interfaces: SaveFragmentPtr, GetFragmentPtr, FragmentAliasIn,
38     PacketAliasIn and PacketAliasOut.
39 
40     The other C program files are briefly described. The data
41     structure framework which holds information needed to translate
42     packets is encapsulated in alias_db.c.  Data is accessed by
43     function calls, so other segments of the program need not know
44     about the underlying data structures.  Alias_ftp.c contains
45     special code for modifying the ftp PORT command used to establish
46     data connections, while alias_irc.c does the same for IRC
47     DCC. Alias_util.c contains a few utility routines.
48 
49     Version 1.0 August, 1996  (cjm)
50 
51     Version 1.1 August 20, 1996  (cjm)
52 	PPP host accepts incoming connections for ports 0 to 1023.
53 	(Gary Roberts pointed out the need to handle incoming
54 	 connections.)
55 
56     Version 1.2 September 7, 1996 (cjm)
57 	Fragment handling error in alias_db.c corrected.
58 	(Tom Torrance helped fix this problem.)
59 
60     Version 1.4 September 16, 1996 (cjm)
61 	- A more generalized method for handling incoming
62 	  connections, without the 0-1023 restriction, is
63 	  implemented in alias_db.c
64 	- Improved ICMP support in alias.c.  Traceroute
65 	  packet streams can now be correctly aliased.
66 	- TCP connection closing logic simplified in
67 	  alias.c and now allows for additional 1 minute
68 	  "grace period" after FIN or RST is observed.
69 
70     Version 1.5 September 17, 1996 (cjm)
71 	Corrected error in handling incoming UDP packets with 0 checksum.
72 	(Tom Torrance helped fix this problem.)
73 
74     Version 1.6 September 18, 1996 (cjm)
75 	Simplified ICMP aliasing scheme.  Should now support
76 	traceroute from Win95 as well as FreeBSD.
77 
78     Version 1.7 January 9, 1997 (cjm)
79 	- Out-of-order fragment handling.
80 	- IP checksum error fixed for ftp transfers
81 	  from aliasing host.
82 	- Integer return codes added to all
83 	  aliasing/de-aliasing functions.
84 	- Some obsolete comments cleaned up.
85 	- Differential checksum computations for
86 	  IP header (TCP, UDP and ICMP were already
87 	  differential).
88 
89     Version 2.1 May 1997 (cjm)
90 	- Added support for outgoing ICMP error
91 	  messages.
92 	- Added two functions PacketAliasIn2()
93 	  and PacketAliasOut2() for dynamic address
94 	  control (e.g. round-robin allocation of
95 	  incoming packets).
96 
97     Version 2.2 July 1997 (cjm)
98 	- Rationalized API function names to begin
99 	  with "PacketAlias..."
100 	- Eliminated PacketAliasIn2() and
101 	  PacketAliasOut2() as poorly conceived.
102 
103     Version 2.3 Dec 1998 (dillon)
104 	- Major bounds checking additions, see FreeBSD/CVS
105 
106     Version 3.1 May, 2000 (salander)
107 	- Added hooks to handle PPTP.
108 
109     Version 3.2 July, 2000 (salander and satoh)
110 	- Added PacketUnaliasOut routine.
111 	- Added hooks to handle RTSP/RTP.
112 
113     See HISTORY file for additional revisions.
114 */
115 
116 #ifdef _KERNEL
117 #include <sys/param.h>
118 #include <sys/systm.h>
119 #include <sys/mbuf.h>
120 #include <sys/sysctl.h>
121 #else
122 #include <sys/types.h>
123 #include <stdlib.h>
124 #include <stdio.h>
125 #include <ctype.h>
126 #include <dlfcn.h>
127 #include <errno.h>
128 #include <string.h>
129 #endif
130 
131 #include <netinet/in_systm.h>
132 #include <netinet/in.h>
133 #include <netinet/ip.h>
134 #include <netinet/ip_icmp.h>
135 #include <netinet/tcp.h>
136 #include <netinet/udp.h>
137 
138 #ifdef _KERNEL
139 #include <netinet/libalias/alias.h>
140 #include <netinet/libalias/alias_local.h>
141 #include <netinet/libalias/alias_mod.h>
142 #else
143 #include <err.h>
144 #include "alias.h"
145 #include "alias_local.h"
146 #include "alias_mod.h"
147 #endif
148 
149 /*
150  * Define libalias SYSCTL Node
151  */
152 #ifdef SYSCTL_NODE
153 
154 SYSCTL_DECL(_net_inet);
155 SYSCTL_DECL(_net_inet_ip);
156 SYSCTL_NODE(_net_inet_ip, OID_AUTO, alias, CTLFLAG_RW, NULL, "Libalias sysctl API");
157 
158 #endif
159 
160 static __inline int
twowords(void * p)161 twowords(void *p)
162 {
163 	uint8_t *c = p;
164 
165 #if BYTE_ORDER == LITTLE_ENDIAN
166 	uint16_t s1 = ((uint16_t)c[1] << 8) + (uint16_t)c[0];
167 	uint16_t s2 = ((uint16_t)c[3] << 8) + (uint16_t)c[2];
168 #else
169 	uint16_t s1 = ((uint16_t)c[0] << 8) + (uint16_t)c[1];
170 	uint16_t s2 = ((uint16_t)c[2] << 8) + (uint16_t)c[3];
171 #endif
172 	return (s1 + s2);
173 }
174 
175 /* TCP Handling Routines
176 
177     TcpMonitorIn()  -- These routines monitor TCP connections, and
178     TcpMonitorOut()    delete a link when a connection is closed.
179 
180 These routines look for SYN, FIN and RST flags to determine when TCP
181 connections open and close.  When a TCP connection closes, the data
182 structure containing packet aliasing information is deleted after
183 a timeout period.
184 */
185 
186 /* Local prototypes */
187 static void	TcpMonitorIn(u_char, struct alias_link *);
188 
189 static void	TcpMonitorOut(u_char, struct alias_link *);
190 
191 static void
TcpMonitorIn(u_char th_flags,struct alias_link * lnk)192 TcpMonitorIn(u_char th_flags, struct alias_link *lnk)
193 {
194 	switch (GetStateIn(lnk)) {
195 	case ALIAS_TCP_STATE_NOT_CONNECTED:
196 		if (th_flags & TH_RST)
197 			SetStateIn(lnk, ALIAS_TCP_STATE_DISCONNECTED);
198 		else if (th_flags & TH_SYN)
199 			SetStateIn(lnk, ALIAS_TCP_STATE_CONNECTED);
200 		break;
201 	case ALIAS_TCP_STATE_CONNECTED:
202 		if (th_flags & (TH_FIN | TH_RST))
203 			SetStateIn(lnk, ALIAS_TCP_STATE_DISCONNECTED);
204 		break;
205 	}
206 }
207 
208 static void
TcpMonitorOut(u_char th_flags,struct alias_link * lnk)209 TcpMonitorOut(u_char th_flags, struct alias_link *lnk)
210 {
211 	switch (GetStateOut(lnk)) {
212 	case ALIAS_TCP_STATE_NOT_CONNECTED:
213 		if (th_flags & TH_RST)
214 			SetStateOut(lnk, ALIAS_TCP_STATE_DISCONNECTED);
215 		else if (th_flags & TH_SYN)
216 			SetStateOut(lnk, ALIAS_TCP_STATE_CONNECTED);
217 		break;
218 	case ALIAS_TCP_STATE_CONNECTED:
219 		if (th_flags & (TH_FIN | TH_RST))
220 			SetStateOut(lnk, ALIAS_TCP_STATE_DISCONNECTED);
221 		break;
222 	}
223 }
224 
225 /* Protocol Specific Packet Aliasing Routines
226 
227     IcmpAliasIn(), IcmpAliasIn1(), IcmpAliasIn2()
228     IcmpAliasOut(), IcmpAliasOut1(), IcmpAliasOut2()
229     ProtoAliasIn(), ProtoAliasOut()
230     UdpAliasIn(), UdpAliasOut()
231     TcpAliasIn(), TcpAliasOut()
232 
233 These routines handle protocol specific details of packet aliasing.
234 One may observe a certain amount of repetitive arithmetic in these
235 functions, the purpose of which is to compute a revised checksum
236 without actually summing over the entire data packet, which could be
237 unnecessarily time consuming.
238 
239 The purpose of the packet aliasing routines is to replace the source
240 address of the outgoing packet and then correctly put it back for
241 any incoming packets.  For TCP and UDP, ports are also re-mapped.
242 
243 For ICMP echo/timestamp requests and replies, the following scheme
244 is used: the ID number is replaced by an alias for the outgoing
245 packet.
246 
247 ICMP error messages are handled by looking at the IP fragment
248 in the data section of the message.
249 
250 For TCP and UDP protocols, a port number is chosen for an outgoing
251 packet, and then incoming packets are identified by IP address and
252 port numbers.  For TCP packets, there is additional logic in the event
253 that sequence and ACK numbers have been altered (as in the case for
254 FTP data port commands).
255 
256 The port numbers used by the packet aliasing module are not true
257 ports in the Unix sense.  No sockets are actually bound to ports.
258 They are more correctly thought of as placeholders.
259 
260 All packets go through the aliasing mechanism, whether they come from
261 the gateway machine or other machines on a local area network.
262 */
263 
264 /* Local prototypes */
265 static int	IcmpAliasIn1(struct libalias *, struct ip *);
266 static int	IcmpAliasIn2(struct libalias *, struct ip *);
267 static int	IcmpAliasIn(struct libalias *, struct ip *);
268 
269 static int	IcmpAliasOut1(struct libalias *, struct ip *, int create);
270 static int	IcmpAliasOut2(struct libalias *, struct ip *);
271 static int	IcmpAliasOut(struct libalias *, struct ip *, int create);
272 
273 static int	ProtoAliasIn(struct libalias *la, struct in_addr ip_src,
274 		    struct ip *pip, u_char ip_p, u_short *ip_sum);
275 static int	ProtoAliasOut(struct libalias *la, struct ip *pip,
276 		    struct in_addr ip_dst, u_char ip_p, u_short *ip_sum,
277 		    int create);
278 
279 static int	UdpAliasIn(struct libalias *, struct ip *);
280 static int	UdpAliasOut(struct libalias *, struct ip *, int, int create);
281 
282 static int	TcpAliasIn(struct libalias *, struct ip *);
283 static int	TcpAliasOut(struct libalias *, struct ip *, int, int create);
284 
285 /*
286     De-alias incoming echo and timestamp replies.
287     Alias incoming echo and timestamp requests.
288 */
289 static int
IcmpAliasIn1(struct libalias * la,struct ip * pip)290 IcmpAliasIn1(struct libalias *la, struct ip *pip)
291 {
292 	struct alias_link *lnk;
293 	struct icmp *ic;
294 
295 	LIBALIAS_LOCK_ASSERT(la);
296 	ic = (struct icmp *)ip_next(pip);
297 
298 	/* Get source address from ICMP data field and restore original data */
299 	lnk = FindIcmpIn(la, pip->ip_src, pip->ip_dst, ic->icmp_id, 1);
300 	if (lnk != NULL) {
301 		u_short original_id;
302 		int accumulate;
303 
304 		original_id = GetOriginalPort(lnk);
305 
306 		/* Adjust ICMP checksum */
307 		accumulate = ic->icmp_id;
308 		accumulate -= original_id;
309 		ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
310 
311 		/* Put original sequence number back in */
312 		ic->icmp_id = original_id;
313 
314 		/* Put original address back into IP header */
315 		{
316 			struct in_addr original_address;
317 
318 			original_address = GetOriginalAddress(lnk);
319 			DifferentialChecksum(&pip->ip_sum,
320 			    &original_address, &pip->ip_dst, 2);
321 			pip->ip_dst = original_address;
322 		}
323 
324 		return (PKT_ALIAS_OK);
325 	}
326 	return (PKT_ALIAS_IGNORED);
327 }
328 
329 /*
330     Alias incoming ICMP error messages containing
331     IP header and first 64 bits of datagram.
332 */
333 static int
IcmpAliasIn2(struct libalias * la,struct ip * pip)334 IcmpAliasIn2(struct libalias *la, struct ip *pip)
335 {
336 	struct ip *ip;
337 	struct icmp *ic, *ic2;
338 	struct udphdr *ud;
339 	struct tcphdr *tc;
340 	struct alias_link *lnk;
341 
342 	LIBALIAS_LOCK_ASSERT(la);
343 	ic = (struct icmp *)ip_next(pip);
344 	ip = &ic->icmp_ip;
345 
346 	ud = (struct udphdr *)ip_next(ip);
347 	tc = (struct tcphdr *)ip_next(ip);
348 	ic2 = (struct icmp *)ip_next(ip);
349 
350 	if (ip->ip_p == IPPROTO_UDP)
351 		lnk = FindUdpTcpIn(la, ip->ip_dst, ip->ip_src,
352 		    ud->uh_dport, ud->uh_sport,
353 		    IPPROTO_UDP, 0);
354 	else if (ip->ip_p == IPPROTO_TCP)
355 		lnk = FindUdpTcpIn(la, ip->ip_dst, ip->ip_src,
356 		    tc->th_dport, tc->th_sport,
357 		    IPPROTO_TCP, 0);
358 	else if (ip->ip_p == IPPROTO_ICMP) {
359 		if (ic2->icmp_type == ICMP_ECHO || ic2->icmp_type == ICMP_TSTAMP)
360 			lnk = FindIcmpIn(la, ip->ip_dst, ip->ip_src, ic2->icmp_id, 0);
361 		else
362 			lnk = NULL;
363 	} else
364 		lnk = NULL;
365 
366 	if (lnk != NULL) {
367 		if (ip->ip_p == IPPROTO_UDP || ip->ip_p == IPPROTO_TCP) {
368 			int accumulate, accumulate2;
369 			struct in_addr original_address;
370 			u_short original_port;
371 
372 			original_address = GetOriginalAddress(lnk);
373 			original_port = GetOriginalPort(lnk);
374 
375 			/* Adjust ICMP checksum */
376 			accumulate = twowords(&ip->ip_src);
377 			accumulate -= twowords(&original_address);
378 			accumulate += ud->uh_sport;
379 			accumulate -= original_port;
380 			accumulate2 = accumulate;
381 			accumulate2 += ip->ip_sum;
382 			ADJUST_CHECKSUM(accumulate, ip->ip_sum);
383 			accumulate2 -= ip->ip_sum;
384 			ADJUST_CHECKSUM(accumulate2, ic->icmp_cksum);
385 
386 			/* Un-alias address in IP header */
387 			DifferentialChecksum(&pip->ip_sum,
388 			    &original_address, &pip->ip_dst, 2);
389 			pip->ip_dst = original_address;
390 
391 			/* Un-alias address and port number of
392 			 * original IP packet fragment contained
393 			 * in ICMP data section */
394 			ip->ip_src = original_address;
395 			ud->uh_sport = original_port;
396 		} else if (ip->ip_p == IPPROTO_ICMP) {
397 			int accumulate, accumulate2;
398 			struct in_addr original_address;
399 			u_short original_id;
400 
401 			original_address = GetOriginalAddress(lnk);
402 			original_id = GetOriginalPort(lnk);
403 
404 			/* Adjust ICMP checksum */
405 			accumulate = twowords(&ip->ip_src);
406 			accumulate -= twowords(&original_address);
407 			accumulate += ic2->icmp_id;
408 			accumulate -= original_id;
409 			accumulate2 = accumulate;
410 			accumulate2 += ip->ip_sum;
411 			ADJUST_CHECKSUM(accumulate, ip->ip_sum);
412 			accumulate2 -= ip->ip_sum;
413 			ADJUST_CHECKSUM(accumulate2, ic->icmp_cksum);
414 
415 			/* Un-alias address in IP header */
416 			DifferentialChecksum(&pip->ip_sum,
417 			    &original_address, &pip->ip_dst, 2);
418 			pip->ip_dst = original_address;
419 
420 			/* Un-alias address of original IP packet and
421 			 * sequence number of embedded ICMP datagram */
422 			ip->ip_src = original_address;
423 			ic2->icmp_id = original_id;
424 		}
425 		return (PKT_ALIAS_OK);
426 	}
427 	return (PKT_ALIAS_IGNORED);
428 }
429 
430 static int
IcmpAliasIn(struct libalias * la,struct ip * pip)431 IcmpAliasIn(struct libalias *la, struct ip *pip)
432 {
433 	struct icmp *ic;
434 	int iresult;
435 	size_t dlen;
436 
437 	LIBALIAS_LOCK_ASSERT(la);
438 
439 	dlen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
440 	if (dlen < ICMP_MINLEN)
441 		return (PKT_ALIAS_IGNORED);
442 
443 	/* Return if proxy-only mode is enabled */
444 	if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
445 		return (PKT_ALIAS_OK);
446 
447 	ic = (struct icmp *)ip_next(pip);
448 
449 	iresult = PKT_ALIAS_IGNORED;
450 	switch (ic->icmp_type) {
451 	case ICMP_ECHOREPLY:
452 	case ICMP_TSTAMPREPLY:
453 		if (ic->icmp_code == 0) {
454 			iresult = IcmpAliasIn1(la, pip);
455 		}
456 		break;
457 	case ICMP_UNREACH:
458 	case ICMP_SOURCEQUENCH:
459 	case ICMP_TIMXCEED:
460 	case ICMP_PARAMPROB:
461 		if (dlen < ICMP_ADVLENMIN ||
462 		    dlen < (size_t)ICMP_ADVLEN(ic))
463 			return (PKT_ALIAS_IGNORED);
464 		iresult = IcmpAliasIn2(la, pip);
465 		break;
466 	case ICMP_ECHO:
467 	case ICMP_TSTAMP:
468 		iresult = IcmpAliasIn1(la, pip);
469 		break;
470 	}
471 	return (iresult);
472 }
473 
474 /*
475     Alias outgoing echo and timestamp requests.
476     De-alias outgoing echo and timestamp replies.
477 */
478 static int
IcmpAliasOut1(struct libalias * la,struct ip * pip,int create)479 IcmpAliasOut1(struct libalias *la, struct ip *pip, int create)
480 {
481 	struct alias_link *lnk;
482 	struct icmp *ic;
483 
484 	LIBALIAS_LOCK_ASSERT(la);
485 	ic = (struct icmp *)ip_next(pip);
486 
487 	/* Save overwritten data for when echo packet returns */
488 	lnk = FindIcmpOut(la, pip->ip_src, pip->ip_dst, ic->icmp_id, create);
489 	if (lnk != NULL) {
490 		u_short alias_id;
491 		int accumulate;
492 
493 		alias_id = GetAliasPort(lnk);
494 
495 		/* Since data field is being modified, adjust ICMP checksum */
496 		accumulate = ic->icmp_id;
497 		accumulate -= alias_id;
498 		ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
499 
500 		/* Alias sequence number */
501 		ic->icmp_id = alias_id;
502 
503 		/* Change source address */
504 		{
505 			struct in_addr alias_address;
506 
507 			alias_address = GetAliasAddress(lnk);
508 			DifferentialChecksum(&pip->ip_sum,
509 			    &alias_address, &pip->ip_src, 2);
510 			pip->ip_src = alias_address;
511 		}
512 
513 		return (PKT_ALIAS_OK);
514 	}
515 	return (PKT_ALIAS_IGNORED);
516 }
517 
518 /*
519     Alias outgoing ICMP error messages containing
520     IP header and first 64 bits of datagram.
521 */
522 static int
IcmpAliasOut2(struct libalias * la,struct ip * pip)523 IcmpAliasOut2(struct libalias *la, struct ip *pip)
524 {
525 	struct ip *ip;
526 	struct icmp *ic, *ic2;
527 	struct udphdr *ud;
528 	struct tcphdr *tc;
529 	struct alias_link *lnk;
530 
531 	LIBALIAS_LOCK_ASSERT(la);
532 	ic = (struct icmp *)ip_next(pip);
533 	ip = &ic->icmp_ip;
534 
535 	ud = (struct udphdr *)ip_next(ip);
536 	tc = (struct tcphdr *)ip_next(ip);
537 	ic2 = (struct icmp *)ip_next(ip);
538 
539 	if (ip->ip_p == IPPROTO_UDP)
540 		lnk = FindUdpTcpOut(la, ip->ip_dst, ip->ip_src,
541 		    ud->uh_dport, ud->uh_sport,
542 		    IPPROTO_UDP, 0);
543 	else if (ip->ip_p == IPPROTO_TCP)
544 		lnk = FindUdpTcpOut(la, ip->ip_dst, ip->ip_src,
545 		    tc->th_dport, tc->th_sport,
546 		    IPPROTO_TCP, 0);
547 	else if (ip->ip_p == IPPROTO_ICMP) {
548 		if (ic2->icmp_type == ICMP_ECHO || ic2->icmp_type == ICMP_TSTAMP)
549 			lnk = FindIcmpOut(la, ip->ip_dst, ip->ip_src, ic2->icmp_id, 0);
550 		else
551 			lnk = NULL;
552 	} else
553 		lnk = NULL;
554 
555 	if (lnk != NULL) {
556 		if (ip->ip_p == IPPROTO_UDP || ip->ip_p == IPPROTO_TCP) {
557 			int accumulate;
558 			struct in_addr alias_address;
559 			u_short alias_port;
560 
561 			alias_address = GetAliasAddress(lnk);
562 			alias_port = GetAliasPort(lnk);
563 
564 			/* Adjust ICMP checksum */
565 			accumulate = twowords(&ip->ip_dst);
566 			accumulate -= twowords(&alias_address);
567 			accumulate += ud->uh_dport;
568 			accumulate -= alias_port;
569 			ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
570 
571 			/*
572 			 * Alias address in IP header if it comes from the host
573 			 * the original TCP/UDP packet was destined for.
574 			 */
575 			if (pip->ip_src.s_addr == ip->ip_dst.s_addr) {
576 				DifferentialChecksum(&pip->ip_sum,
577 				    &alias_address, &pip->ip_src, 2);
578 				pip->ip_src = alias_address;
579 			}
580 			/* Alias address and port number of original IP packet
581 			 * fragment contained in ICMP data section */
582 			ip->ip_dst = alias_address;
583 			ud->uh_dport = alias_port;
584 		} else if (ip->ip_p == IPPROTO_ICMP) {
585 			int accumulate;
586 			struct in_addr alias_address;
587 			u_short alias_id;
588 
589 			alias_address = GetAliasAddress(lnk);
590 			alias_id = GetAliasPort(lnk);
591 
592 			/* Adjust ICMP checksum */
593 			accumulate = twowords(&ip->ip_dst);
594 			accumulate -= twowords(&alias_address);
595 			accumulate += ic2->icmp_id;
596 			accumulate -= alias_id;
597 			ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
598 
599 			/*
600 			 * Alias address in IP header if it comes from the host
601 			 * the original ICMP message was destined for.
602 			 */
603 			if (pip->ip_src.s_addr == ip->ip_dst.s_addr) {
604 				DifferentialChecksum(&pip->ip_sum,
605 				    &alias_address, &pip->ip_src, 2);
606 				pip->ip_src = alias_address;
607 			}
608 			/* Alias address of original IP packet and
609 			 * sequence number of embedded ICMP datagram */
610 			ip->ip_dst = alias_address;
611 			ic2->icmp_id = alias_id;
612 		}
613 		return (PKT_ALIAS_OK);
614 	}
615 	return (PKT_ALIAS_IGNORED);
616 }
617 
618 static int
IcmpAliasOut(struct libalias * la,struct ip * pip,int create)619 IcmpAliasOut(struct libalias *la, struct ip *pip, int create)
620 {
621 	int iresult;
622 	struct icmp *ic;
623 
624 	LIBALIAS_LOCK_ASSERT(la);
625 	(void)create;
626 
627 	/* Return if proxy-only mode is enabled */
628 	if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
629 		return (PKT_ALIAS_OK);
630 
631 	ic = (struct icmp *)ip_next(pip);
632 
633 	iresult = PKT_ALIAS_IGNORED;
634 	switch (ic->icmp_type) {
635 	case ICMP_ECHO:
636 	case ICMP_TSTAMP:
637 		if (ic->icmp_code == 0) {
638 			iresult = IcmpAliasOut1(la, pip, create);
639 		}
640 		break;
641 	case ICMP_UNREACH:
642 	case ICMP_SOURCEQUENCH:
643 	case ICMP_TIMXCEED:
644 	case ICMP_PARAMPROB:
645 		iresult = IcmpAliasOut2(la, pip);
646 		break;
647 	case ICMP_ECHOREPLY:
648 	case ICMP_TSTAMPREPLY:
649 		iresult = IcmpAliasOut1(la, pip, create);
650 	}
651 	return (iresult);
652 }
653 
654 /*
655   Handle incoming IP packets. The
656   only thing which is done in this case is to alias
657   the dest IP address of the packet to our inside
658   machine.
659 */
660 static int
ProtoAliasIn(struct libalias * la,struct in_addr ip_src,struct ip * pip,u_char ip_p,u_short * ip_sum)661 ProtoAliasIn(struct libalias *la, struct in_addr ip_src,
662     struct ip *pip, u_char ip_p, u_short *ip_sum)
663 {
664 	struct alias_link *lnk;
665 
666 	LIBALIAS_LOCK_ASSERT(la);
667 	/* Return if proxy-only mode is enabled */
668 	if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
669 		return (PKT_ALIAS_OK);
670 
671 	lnk = FindProtoIn(la, ip_src, pip->ip_dst, ip_p);
672 	if (lnk != NULL) {
673 		struct in_addr original_address;
674 
675 		original_address = GetOriginalAddress(lnk);
676 
677 		/* Restore original IP address */
678 		DifferentialChecksum(ip_sum,
679 		    &original_address, &pip->ip_dst, 2);
680 		pip->ip_dst = original_address;
681 
682 		return (PKT_ALIAS_OK);
683 	}
684 	return (PKT_ALIAS_IGNORED);
685 }
686 
687 /*
688   Handle outgoing IP packets. The
689   only thing which is done in this case is to alias
690   the source IP address of the packet.
691 */
692 static int
ProtoAliasOut(struct libalias * la,struct ip * pip,struct in_addr ip_dst,u_char ip_p,u_short * ip_sum,int create)693 ProtoAliasOut(struct libalias *la, struct ip *pip,
694     struct in_addr ip_dst, u_char ip_p, u_short *ip_sum, int create)
695 {
696 	struct alias_link *lnk;
697 
698 	LIBALIAS_LOCK_ASSERT(la);
699 
700 	/* Return if proxy-only mode is enabled */
701 	if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
702 		return (PKT_ALIAS_OK);
703 
704 	if (!create)
705 		return (PKT_ALIAS_IGNORED);
706 
707 	lnk = FindProtoOut(la, pip->ip_src, ip_dst, ip_p);
708 	if (lnk != NULL) {
709 		struct in_addr alias_address;
710 
711 		alias_address = GetAliasAddress(lnk);
712 
713 		/* Change source address */
714 		DifferentialChecksum(ip_sum,
715 		    &alias_address, &pip->ip_src, 2);
716 		pip->ip_src = alias_address;
717 
718 		return (PKT_ALIAS_OK);
719 	}
720 	return (PKT_ALIAS_IGNORED);
721 }
722 
723 #define MF_ISSET(_pip) (ntohs((_pip)->ip_off) & IP_MF)
724 #define FRAG_NO_HDR(_pip) (ntohs((_pip)->ip_off) & IP_OFFMASK)
725 
726 static struct udphdr *
ValidateUdpLength(struct ip * pip)727 ValidateUdpLength(struct ip *pip)
728 {
729 	struct udphdr *ud;
730 	size_t dlen;
731 
732 #ifdef _KERNEL
733 	KASSERT(!FRAG_NO_HDR(pip), ("header-less fragment isn't expected here"));
734 #endif
735 	dlen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
736 	if (dlen < sizeof(struct udphdr))
737 		return (NULL);
738 	ud = (struct udphdr *)ip_next(pip);
739 	if (!MF_ISSET(pip) && dlen < ntohs(ud->uh_ulen))
740 		return (NULL);
741 	return (ud);
742 }
743 
744 static int
UdpAliasIn(struct libalias * la,struct ip * pip)745 UdpAliasIn(struct libalias *la, struct ip *pip)
746 {
747 	struct udphdr *ud;
748 	struct alias_link *lnk;
749 
750 	LIBALIAS_LOCK_ASSERT(la);
751 
752 	ud = ValidateUdpLength(pip);
753 	if (ud == NULL)
754 		return (PKT_ALIAS_IGNORED);
755 
756 	lnk = FindUdpTcpIn(la, pip->ip_src, pip->ip_dst,
757 	    ud->uh_sport, ud->uh_dport,
758 	    IPPROTO_UDP, !(la->packetAliasMode & PKT_ALIAS_PROXY_ONLY));
759 	if (lnk != NULL) {
760 		struct in_addr alias_address;
761 		struct in_addr original_address;
762 		struct in_addr proxy_address;
763 		u_short alias_port;
764 		u_short proxy_port;
765 		int accumulate;
766 		int error;
767 		struct alias_data ad = {
768 			.lnk = lnk,
769 			.oaddr = &original_address,
770 			.aaddr = &alias_address,
771 			.aport = &alias_port,
772 			.sport = &ud->uh_sport,
773 			.dport = &ud->uh_dport,
774 			.maxpktsize = 0
775 		};
776 
777 		alias_address = GetAliasAddress(lnk);
778 		original_address = GetOriginalAddress(lnk);
779 		proxy_address = GetProxyAddress(lnk);
780 		alias_port = ud->uh_dport;
781 		ud->uh_dport = GetOriginalPort(lnk);
782 		proxy_port = GetProxyPort(lnk);
783 
784 		/* Walk out chain. */
785 		error = find_handler(IN, UDP, la, pip, &ad);
786 		/* If we cannot figure out the packet, ignore it. */
787 		if (error < 0)
788 			return (PKT_ALIAS_IGNORED);
789 
790 		/* If UDP checksum is not zero, then adjust since
791 		 * destination port is being unaliased and
792 		 * destination address is being altered. */
793 		if (ud->uh_sum != 0) {
794 			accumulate = alias_port;
795 			accumulate -= ud->uh_dport;
796 			accumulate += twowords(&alias_address);
797 			accumulate -= twowords(&original_address);
798 
799 			/* If this is a proxy packet, modify checksum
800 			 * because of source change.*/
801 			if (proxy_port != 0) {
802 				accumulate += ud->uh_sport;
803 				accumulate -= proxy_port;
804 			}
805 
806 			if (proxy_address.s_addr != 0) {
807 				accumulate += twowords(&pip->ip_src);
808 				accumulate -= twowords(&proxy_address);
809 			}
810 
811 			ADJUST_CHECKSUM(accumulate, ud->uh_sum);
812 		}
813 
814 		/* XXX: Could the two if's below be concatenated to one ? */
815 		/* Restore source port and/or address in case of proxying*/
816 		if (proxy_port != 0)
817 			ud->uh_sport = proxy_port;
818 
819 		if (proxy_address.s_addr != 0) {
820 			DifferentialChecksum(&pip->ip_sum,
821 			    &proxy_address, &pip->ip_src, 2);
822 			pip->ip_src = proxy_address;
823 		}
824 
825 		/* Restore original IP address */
826 		DifferentialChecksum(&pip->ip_sum,
827 		    &original_address, &pip->ip_dst, 2);
828 		pip->ip_dst = original_address;
829 
830 		return (PKT_ALIAS_OK);
831 	}
832 	return (PKT_ALIAS_IGNORED);
833 }
834 
835 static int
UdpAliasOut(struct libalias * la,struct ip * pip,int maxpacketsize,int create)836 UdpAliasOut(struct libalias *la, struct ip *pip, int maxpacketsize, int create)
837 {
838 	struct udphdr *ud;
839 	struct alias_link *lnk;
840 	struct in_addr dest_address;
841 	struct in_addr proxy_server_address;
842 	u_short dest_port;
843 	u_short proxy_server_port;
844 	int proxy_type;
845 	int error;
846 
847 	LIBALIAS_LOCK_ASSERT(la);
848 
849 	ud = ValidateUdpLength(pip);
850 	if (ud == NULL)
851 		return (PKT_ALIAS_IGNORED);
852 
853 	/* Return if proxy-only mode is enabled and not proxyrule found.*/
854 	proxy_type = ProxyCheck(la, &proxy_server_address, &proxy_server_port,
855 	    pip->ip_src, pip->ip_dst, ud->uh_dport, pip->ip_p);
856 	if (proxy_type == 0 && (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY))
857 		return (PKT_ALIAS_OK);
858 
859 	/* If this is a transparent proxy, save original destination,
860 	 * then alter the destination and adjust checksums */
861 	dest_port = ud->uh_dport;
862 	dest_address = pip->ip_dst;
863 
864 	if (proxy_type != 0) {
865 		int accumulate;
866 
867 		accumulate = twowords(&pip->ip_dst);
868 		accumulate -= twowords(&proxy_server_address);
869 
870 		ADJUST_CHECKSUM(accumulate, pip->ip_sum);
871 
872 		if (ud->uh_sum != 0) {
873 			accumulate = twowords(&pip->ip_dst);
874 			accumulate -= twowords(&proxy_server_address);
875 			accumulate += ud->uh_dport;
876 			accumulate -= proxy_server_port;
877 			ADJUST_CHECKSUM(accumulate, ud->uh_sum);
878 		}
879 		pip->ip_dst = proxy_server_address;
880 		ud->uh_dport = proxy_server_port;
881 	}
882 	lnk = FindUdpTcpOut(la, pip->ip_src, pip->ip_dst,
883 	    ud->uh_sport, ud->uh_dport,
884 	    IPPROTO_UDP, create);
885 	if (lnk != NULL) {
886 		u_short alias_port;
887 		struct in_addr alias_address;
888 		struct alias_data ad = {
889 			.lnk = lnk,
890 			.oaddr = NULL,
891 			.aaddr = &alias_address,
892 			.aport = &alias_port,
893 			.sport = &ud->uh_sport,
894 			.dport = &ud->uh_dport,
895 			.maxpktsize = 0
896 		};
897 
898 		/* Save original destination address, if this is a proxy packet.
899 		 * Also modify packet to include destination encoding.  This may
900 		 * change the size of IP header. */
901 		if (proxy_type != 0) {
902 			SetProxyPort(lnk, dest_port);
903 			SetProxyAddress(lnk, dest_address);
904 			ProxyModify(la, lnk, pip, maxpacketsize, proxy_type);
905 			ud = (struct udphdr *)ip_next(pip);
906 		}
907 
908 		alias_address = GetAliasAddress(lnk);
909 		alias_port = GetAliasPort(lnk);
910 
911 		/* Walk out chain. */
912 		error = find_handler(OUT, UDP, la, pip, &ad);
913 
914 		/* If UDP checksum is not zero, adjust since source port is */
915 		/* being aliased and source address is being altered	*/
916 		if (ud->uh_sum != 0) {
917 			int accumulate;
918 
919 			accumulate = ud->uh_sport;
920 			accumulate -= alias_port;
921 			accumulate += twowords(&pip->ip_src);
922 			accumulate -= twowords(&alias_address);
923 			ADJUST_CHECKSUM(accumulate, ud->uh_sum);
924 		}
925 		/* Put alias port in UDP header */
926 		ud->uh_sport = alias_port;
927 
928 		/* Change source address */
929 		DifferentialChecksum(&pip->ip_sum,
930 		    &alias_address, &pip->ip_src, 2);
931 		pip->ip_src = alias_address;
932 
933 		return (PKT_ALIAS_OK);
934 	}
935 	return (PKT_ALIAS_IGNORED);
936 }
937 
938 static int
TcpAliasIn(struct libalias * la,struct ip * pip)939 TcpAliasIn(struct libalias *la, struct ip *pip)
940 {
941 	struct tcphdr *tc;
942 	struct alias_link *lnk;
943 	size_t dlen;
944 
945 	LIBALIAS_LOCK_ASSERT(la);
946 
947 	dlen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
948 	if (dlen < sizeof(struct tcphdr))
949 		return (PKT_ALIAS_IGNORED);
950 	tc = (struct tcphdr *)ip_next(pip);
951 
952 	lnk = FindUdpTcpIn(la, pip->ip_src, pip->ip_dst,
953 	    tc->th_sport, tc->th_dport,
954 	    IPPROTO_TCP,
955 	    !(la->packetAliasMode & PKT_ALIAS_PROXY_ONLY));
956 	if (lnk != NULL) {
957 		struct in_addr alias_address;
958 		struct in_addr original_address;
959 		struct in_addr proxy_address;
960 		u_short alias_port;
961 		u_short proxy_port;
962 		int accumulate, error;
963 
964 		/*
965 		 * The init of MANY vars is a bit below, but aliashandlepptpin
966 		 * seems to need the destination port that came within the
967 		 * packet and not the original one looks below [*].
968 		 */
969 
970 		struct alias_data ad = {
971 			.lnk = lnk,
972 			.oaddr = NULL,
973 			.aaddr = NULL,
974 			.aport = NULL,
975 			.sport = &tc->th_sport,
976 			.dport = &tc->th_dport,
977 			.maxpktsize = 0
978 		};
979 
980 		/* Walk out chain. */
981 		error = find_handler(IN, TCP, la, pip, &ad);
982 
983 		alias_address = GetAliasAddress(lnk);
984 		original_address = GetOriginalAddress(lnk);
985 		proxy_address = GetProxyAddress(lnk);
986 		alias_port = tc->th_dport;
987 		tc->th_dport = GetOriginalPort(lnk);
988 		proxy_port = GetProxyPort(lnk);
989 
990 		/*
991 		 * Look above, if anyone is going to add find_handler AFTER
992 		 * this aliashandlepptpin/point, please redo alias_data too.
993 		 * Uncommenting the piece here below should be enough.
994 		 */
995 #if 0
996 				 struct alias_data ad = {
997 					.lnk = lnk,
998 					.oaddr = &original_address,
999 					.aaddr = &alias_address,
1000 					.aport = &alias_port,
1001 					.sport = &ud->uh_sport,
1002 					.dport = &ud->uh_dport,
1003 					.maxpktsize = 0
1004 				};
1005 
1006 				/* Walk out chain. */
1007 				error = find_handler(la, pip, &ad);
1008 				if (error == EHDNOF)
1009 					printf("Protocol handler not found\n");
1010 #endif
1011 
1012 		/* Adjust TCP checksum since destination port is being
1013 		 * unaliased and destination port is being altered. */
1014 		accumulate = alias_port;
1015 		accumulate -= tc->th_dport;
1016 		accumulate += twowords(&alias_address);
1017 		accumulate -= twowords(&original_address);
1018 
1019 		/* If this is a proxy, then modify the TCP source port
1020 		 * and checksum accumulation */
1021 		if (proxy_port != 0) {
1022 			accumulate += tc->th_sport;
1023 			tc->th_sport = proxy_port;
1024 			accumulate -= tc->th_sport;
1025 			accumulate += twowords(&pip->ip_src);
1026 			accumulate -= twowords(&proxy_address);
1027 		}
1028 		/* See if ACK number needs to be modified */
1029 		if (GetAckModified(lnk) == 1) {
1030 			int delta;
1031 
1032 			tc = (struct tcphdr *)ip_next(pip);
1033 			delta = GetDeltaAckIn(tc->th_ack, lnk);
1034 			if (delta != 0) {
1035 				accumulate += twowords(&tc->th_ack);
1036 				tc->th_ack = htonl(ntohl(tc->th_ack) - delta);
1037 				accumulate -= twowords(&tc->th_ack);
1038 			}
1039 		}
1040 		ADJUST_CHECKSUM(accumulate, tc->th_sum);
1041 
1042 		/* Restore original IP address */
1043 		accumulate = twowords(&pip->ip_dst);
1044 		pip->ip_dst = original_address;
1045 		accumulate -= twowords(&pip->ip_dst);
1046 
1047 		/* If this is a transparent proxy packet,
1048 		 * then modify the source address */
1049 		if (proxy_address.s_addr != 0) {
1050 			accumulate += twowords(&pip->ip_src);
1051 			pip->ip_src = proxy_address;
1052 			accumulate -= twowords(&pip->ip_src);
1053 		}
1054 		ADJUST_CHECKSUM(accumulate, pip->ip_sum);
1055 
1056 		/* Monitor TCP connection state */
1057 		tc = (struct tcphdr *)ip_next(pip);
1058 		TcpMonitorIn(tc->th_flags, lnk);
1059 
1060 		return (PKT_ALIAS_OK);
1061 	}
1062 	return (PKT_ALIAS_IGNORED);
1063 }
1064 
1065 static int
TcpAliasOut(struct libalias * la,struct ip * pip,int maxpacketsize,int create)1066 TcpAliasOut(struct libalias *la, struct ip *pip, int maxpacketsize, int create)
1067 {
1068 	int proxy_type, error;
1069 	u_short dest_port;
1070 	u_short proxy_server_port;
1071 	size_t dlen;
1072 	struct in_addr dest_address;
1073 	struct in_addr proxy_server_address;
1074 	struct tcphdr *tc;
1075 	struct alias_link *lnk;
1076 
1077 	LIBALIAS_LOCK_ASSERT(la);
1078 
1079 	dlen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
1080 	if (dlen < sizeof(struct tcphdr))
1081 		return (PKT_ALIAS_IGNORED);
1082 	tc = (struct tcphdr *)ip_next(pip);
1083 
1084 	if (create)
1085 		proxy_type = ProxyCheck(la, &proxy_server_address,
1086 		    &proxy_server_port, pip->ip_src, pip->ip_dst,
1087 		    tc->th_dport, pip->ip_p);
1088 	else
1089 		proxy_type = 0;
1090 
1091 	if (proxy_type == 0 && (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY))
1092 		return (PKT_ALIAS_OK);
1093 
1094 	/* If this is a transparent proxy, save original destination,
1095 	 * then alter the destination and adjust checksums */
1096 	dest_port = tc->th_dport;
1097 	dest_address = pip->ip_dst;
1098 	if (proxy_type != 0) {
1099 		int accumulate;
1100 
1101 		accumulate = tc->th_dport;
1102 		tc->th_dport = proxy_server_port;
1103 		accumulate -= tc->th_dport;
1104 		accumulate += twowords(&pip->ip_dst);
1105 		accumulate -= twowords(&proxy_server_address);
1106 		ADJUST_CHECKSUM(accumulate, tc->th_sum);
1107 
1108 		accumulate = twowords(&pip->ip_dst);
1109 		pip->ip_dst = proxy_server_address;
1110 		accumulate -= twowords(&pip->ip_dst);
1111 		ADJUST_CHECKSUM(accumulate, pip->ip_sum);
1112 	}
1113 	lnk = FindUdpTcpOut(la, pip->ip_src, pip->ip_dst,
1114 	    tc->th_sport, tc->th_dport,
1115 	    IPPROTO_TCP, create);
1116 	if (lnk == NULL)
1117 		return (PKT_ALIAS_IGNORED);
1118 	if (lnk != NULL) {
1119 		u_short alias_port;
1120 		struct in_addr alias_address;
1121 		int accumulate;
1122 		struct alias_data ad = {
1123 			.lnk = lnk,
1124 			.oaddr = NULL,
1125 			.aaddr = &alias_address,
1126 			.aport = &alias_port,
1127 			.sport = &tc->th_sport,
1128 			.dport = &tc->th_dport,
1129 			.maxpktsize = maxpacketsize
1130 		};
1131 
1132 		/* Save original destination address, if this is a proxy packet.
1133 		 * Also modify packet to include destination
1134 		 * encoding.  This may change the size of IP header. */
1135 		if (proxy_type != 0) {
1136 			SetProxyPort(lnk, dest_port);
1137 			SetProxyAddress(lnk, dest_address);
1138 			ProxyModify(la, lnk, pip, maxpacketsize, proxy_type);
1139 			tc = (struct tcphdr *)ip_next(pip);
1140 		}
1141 		/* Get alias address and port */
1142 		alias_port = GetAliasPort(lnk);
1143 		alias_address = GetAliasAddress(lnk);
1144 
1145 		/* Monitor TCP connection state */
1146 		tc = (struct tcphdr *)ip_next(pip);
1147 		TcpMonitorOut(tc->th_flags, lnk);
1148 
1149 		/* Walk out chain. */
1150 		error = find_handler(OUT, TCP, la, pip, &ad);
1151 
1152 		/* Adjust TCP checksum since source port is being aliased
1153 		 * and source address is being altered */
1154 		accumulate = tc->th_sport;
1155 		tc->th_sport = alias_port;
1156 		accumulate -= tc->th_sport;
1157 		accumulate += twowords(&pip->ip_src);
1158 		accumulate -= twowords(&alias_address);
1159 
1160 		/* Modify sequence number if necessary */
1161 		if (GetAckModified(lnk) == 1) {
1162 			int delta;
1163 
1164 			tc = (struct tcphdr *)ip_next(pip);
1165 			delta = GetDeltaSeqOut(tc->th_seq, lnk);
1166 			if (delta != 0) {
1167 				accumulate += twowords(&tc->th_seq);
1168 				tc->th_seq = htonl(ntohl(tc->th_seq) + delta);
1169 				accumulate -= twowords(&tc->th_seq);
1170 			}
1171 		}
1172 		ADJUST_CHECKSUM(accumulate, tc->th_sum);
1173 
1174 		/* Change source address */
1175 		accumulate = twowords(&pip->ip_src);
1176 		pip->ip_src = alias_address;
1177 		accumulate -= twowords(&pip->ip_src);
1178 		ADJUST_CHECKSUM(accumulate, pip->ip_sum);
1179 
1180 		return (PKT_ALIAS_OK);
1181 	}
1182 	return (PKT_ALIAS_IGNORED);
1183 }
1184 
1185 /* Fragment Handling
1186 
1187     FragmentIn()
1188     FragmentOut()
1189 
1190 The packet aliasing module has a limited ability for handling IP
1191 fragments.  If the ICMP, TCP or UDP header is in the first fragment
1192 received, then the ID number of the IP packet is saved, and other
1193 fragments are identified according to their ID number and IP address
1194 they were sent from.  Pointers to unresolved fragments can also be
1195 saved and recalled when a header fragment is seen.
1196 */
1197 
1198 /* Local prototypes */
1199 static int	FragmentIn(struct libalias *la, struct in_addr ip_src,
1200 		    struct ip *pip, u_short ip_id, u_short *ip_sum);
1201 static int	FragmentOut(struct libalias *, struct ip *pip,
1202 		    u_short *ip_sum);
1203 
1204 static int
FragmentIn(struct libalias * la,struct in_addr ip_src,struct ip * pip,u_short ip_id,u_short * ip_sum)1205 FragmentIn(struct libalias *la, struct in_addr ip_src, struct ip *pip,
1206     u_short ip_id, u_short *ip_sum)
1207 {
1208 	struct alias_link *lnk;
1209 
1210 	LIBALIAS_LOCK_ASSERT(la);
1211 	lnk = FindFragmentIn2(la, ip_src, pip->ip_dst, ip_id);
1212 	if (lnk != NULL) {
1213 		struct in_addr original_address;
1214 
1215 		GetFragmentAddr(lnk, &original_address);
1216 		DifferentialChecksum(ip_sum,
1217 		    &original_address, &pip->ip_dst, 2);
1218 		pip->ip_dst = original_address;
1219 
1220 		return (PKT_ALIAS_OK);
1221 	}
1222 	return (PKT_ALIAS_UNRESOLVED_FRAGMENT);
1223 }
1224 
1225 static int
FragmentOut(struct libalias * la,struct ip * pip,u_short * ip_sum)1226 FragmentOut(struct libalias *la, struct ip *pip, u_short *ip_sum)
1227 {
1228 	struct in_addr alias_address;
1229 
1230 	LIBALIAS_LOCK_ASSERT(la);
1231 	alias_address = FindAliasAddress(la, pip->ip_src);
1232 	DifferentialChecksum(ip_sum,
1233 	    &alias_address, &pip->ip_src, 2);
1234 	pip->ip_src = alias_address;
1235 
1236 	return (PKT_ALIAS_OK);
1237 }
1238 
1239 /* Outside World Access
1240 
1241 	PacketAliasSaveFragment()
1242 	PacketAliasGetFragment()
1243 	PacketAliasFragmentIn()
1244 	PacketAliasIn()
1245 	PacketAliasOut()
1246 	PacketUnaliasOut()
1247 
1248 (prototypes in alias.h)
1249 */
1250 
1251 int
LibAliasSaveFragment(struct libalias * la,void * ptr)1252 LibAliasSaveFragment(struct libalias *la, void *ptr)
1253 {
1254 	int iresult;
1255 	struct alias_link *lnk;
1256 	struct ip *pip;
1257 
1258 	LIBALIAS_LOCK(la);
1259 	pip = (struct ip *)ptr;
1260 	lnk = AddFragmentPtrLink(la, pip->ip_src, pip->ip_id);
1261 	iresult = PKT_ALIAS_ERROR;
1262 	if (lnk != NULL) {
1263 		SetFragmentPtr(lnk, ptr);
1264 		iresult = PKT_ALIAS_OK;
1265 	}
1266 	LIBALIAS_UNLOCK(la);
1267 	return (iresult);
1268 }
1269 
1270 void *
LibAliasGetFragment(struct libalias * la,void * ptr)1271 LibAliasGetFragment(struct libalias *la, void *ptr)
1272 {
1273 	struct alias_link *lnk;
1274 	void *fptr;
1275 	struct ip *pip;
1276 
1277 	LIBALIAS_LOCK(la);
1278 	pip = (struct ip *)ptr;
1279 	lnk = FindFragmentPtr(la, pip->ip_src, pip->ip_id);
1280 	if (lnk != NULL) {
1281 		GetFragmentPtr(lnk, &fptr);
1282 		SetFragmentPtr(lnk, NULL);
1283 		SetExpire(lnk, 0);	/* Deletes link */
1284 	} else
1285 		fptr = NULL;
1286 
1287 	LIBALIAS_UNLOCK(la);
1288 	return (fptr);
1289 }
1290 
1291 void
LibAliasFragmentIn(struct libalias * la,void * ptr,void * ptr_fragment)1292 LibAliasFragmentIn(struct libalias *la,
1293     void *ptr,	/* Points to correctly de-aliased header fragment */
1294     void *ptr_fragment	/* fragment which must be de-aliased   */
1295 )
1296 {
1297 	struct ip *pip;
1298 	struct ip *fpip;
1299 
1300 	LIBALIAS_LOCK(la);
1301 	(void)la;
1302 	pip = (struct ip *)ptr;
1303 	fpip = (struct ip *)ptr_fragment;
1304 
1305 	DifferentialChecksum(&fpip->ip_sum,
1306 	    &pip->ip_dst, &fpip->ip_dst, 2);
1307 	fpip->ip_dst = pip->ip_dst;
1308 	LIBALIAS_UNLOCK(la);
1309 }
1310 
1311 /* Local prototypes */
1312 static int
1313 LibAliasOutLocked(struct libalias *la, struct ip *pip,
1314     int maxpacketsize, int create);
1315 static int
1316 LibAliasInLocked(struct libalias *la, struct ip *pip,
1317     int maxpacketsize);
1318 
1319 int
LibAliasIn(struct libalias * la,void * ptr,int maxpacketsize)1320 LibAliasIn(struct libalias *la, void *ptr, int maxpacketsize)
1321 {
1322 	int res;
1323 
1324 	LIBALIAS_LOCK(la);
1325 	res = LibAliasInLocked(la, (struct ip *)ptr, maxpacketsize);
1326 	LIBALIAS_UNLOCK(la);
1327 	return (res);
1328 }
1329 
1330 static int
LibAliasInLocked(struct libalias * la,struct ip * pip,int maxpacketsize)1331 LibAliasInLocked(struct libalias *la, struct ip *pip, int maxpacketsize)
1332 {
1333 	struct in_addr alias_addr;
1334 	int iresult;
1335 
1336 	if (la->packetAliasMode & PKT_ALIAS_REVERSE) {
1337 		la->packetAliasMode &= ~PKT_ALIAS_REVERSE;
1338 		iresult = LibAliasOutLocked(la, pip, maxpacketsize, 1);
1339 		la->packetAliasMode |= PKT_ALIAS_REVERSE;
1340 		goto getout;
1341 	}
1342 	HouseKeeping(la);
1343 	alias_addr = pip->ip_dst;
1344 
1345 	/* Defense against mangled packets */
1346 	if (ntohs(pip->ip_len) > maxpacketsize
1347 	    || (pip->ip_hl << 2) > maxpacketsize) {
1348 		iresult = PKT_ALIAS_IGNORED;
1349 		goto getout;
1350 	}
1351 
1352 	if (FRAG_NO_HDR(pip)) {
1353 		iresult = FragmentIn(la, pip->ip_src, pip, pip->ip_id,
1354 		    &pip->ip_sum);
1355 		goto getout;
1356 	}
1357 
1358 	iresult = PKT_ALIAS_IGNORED;
1359 	switch (pip->ip_p) {
1360 	case IPPROTO_ICMP:
1361 		iresult = IcmpAliasIn(la, pip);
1362 		break;
1363 	case IPPROTO_UDP:
1364 		iresult = UdpAliasIn(la, pip);
1365 		break;
1366 	case IPPROTO_TCP:
1367 		iresult = TcpAliasIn(la, pip);
1368 		break;
1369 #ifdef _KERNEL
1370 	case IPPROTO_SCTP:
1371 		iresult = SctpAlias(la, pip, SN_TO_LOCAL);
1372 		break;
1373 #endif
1374 	case IPPROTO_GRE: {
1375 		int error;
1376 		struct alias_data ad = {
1377 			.lnk = NULL,
1378 			.oaddr = NULL,
1379 			.aaddr = NULL,
1380 			.aport = NULL,
1381 			.sport = NULL,
1382 			.dport = NULL,
1383 			.maxpktsize = 0
1384 		};
1385 
1386 		/* Walk out chain. */
1387 		error = find_handler(IN, IP, la, pip, &ad);
1388 		if (error == 0)
1389 			iresult = PKT_ALIAS_OK;
1390 		else
1391 			iresult = ProtoAliasIn(la, pip->ip_src,
1392 			    pip, pip->ip_p, &pip->ip_sum);
1393 		break;
1394 	}
1395 	default:
1396 		iresult = ProtoAliasIn(la, pip->ip_src, pip,
1397 		    pip->ip_p, &pip->ip_sum);
1398 		break;
1399 	}
1400 
1401 	if (MF_ISSET(pip)) {
1402 		struct alias_link *lnk;
1403 
1404 		lnk = FindFragmentIn1(la, pip->ip_src, alias_addr, pip->ip_id);
1405 		if (lnk != NULL) {
1406 			iresult = PKT_ALIAS_FOUND_HEADER_FRAGMENT;
1407 			SetFragmentAddr(lnk, pip->ip_dst);
1408 		} else {
1409 			iresult = PKT_ALIAS_ERROR;
1410 		}
1411 	}
1412 
1413 getout:
1414 	return (iresult);
1415 }
1416 
1417 /* Unregistered address ranges */
1418 
1419 /* 10.0.0.0   ->   10.255.255.255 */
1420 #define UNREG_ADDR_A_LOWER 0x0a000000
1421 #define UNREG_ADDR_A_UPPER 0x0affffff
1422 
1423 /* 172.16.0.0  ->  172.31.255.255 */
1424 #define UNREG_ADDR_B_LOWER 0xac100000
1425 #define UNREG_ADDR_B_UPPER 0xac1fffff
1426 
1427 /* 192.168.0.0 -> 192.168.255.255 */
1428 #define UNREG_ADDR_C_LOWER 0xc0a80000
1429 #define UNREG_ADDR_C_UPPER 0xc0a8ffff
1430 
1431 /* 100.64.0.0  -> 100.127.255.255 (RFC 6598 - Carrier Grade NAT) */
1432 #define UNREG_ADDR_CGN_LOWER 0x64400000
1433 #define UNREG_ADDR_CGN_UPPER 0x647fffff
1434 
1435 int
LibAliasOut(struct libalias * la,void * ptr,int maxpacketsize)1436 LibAliasOut(struct libalias *la, void *ptr, int maxpacketsize)
1437 {
1438 	int res;
1439 
1440 	LIBALIAS_LOCK(la);
1441 	res = LibAliasOutLocked(la, (struct ip *)ptr, maxpacketsize, 1);
1442 	LIBALIAS_UNLOCK(la);
1443 	return (res);
1444 }
1445 
1446 int
LibAliasOutTry(struct libalias * la,void * ptr,int maxpacketsize,int create)1447 LibAliasOutTry(struct libalias *la, void *ptr, int maxpacketsize, int create)
1448 {
1449 	int res;
1450 
1451 	LIBALIAS_LOCK(la);
1452 	res = LibAliasOutLocked(la, (struct ip *)ptr, maxpacketsize, create);
1453 	LIBALIAS_UNLOCK(la);
1454 	return (res);
1455 }
1456 
1457 static int
LibAliasOutLocked(struct libalias * la,struct ip * pip,int maxpacketsize,int create)1458 LibAliasOutLocked(struct libalias *la,
1459     struct ip *pip,	/* valid IP packet */
1460     int maxpacketsize,	/* How much the packet data may grow (FTP and IRC inline changes) */
1461     int create		/* Create new entries ? */
1462 )
1463 {
1464 	int iresult;
1465 	struct in_addr addr_save;
1466 
1467 	if (la->packetAliasMode & PKT_ALIAS_REVERSE) {
1468 		la->packetAliasMode &= ~PKT_ALIAS_REVERSE;
1469 		iresult = LibAliasInLocked(la, pip, maxpacketsize);
1470 		la->packetAliasMode |= PKT_ALIAS_REVERSE;
1471 		goto getout;
1472 	}
1473 	HouseKeeping(la);
1474 
1475 	/* Defense against mangled packets */
1476 	if (ntohs(pip->ip_len) > maxpacketsize
1477 	    || (pip->ip_hl << 2) > maxpacketsize) {
1478 		iresult = PKT_ALIAS_IGNORED;
1479 		goto getout;
1480 	}
1481 
1482 	addr_save = GetDefaultAliasAddress(la);
1483 	if (la->packetAliasMode & PKT_ALIAS_UNREGISTERED_ONLY ||
1484 	    la->packetAliasMode & PKT_ALIAS_UNREGISTERED_CGN) {
1485 		u_long addr;
1486 		int iclass;
1487 
1488 		iclass = 0;
1489 		addr = ntohl(pip->ip_src.s_addr);
1490 		if (addr >= UNREG_ADDR_C_LOWER && addr <= UNREG_ADDR_C_UPPER)
1491 			iclass = 3;
1492 		else if (addr >= UNREG_ADDR_B_LOWER && addr <= UNREG_ADDR_B_UPPER)
1493 			iclass = 2;
1494 		else if (addr >= UNREG_ADDR_A_LOWER && addr <= UNREG_ADDR_A_UPPER)
1495 			iclass = 1;
1496 		else if (addr >= UNREG_ADDR_CGN_LOWER && addr <= UNREG_ADDR_CGN_UPPER &&
1497 		    la->packetAliasMode & PKT_ALIAS_UNREGISTERED_CGN)
1498 			iclass = 4;
1499 
1500 		if (iclass == 0) {
1501 			SetDefaultAliasAddress(la, pip->ip_src);
1502 		}
1503 	} else if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY) {
1504 		SetDefaultAliasAddress(la, pip->ip_src);
1505 	}
1506 
1507 	if (FRAG_NO_HDR(pip)) {
1508 		iresult = FragmentOut(la, pip, &pip->ip_sum);
1509 		goto getout_restore;
1510 	}
1511 
1512 	iresult = PKT_ALIAS_IGNORED;
1513 	switch (pip->ip_p) {
1514 	case IPPROTO_ICMP:
1515 		iresult = IcmpAliasOut(la, pip, create);
1516 		break;
1517 	case IPPROTO_UDP:
1518 		iresult = UdpAliasOut(la, pip, maxpacketsize, create);
1519 		break;
1520 	case IPPROTO_TCP:
1521 		iresult = TcpAliasOut(la, pip, maxpacketsize, create);
1522 		break;
1523 #ifdef _KERNEL
1524 	case IPPROTO_SCTP:
1525 		iresult = SctpAlias(la, pip, SN_TO_GLOBAL);
1526 		break;
1527 #endif
1528 	case IPPROTO_GRE: {
1529 		int error;
1530 		struct alias_data ad = {
1531 			.lnk = NULL,
1532 			.oaddr = NULL,
1533 			.aaddr = NULL,
1534 			.aport = NULL,
1535 			.sport = NULL,
1536 			.dport = NULL,
1537 			.maxpktsize = 0
1538 		};
1539 		/* Walk out chain. */
1540 		error = find_handler(OUT, IP, la, pip, &ad);
1541 		if (error == 0)
1542 			iresult = PKT_ALIAS_OK;
1543 		else
1544 			iresult = ProtoAliasOut(la, pip,
1545 			    pip->ip_dst, pip->ip_p, &pip->ip_sum, create);
1546 		break;
1547 		}
1548 	default:
1549 		iresult = ProtoAliasOut(la, pip,
1550 		    pip->ip_dst, pip->ip_p, &pip->ip_sum, create);
1551 		break;
1552 	}
1553 
1554 getout_restore:
1555 	SetDefaultAliasAddress(la, addr_save);
1556 getout:
1557 	return (iresult);
1558 }
1559 
1560 int
LibAliasUnaliasOut(struct libalias * la,void * ptr,int maxpacketsize)1561 LibAliasUnaliasOut(struct libalias *la,
1562     void *ptr,		/* valid IP packet */
1563     int maxpacketsize	/* for error checking */
1564 )
1565 {
1566 	struct ip *pip;
1567 	struct icmp *ic;
1568 	struct udphdr *ud;
1569 	struct tcphdr *tc;
1570 	struct alias_link *lnk;
1571 	int iresult = PKT_ALIAS_IGNORED;
1572 
1573 	LIBALIAS_LOCK(la);
1574 	pip = (struct ip *)ptr;
1575 
1576 	/* Defense against mangled packets */
1577 	if (ntohs(pip->ip_len) > maxpacketsize
1578 	    || (pip->ip_hl << 2) > maxpacketsize)
1579 		goto getout;
1580 
1581 	ud = (struct udphdr *)ip_next(pip);
1582 	tc = (struct tcphdr *)ip_next(pip);
1583 	ic = (struct icmp *)ip_next(pip);
1584 
1585 	/* Find a link */
1586 	if (pip->ip_p == IPPROTO_UDP)
1587 		lnk = FindUdpTcpIn(la, pip->ip_dst, pip->ip_src,
1588 		    ud->uh_dport, ud->uh_sport,
1589 		    IPPROTO_UDP, 0);
1590 	else if (pip->ip_p == IPPROTO_TCP)
1591 		lnk = FindUdpTcpIn(la, pip->ip_dst, pip->ip_src,
1592 		    tc->th_dport, tc->th_sport,
1593 		    IPPROTO_TCP, 0);
1594 	else if (pip->ip_p == IPPROTO_ICMP)
1595 		lnk = FindIcmpIn(la, pip->ip_dst, pip->ip_src, ic->icmp_id, 0);
1596 	else
1597 		lnk = NULL;
1598 
1599 	/* Change it from an aliased packet to an unaliased packet */
1600 	if (lnk != NULL) {
1601 		if (pip->ip_p == IPPROTO_UDP || pip->ip_p == IPPROTO_TCP) {
1602 			int accumulate;
1603 			struct in_addr original_address;
1604 			u_short original_port;
1605 
1606 			original_address = GetOriginalAddress(lnk);
1607 			original_port = GetOriginalPort(lnk);
1608 
1609 			/* Adjust TCP/UDP checksum */
1610 			accumulate = twowords(&pip->ip_src);
1611 			accumulate -= twowords(&original_address);
1612 
1613 			if (pip->ip_p == IPPROTO_UDP) {
1614 				accumulate += ud->uh_sport;
1615 				accumulate -= original_port;
1616 				ADJUST_CHECKSUM(accumulate, ud->uh_sum);
1617 			} else {
1618 				accumulate += tc->th_sport;
1619 				accumulate -= original_port;
1620 				ADJUST_CHECKSUM(accumulate, tc->th_sum);
1621 			}
1622 
1623 			/* Adjust IP checksum */
1624 			DifferentialChecksum(&pip->ip_sum,
1625 			    &original_address, &pip->ip_src, 2);
1626 
1627 			/* Un-alias source address and port number */
1628 			pip->ip_src = original_address;
1629 			if (pip->ip_p == IPPROTO_UDP)
1630 				ud->uh_sport = original_port;
1631 			else
1632 				tc->th_sport = original_port;
1633 
1634 			iresult = PKT_ALIAS_OK;
1635 		} else if (pip->ip_p == IPPROTO_ICMP) {
1636 			int accumulate;
1637 			struct in_addr original_address;
1638 			u_short original_id;
1639 
1640 			original_address = GetOriginalAddress(lnk);
1641 			original_id = GetOriginalPort(lnk);
1642 
1643 			/* Adjust ICMP checksum */
1644 			accumulate = twowords(&pip->ip_src);
1645 			accumulate -= twowords(&original_address);
1646 			accumulate += ic->icmp_id;
1647 			accumulate -= original_id;
1648 			ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
1649 
1650 			/* Adjust IP checksum */
1651 			DifferentialChecksum(&pip->ip_sum,
1652 			    &original_address, &pip->ip_src, 2);
1653 
1654 			/* Un-alias source address and port number */
1655 			pip->ip_src = original_address;
1656 			ic->icmp_id = original_id;
1657 
1658 			iresult = PKT_ALIAS_OK;
1659 		}
1660 	}
1661 getout:
1662 	LIBALIAS_UNLOCK(la);
1663 	return (iresult);
1664 }
1665 
1666 #ifndef _KERNEL
1667 
1668 int
LibAliasRefreshModules(void)1669 LibAliasRefreshModules(void)
1670 {
1671 	char buf[256], conf[] = "/etc/libalias.conf";
1672 	FILE *fd;
1673 	int i, len;
1674 
1675 	fd = fopen(conf, "r");
1676 	if (fd == NULL)
1677 		err(1, "fopen(%s)", conf);
1678 
1679 	LibAliasUnLoadAllModule();
1680 
1681 	for (;;) {
1682 		fgets(buf, 256, fd);
1683 		if (feof(fd))
1684 			break;
1685 		len = strlen(buf);
1686 		if (len > 1) {
1687 			for (i = 0; i < len; i++)
1688 				if (!isspace(buf[i]))
1689 					break;
1690 			if (buf[i] == '#')
1691 				continue;
1692 			buf[len - 1] = '\0';
1693 			LibAliasLoadModule(buf);
1694 		}
1695 	}
1696 	fclose(fd);
1697 	return (0);
1698 }
1699 
1700 int
LibAliasLoadModule(char * path)1701 LibAliasLoadModule(char *path)
1702 {
1703 	struct dll *t;
1704 	void *handle;
1705 	struct proto_handler *m;
1706 	const char *error;
1707 	moduledata_t *p;
1708 
1709 	handle = dlopen (path, RTLD_LAZY);
1710 	if (!handle) {
1711 		fprintf(stderr, "%s\n", dlerror());
1712 		return (EINVAL);
1713 	}
1714 
1715 	p = dlsym(handle, "alias_mod");
1716 	if ((error = dlerror()) != NULL)  {
1717 		fprintf(stderr, "%s\n", dlerror());
1718 		return (EINVAL);
1719 	}
1720 
1721 	t = malloc(sizeof(struct dll));
1722 	if (t == NULL)
1723 		return (ENOMEM);
1724 	strncpy(t->name, p->name, DLL_LEN);
1725 	t->handle = handle;
1726 	if (attach_dll(t) == EEXIST) {
1727 		free(t);
1728 		fprintf(stderr, "dll conflict\n");
1729 		return (EEXIST);
1730 	}
1731 
1732 	m = dlsym(t->handle, "handlers");
1733 	if ((error = dlerror()) != NULL)  {
1734 		fprintf(stderr, "%s\n", error);
1735 		return (EINVAL);
1736 	}
1737 
1738 	LibAliasAttachHandlers(m);
1739 	return (0);
1740 }
1741 
1742 int
LibAliasUnLoadAllModule(void)1743 LibAliasUnLoadAllModule(void)
1744 {
1745 	struct dll *t;
1746 	struct proto_handler *p;
1747 
1748 	/* Unload all modules then reload everything. */
1749 	while ((p = first_handler()) != NULL) {
1750 		LibAliasDetachHandlers(p);
1751 	}
1752 	while ((t = walk_dll_chain()) != NULL) {
1753 		dlclose(t->handle);
1754 		free(t);
1755 	}
1756 	return (1);
1757 }
1758 
1759 #endif
1760 
1761 #ifdef _KERNEL
1762 /*
1763  * m_megapullup() - this function is a big hack.
1764  * Thankfully, it's only used in ng_nat and ipfw+nat.
1765  *
1766  * It allocates an mbuf with cluster and copies the specified part of the chain
1767  * into cluster, so that it is all contiguous and can be accessed via a plain
1768  * (char *) pointer. This is required, because libalias doesn't know how to
1769  * handle mbuf chains.
1770  *
1771  * On success, m_megapullup returns an mbuf (possibly with cluster) containing
1772  * the input packet, on failure NULL. The input packet is always consumed.
1773  */
1774 struct mbuf *
m_megapullup(struct mbuf * m,int len)1775 m_megapullup(struct mbuf *m, int len)
1776 {
1777 	struct mbuf *mcl;
1778 
1779 	if (len > m->m_pkthdr.len)
1780 		goto bad;
1781 
1782 	if (m->m_next == NULL && M_WRITABLE(m))
1783 		return (m);
1784 
1785 	if (len <= MJUMPAGESIZE)
1786 		mcl = m_get2(len, M_NOWAIT, MT_DATA, M_PKTHDR);
1787 	else if (len <= MJUM9BYTES)
1788 		mcl = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUM9BYTES);
1789 	else if (len <= MJUM16BYTES)
1790 		mcl = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUM16BYTES);
1791 	else
1792 		goto bad;
1793 	if (mcl == NULL)
1794 		goto bad;
1795 	m_align(mcl, len);
1796 	m_move_pkthdr(mcl, m);
1797 	m_copydata(m, 0, len, mtod(mcl, caddr_t));
1798 	mcl->m_len = mcl->m_pkthdr.len = len;
1799 	m_freem(m);
1800 
1801 	return (mcl);
1802 bad:
1803 	m_freem(m);
1804 	return (NULL);
1805 }
1806 #endif
1807