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