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