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