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