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