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