xref: /freebsd/sys/netinet/libalias/alias.c (revision 8881d206f4e68b564c2c5f50fc717086fc3e827a)
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 #define MF_ISSET(_pip) (ntohs((_pip)->ip_off) & IP_MF)
725 #define FRAG_NO_HDR(_pip) (ntohs((_pip)->ip_off) & IP_OFFMASK)
726 
727 static struct udphdr *
728 ValidateUdpLength(struct ip *pip)
729 {
730 	struct udphdr *ud;
731 	size_t dlen;
732 
733 #ifdef _KERNEL
734 	KASSERT(!FRAG_NO_HDR(pip), ("header-less fragment isn't expected here"));
735 #endif
736 	dlen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
737 	if (dlen < sizeof(struct udphdr))
738 		return (NULL);
739 	ud = (struct udphdr *)ip_next(pip);
740 	if (!MF_ISSET(pip) && dlen < ntohs(ud->uh_ulen))
741 		return (NULL);
742 	return (ud);
743 }
744 
745 static int
746 UdpAliasIn(struct libalias *la, struct ip *pip)
747 {
748 	struct udphdr *ud;
749 	struct alias_link *lnk;
750 
751 	LIBALIAS_LOCK_ASSERT(la);
752 
753 	ud = ValidateUdpLength(pip);
754 	if (ud == NULL)
755 		return (PKT_ALIAS_IGNORED);
756 
757 	lnk = FindUdpTcpIn(la, pip->ip_src, pip->ip_dst,
758 	    ud->uh_sport, ud->uh_dport,
759 	    IPPROTO_UDP, !(la->packetAliasMode & PKT_ALIAS_PROXY_ONLY));
760 	if (lnk != NULL) {
761 		struct in_addr alias_address;
762 		struct in_addr original_address;
763 		struct in_addr proxy_address;
764 		u_short alias_port;
765 		u_short proxy_port;
766 		int accumulate;
767 		int error;
768 		struct alias_data ad = {
769 			.lnk = lnk,
770 			.oaddr = &original_address,
771 			.aaddr = &alias_address,
772 			.aport = &alias_port,
773 			.sport = &ud->uh_sport,
774 			.dport = &ud->uh_dport,
775 			.maxpktsize = 0
776 		};
777 
778 		alias_address = GetAliasAddress(lnk);
779 		original_address = GetOriginalAddress(lnk);
780 		proxy_address = GetProxyAddress(lnk);
781 		alias_port = ud->uh_dport;
782 		ud->uh_dport = GetOriginalPort(lnk);
783 		proxy_port = GetProxyPort(lnk);
784 
785 		/* Walk out chain. */
786 		error = find_handler(IN, UDP, la, pip, &ad);
787 		/* If we cannot figure out the packet, ignore it. */
788 		if (error < 0)
789 			return (PKT_ALIAS_IGNORED);
790 
791 		/* If UDP checksum is not zero, then adjust since
792 		 * destination port is being unaliased and
793 		 * destination address is being altered. */
794 		if (ud->uh_sum != 0) {
795 			accumulate = alias_port;
796 			accumulate -= ud->uh_dport;
797 			accumulate += twowords(&alias_address);
798 			accumulate -= twowords(&original_address);
799 
800 			/* If this is a proxy packet, modify checksum
801 			 * because of source change.*/
802 			if (proxy_port != 0) {
803 				accumulate += ud->uh_sport;
804 				accumulate -= proxy_port;
805 			}
806 
807 			if (proxy_address.s_addr != 0) {
808 				accumulate += twowords(&pip->ip_src);
809 				accumulate -= twowords(&proxy_address);
810 			}
811 
812 			ADJUST_CHECKSUM(accumulate, ud->uh_sum);
813 		}
814 
815 		/* XXX: Could the two if's below be concatenated to one ? */
816 		/* Restore source port and/or address in case of proxying*/
817 		if (proxy_port != 0)
818 			ud->uh_sport = proxy_port;
819 
820 		if (proxy_address.s_addr != 0) {
821 			DifferentialChecksum(&pip->ip_sum,
822 			    &proxy_address, &pip->ip_src, 2);
823 			pip->ip_src = proxy_address;
824 		}
825 
826 		/* Restore original IP address */
827 		DifferentialChecksum(&pip->ip_sum,
828 		    &original_address, &pip->ip_dst, 2);
829 		pip->ip_dst = original_address;
830 
831 		return (PKT_ALIAS_OK);
832 	}
833 	return (PKT_ALIAS_IGNORED);
834 }
835 
836 static int
837 UdpAliasOut(struct libalias *la, struct ip *pip, int maxpacketsize, int create)
838 {
839 	struct udphdr *ud;
840 	struct alias_link *lnk;
841 	struct in_addr dest_address;
842 	struct in_addr proxy_server_address;
843 	u_short dest_port;
844 	u_short proxy_server_port;
845 	int proxy_type;
846 	int error;
847 
848 	LIBALIAS_LOCK_ASSERT(la);
849 
850 	ud = ValidateUdpLength(pip);
851 	if (ud == NULL)
852 		return (PKT_ALIAS_IGNORED);
853 
854 	/* Return if proxy-only mode is enabled and not proxyrule found.*/
855 	proxy_type = ProxyCheck(la, &proxy_server_address, &proxy_server_port,
856 	    pip->ip_src, pip->ip_dst, ud->uh_dport, pip->ip_p);
857 	if (proxy_type == 0 && (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY))
858 		return (PKT_ALIAS_OK);
859 
860 	/* If this is a transparent proxy, save original destination,
861 	 * then alter the destination and adjust checksums */
862 	dest_port = ud->uh_dport;
863 	dest_address = pip->ip_dst;
864 
865 	if (proxy_type != 0) {
866 		int accumulate;
867 
868 		accumulate = twowords(&pip->ip_dst);
869 		accumulate -= twowords(&proxy_server_address);
870 
871 		ADJUST_CHECKSUM(accumulate, pip->ip_sum);
872 
873 		if (ud->uh_sum != 0) {
874 			accumulate = twowords(&pip->ip_dst);
875 			accumulate -= twowords(&proxy_server_address);
876 			accumulate += ud->uh_dport;
877 			accumulate -= proxy_server_port;
878 			ADJUST_CHECKSUM(accumulate, ud->uh_sum);
879 		}
880 		pip->ip_dst = proxy_server_address;
881 		ud->uh_dport = proxy_server_port;
882 	}
883 	lnk = FindUdpTcpOut(la, pip->ip_src, pip->ip_dst,
884 	    ud->uh_sport, ud->uh_dport,
885 	    IPPROTO_UDP, create);
886 	if (lnk != NULL) {
887 		u_short alias_port;
888 		struct in_addr alias_address;
889 		struct alias_data ad = {
890 			.lnk = lnk,
891 			.oaddr = NULL,
892 			.aaddr = &alias_address,
893 			.aport = &alias_port,
894 			.sport = &ud->uh_sport,
895 			.dport = &ud->uh_dport,
896 			.maxpktsize = 0
897 		};
898 
899 		/* Save original destination address, if this is a proxy packet.
900 		 * Also modify packet to include destination encoding.  This may
901 		 * change the size of IP header. */
902 		if (proxy_type != 0) {
903 			SetProxyPort(lnk, dest_port);
904 			SetProxyAddress(lnk, dest_address);
905 			ProxyModify(la, lnk, pip, maxpacketsize, proxy_type);
906 			ud = (struct udphdr *)ip_next(pip);
907 		}
908 
909 		alias_address = GetAliasAddress(lnk);
910 		alias_port = GetAliasPort(lnk);
911 
912 		/* Walk out chain. */
913 		error = find_handler(OUT, UDP, la, pip, &ad);
914 
915 		/* If UDP checksum is not zero, adjust since source port is */
916 		/* being aliased and source address is being altered	*/
917 		if (ud->uh_sum != 0) {
918 			int accumulate;
919 
920 			accumulate = ud->uh_sport;
921 			accumulate -= alias_port;
922 			accumulate += twowords(&pip->ip_src);
923 			accumulate -= twowords(&alias_address);
924 			ADJUST_CHECKSUM(accumulate, ud->uh_sum);
925 		}
926 		/* Put alias port in UDP header */
927 		ud->uh_sport = alias_port;
928 
929 		/* Change source address */
930 		DifferentialChecksum(&pip->ip_sum,
931 		    &alias_address, &pip->ip_src, 2);
932 		pip->ip_src = alias_address;
933 
934 		return (PKT_ALIAS_OK);
935 	}
936 	return (PKT_ALIAS_IGNORED);
937 }
938 
939 static int
940 TcpAliasIn(struct libalias *la, struct ip *pip)
941 {
942 	struct tcphdr *tc;
943 	struct alias_link *lnk;
944 	size_t dlen;
945 
946 	LIBALIAS_LOCK_ASSERT(la);
947 
948 	dlen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
949 	if (dlen < sizeof(struct tcphdr))
950 		return (PKT_ALIAS_IGNORED);
951 	tc = (struct tcphdr *)ip_next(pip);
952 
953 	lnk = FindUdpTcpIn(la, pip->ip_src, pip->ip_dst,
954 	    tc->th_sport, tc->th_dport,
955 	    IPPROTO_TCP,
956 	    !(la->packetAliasMode & PKT_ALIAS_PROXY_ONLY));
957 	if (lnk != NULL) {
958 		struct in_addr alias_address;
959 		struct in_addr original_address;
960 		struct in_addr proxy_address;
961 		u_short alias_port;
962 		u_short proxy_port;
963 		int accumulate, error;
964 
965 		/*
966 		 * The init of MANY vars is a bit below, but aliashandlepptpin
967 		 * seems to need the destination port that came within the
968 		 * packet and not the original one looks below [*].
969 		 */
970 
971 		struct alias_data ad = {
972 			.lnk = lnk,
973 			.oaddr = NULL,
974 			.aaddr = NULL,
975 			.aport = NULL,
976 			.sport = &tc->th_sport,
977 			.dport = &tc->th_dport,
978 			.maxpktsize = 0
979 		};
980 
981 		/* Walk out chain. */
982 		error = find_handler(IN, TCP, la, pip, &ad);
983 
984 		alias_address = GetAliasAddress(lnk);
985 		original_address = GetOriginalAddress(lnk);
986 		proxy_address = GetProxyAddress(lnk);
987 		alias_port = tc->th_dport;
988 		tc->th_dport = GetOriginalPort(lnk);
989 		proxy_port = GetProxyPort(lnk);
990 
991 		/*
992 		 * Look above, if anyone is going to add find_handler AFTER
993 		 * this aliashandlepptpin/point, please redo alias_data too.
994 		 * Uncommenting the piece here below should be enough.
995 		 */
996 #if 0
997 				 struct alias_data ad = {
998 					.lnk = lnk,
999 					.oaddr = &original_address,
1000 					.aaddr = &alias_address,
1001 					.aport = &alias_port,
1002 					.sport = &ud->uh_sport,
1003 					.dport = &ud->uh_dport,
1004 					.maxpktsize = 0
1005 				};
1006 
1007 				/* Walk out chain. */
1008 				error = find_handler(la, pip, &ad);
1009 				if (error == EHDNOF)
1010 					printf("Protocol handler not found\n");
1011 #endif
1012 
1013 		/* Adjust TCP checksum since destination port is being
1014 		 * unaliased and destination port is being altered. */
1015 		accumulate = alias_port;
1016 		accumulate -= tc->th_dport;
1017 		accumulate += twowords(&alias_address);
1018 		accumulate -= twowords(&original_address);
1019 
1020 		/* If this is a proxy, then modify the TCP source port
1021 		 * and checksum accumulation */
1022 		if (proxy_port != 0) {
1023 			accumulate += tc->th_sport;
1024 			tc->th_sport = proxy_port;
1025 			accumulate -= tc->th_sport;
1026 			accumulate += twowords(&pip->ip_src);
1027 			accumulate -= twowords(&proxy_address);
1028 		}
1029 		/* See if ACK number needs to be modified */
1030 		if (GetAckModified(lnk) == 1) {
1031 			int delta;
1032 
1033 			tc = (struct tcphdr *)ip_next(pip);
1034 			delta = GetDeltaAckIn(tc->th_ack, lnk);
1035 			if (delta != 0) {
1036 				accumulate += twowords(&tc->th_ack);
1037 				tc->th_ack = htonl(ntohl(tc->th_ack) - delta);
1038 				accumulate -= twowords(&tc->th_ack);
1039 			}
1040 		}
1041 		ADJUST_CHECKSUM(accumulate, tc->th_sum);
1042 
1043 		/* Restore original IP address */
1044 		accumulate = twowords(&pip->ip_dst);
1045 		pip->ip_dst = original_address;
1046 		accumulate -= twowords(&pip->ip_dst);
1047 
1048 		/* If this is a transparent proxy packet,
1049 		 * then modify the source address */
1050 		if (proxy_address.s_addr != 0) {
1051 			accumulate += twowords(&pip->ip_src);
1052 			pip->ip_src = proxy_address;
1053 			accumulate -= twowords(&pip->ip_src);
1054 		}
1055 		ADJUST_CHECKSUM(accumulate, pip->ip_sum);
1056 
1057 		/* Monitor TCP connection state */
1058 		tc = (struct tcphdr *)ip_next(pip);
1059 		TcpMonitorIn(tc->th_flags, lnk);
1060 
1061 		return (PKT_ALIAS_OK);
1062 	}
1063 	return (PKT_ALIAS_IGNORED);
1064 }
1065 
1066 static int
1067 TcpAliasOut(struct libalias *la, struct ip *pip, int maxpacketsize, int create)
1068 {
1069 	int proxy_type, error;
1070 	u_short dest_port;
1071 	u_short proxy_server_port;
1072 	size_t dlen;
1073 	struct in_addr dest_address;
1074 	struct in_addr proxy_server_address;
1075 	struct tcphdr *tc;
1076 	struct alias_link *lnk;
1077 
1078 	LIBALIAS_LOCK_ASSERT(la);
1079 
1080 	dlen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
1081 	if (dlen < sizeof(struct tcphdr))
1082 		return (PKT_ALIAS_IGNORED);
1083 	tc = (struct tcphdr *)ip_next(pip);
1084 
1085 	if (create)
1086 		proxy_type = ProxyCheck(la, &proxy_server_address,
1087 		    &proxy_server_port, pip->ip_src, pip->ip_dst,
1088 		    tc->th_dport, pip->ip_p);
1089 	else
1090 		proxy_type = 0;
1091 
1092 	if (proxy_type == 0 && (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY))
1093 		return (PKT_ALIAS_OK);
1094 
1095 	/* If this is a transparent proxy, save original destination,
1096 	 * then alter the destination and adjust checksums */
1097 	dest_port = tc->th_dport;
1098 	dest_address = pip->ip_dst;
1099 	if (proxy_type != 0) {
1100 		int accumulate;
1101 
1102 		accumulate = tc->th_dport;
1103 		tc->th_dport = proxy_server_port;
1104 		accumulate -= tc->th_dport;
1105 		accumulate += twowords(&pip->ip_dst);
1106 		accumulate -= twowords(&proxy_server_address);
1107 		ADJUST_CHECKSUM(accumulate, tc->th_sum);
1108 
1109 		accumulate = twowords(&pip->ip_dst);
1110 		pip->ip_dst = proxy_server_address;
1111 		accumulate -= twowords(&pip->ip_dst);
1112 		ADJUST_CHECKSUM(accumulate, pip->ip_sum);
1113 	}
1114 	lnk = FindUdpTcpOut(la, pip->ip_src, pip->ip_dst,
1115 	    tc->th_sport, tc->th_dport,
1116 	    IPPROTO_TCP, create);
1117 	if (lnk == NULL)
1118 		return (PKT_ALIAS_IGNORED);
1119 	if (lnk != NULL) {
1120 		u_short alias_port;
1121 		struct in_addr alias_address;
1122 		int accumulate;
1123 		struct alias_data ad = {
1124 			.lnk = lnk,
1125 			.oaddr = NULL,
1126 			.aaddr = &alias_address,
1127 			.aport = &alias_port,
1128 			.sport = &tc->th_sport,
1129 			.dport = &tc->th_dport,
1130 			.maxpktsize = maxpacketsize
1131 		};
1132 
1133 		/* Save original destination address, if this is a proxy packet.
1134 		 * Also modify packet to include destination
1135 		 * encoding.  This may change the size of IP header. */
1136 		if (proxy_type != 0) {
1137 			SetProxyPort(lnk, dest_port);
1138 			SetProxyAddress(lnk, dest_address);
1139 			ProxyModify(la, lnk, pip, maxpacketsize, proxy_type);
1140 			tc = (struct tcphdr *)ip_next(pip);
1141 		}
1142 		/* Get alias address and port */
1143 		alias_port = GetAliasPort(lnk);
1144 		alias_address = GetAliasAddress(lnk);
1145 
1146 		/* Monitor TCP connection state */
1147 		tc = (struct tcphdr *)ip_next(pip);
1148 		TcpMonitorOut(tc->th_flags, lnk);
1149 
1150 		/* Walk out chain. */
1151 		error = find_handler(OUT, TCP, la, pip, &ad);
1152 
1153 		/* Adjust TCP checksum since source port is being aliased
1154 		 * and source address is being altered */
1155 		accumulate = tc->th_sport;
1156 		tc->th_sport = alias_port;
1157 		accumulate -= tc->th_sport;
1158 		accumulate += twowords(&pip->ip_src);
1159 		accumulate -= twowords(&alias_address);
1160 
1161 		/* Modify sequence number if necessary */
1162 		if (GetAckModified(lnk) == 1) {
1163 			int delta;
1164 
1165 			tc = (struct tcphdr *)ip_next(pip);
1166 			delta = GetDeltaSeqOut(tc->th_seq, lnk);
1167 			if (delta != 0) {
1168 				accumulate += twowords(&tc->th_seq);
1169 				tc->th_seq = htonl(ntohl(tc->th_seq) + delta);
1170 				accumulate -= twowords(&tc->th_seq);
1171 			}
1172 		}
1173 		ADJUST_CHECKSUM(accumulate, tc->th_sum);
1174 
1175 		/* Change source address */
1176 		accumulate = twowords(&pip->ip_src);
1177 		pip->ip_src = alias_address;
1178 		accumulate -= twowords(&pip->ip_src);
1179 		ADJUST_CHECKSUM(accumulate, pip->ip_sum);
1180 
1181 		return (PKT_ALIAS_OK);
1182 	}
1183 	return (PKT_ALIAS_IGNORED);
1184 }
1185 
1186 /* Fragment Handling
1187 
1188     FragmentIn()
1189     FragmentOut()
1190 
1191 The packet aliasing module has a limited ability for handling IP
1192 fragments.  If the ICMP, TCP or UDP header is in the first fragment
1193 received, then the ID number of the IP packet is saved, and other
1194 fragments are identified according to their ID number and IP address
1195 they were sent from.  Pointers to unresolved fragments can also be
1196 saved and recalled when a header fragment is seen.
1197 */
1198 
1199 /* Local prototypes */
1200 static int	FragmentIn(struct libalias *la, struct in_addr ip_src,
1201 		    struct ip *pip, u_short ip_id, u_short *ip_sum);
1202 static int	FragmentOut(struct libalias *, struct ip *pip,
1203 		    u_short *ip_sum);
1204 
1205 static int
1206 FragmentIn(struct libalias *la, struct in_addr ip_src, struct ip *pip,
1207     u_short ip_id, u_short *ip_sum)
1208 {
1209 	struct alias_link *lnk;
1210 
1211 	LIBALIAS_LOCK_ASSERT(la);
1212 	lnk = FindFragmentIn2(la, ip_src, pip->ip_dst, ip_id);
1213 	if (lnk != NULL) {
1214 		struct in_addr original_address;
1215 
1216 		GetFragmentAddr(lnk, &original_address);
1217 		DifferentialChecksum(ip_sum,
1218 		    &original_address, &pip->ip_dst, 2);
1219 		pip->ip_dst = original_address;
1220 
1221 		return (PKT_ALIAS_OK);
1222 	}
1223 	return (PKT_ALIAS_UNRESOLVED_FRAGMENT);
1224 }
1225 
1226 static int
1227 FragmentOut(struct libalias *la, struct ip *pip, u_short *ip_sum)
1228 {
1229 	struct in_addr alias_address;
1230 
1231 	LIBALIAS_LOCK_ASSERT(la);
1232 	alias_address = FindAliasAddress(la, pip->ip_src);
1233 	DifferentialChecksum(ip_sum,
1234 	    &alias_address, &pip->ip_src, 2);
1235 	pip->ip_src = alias_address;
1236 
1237 	return (PKT_ALIAS_OK);
1238 }
1239 
1240 /* Outside World Access
1241 
1242 	PacketAliasSaveFragment()
1243 	PacketAliasGetFragment()
1244 	PacketAliasFragmentIn()
1245 	PacketAliasIn()
1246 	PacketAliasOut()
1247 	PacketUnaliasOut()
1248 
1249 (prototypes in alias.h)
1250 */
1251 
1252 int
1253 LibAliasSaveFragment(struct libalias *la, void *ptr)
1254 {
1255 	int iresult;
1256 	struct alias_link *lnk;
1257 	struct ip *pip;
1258 
1259 	LIBALIAS_LOCK(la);
1260 	pip = (struct ip *)ptr;
1261 	lnk = AddFragmentPtrLink(la, pip->ip_src, pip->ip_id);
1262 	iresult = PKT_ALIAS_ERROR;
1263 	if (lnk != NULL) {
1264 		SetFragmentPtr(lnk, ptr);
1265 		iresult = PKT_ALIAS_OK;
1266 	}
1267 	LIBALIAS_UNLOCK(la);
1268 	return (iresult);
1269 }
1270 
1271 void *
1272 LibAliasGetFragment(struct libalias *la, void *ptr)
1273 {
1274 	struct alias_link *lnk;
1275 	void *fptr;
1276 	struct ip *pip;
1277 
1278 	LIBALIAS_LOCK(la);
1279 	pip = (struct ip *)ptr;
1280 	lnk = FindFragmentPtr(la, pip->ip_src, pip->ip_id);
1281 	if (lnk != NULL) {
1282 		GetFragmentPtr(lnk, &fptr);
1283 		SetFragmentPtr(lnk, NULL);
1284 		SetExpire(lnk, 0);	/* Deletes link */
1285 	} else
1286 		fptr = NULL;
1287 
1288 	LIBALIAS_UNLOCK(la);
1289 	return (fptr);
1290 }
1291 
1292 void
1293 LibAliasFragmentIn(struct libalias *la,
1294     void *ptr,	/* Points to correctly de-aliased header fragment */
1295     void *ptr_fragment	/* fragment which must be de-aliased   */
1296 )
1297 {
1298 	struct ip *pip;
1299 	struct ip *fpip;
1300 
1301 	LIBALIAS_LOCK(la);
1302 	(void)la;
1303 	pip = (struct ip *)ptr;
1304 	fpip = (struct ip *)ptr_fragment;
1305 
1306 	DifferentialChecksum(&fpip->ip_sum,
1307 	    &pip->ip_dst, &fpip->ip_dst, 2);
1308 	fpip->ip_dst = pip->ip_dst;
1309 	LIBALIAS_UNLOCK(la);
1310 }
1311 
1312 /* Local prototypes */
1313 static int
1314 LibAliasOutLocked(struct libalias *la, struct ip *pip,
1315     int maxpacketsize, int create);
1316 static int
1317 LibAliasInLocked(struct libalias *la, struct ip *pip,
1318     int maxpacketsize);
1319 
1320 int
1321 LibAliasIn(struct libalias *la, void *ptr, int maxpacketsize)
1322 {
1323 	int res;
1324 
1325 	LIBALIAS_LOCK(la);
1326 	res = LibAliasInLocked(la, (struct ip *)ptr, maxpacketsize);
1327 	LIBALIAS_UNLOCK(la);
1328 	return (res);
1329 }
1330 
1331 static int
1332 LibAliasInLocked(struct libalias *la, struct ip *pip, int maxpacketsize)
1333 {
1334 	struct in_addr alias_addr;
1335 	int iresult;
1336 
1337 	if (la->packetAliasMode & PKT_ALIAS_REVERSE) {
1338 		la->packetAliasMode &= ~PKT_ALIAS_REVERSE;
1339 		iresult = LibAliasOutLocked(la, pip, maxpacketsize, 1);
1340 		la->packetAliasMode |= PKT_ALIAS_REVERSE;
1341 		goto getout;
1342 	}
1343 	HouseKeeping(la);
1344 	alias_addr = pip->ip_dst;
1345 
1346 	/* Defense against mangled packets */
1347 	if (ntohs(pip->ip_len) > maxpacketsize
1348 	    || (pip->ip_hl << 2) > maxpacketsize) {
1349 		iresult = PKT_ALIAS_IGNORED;
1350 		goto getout;
1351 	}
1352 
1353 	if (FRAG_NO_HDR(pip)) {
1354 		iresult = FragmentIn(la, pip->ip_src, pip, pip->ip_id,
1355 		    &pip->ip_sum);
1356 		goto getout;
1357 	}
1358 
1359 	iresult = PKT_ALIAS_IGNORED;
1360 	switch (pip->ip_p) {
1361 	case IPPROTO_ICMP:
1362 		iresult = IcmpAliasIn(la, pip);
1363 		break;
1364 	case IPPROTO_UDP:
1365 		iresult = UdpAliasIn(la, pip);
1366 		break;
1367 	case IPPROTO_TCP:
1368 		iresult = TcpAliasIn(la, pip);
1369 		break;
1370 #ifdef _KERNEL
1371 	case IPPROTO_SCTP:
1372 		iresult = SctpAlias(la, pip, SN_TO_LOCAL);
1373 		break;
1374 #endif
1375 	case IPPROTO_GRE: {
1376 		int error;
1377 		struct alias_data ad = {
1378 			.lnk = NULL,
1379 			.oaddr = NULL,
1380 			.aaddr = NULL,
1381 			.aport = NULL,
1382 			.sport = NULL,
1383 			.dport = NULL,
1384 			.maxpktsize = 0
1385 		};
1386 
1387 		/* Walk out chain. */
1388 		error = find_handler(IN, IP, la, pip, &ad);
1389 		if (error == 0)
1390 			iresult = PKT_ALIAS_OK;
1391 		else
1392 			iresult = ProtoAliasIn(la, pip->ip_src,
1393 			    pip, pip->ip_p, &pip->ip_sum);
1394 		break;
1395 	}
1396 	default:
1397 		iresult = ProtoAliasIn(la, pip->ip_src, pip,
1398 		    pip->ip_p, &pip->ip_sum);
1399 		break;
1400 	}
1401 
1402 	if (MF_ISSET(pip)) {
1403 		struct alias_link *lnk;
1404 
1405 		lnk = FindFragmentIn1(la, pip->ip_src, alias_addr, pip->ip_id);
1406 		if (lnk != NULL) {
1407 			iresult = PKT_ALIAS_FOUND_HEADER_FRAGMENT;
1408 			SetFragmentAddr(lnk, pip->ip_dst);
1409 		} else {
1410 			iresult = PKT_ALIAS_ERROR;
1411 		}
1412 	}
1413 
1414 getout:
1415 	return (iresult);
1416 }
1417 
1418 /* Unregistered address ranges */
1419 
1420 /* 10.0.0.0   ->   10.255.255.255 */
1421 #define UNREG_ADDR_A_LOWER 0x0a000000
1422 #define UNREG_ADDR_A_UPPER 0x0affffff
1423 
1424 /* 172.16.0.0  ->  172.31.255.255 */
1425 #define UNREG_ADDR_B_LOWER 0xac100000
1426 #define UNREG_ADDR_B_UPPER 0xac1fffff
1427 
1428 /* 192.168.0.0 -> 192.168.255.255 */
1429 #define UNREG_ADDR_C_LOWER 0xc0a80000
1430 #define UNREG_ADDR_C_UPPER 0xc0a8ffff
1431 
1432 /* 100.64.0.0  -> 100.127.255.255 (RFC 6598 - Carrier Grade NAT) */
1433 #define UNREG_ADDR_CGN_LOWER 0x64400000
1434 #define UNREG_ADDR_CGN_UPPER 0x647fffff
1435 
1436 int
1437 LibAliasOut(struct libalias *la, void *ptr, int maxpacketsize)
1438 {
1439 	int res;
1440 
1441 	LIBALIAS_LOCK(la);
1442 	res = LibAliasOutLocked(la, (struct ip *)ptr, maxpacketsize, 1);
1443 	LIBALIAS_UNLOCK(la);
1444 	return (res);
1445 }
1446 
1447 int
1448 LibAliasOutTry(struct libalias *la, void *ptr, int maxpacketsize, int create)
1449 {
1450 	int res;
1451 
1452 	LIBALIAS_LOCK(la);
1453 	res = LibAliasOutLocked(la, (struct ip *)ptr, maxpacketsize, create);
1454 	LIBALIAS_UNLOCK(la);
1455 	return (res);
1456 }
1457 
1458 static int
1459 LibAliasOutLocked(struct libalias *la,
1460     struct ip *pip,	/* valid IP packet */
1461     int maxpacketsize,	/* How much the packet data may grow (FTP and IRC inline changes) */
1462     int create		/* Create new entries ? */
1463 )
1464 {
1465 	int iresult;
1466 	struct in_addr addr_save;
1467 
1468 	if (la->packetAliasMode & PKT_ALIAS_REVERSE) {
1469 		la->packetAliasMode &= ~PKT_ALIAS_REVERSE;
1470 		iresult = LibAliasInLocked(la, pip, maxpacketsize);
1471 		la->packetAliasMode |= PKT_ALIAS_REVERSE;
1472 		goto getout;
1473 	}
1474 	HouseKeeping(la);
1475 
1476 	/* Defense against mangled packets */
1477 	if (ntohs(pip->ip_len) > maxpacketsize
1478 	    || (pip->ip_hl << 2) > maxpacketsize) {
1479 		iresult = PKT_ALIAS_IGNORED;
1480 		goto getout;
1481 	}
1482 
1483 	addr_save = GetDefaultAliasAddress(la);
1484 	if (la->packetAliasMode & PKT_ALIAS_UNREGISTERED_ONLY ||
1485 	    la->packetAliasMode & PKT_ALIAS_UNREGISTERED_CGN) {
1486 		u_long addr;
1487 		int iclass;
1488 
1489 		iclass = 0;
1490 		addr = ntohl(pip->ip_src.s_addr);
1491 		if (addr >= UNREG_ADDR_C_LOWER && addr <= UNREG_ADDR_C_UPPER)
1492 			iclass = 3;
1493 		else if (addr >= UNREG_ADDR_B_LOWER && addr <= UNREG_ADDR_B_UPPER)
1494 			iclass = 2;
1495 		else if (addr >= UNREG_ADDR_A_LOWER && addr <= UNREG_ADDR_A_UPPER)
1496 			iclass = 1;
1497 		else if (addr >= UNREG_ADDR_CGN_LOWER && addr <= UNREG_ADDR_CGN_UPPER &&
1498 		    la->packetAliasMode & PKT_ALIAS_UNREGISTERED_CGN)
1499 			iclass = 4;
1500 
1501 		if (iclass == 0) {
1502 			SetDefaultAliasAddress(la, pip->ip_src);
1503 		}
1504 	} else if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY) {
1505 		SetDefaultAliasAddress(la, pip->ip_src);
1506 	}
1507 
1508 	if (FRAG_NO_HDR(pip)) {
1509 		iresult = FragmentOut(la, pip, &pip->ip_sum);
1510 		goto getout_restore;
1511 	}
1512 
1513 	iresult = PKT_ALIAS_IGNORED;
1514 	switch (pip->ip_p) {
1515 	case IPPROTO_ICMP:
1516 		iresult = IcmpAliasOut(la, pip, create);
1517 		break;
1518 	case IPPROTO_UDP:
1519 		iresult = UdpAliasOut(la, pip, maxpacketsize, create);
1520 		break;
1521 	case IPPROTO_TCP:
1522 		iresult = TcpAliasOut(la, pip, maxpacketsize, create);
1523 		break;
1524 #ifdef _KERNEL
1525 	case IPPROTO_SCTP:
1526 		iresult = SctpAlias(la, pip, SN_TO_GLOBAL);
1527 		break;
1528 #endif
1529 	case IPPROTO_GRE: {
1530 		int error;
1531 		struct alias_data ad = {
1532 			.lnk = NULL,
1533 			.oaddr = NULL,
1534 			.aaddr = NULL,
1535 			.aport = NULL,
1536 			.sport = NULL,
1537 			.dport = NULL,
1538 			.maxpktsize = 0
1539 		};
1540 		/* Walk out chain. */
1541 		error = find_handler(OUT, IP, la, pip, &ad);
1542 		if (error == 0)
1543 			iresult = PKT_ALIAS_OK;
1544 		else
1545 			iresult = ProtoAliasOut(la, pip,
1546 			    pip->ip_dst, pip->ip_p, &pip->ip_sum, create);
1547 		break;
1548 		}
1549 	default:
1550 		iresult = ProtoAliasOut(la, pip,
1551 		    pip->ip_dst, pip->ip_p, &pip->ip_sum, create);
1552 		break;
1553 	}
1554 
1555 getout_restore:
1556 	SetDefaultAliasAddress(la, addr_save);
1557 getout:
1558 	return (iresult);
1559 }
1560 
1561 int
1562 LibAliasUnaliasOut(struct libalias *la,
1563     void *ptr,		/* valid IP packet */
1564     int maxpacketsize	/* for error checking */
1565 )
1566 {
1567 	struct ip *pip;
1568 	struct icmp *ic;
1569 	struct udphdr *ud;
1570 	struct tcphdr *tc;
1571 	struct alias_link *lnk;
1572 	int iresult = PKT_ALIAS_IGNORED;
1573 
1574 	LIBALIAS_LOCK(la);
1575 	pip = (struct ip *)ptr;
1576 
1577 	/* Defense against mangled packets */
1578 	if (ntohs(pip->ip_len) > maxpacketsize
1579 	    || (pip->ip_hl << 2) > maxpacketsize)
1580 		goto getout;
1581 
1582 	ud = (struct udphdr *)ip_next(pip);
1583 	tc = (struct tcphdr *)ip_next(pip);
1584 	ic = (struct icmp *)ip_next(pip);
1585 
1586 	/* Find a link */
1587 	if (pip->ip_p == IPPROTO_UDP)
1588 		lnk = FindUdpTcpIn(la, pip->ip_dst, pip->ip_src,
1589 		    ud->uh_dport, ud->uh_sport,
1590 		    IPPROTO_UDP, 0);
1591 	else if (pip->ip_p == IPPROTO_TCP)
1592 		lnk = FindUdpTcpIn(la, pip->ip_dst, pip->ip_src,
1593 		    tc->th_dport, tc->th_sport,
1594 		    IPPROTO_TCP, 0);
1595 	else if (pip->ip_p == IPPROTO_ICMP)
1596 		lnk = FindIcmpIn(la, pip->ip_dst, pip->ip_src, ic->icmp_id, 0);
1597 	else
1598 		lnk = NULL;
1599 
1600 	/* Change it from an aliased packet to an unaliased packet */
1601 	if (lnk != NULL) {
1602 		if (pip->ip_p == IPPROTO_UDP || pip->ip_p == IPPROTO_TCP) {
1603 			int accumulate;
1604 			struct in_addr original_address;
1605 			u_short original_port;
1606 
1607 			original_address = GetOriginalAddress(lnk);
1608 			original_port = GetOriginalPort(lnk);
1609 
1610 			/* Adjust TCP/UDP checksum */
1611 			accumulate = twowords(&pip->ip_src);
1612 			accumulate -= twowords(&original_address);
1613 
1614 			if (pip->ip_p == IPPROTO_UDP) {
1615 				accumulate += ud->uh_sport;
1616 				accumulate -= original_port;
1617 				ADJUST_CHECKSUM(accumulate, ud->uh_sum);
1618 			} else {
1619 				accumulate += tc->th_sport;
1620 				accumulate -= original_port;
1621 				ADJUST_CHECKSUM(accumulate, tc->th_sum);
1622 			}
1623 
1624 			/* Adjust IP checksum */
1625 			DifferentialChecksum(&pip->ip_sum,
1626 			    &original_address, &pip->ip_src, 2);
1627 
1628 			/* Un-alias source address and port number */
1629 			pip->ip_src = original_address;
1630 			if (pip->ip_p == IPPROTO_UDP)
1631 				ud->uh_sport = original_port;
1632 			else
1633 				tc->th_sport = original_port;
1634 
1635 			iresult = PKT_ALIAS_OK;
1636 		} else if (pip->ip_p == IPPROTO_ICMP) {
1637 			int accumulate;
1638 			struct in_addr original_address;
1639 			u_short original_id;
1640 
1641 			original_address = GetOriginalAddress(lnk);
1642 			original_id = GetOriginalPort(lnk);
1643 
1644 			/* Adjust ICMP checksum */
1645 			accumulate = twowords(&pip->ip_src);
1646 			accumulate -= twowords(&original_address);
1647 			accumulate += ic->icmp_id;
1648 			accumulate -= original_id;
1649 			ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
1650 
1651 			/* Adjust IP checksum */
1652 			DifferentialChecksum(&pip->ip_sum,
1653 			    &original_address, &pip->ip_src, 2);
1654 
1655 			/* Un-alias source address and port number */
1656 			pip->ip_src = original_address;
1657 			ic->icmp_id = original_id;
1658 
1659 			iresult = PKT_ALIAS_OK;
1660 		}
1661 	}
1662 getout:
1663 	LIBALIAS_UNLOCK(la);
1664 	return (iresult);
1665 }
1666 
1667 #ifndef _KERNEL
1668 
1669 int
1670 LibAliasRefreshModules(void)
1671 {
1672 	char buf[256], conf[] = "/etc/libalias.conf";
1673 	FILE *fd;
1674 	int i, len;
1675 
1676 	fd = fopen(conf, "r");
1677 	if (fd == NULL)
1678 		err(1, "fopen(%s)", conf);
1679 
1680 	LibAliasUnLoadAllModule();
1681 
1682 	for (;;) {
1683 		fgets(buf, 256, fd);
1684 		if (feof(fd))
1685 			break;
1686 		len = strlen(buf);
1687 		if (len > 1) {
1688 			for (i = 0; i < len; i++)
1689 				if (!isspace(buf[i]))
1690 					break;
1691 			if (buf[i] == '#')
1692 				continue;
1693 			buf[len - 1] = '\0';
1694 			LibAliasLoadModule(buf);
1695 		}
1696 	}
1697 	fclose(fd);
1698 	return (0);
1699 }
1700 
1701 int
1702 LibAliasLoadModule(char *path)
1703 {
1704 	struct dll *t;
1705 	void *handle;
1706 	struct proto_handler *m;
1707 	const char *error;
1708 	moduledata_t *p;
1709 
1710 	handle = dlopen (path, RTLD_LAZY);
1711 	if (!handle) {
1712 		fprintf(stderr, "%s\n", dlerror());
1713 		return (EINVAL);
1714 	}
1715 
1716 	p = dlsym(handle, "alias_mod");
1717 	if ((error = dlerror()) != NULL)  {
1718 		fprintf(stderr, "%s\n", dlerror());
1719 		return (EINVAL);
1720 	}
1721 
1722 	t = malloc(sizeof(struct dll));
1723 	if (t == NULL)
1724 		return (ENOMEM);
1725 	strncpy(t->name, p->name, DLL_LEN);
1726 	t->handle = handle;
1727 	if (attach_dll(t) == EEXIST) {
1728 		free(t);
1729 		fprintf(stderr, "dll conflict\n");
1730 		return (EEXIST);
1731 	}
1732 
1733 	m = dlsym(t->handle, "handlers");
1734 	if ((error = dlerror()) != NULL)  {
1735 		fprintf(stderr, "%s\n", error);
1736 		return (EINVAL);
1737 	}
1738 
1739 	LibAliasAttachHandlers(m);
1740 	return (0);
1741 }
1742 
1743 int
1744 LibAliasUnLoadAllModule(void)
1745 {
1746 	struct dll *t;
1747 	struct proto_handler *p;
1748 
1749 	/* Unload all modules then reload everything. */
1750 	while ((p = first_handler()) != NULL) {
1751 		LibAliasDetachHandlers(p);
1752 	}
1753 	while ((t = walk_dll_chain()) != NULL) {
1754 		dlclose(t->handle);
1755 		free(t);
1756 	}
1757 	return (1);
1758 }
1759 
1760 #endif
1761 
1762 #ifdef _KERNEL
1763 /*
1764  * m_megapullup() - this function is a big hack.
1765  * Thankfully, it's only used in ng_nat and ipfw+nat.
1766  *
1767  * It allocates an mbuf with cluster and copies the specified part of the chain
1768  * into cluster, so that it is all contiguous and can be accessed via a plain
1769  * (char *) pointer. This is required, because libalias doesn't know how to
1770  * handle mbuf chains.
1771  *
1772  * On success, m_megapullup returns an mbuf (possibly with cluster) containing
1773  * the input packet, on failure NULL. The input packet is always consumed.
1774  */
1775 struct mbuf *
1776 m_megapullup(struct mbuf *m, int len)
1777 {
1778 	struct mbuf *mcl;
1779 
1780 	if (len > m->m_pkthdr.len)
1781 		goto bad;
1782 
1783 	if (m->m_next == NULL && M_WRITABLE(m))
1784 		return (m);
1785 
1786 	if (len <= MJUMPAGESIZE)
1787 		mcl = m_get2(len, M_NOWAIT, MT_DATA, M_PKTHDR);
1788 	else if (len <= MJUM9BYTES)
1789 		mcl = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUM9BYTES);
1790 	else if (len <= MJUM16BYTES)
1791 		mcl = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUM16BYTES);
1792 	else
1793 		goto bad;
1794 	if (mcl == NULL)
1795 		goto bad;
1796 	m_align(mcl, len);
1797 	m_move_pkthdr(mcl, m);
1798 	m_copydata(m, 0, len, mtod(mcl, caddr_t));
1799 	mcl->m_len = mcl->m_pkthdr.len = len;
1800 	m_freem(m);
1801 
1802 	return (mcl);
1803 bad:
1804 	m_freem(m);
1805 	return (NULL);
1806 }
1807 #endif
1808