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