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