xref: /freebsd/sys/netinet/libalias/alias.c (revision 74bf4e164ba5851606a27d4feff27717452583e5)
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 #include <sys/types.h>
115 
116 #include <netinet/in_systm.h>
117 #include <netinet/in.h>
118 #include <netinet/ip.h>
119 #include <netinet/ip_icmp.h>
120 #include <netinet/tcp.h>
121 #include <netinet/udp.h>
122 
123 #include <stdio.h>
124 
125 #include "alias_local.h"
126 #include "alias.h"
127 
128 #define NETBIOS_NS_PORT_NUMBER 137
129 #define NETBIOS_DGM_PORT_NUMBER 138
130 #define FTP_CONTROL_PORT_NUMBER 21
131 #define IRC_CONTROL_PORT_NUMBER_1 6667
132 #define IRC_CONTROL_PORT_NUMBER_2 6668
133 #define CUSEEME_PORT_NUMBER 7648
134 #define RTSP_CONTROL_PORT_NUMBER_1 554
135 #define RTSP_CONTROL_PORT_NUMBER_2 7070
136 #define TFTP_PORT_NUMBER 69
137 #define PPTP_CONTROL_PORT_NUMBER 1723
138 
139 static __inline int
140 twowords(void *p)
141 {
142 	uint8_t *c = p;
143 
144 #if BYTE_ORDER == LITTLE_ENDIAN
145 	uint16_t s1 = ((uint16_t)c[1] << 8) + (uint16_t)c[0];
146 	uint16_t s2 = ((uint16_t)c[3] << 8) + (uint16_t)c[2];
147 #else
148 	uint16_t s1 = ((uint16_t)c[0] << 8) + (uint16_t)c[1];
149 	uint16_t s2 = ((uint16_t)c[2] << 8) + (uint16_t)c[3];
150 #endif
151 	return (s1 + s2);
152 }
153 
154 /* TCP Handling Routines
155 
156     TcpMonitorIn()  -- These routines monitor TCP connections, and
157     TcpMonitorOut()    delete a link when a connection is closed.
158 
159 These routines look for SYN, FIN and RST flags to determine when TCP
160 connections open and close.  When a TCP connection closes, the data
161 structure containing packet aliasing information is deleted after
162 a timeout period.
163 */
164 
165 /* Local prototypes */
166 static void	TcpMonitorIn(struct ip *, struct alias_link *);
167 
168 static void	TcpMonitorOut(struct ip *, struct alias_link *);
169 
170 
171 static void
172 TcpMonitorIn(struct ip *pip, struct alias_link *lnk)
173 {
174 	struct tcphdr *tc;
175 
176 	tc = (struct tcphdr *)ip_next(pip);
177 
178 	switch (GetStateIn(lnk)) {
179 	case ALIAS_TCP_STATE_NOT_CONNECTED:
180 		if (tc->th_flags & TH_RST)
181 			SetStateIn(lnk, ALIAS_TCP_STATE_DISCONNECTED);
182 		else if (tc->th_flags & TH_SYN)
183 			SetStateIn(lnk, ALIAS_TCP_STATE_CONNECTED);
184 		break;
185 	case ALIAS_TCP_STATE_CONNECTED:
186 		if (tc->th_flags & (TH_FIN | TH_RST))
187 			SetStateIn(lnk, ALIAS_TCP_STATE_DISCONNECTED);
188 		break;
189 	}
190 }
191 
192 static void
193 TcpMonitorOut(struct ip *pip, struct alias_link *lnk)
194 {
195 	struct tcphdr *tc;
196 
197 	tc = (struct tcphdr *)ip_next(pip);
198 
199 	switch (GetStateOut(lnk)) {
200 	case ALIAS_TCP_STATE_NOT_CONNECTED:
201 		if (tc->th_flags & TH_RST)
202 			SetStateOut(lnk, ALIAS_TCP_STATE_DISCONNECTED);
203 		else if (tc->th_flags & TH_SYN)
204 			SetStateOut(lnk, ALIAS_TCP_STATE_CONNECTED);
205 		break;
206 	case ALIAS_TCP_STATE_CONNECTED:
207 		if (tc->th_flags & (TH_FIN | TH_RST))
208 			SetStateOut(lnk, ALIAS_TCP_STATE_DISCONNECTED);
209 		break;
210 	}
211 }
212 
213 
214 
215 
216 
217 /* Protocol Specific Packet Aliasing Routines
218 
219     IcmpAliasIn(), IcmpAliasIn1(), IcmpAliasIn2()
220     IcmpAliasOut(), IcmpAliasOut1(), IcmpAliasOut2()
221     ProtoAliasIn(), ProtoAliasOut()
222     UdpAliasIn(), UdpAliasOut()
223     TcpAliasIn(), TcpAliasOut()
224 
225 These routines handle protocol specific details of packet aliasing.
226 One may observe a certain amount of repetitive arithmetic in these
227 functions, the purpose of which is to compute a revised checksum
228 without actually summing over the entire data packet, which could be
229 unnecessarily time consuming.
230 
231 The purpose of the packet aliasing routines is to replace the source
232 address of the outgoing packet and then correctly put it back for
233 any incoming packets.  For TCP and UDP, ports are also re-mapped.
234 
235 For ICMP echo/timestamp requests and replies, the following scheme
236 is used: the ID number is replaced by an alias for the outgoing
237 packet.
238 
239 ICMP error messages are handled by looking at the IP fragment
240 in the data section of the message.
241 
242 For TCP and UDP protocols, a port number is chosen for an outgoing
243 packet, and then incoming packets are identified by IP address and
244 port numbers.  For TCP packets, there is additional logic in the event
245 that sequence and ACK numbers have been altered (as in the case for
246 FTP data port commands).
247 
248 The port numbers used by the packet aliasing module are not true
249 ports in the Unix sense.  No sockets are actually bound to ports.
250 They are more correctly thought of as placeholders.
251 
252 All packets go through the aliasing mechanism, whether they come from
253 the gateway machine or other machines on a local area network.
254 */
255 
256 
257 /* Local prototypes */
258 static int	IcmpAliasIn1(struct libalias *, struct ip *);
259 static int	IcmpAliasIn2(struct libalias *, struct ip *);
260 static int	IcmpAliasIn(struct libalias *, struct ip *);
261 
262 static int	IcmpAliasOut1(struct libalias *, struct ip *, int create);
263 static int	IcmpAliasOut2(struct libalias *, struct ip *);
264 static int	IcmpAliasOut(struct libalias *, struct ip *, int create);
265 
266 static int	ProtoAliasIn(struct libalias *, struct ip *);
267 static int	ProtoAliasOut(struct libalias *, struct ip *, int create);
268 
269 static int	UdpAliasIn(struct libalias *, struct ip *);
270 static int	UdpAliasOut(struct libalias *, struct ip *, int create);
271 
272 static int	TcpAliasIn(struct libalias *, struct ip *);
273 static int	TcpAliasOut(struct libalias *, struct ip *, int, int create);
274 
275 
276 static int
277 IcmpAliasIn1(struct libalias *la, struct ip *pip)
278 {
279 /*
280     De-alias incoming echo and timestamp replies.
281     Alias incoming echo and timestamp requests.
282 */
283 	struct alias_link *lnk;
284 	struct icmp *ic;
285 
286 	ic = (struct icmp *)ip_next(pip);
287 
288 /* Get source address from ICMP data field and restore original data */
289 	lnk = FindIcmpIn(la, pip->ip_src, pip->ip_dst, ic->icmp_id, 1);
290 	if (lnk != NULL) {
291 		u_short original_id;
292 		int accumulate;
293 
294 		original_id = GetOriginalPort(lnk);
295 
296 /* Adjust ICMP checksum */
297 		accumulate = ic->icmp_id;
298 		accumulate -= original_id;
299 		ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
300 
301 /* Put original sequence number back in */
302 		ic->icmp_id = original_id;
303 
304 /* Put original address back into IP header */
305 		{
306 			struct in_addr original_address;
307 
308 			original_address = GetOriginalAddress(lnk);
309 			DifferentialChecksum(&pip->ip_sum,
310 			    &original_address, &pip->ip_dst, 2);
311 			pip->ip_dst = original_address;
312 		}
313 
314 		return (PKT_ALIAS_OK);
315 	}
316 	return (PKT_ALIAS_IGNORED);
317 }
318 
319 static int
320 IcmpAliasIn2(struct libalias *la, struct ip *pip)
321 {
322 /*
323     Alias incoming ICMP error messages containing
324     IP header and first 64 bits of datagram.
325 */
326 	struct ip *ip;
327 	struct icmp *ic, *ic2;
328 	struct udphdr *ud;
329 	struct tcphdr *tc;
330 	struct alias_link *lnk;
331 
332 	ic = (struct icmp *)ip_next(pip);
333 	ip = &ic->icmp_ip;
334 
335 	ud = (struct udphdr *)ip_next(ip);
336 	tc = (struct tcphdr *)ip_next(ip);
337 	ic2 = (struct icmp *)ip_next(ip);
338 
339 	if (ip->ip_p == IPPROTO_UDP)
340 		lnk = FindUdpTcpIn(la, ip->ip_dst, ip->ip_src,
341 		    ud->uh_dport, ud->uh_sport,
342 		    IPPROTO_UDP, 0);
343 	else if (ip->ip_p == IPPROTO_TCP)
344 		lnk = FindUdpTcpIn(la, ip->ip_dst, ip->ip_src,
345 		    tc->th_dport, tc->th_sport,
346 		    IPPROTO_TCP, 0);
347 	else if (ip->ip_p == IPPROTO_ICMP) {
348 		if (ic2->icmp_type == ICMP_ECHO || ic2->icmp_type == ICMP_TSTAMP)
349 			lnk = FindIcmpIn(la, ip->ip_dst, ip->ip_src, ic2->icmp_id, 0);
350 		else
351 			lnk = NULL;
352 	} else
353 		lnk = NULL;
354 
355 	if (lnk != NULL) {
356 		if (ip->ip_p == IPPROTO_UDP || ip->ip_p == IPPROTO_TCP) {
357 			int accumulate, accumulate2;
358 			struct in_addr original_address;
359 			u_short original_port;
360 
361 			original_address = GetOriginalAddress(lnk);
362 			original_port = GetOriginalPort(lnk);
363 
364 /* Adjust ICMP checksum */
365 			accumulate = twowords(&ip->ip_src);
366 			accumulate -= twowords(&original_address);
367 			accumulate += ud->uh_sport;
368 			accumulate -= original_port;
369 			accumulate2 = accumulate;
370 			accumulate2 += ip->ip_sum;
371 			ADJUST_CHECKSUM(accumulate, ip->ip_sum);
372 			accumulate2 -= ip->ip_sum;
373 			ADJUST_CHECKSUM(accumulate2, ic->icmp_cksum);
374 
375 /* Un-alias address in IP header */
376 			DifferentialChecksum(&pip->ip_sum,
377 			    &original_address, &pip->ip_dst, 2);
378 			pip->ip_dst = original_address;
379 
380 /* Un-alias address and port number of original IP packet
381 fragment contained in ICMP data section */
382 			ip->ip_src = original_address;
383 			ud->uh_sport = original_port;
384 		} else if (ip->ip_p == IPPROTO_ICMP) {
385 			int accumulate, accumulate2;
386 			struct in_addr original_address;
387 			u_short original_id;
388 
389 			original_address = GetOriginalAddress(lnk);
390 			original_id = GetOriginalPort(lnk);
391 
392 /* Adjust ICMP checksum */
393 			accumulate = twowords(&ip->ip_src);
394 			accumulate -= twowords(&original_address);
395 			accumulate += ic2->icmp_id;
396 			accumulate -= original_id;
397 			accumulate2 = accumulate;
398 			accumulate2 += ip->ip_sum;
399 			ADJUST_CHECKSUM(accumulate, ip->ip_sum);
400 			accumulate2 -= ip->ip_sum;
401 			ADJUST_CHECKSUM(accumulate2, ic->icmp_cksum);
402 
403 /* Un-alias address in IP header */
404 			DifferentialChecksum(&pip->ip_sum,
405 			    &original_address, &pip->ip_dst, 2);
406 			pip->ip_dst = original_address;
407 
408 /* Un-alias address of original IP packet and sequence number of
409    embedded ICMP datagram */
410 			ip->ip_src = original_address;
411 			ic2->icmp_id = original_id;
412 		}
413 		return (PKT_ALIAS_OK);
414 	}
415 	return (PKT_ALIAS_IGNORED);
416 }
417 
418 
419 static int
420 IcmpAliasIn(struct libalias *la, struct ip *pip)
421 {
422 	int iresult;
423 	struct icmp *ic;
424 
425 /* Return if proxy-only mode is enabled */
426 	if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
427 		return (PKT_ALIAS_OK);
428 
429 	ic = (struct icmp *)ip_next(pip);
430 
431 	iresult = PKT_ALIAS_IGNORED;
432 	switch (ic->icmp_type) {
433 	case ICMP_ECHOREPLY:
434 	case ICMP_TSTAMPREPLY:
435 		if (ic->icmp_code == 0) {
436 			iresult = IcmpAliasIn1(la, pip);
437 		}
438 		break;
439 	case ICMP_UNREACH:
440 	case ICMP_SOURCEQUENCH:
441 	case ICMP_TIMXCEED:
442 	case ICMP_PARAMPROB:
443 		iresult = IcmpAliasIn2(la, pip);
444 		break;
445 	case ICMP_ECHO:
446 	case ICMP_TSTAMP:
447 		iresult = IcmpAliasIn1(la, pip);
448 		break;
449 	}
450 	return (iresult);
451 }
452 
453 
454 static int
455 IcmpAliasOut1(struct libalias *la, struct ip *pip, int create)
456 {
457 /*
458     Alias outgoing echo and timestamp requests.
459     De-alias outgoing echo and timestamp replies.
460 */
461 	struct alias_link *lnk;
462 	struct icmp *ic;
463 
464 	ic = (struct icmp *)ip_next(pip);
465 
466 /* Save overwritten data for when echo packet returns */
467 	lnk = FindIcmpOut(la, pip->ip_src, pip->ip_dst, ic->icmp_id, create);
468 	if (lnk != NULL) {
469 		u_short alias_id;
470 		int accumulate;
471 
472 		alias_id = GetAliasPort(lnk);
473 
474 /* Since data field is being modified, adjust ICMP checksum */
475 		accumulate = ic->icmp_id;
476 		accumulate -= alias_id;
477 		ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
478 
479 /* Alias sequence number */
480 		ic->icmp_id = alias_id;
481 
482 /* Change source address */
483 		{
484 			struct in_addr alias_address;
485 
486 			alias_address = GetAliasAddress(lnk);
487 			DifferentialChecksum(&pip->ip_sum,
488 			    &alias_address, &pip->ip_src, 2);
489 			pip->ip_src = alias_address;
490 		}
491 
492 		return (PKT_ALIAS_OK);
493 	}
494 	return (PKT_ALIAS_IGNORED);
495 }
496 
497 
498 static int
499 IcmpAliasOut2(struct libalias *la, struct ip *pip)
500 {
501 /*
502     Alias outgoing ICMP error messages containing
503     IP header and first 64 bits of datagram.
504 */
505 	struct ip *ip;
506 	struct icmp *ic, *ic2;
507 	struct udphdr *ud;
508 	struct tcphdr *tc;
509 	struct alias_link *lnk;
510 
511 	ic = (struct icmp *)ip_next(pip);
512 	ip = &ic->icmp_ip;
513 
514 	ud = (struct udphdr *)ip_next(ip);
515 	tc = (struct tcphdr *)ip_next(ip);
516 	ic2 = (struct icmp *)ip_next(ip);
517 
518 	if (ip->ip_p == IPPROTO_UDP)
519 		lnk = FindUdpTcpOut(la, ip->ip_dst, ip->ip_src,
520 		    ud->uh_dport, ud->uh_sport,
521 		    IPPROTO_UDP, 0);
522 	else if (ip->ip_p == IPPROTO_TCP)
523 		lnk = FindUdpTcpOut(la, ip->ip_dst, ip->ip_src,
524 		    tc->th_dport, tc->th_sport,
525 		    IPPROTO_TCP, 0);
526 	else if (ip->ip_p == IPPROTO_ICMP) {
527 		if (ic2->icmp_type == ICMP_ECHO || ic2->icmp_type == ICMP_TSTAMP)
528 			lnk = FindIcmpOut(la, ip->ip_dst, ip->ip_src, ic2->icmp_id, 0);
529 		else
530 			lnk = NULL;
531 	} else
532 		lnk = NULL;
533 
534 	if (lnk != NULL) {
535 		if (ip->ip_p == IPPROTO_UDP || ip->ip_p == IPPROTO_TCP) {
536 			int accumulate;
537 			struct in_addr alias_address;
538 			u_short alias_port;
539 
540 			alias_address = GetAliasAddress(lnk);
541 			alias_port = GetAliasPort(lnk);
542 
543 /* Adjust ICMP checksum */
544 			accumulate = twowords(&ip->ip_dst);
545 			accumulate -= twowords(&alias_address);
546 			accumulate += ud->uh_dport;
547 			accumulate -= alias_port;
548 			ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
549 
550 /*
551  * Alias address in IP header if it comes from the host
552  * the original TCP/UDP packet was destined for.
553  */
554 			if (pip->ip_src.s_addr == ip->ip_dst.s_addr) {
555 				DifferentialChecksum(&pip->ip_sum,
556 				    &alias_address, &pip->ip_src, 2);
557 				pip->ip_src = alias_address;
558 			}
559 /* Alias address and port number of original IP packet
560 fragment contained in ICMP data section */
561 			ip->ip_dst = alias_address;
562 			ud->uh_dport = alias_port;
563 		} else if (ip->ip_p == IPPROTO_ICMP) {
564 			int accumulate;
565 			struct in_addr alias_address;
566 			u_short alias_id;
567 
568 			alias_address = GetAliasAddress(lnk);
569 			alias_id = GetAliasPort(lnk);
570 
571 /* Adjust ICMP checksum */
572 			accumulate = twowords(&ip->ip_dst);
573 			accumulate -= twowords(&alias_address);
574 			accumulate += ic2->icmp_id;
575 			accumulate -= alias_id;
576 			ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
577 
578 /*
579  * Alias address in IP header if it comes from the host
580  * the original ICMP message was destined for.
581  */
582 			if (pip->ip_src.s_addr == ip->ip_dst.s_addr) {
583 				DifferentialChecksum(&pip->ip_sum,
584 				    &alias_address, &pip->ip_src, 2);
585 				pip->ip_src = alias_address;
586 			}
587 /* Alias address of original IP packet and sequence number of
588    embedded ICMP datagram */
589 			ip->ip_dst = alias_address;
590 			ic2->icmp_id = alias_id;
591 		}
592 		return (PKT_ALIAS_OK);
593 	}
594 	return (PKT_ALIAS_IGNORED);
595 }
596 
597 
598 static int
599 IcmpAliasOut(struct libalias *la, struct ip *pip, int create)
600 {
601 	int iresult;
602 	struct icmp *ic;
603 
604 	(void)create;
605 
606 /* Return if proxy-only mode is enabled */
607 	if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
608 		return (PKT_ALIAS_OK);
609 
610 	ic = (struct icmp *)ip_next(pip);
611 
612 	iresult = PKT_ALIAS_IGNORED;
613 	switch (ic->icmp_type) {
614 	case ICMP_ECHO:
615 	case ICMP_TSTAMP:
616 		if (ic->icmp_code == 0) {
617 			iresult = IcmpAliasOut1(la, pip, create);
618 		}
619 		break;
620 	case ICMP_UNREACH:
621 	case ICMP_SOURCEQUENCH:
622 	case ICMP_TIMXCEED:
623 	case ICMP_PARAMPROB:
624 		iresult = IcmpAliasOut2(la, pip);
625 		break;
626 	case ICMP_ECHOREPLY:
627 	case ICMP_TSTAMPREPLY:
628 		iresult = IcmpAliasOut1(la, pip, create);
629 	}
630 	return (iresult);
631 }
632 
633 
634 
635 static int
636 ProtoAliasIn(struct libalias *la, struct ip *pip)
637 {
638 /*
639   Handle incoming IP packets. The
640   only thing which is done in this case is to alias
641   the dest IP address of the packet to our inside
642   machine.
643 */
644 	struct alias_link *lnk;
645 
646 /* Return if proxy-only mode is enabled */
647 	if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
648 		return (PKT_ALIAS_OK);
649 
650 	lnk = FindProtoIn(la, pip->ip_src, pip->ip_dst, pip->ip_p);
651 	if (lnk != NULL) {
652 		struct in_addr original_address;
653 
654 		original_address = GetOriginalAddress(lnk);
655 
656 /* Restore original IP address */
657 		DifferentialChecksum(&pip->ip_sum,
658 		    &original_address, &pip->ip_dst, 2);
659 		pip->ip_dst = original_address;
660 
661 		return (PKT_ALIAS_OK);
662 	}
663 	return (PKT_ALIAS_IGNORED);
664 }
665 
666 
667 static int
668 ProtoAliasOut(struct libalias *la, struct ip *pip, int create)
669 {
670 /*
671   Handle outgoing IP packets. The
672   only thing which is done in this case is to alias
673   the source IP address of the packet.
674 */
675 	struct alias_link *lnk;
676 
677 	(void)create;
678 
679 /* Return if proxy-only mode is enabled */
680 	if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
681 		return (PKT_ALIAS_OK);
682 
683 	lnk = FindProtoOut(la, pip->ip_src, pip->ip_dst, pip->ip_p);
684 	if (lnk != NULL) {
685 		struct in_addr alias_address;
686 
687 		alias_address = GetAliasAddress(lnk);
688 
689 /* Change source address */
690 		DifferentialChecksum(&pip->ip_sum,
691 		    &alias_address, &pip->ip_src, 2);
692 		pip->ip_src = alias_address;
693 
694 		return (PKT_ALIAS_OK);
695 	}
696 	return (PKT_ALIAS_IGNORED);
697 }
698 
699 
700 static int
701 UdpAliasIn(struct libalias *la, struct ip *pip)
702 {
703 	struct udphdr *ud;
704 	struct alias_link *lnk;
705 
706 /* Return if proxy-only mode is enabled */
707 	if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
708 		return (PKT_ALIAS_OK);
709 
710 	ud = (struct udphdr *)ip_next(pip);
711 
712 	lnk = FindUdpTcpIn(la, pip->ip_src, pip->ip_dst,
713 	    ud->uh_sport, ud->uh_dport,
714 	    IPPROTO_UDP, 1);
715 	if (lnk != NULL) {
716 		struct in_addr alias_address;
717 		struct in_addr original_address;
718 		u_short alias_port;
719 		int accumulate;
720 		int r = 0;
721 
722 		alias_address = GetAliasAddress(lnk);
723 		original_address = GetOriginalAddress(lnk);
724 		alias_port = ud->uh_dport;
725 		ud->uh_dport = GetOriginalPort(lnk);
726 
727 /* Special processing for IP encoding protocols */
728 		if (ntohs(ud->uh_dport) == CUSEEME_PORT_NUMBER)
729 			AliasHandleCUSeeMeIn(la, pip, original_address);
730 /* If NETBIOS Datagram, It should be alias address in UDP Data, too */
731 		else if (ntohs(ud->uh_dport) == NETBIOS_DGM_PORT_NUMBER
732 		    || ntohs(ud->uh_sport) == NETBIOS_DGM_PORT_NUMBER)
733 			r = AliasHandleUdpNbt(la, pip, lnk, &original_address, ud->uh_dport);
734 		else if (ntohs(ud->uh_dport) == NETBIOS_NS_PORT_NUMBER
735 		    || ntohs(ud->uh_sport) == NETBIOS_NS_PORT_NUMBER)
736 			r = AliasHandleUdpNbtNS(la, pip, lnk, &alias_address, &alias_port,
737 			    &original_address, &ud->uh_dport);
738 
739 /* If UDP checksum is not zero, then adjust since destination port */
740 /* is being unaliased and destination address is being altered.    */
741 		if (ud->uh_sum != 0) {
742 			accumulate = alias_port;
743 			accumulate -= ud->uh_dport;
744 			accumulate += twowords(&alias_address);
745 			accumulate -= twowords(&original_address);
746 			ADJUST_CHECKSUM(accumulate, ud->uh_sum);
747 		}
748 /* Restore original IP address */
749 		DifferentialChecksum(&pip->ip_sum,
750 		    &original_address, &pip->ip_dst, 2);
751 		pip->ip_dst = original_address;
752 
753 		/*
754 		 * If we cannot figure out the packet, ignore it.
755 		 */
756 		if (r < 0)
757 			return (PKT_ALIAS_IGNORED);
758 		else
759 			return (PKT_ALIAS_OK);
760 	}
761 	return (PKT_ALIAS_IGNORED);
762 }
763 
764 static int
765 UdpAliasOut(struct libalias *la, struct ip *pip, int create)
766 {
767 	struct udphdr *ud;
768 	struct alias_link *lnk;
769 
770 /* Return if proxy-only mode is enabled */
771 	if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
772 		return (PKT_ALIAS_OK);
773 
774 	ud = (struct udphdr *)ip_next(pip);
775 
776 	lnk = FindUdpTcpOut(la, pip->ip_src, pip->ip_dst,
777 	    ud->uh_sport, ud->uh_dport,
778 	    IPPROTO_UDP, create);
779 	if (lnk != NULL) {
780 		u_short alias_port;
781 		struct in_addr alias_address;
782 
783 		alias_address = GetAliasAddress(lnk);
784 		alias_port = GetAliasPort(lnk);
785 
786 /* Special processing for IP encoding protocols */
787 		if (ntohs(ud->uh_dport) == CUSEEME_PORT_NUMBER)
788 			AliasHandleCUSeeMeOut(la, pip, lnk);
789 /* If NETBIOS Datagram, It should be alias address in UDP Data, too */
790 		else if (ntohs(ud->uh_dport) == NETBIOS_DGM_PORT_NUMBER
791 		    || ntohs(ud->uh_sport) == NETBIOS_DGM_PORT_NUMBER)
792 			AliasHandleUdpNbt(la, pip, lnk, &alias_address, alias_port);
793 		else if (ntohs(ud->uh_dport) == NETBIOS_NS_PORT_NUMBER
794 		    || ntohs(ud->uh_sport) == NETBIOS_NS_PORT_NUMBER)
795 			AliasHandleUdpNbtNS(la, pip, lnk, &pip->ip_src, &ud->uh_sport,
796 			    &alias_address, &alias_port);
797 /*
798  * We don't know in advance what TID the TFTP server will choose,
799  * so we create a wilcard link (destination port is unspecified)
800  * that will match any TID from a given destination.
801  */
802 		else if (ntohs(ud->uh_dport) == TFTP_PORT_NUMBER)
803 			FindRtspOut(la, pip->ip_src, pip->ip_dst,
804 			    ud->uh_sport, alias_port, IPPROTO_UDP);
805 
806 /* If UDP checksum is not zero, adjust since source port is */
807 /* being aliased and source address is being altered        */
808 		if (ud->uh_sum != 0) {
809 			int accumulate;
810 
811 			accumulate = ud->uh_sport;
812 			accumulate -= alias_port;
813 			accumulate += twowords(&pip->ip_src);
814 			accumulate -= twowords(&alias_address);
815 			ADJUST_CHECKSUM(accumulate, ud->uh_sum);
816 		}
817 /* Put alias port in UDP header */
818 		ud->uh_sport = alias_port;
819 
820 /* Change source address */
821 		DifferentialChecksum(&pip->ip_sum,
822 		    &alias_address, &pip->ip_src, 2);
823 		pip->ip_src = alias_address;
824 
825 		return (PKT_ALIAS_OK);
826 	}
827 	return (PKT_ALIAS_IGNORED);
828 }
829 
830 
831 
832 static int
833 TcpAliasIn(struct libalias *la, struct ip *pip)
834 {
835 	struct tcphdr *tc;
836 	struct alias_link *lnk;
837 
838 	tc = (struct tcphdr *)ip_next(pip);
839 
840 	lnk = FindUdpTcpIn(la, pip->ip_src, pip->ip_dst,
841 	    tc->th_sport, tc->th_dport,
842 	    IPPROTO_TCP,
843 	    !(la->packetAliasMode & PKT_ALIAS_PROXY_ONLY));
844 	if (lnk != NULL) {
845 		struct in_addr alias_address;
846 		struct in_addr original_address;
847 		struct in_addr proxy_address;
848 		u_short alias_port;
849 		u_short proxy_port;
850 		int accumulate;
851 
852 /* Special processing for IP encoding protocols */
853 		if (ntohs(tc->th_dport) == PPTP_CONTROL_PORT_NUMBER
854 		    || ntohs(tc->th_sport) == PPTP_CONTROL_PORT_NUMBER)
855 			AliasHandlePptpIn(la, pip, lnk);
856 		else if (la->skinnyPort != 0 && (ntohs(tc->th_dport) == la->skinnyPort
857 		    || ntohs(tc->th_sport) == la->skinnyPort))
858 			AliasHandleSkinny(la, pip, lnk);
859 
860 		alias_address = GetAliasAddress(lnk);
861 		original_address = GetOriginalAddress(lnk);
862 		proxy_address = GetProxyAddress(lnk);
863 		alias_port = tc->th_dport;
864 		tc->th_dport = GetOriginalPort(lnk);
865 		proxy_port = GetProxyPort(lnk);
866 
867 /* Adjust TCP checksum since destination port is being unaliased */
868 /* and destination port is being altered.                        */
869 		accumulate = alias_port;
870 		accumulate -= tc->th_dport;
871 		accumulate += twowords(&alias_address);
872 		accumulate -= twowords(&original_address);
873 
874 /* If this is a proxy, then modify the TCP source port and
875    checksum accumulation */
876 		if (proxy_port != 0) {
877 			accumulate += tc->th_sport;
878 			tc->th_sport = proxy_port;
879 			accumulate -= tc->th_sport;
880 			accumulate += twowords(&pip->ip_src);
881 			accumulate -= twowords(&proxy_address);
882 		}
883 /* See if ACK number needs to be modified */
884 		if (GetAckModified(lnk) == 1) {
885 			int delta;
886 
887 			delta = GetDeltaAckIn(pip, lnk);
888 			if (delta != 0) {
889 				accumulate += twowords(&tc->th_ack);
890 				tc->th_ack = htonl(ntohl(tc->th_ack) - delta);
891 				accumulate -= twowords(&tc->th_ack);
892 			}
893 		}
894 		ADJUST_CHECKSUM(accumulate, tc->th_sum);
895 
896 /* Restore original IP address */
897 		accumulate = twowords(&pip->ip_dst);
898 		pip->ip_dst = original_address;
899 		accumulate -= twowords(&pip->ip_dst);
900 
901 /* If this is a transparent proxy packet, then modify the source
902    address */
903 		if (proxy_address.s_addr != 0) {
904 			accumulate += twowords(&pip->ip_src);
905 			pip->ip_src = proxy_address;
906 			accumulate -= twowords(&pip->ip_src);
907 		}
908 		ADJUST_CHECKSUM(accumulate, pip->ip_sum);
909 
910 /* Monitor TCP connection state */
911 		TcpMonitorIn(pip, lnk);
912 
913 		return (PKT_ALIAS_OK);
914 	}
915 	return (PKT_ALIAS_IGNORED);
916 }
917 
918 static int
919 TcpAliasOut(struct libalias *la, struct ip *pip, int maxpacketsize, int create)
920 {
921 	int proxy_type;
922 	u_short dest_port;
923 	u_short proxy_server_port;
924 	struct in_addr dest_address;
925 	struct in_addr proxy_server_address;
926 	struct tcphdr *tc;
927 	struct alias_link *lnk;
928 
929 	tc = (struct tcphdr *)ip_next(pip);
930 
931 	proxy_type = ProxyCheck(la, pip, &proxy_server_address, &proxy_server_port);
932 
933 	if (proxy_type == 0 && (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY))
934 		return (PKT_ALIAS_OK);
935 
936 /* If this is a transparent proxy, save original destination,
937    then alter the destination and adjust checksums */
938 	dest_port = tc->th_dport;
939 	dest_address = pip->ip_dst;
940 	if (proxy_type != 0) {
941 		int accumulate;
942 
943 		accumulate = tc->th_dport;
944 		tc->th_dport = proxy_server_port;
945 		accumulate -= tc->th_dport;
946 		accumulate += twowords(&pip->ip_dst);
947 		accumulate -= twowords(&proxy_server_address);
948 		ADJUST_CHECKSUM(accumulate, tc->th_sum);
949 
950 		accumulate = twowords(&pip->ip_dst);
951 		pip->ip_dst = proxy_server_address;
952 		accumulate -= twowords(&pip->ip_dst);
953 		ADJUST_CHECKSUM(accumulate, pip->ip_sum);
954 	}
955 	lnk = FindUdpTcpOut(la, pip->ip_src, pip->ip_dst,
956 	    tc->th_sport, tc->th_dport,
957 	    IPPROTO_TCP, create);
958 	if (lnk == NULL)
959 		return (PKT_ALIAS_IGNORED);
960 	if (lnk != NULL) {
961 		u_short alias_port;
962 		struct in_addr alias_address;
963 		int accumulate;
964 
965 /* Save original destination address, if this is a proxy packet.
966    Also modify packet to include destination encoding.  This may
967    change the size of IP header. */
968 		if (proxy_type != 0) {
969 			SetProxyPort(lnk, dest_port);
970 			SetProxyAddress(lnk, dest_address);
971 			ProxyModify(la, lnk, pip, maxpacketsize, proxy_type);
972 			tc = (struct tcphdr *)ip_next(pip);
973 		}
974 /* Get alias address and port */
975 		alias_port = GetAliasPort(lnk);
976 		alias_address = GetAliasAddress(lnk);
977 
978 /* Monitor TCP connection state */
979 		TcpMonitorOut(pip, lnk);
980 
981 /* Special processing for IP encoding protocols */
982 		if (ntohs(tc->th_dport) == FTP_CONTROL_PORT_NUMBER
983 		    || ntohs(tc->th_sport) == FTP_CONTROL_PORT_NUMBER)
984 			AliasHandleFtpOut(la, pip, lnk, maxpacketsize);
985 		else if (ntohs(tc->th_dport) == IRC_CONTROL_PORT_NUMBER_1
986 		    || ntohs(tc->th_dport) == IRC_CONTROL_PORT_NUMBER_2)
987 			AliasHandleIrcOut(la, pip, lnk, maxpacketsize);
988 		else if (ntohs(tc->th_dport) == RTSP_CONTROL_PORT_NUMBER_1
989 			    || ntohs(tc->th_sport) == RTSP_CONTROL_PORT_NUMBER_1
990 			    || ntohs(tc->th_dport) == RTSP_CONTROL_PORT_NUMBER_2
991 		    || ntohs(tc->th_sport) == RTSP_CONTROL_PORT_NUMBER_2)
992 			AliasHandleRtspOut(la, pip, lnk, maxpacketsize);
993 		else if (ntohs(tc->th_dport) == PPTP_CONTROL_PORT_NUMBER
994 		    || ntohs(tc->th_sport) == PPTP_CONTROL_PORT_NUMBER)
995 			AliasHandlePptpOut(la, pip, lnk);
996 		else if (la->skinnyPort != 0 && (ntohs(tc->th_sport) == la->skinnyPort
997 		    || ntohs(tc->th_dport) == la->skinnyPort))
998 			AliasHandleSkinny(la, pip, lnk);
999 
1000 /* Adjust TCP checksum since source port is being aliased */
1001 /* and source address is being altered                    */
1002 		accumulate = tc->th_sport;
1003 		tc->th_sport = alias_port;
1004 		accumulate -= tc->th_sport;
1005 		accumulate += twowords(&pip->ip_src);
1006 		accumulate -= twowords(&alias_address);
1007 
1008 /* Modify sequence number if necessary */
1009 		if (GetAckModified(lnk) == 1) {
1010 			int delta;
1011 
1012 			delta = GetDeltaSeqOut(pip, lnk);
1013 			if (delta != 0) {
1014 				accumulate += twowords(&tc->th_seq);
1015 				tc->th_seq = htonl(ntohl(tc->th_seq) + delta);
1016 				accumulate -= twowords(&tc->th_seq);
1017 			}
1018 		}
1019 		ADJUST_CHECKSUM(accumulate, tc->th_sum);
1020 
1021 /* Change source address */
1022 		accumulate = twowords(&pip->ip_src);
1023 		pip->ip_src = alias_address;
1024 		accumulate -= twowords(&pip->ip_src);
1025 		ADJUST_CHECKSUM(accumulate, pip->ip_sum);
1026 
1027 		return (PKT_ALIAS_OK);
1028 	}
1029 	return (PKT_ALIAS_IGNORED);
1030 }
1031 
1032 
1033 
1034 
1035 /* Fragment Handling
1036 
1037     FragmentIn()
1038     FragmentOut()
1039 
1040 The packet aliasing module has a limited ability for handling IP
1041 fragments.  If the ICMP, TCP or UDP header is in the first fragment
1042 received, then the ID number of the IP packet is saved, and other
1043 fragments are identified according to their ID number and IP address
1044 they were sent from.  Pointers to unresolved fragments can also be
1045 saved and recalled when a header fragment is seen.
1046 */
1047 
1048 /* Local prototypes */
1049 static int	FragmentIn(struct libalias *, struct ip *);
1050 static int	FragmentOut(struct libalias *, struct ip *);
1051 
1052 
1053 static int
1054 FragmentIn(struct libalias *la, struct ip *pip)
1055 {
1056 	struct alias_link *lnk;
1057 
1058 	lnk = FindFragmentIn2(la, pip->ip_src, pip->ip_dst, pip->ip_id);
1059 	if (lnk != NULL) {
1060 		struct in_addr original_address;
1061 
1062 		GetFragmentAddr(lnk, &original_address);
1063 		DifferentialChecksum(&pip->ip_sum,
1064 		    &original_address, &pip->ip_dst, 2);
1065 		pip->ip_dst = original_address;
1066 
1067 		return (PKT_ALIAS_OK);
1068 	}
1069 	return (PKT_ALIAS_UNRESOLVED_FRAGMENT);
1070 }
1071 
1072 
1073 static int
1074 FragmentOut(struct libalias *la, struct ip *pip)
1075 {
1076 	struct in_addr alias_address;
1077 
1078 	alias_address = FindAliasAddress(la, pip->ip_src);
1079 	DifferentialChecksum(&pip->ip_sum,
1080 	    &alias_address, &pip->ip_src, 2);
1081 	pip->ip_src = alias_address;
1082 
1083 	return (PKT_ALIAS_OK);
1084 }
1085 
1086 
1087 
1088 
1089 
1090 
1091 /* Outside World Access
1092 
1093 	PacketAliasSaveFragment()
1094 	PacketAliasGetFragment()
1095 	PacketAliasFragmentIn()
1096 	PacketAliasIn()
1097 	PacketAliasOut()
1098 	PacketUnaliasOut()
1099 
1100 (prototypes in alias.h)
1101 */
1102 
1103 
1104 int
1105 LibAliasSaveFragment(struct libalias *la, char *ptr)
1106 {
1107 	int iresult;
1108 	struct alias_link *lnk;
1109 	struct ip *pip;
1110 
1111 	pip = (struct ip *)ptr;
1112 	lnk = AddFragmentPtrLink(la, pip->ip_src, pip->ip_id);
1113 	iresult = PKT_ALIAS_ERROR;
1114 	if (lnk != NULL) {
1115 		SetFragmentPtr(lnk, ptr);
1116 		iresult = PKT_ALIAS_OK;
1117 	}
1118 	return (iresult);
1119 }
1120 
1121 
1122 char           *
1123 LibAliasGetFragment(struct libalias *la, char *ptr)
1124 {
1125 	struct alias_link *lnk;
1126 	char *fptr;
1127 	struct ip *pip;
1128 
1129 	pip = (struct ip *)ptr;
1130 	lnk = FindFragmentPtr(la, pip->ip_src, pip->ip_id);
1131 	if (lnk != NULL) {
1132 		GetFragmentPtr(lnk, &fptr);
1133 		SetFragmentPtr(lnk, NULL);
1134 		SetExpire(lnk, 0);	/* Deletes link */
1135 
1136 		return (fptr);
1137 	} else {
1138 		return (NULL);
1139 	}
1140 }
1141 
1142 
1143 void
1144 LibAliasFragmentIn(struct libalias *la, char *ptr,	/* Points to correctly
1145 							 * de-aliased header
1146 							 * fragment */
1147     char *ptr_fragment		/* Points to fragment which must be
1148 				 * de-aliased   */
1149 )
1150 {
1151 	struct ip *pip;
1152 	struct ip *fpip;
1153 
1154 	(void)la;
1155 	pip = (struct ip *)ptr;
1156 	fpip = (struct ip *)ptr_fragment;
1157 
1158 	DifferentialChecksum(&fpip->ip_sum,
1159 	    &pip->ip_dst, &fpip->ip_dst, 2);
1160 	fpip->ip_dst = pip->ip_dst;
1161 }
1162 
1163 
1164 int
1165 LibAliasIn(struct libalias *la, char *ptr, int maxpacketsize)
1166 {
1167 	struct in_addr alias_addr;
1168 	struct ip *pip;
1169 	int iresult;
1170 
1171 	if (la->packetAliasMode & PKT_ALIAS_REVERSE) {
1172 		la->packetAliasMode &= ~PKT_ALIAS_REVERSE;
1173 		iresult = PacketAliasOut(ptr, maxpacketsize);
1174 		la->packetAliasMode |= PKT_ALIAS_REVERSE;
1175 		return (iresult);
1176 	}
1177 	HouseKeeping(la);
1178 	ClearCheckNewLink(la);
1179 	pip = (struct ip *)ptr;
1180 	alias_addr = pip->ip_dst;
1181 
1182 	/* Defense against mangled packets */
1183 	if (ntohs(pip->ip_len) > maxpacketsize
1184 	    || (pip->ip_hl << 2) > maxpacketsize)
1185 		return (PKT_ALIAS_IGNORED);
1186 
1187 	iresult = PKT_ALIAS_IGNORED;
1188 	if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
1189 		switch (pip->ip_p) {
1190 		case IPPROTO_ICMP:
1191 			iresult = IcmpAliasIn(la, pip);
1192 			break;
1193 		case IPPROTO_UDP:
1194 			iresult = UdpAliasIn(la, pip);
1195 			break;
1196 		case IPPROTO_TCP:
1197 			iresult = TcpAliasIn(la, pip);
1198 			break;
1199 		case IPPROTO_GRE:
1200 			if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY ||
1201 			    AliasHandlePptpGreIn(la, pip) == 0)
1202 				iresult = PKT_ALIAS_OK;
1203 			else
1204 				iresult = ProtoAliasIn(la, pip);
1205 			break;
1206 		default:
1207 			iresult = ProtoAliasIn(la, pip);
1208 			break;
1209 		}
1210 
1211 		if (ntohs(pip->ip_off) & IP_MF) {
1212 			struct alias_link *lnk;
1213 
1214 			lnk = FindFragmentIn1(la, pip->ip_src, alias_addr, pip->ip_id);
1215 			if (lnk != NULL) {
1216 				iresult = PKT_ALIAS_FOUND_HEADER_FRAGMENT;
1217 				SetFragmentAddr(lnk, pip->ip_dst);
1218 			} else {
1219 				iresult = PKT_ALIAS_ERROR;
1220 			}
1221 		}
1222 	} else {
1223 		iresult = FragmentIn(la, pip);
1224 	}
1225 
1226 	return (iresult);
1227 }
1228 
1229 
1230 
1231 /* Unregistered address ranges */
1232 
1233 /* 10.0.0.0   ->   10.255.255.255 */
1234 #define UNREG_ADDR_A_LOWER 0x0a000000
1235 #define UNREG_ADDR_A_UPPER 0x0affffff
1236 
1237 /* 172.16.0.0  ->  172.31.255.255 */
1238 #define UNREG_ADDR_B_LOWER 0xac100000
1239 #define UNREG_ADDR_B_UPPER 0xac1fffff
1240 
1241 /* 192.168.0.0 -> 192.168.255.255 */
1242 #define UNREG_ADDR_C_LOWER 0xc0a80000
1243 #define UNREG_ADDR_C_UPPER 0xc0a8ffff
1244 
1245 int
1246 LibAliasOut(struct libalias *la, char *ptr,	/* valid IP packet */
1247     int maxpacketsize		/* How much the packet data may grow (FTP
1248 				 * and IRC inline changes) */
1249 )
1250 {
1251 	return (LibAliasOutTry(la, ptr, maxpacketsize, 1));
1252 }
1253 
1254 int
1255 LibAliasOutTry(struct libalias *la, char *ptr,	/* valid IP packet */
1256     int maxpacketsize,		/* How much the packet data may grow (FTP
1257 				 * and IRC inline changes) */
1258     int create			/* Create new entries ? */
1259 )
1260 {
1261 	int iresult;
1262 	struct in_addr addr_save;
1263 	struct ip *pip;
1264 
1265 	if (la->packetAliasMode & PKT_ALIAS_REVERSE) {
1266 		la->packetAliasMode &= ~PKT_ALIAS_REVERSE;
1267 		iresult = PacketAliasIn(ptr, maxpacketsize);
1268 		la->packetAliasMode |= PKT_ALIAS_REVERSE;
1269 		return (iresult);
1270 	}
1271 	HouseKeeping(la);
1272 	ClearCheckNewLink(la);
1273 	pip = (struct ip *)ptr;
1274 
1275 	/* Defense against mangled packets */
1276 	if (ntohs(pip->ip_len) > maxpacketsize
1277 	    || (pip->ip_hl << 2) > maxpacketsize)
1278 		return (PKT_ALIAS_IGNORED);
1279 
1280 	addr_save = GetDefaultAliasAddress(la);
1281 	if (la->packetAliasMode & PKT_ALIAS_UNREGISTERED_ONLY) {
1282 		u_long addr;
1283 		int iclass;
1284 
1285 		iclass = 0;
1286 		addr = ntohl(pip->ip_src.s_addr);
1287 		if (addr >= UNREG_ADDR_C_LOWER && addr <= UNREG_ADDR_C_UPPER)
1288 			iclass = 3;
1289 		else if (addr >= UNREG_ADDR_B_LOWER && addr <= UNREG_ADDR_B_UPPER)
1290 			iclass = 2;
1291 		else if (addr >= UNREG_ADDR_A_LOWER && addr <= UNREG_ADDR_A_UPPER)
1292 			iclass = 1;
1293 
1294 		if (iclass == 0) {
1295 			SetDefaultAliasAddress(la, pip->ip_src);
1296 		}
1297 	} else if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY) {
1298 		SetDefaultAliasAddress(la, pip->ip_src);
1299 	}
1300 	iresult = PKT_ALIAS_IGNORED;
1301 	if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
1302 		switch (pip->ip_p) {
1303 		case IPPROTO_ICMP:
1304 			iresult = IcmpAliasOut(la, pip, create);
1305 			break;
1306 		case IPPROTO_UDP:
1307 			iresult = UdpAliasOut(la, pip, create);
1308 			break;
1309 			case IPPROTO_TCP:
1310 			iresult = TcpAliasOut(la, pip, maxpacketsize, create);
1311 			break;
1312 		case IPPROTO_GRE:
1313 			if (AliasHandlePptpGreOut(la, pip) == 0)
1314 				iresult = PKT_ALIAS_OK;
1315 			else
1316 				iresult = ProtoAliasOut(la, pip, create);
1317 			break;
1318 		default:
1319 			iresult = ProtoAliasOut(la, pip, create);
1320 			break;
1321 		}
1322 	} else {
1323 		iresult = FragmentOut(la, pip);
1324 	}
1325 
1326 	SetDefaultAliasAddress(la, addr_save);
1327 	return (iresult);
1328 }
1329 
1330 int
1331 LibAliasUnaliasOut(struct libalias *la, char *ptr,	/* valid IP packet */
1332     int maxpacketsize		/* for error checking */
1333 )
1334 {
1335 	struct ip *pip;
1336 	struct icmp *ic;
1337 	struct udphdr *ud;
1338 	struct tcphdr *tc;
1339 	struct alias_link *lnk;
1340 	int iresult = PKT_ALIAS_IGNORED;
1341 
1342 	pip = (struct ip *)ptr;
1343 
1344 	/* Defense against mangled packets */
1345 	if (ntohs(pip->ip_len) > maxpacketsize
1346 	    || (pip->ip_hl << 2) > maxpacketsize)
1347 		return (iresult);
1348 
1349 	ud = (struct udphdr *)ip_next(pip);
1350 	tc = (struct tcphdr *)ip_next(pip);
1351 	ic = (struct icmp *)ip_next(pip);
1352 
1353 	/* Find a link */
1354 	if (pip->ip_p == IPPROTO_UDP)
1355 		lnk = FindUdpTcpIn(la, pip->ip_dst, pip->ip_src,
1356 		    ud->uh_dport, ud->uh_sport,
1357 		    IPPROTO_UDP, 0);
1358 	else if (pip->ip_p == IPPROTO_TCP)
1359 		lnk = FindUdpTcpIn(la, pip->ip_dst, pip->ip_src,
1360 		    tc->th_dport, tc->th_sport,
1361 		    IPPROTO_TCP, 0);
1362 	else if (pip->ip_p == IPPROTO_ICMP)
1363 		lnk = FindIcmpIn(la, pip->ip_dst, pip->ip_src, ic->icmp_id, 0);
1364 	else
1365 		lnk = NULL;
1366 
1367 	/* Change it from an aliased packet to an unaliased packet */
1368 	if (lnk != NULL) {
1369 		if (pip->ip_p == IPPROTO_UDP || pip->ip_p == IPPROTO_TCP) {
1370 			int accumulate;
1371 			struct in_addr original_address;
1372 			u_short original_port;
1373 
1374 			original_address = GetOriginalAddress(lnk);
1375 			original_port = GetOriginalPort(lnk);
1376 
1377 			/* Adjust TCP/UDP checksum */
1378 			accumulate = twowords(&pip->ip_src);
1379 			accumulate -= twowords(&original_address);
1380 
1381 			if (pip->ip_p == IPPROTO_UDP) {
1382 				accumulate += ud->uh_sport;
1383 				accumulate -= original_port;
1384 				ADJUST_CHECKSUM(accumulate, ud->uh_sum);
1385 			} else {
1386 				accumulate += tc->th_sport;
1387 				accumulate -= original_port;
1388 				ADJUST_CHECKSUM(accumulate, tc->th_sum);
1389 			}
1390 
1391 			/* Adjust IP checksum */
1392 			DifferentialChecksum(&pip->ip_sum,
1393 			    &original_address, &pip->ip_src, 2);
1394 
1395 			/* Un-alias source address and port number */
1396 			pip->ip_src = original_address;
1397 			if (pip->ip_p == IPPROTO_UDP)
1398 				ud->uh_sport = original_port;
1399 			else
1400 				tc->th_sport = original_port;
1401 
1402 			iresult = PKT_ALIAS_OK;
1403 
1404 		} else if (pip->ip_p == IPPROTO_ICMP) {
1405 
1406 			int accumulate;
1407 			struct in_addr original_address;
1408 			u_short original_id;
1409 
1410 			original_address = GetOriginalAddress(lnk);
1411 			original_id = GetOriginalPort(lnk);
1412 
1413 			/* Adjust ICMP checksum */
1414 			accumulate = twowords(&pip->ip_src);
1415 			accumulate -= twowords(&original_address);
1416 			accumulate += ic->icmp_id;
1417 			accumulate -= original_id;
1418 			ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
1419 
1420 			/* Adjust IP checksum */
1421 			DifferentialChecksum(&pip->ip_sum,
1422 			    &original_address, &pip->ip_src, 2);
1423 
1424 			/* Un-alias source address and port number */
1425 			pip->ip_src = original_address;
1426 			ic->icmp_id = original_id;
1427 
1428 			iresult = PKT_ALIAS_OK;
1429 		}
1430 	}
1431 	return (iresult);
1432 
1433 }
1434