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