xref: /freebsd/sys/netinet/libalias/alias.c (revision c6e88cbf92e43c8461d5434e5b02303b51a7099b)
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 		accumulate -= twowords(&pip->ip_dst);
888 
889 /* If this is a transparent proxy packet, then modify the source
890    address */
891 		if (proxy_address.s_addr != 0) {
892 			accumulate += twowords(&pip->ip_src);
893 			pip->ip_src = proxy_address;
894 			accumulate -= twowords(&pip->ip_src);
895 		}
896 		ADJUST_CHECKSUM(accumulate, pip->ip_sum);
897 
898 /* Monitor TCP connection state */
899 		TcpMonitorIn(pip, link);
900 
901 		return (PKT_ALIAS_OK);
902 	}
903 	return (PKT_ALIAS_IGNORED);
904 }
905 
906 static int
907 TcpAliasOut(struct libalias *la, struct ip *pip, int maxpacketsize)
908 {
909 	int proxy_type;
910 	u_short dest_port;
911 	u_short proxy_server_port;
912 	struct in_addr dest_address;
913 	struct in_addr proxy_server_address;
914 	struct tcphdr *tc;
915 	struct alias_link *link;
916 
917 	tc = (struct tcphdr *)((char *)pip + (pip->ip_hl << 2));
918 
919 	proxy_type = ProxyCheck(la, pip, &proxy_server_address, &proxy_server_port);
920 
921 	if (proxy_type == 0 && (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY))
922 		return PKT_ALIAS_OK;
923 
924 /* If this is a transparent proxy, save original destination,
925    then alter the destination and adjust checksums */
926 	dest_port = tc->th_dport;
927 	dest_address = pip->ip_dst;
928 	if (proxy_type != 0) {
929 		int accumulate;
930 
931 		accumulate = tc->th_dport;
932 		tc->th_dport = proxy_server_port;
933 		accumulate -= tc->th_dport;
934 		accumulate += twowords(&pip->ip_dst);
935 		accumulate -= twowords(&proxy_server_address);
936 		ADJUST_CHECKSUM(accumulate, tc->th_sum);
937 
938 		accumulate = twowords(&pip->ip_dst);
939 		pip->ip_dst = proxy_server_address;
940 		accumulate -= twowords(&pip->ip_dst);
941 		ADJUST_CHECKSUM(accumulate, pip->ip_sum);
942 	}
943 	link = FindUdpTcpOut(la, pip->ip_src, pip->ip_dst,
944 	    tc->th_sport, tc->th_dport,
945 	    IPPROTO_TCP, 1);
946 	if (link != NULL) {
947 		u_short alias_port;
948 		struct in_addr alias_address;
949 		int accumulate;
950 
951 /* Save original destination address, if this is a proxy packet.
952    Also modify packet to include destination encoding.  This may
953    change the size of IP header. */
954 		if (proxy_type != 0) {
955 			SetProxyPort(link, dest_port);
956 			SetProxyAddress(link, dest_address);
957 			ProxyModify(la, link, pip, maxpacketsize, proxy_type);
958 			tc = (struct tcphdr *)((char *)pip + (pip->ip_hl << 2));
959 		}
960 /* Get alias address and port */
961 		alias_port = GetAliasPort(link);
962 		alias_address = GetAliasAddress(link);
963 
964 /* Monitor TCP connection state */
965 		TcpMonitorOut(pip, link);
966 
967 /* Special processing for IP encoding protocols */
968 		if (ntohs(tc->th_dport) == FTP_CONTROL_PORT_NUMBER
969 		    || ntohs(tc->th_sport) == FTP_CONTROL_PORT_NUMBER)
970 			AliasHandleFtpOut(la, pip, link, maxpacketsize);
971 		else if (ntohs(tc->th_dport) == IRC_CONTROL_PORT_NUMBER_1
972 		    || ntohs(tc->th_dport) == IRC_CONTROL_PORT_NUMBER_2)
973 			AliasHandleIrcOut(la, pip, link, maxpacketsize);
974 		else if (ntohs(tc->th_dport) == RTSP_CONTROL_PORT_NUMBER_1
975 			    || ntohs(tc->th_sport) == RTSP_CONTROL_PORT_NUMBER_1
976 			    || ntohs(tc->th_dport) == RTSP_CONTROL_PORT_NUMBER_2
977 		    || ntohs(tc->th_sport) == RTSP_CONTROL_PORT_NUMBER_2)
978 			AliasHandleRtspOut(la, pip, link, maxpacketsize);
979 		else if (ntohs(tc->th_dport) == PPTP_CONTROL_PORT_NUMBER
980 		    || ntohs(tc->th_sport) == PPTP_CONTROL_PORT_NUMBER)
981 			AliasHandlePptpOut(la, pip, link);
982 		else if (la->skinnyPort != 0 && (ntohs(tc->th_sport) == la->skinnyPort
983 		    || ntohs(tc->th_dport) == la->skinnyPort))
984 			AliasHandleSkinny(la, pip, link);
985 
986 /* Adjust TCP checksum since source port is being aliased */
987 /* and source address is being altered                    */
988 		accumulate = tc->th_sport;
989 		tc->th_sport = alias_port;
990 		accumulate -= tc->th_sport;
991 		accumulate += twowords(&pip->ip_src);
992 		accumulate -= twowords(&alias_address);
993 
994 /* Modify sequence number if necessary */
995 		if (GetAckModified(link) == 1) {
996 			int delta;
997 
998 			delta = GetDeltaSeqOut(pip, link);
999 			if (delta != 0) {
1000 				accumulate += twowords(&tc->th_seq);
1001 				tc->th_seq = htonl(ntohl(tc->th_seq) + delta);
1002 				accumulate -= twowords(&tc->th_seq);
1003 			}
1004 		}
1005 		ADJUST_CHECKSUM(accumulate, tc->th_sum);
1006 
1007 /* Change source address */
1008 		accumulate = twowords(&pip->ip_src);
1009 		pip->ip_src = alias_address;
1010 		accumulate -= twowords(&pip->ip_src);
1011 		ADJUST_CHECKSUM(accumulate, pip->ip_sum);
1012 
1013 		return (PKT_ALIAS_OK);
1014 	}
1015 	return (PKT_ALIAS_IGNORED);
1016 }
1017 
1018 
1019 
1020 
1021 /* Fragment Handling
1022 
1023     FragmentIn()
1024     FragmentOut()
1025 
1026 The packet aliasing module has a limited ability for handling IP
1027 fragments.  If the ICMP, TCP or UDP header is in the first fragment
1028 received, then the ID number of the IP packet is saved, and other
1029 fragments are identified according to their ID number and IP address
1030 they were sent from.  Pointers to unresolved fragments can also be
1031 saved and recalled when a header fragment is seen.
1032 */
1033 
1034 /* Local prototypes */
1035 static int	FragmentIn(struct libalias *, struct ip *);
1036 static int	FragmentOut(struct libalias *, struct ip *);
1037 
1038 
1039 static int
1040 FragmentIn(struct libalias *la, struct ip *pip)
1041 {
1042 	struct alias_link *link;
1043 
1044 	link = FindFragmentIn2(la, pip->ip_src, pip->ip_dst, pip->ip_id);
1045 	if (link != NULL) {
1046 		struct in_addr original_address;
1047 
1048 		GetFragmentAddr(link, &original_address);
1049 		DifferentialChecksum(&pip->ip_sum,
1050 		    &original_address, &pip->ip_dst, 2);
1051 		pip->ip_dst = original_address;
1052 
1053 		return (PKT_ALIAS_OK);
1054 	}
1055 	return (PKT_ALIAS_UNRESOLVED_FRAGMENT);
1056 }
1057 
1058 
1059 static int
1060 FragmentOut(struct libalias *la, struct ip *pip)
1061 {
1062 	struct in_addr alias_address;
1063 
1064 	alias_address = FindAliasAddress(la, pip->ip_src);
1065 	DifferentialChecksum(&pip->ip_sum,
1066 	    &alias_address, &pip->ip_src, 2);
1067 	pip->ip_src = alias_address;
1068 
1069 	return (PKT_ALIAS_OK);
1070 }
1071 
1072 
1073 
1074 
1075 
1076 
1077 /* Outside World Access
1078 
1079         PacketAliasSaveFragment()
1080         PacketAliasGetFragment()
1081         PacketAliasFragmentIn()
1082         PacketAliasIn()
1083         PacketAliasOut()
1084         PacketUnaliasOut()
1085 
1086 (prototypes in alias.h)
1087 */
1088 
1089 
1090 int
1091 LibAliasSaveFragment(struct libalias *la, char *ptr)
1092 {
1093 	int iresult;
1094 	struct alias_link *link;
1095 	struct ip *pip;
1096 
1097 	pip = (struct ip *)ptr;
1098 	link = AddFragmentPtrLink(la, pip->ip_src, pip->ip_id);
1099 	iresult = PKT_ALIAS_ERROR;
1100 	if (link != NULL) {
1101 		SetFragmentPtr(link, ptr);
1102 		iresult = PKT_ALIAS_OK;
1103 	}
1104 	return (iresult);
1105 }
1106 
1107 
1108 char           *
1109 LibAliasGetFragment(struct libalias *la, char *ptr)
1110 {
1111 	struct alias_link *link;
1112 	char *fptr;
1113 	struct ip *pip;
1114 
1115 	pip = (struct ip *)ptr;
1116 	link = FindFragmentPtr(la, pip->ip_src, pip->ip_id);
1117 	if (link != NULL) {
1118 		GetFragmentPtr(link, &fptr);
1119 		SetFragmentPtr(link, NULL);
1120 		SetExpire(link, 0);	/* Deletes link */
1121 
1122 		return (fptr);
1123 	} else {
1124 		return (NULL);
1125 	}
1126 }
1127 
1128 
1129 void
1130 LibAliasFragmentIn(struct libalias *la, char *ptr,	/* Points to correctly
1131 							 * de-aliased header
1132 							 * fragment */
1133     char *ptr_fragment		/* Points to fragment which must be
1134 				 * de-aliased   */
1135 )
1136 {
1137 	struct ip *pip;
1138 	struct ip *fpip;
1139 
1140 	pip = (struct ip *)ptr;
1141 	fpip = (struct ip *)ptr_fragment;
1142 
1143 	DifferentialChecksum(&fpip->ip_sum,
1144 	    &pip->ip_dst, &fpip->ip_dst, 2);
1145 	fpip->ip_dst = pip->ip_dst;
1146 }
1147 
1148 
1149 int
1150 LibAliasIn(struct libalias *la, char *ptr, int maxpacketsize)
1151 {
1152 	struct in_addr alias_addr;
1153 	struct ip *pip;
1154 	int iresult;
1155 
1156 	if (la->packetAliasMode & PKT_ALIAS_REVERSE) {
1157 		la->packetAliasMode &= ~PKT_ALIAS_REVERSE;
1158 		iresult = PacketAliasOut(ptr, maxpacketsize);
1159 		la->packetAliasMode |= PKT_ALIAS_REVERSE;
1160 		return iresult;
1161 	}
1162 	HouseKeeping(la);
1163 	ClearCheckNewLink(la);
1164 	pip = (struct ip *)ptr;
1165 	alias_addr = pip->ip_dst;
1166 
1167 	/* Defense against mangled packets */
1168 	if (ntohs(pip->ip_len) > maxpacketsize
1169 	    || (pip->ip_hl << 2) > maxpacketsize)
1170 		return PKT_ALIAS_IGNORED;
1171 
1172 	iresult = PKT_ALIAS_IGNORED;
1173 	if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
1174 		switch (pip->ip_p) {
1175 		case IPPROTO_ICMP:
1176 			iresult = IcmpAliasIn(la, pip);
1177 			break;
1178 		case IPPROTO_UDP:
1179 			iresult = UdpAliasIn(la, pip);
1180 			break;
1181 		case IPPROTO_TCP:
1182 			iresult = TcpAliasIn(la, pip);
1183 			break;
1184 		case IPPROTO_GRE:
1185 			if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY ||
1186 			    AliasHandlePptpGreIn(la, pip) == 0)
1187 				iresult = PKT_ALIAS_OK;
1188 			else
1189 				iresult = ProtoAliasIn(la, pip);
1190 			break;
1191 		default:
1192 			iresult = ProtoAliasIn(la, pip);
1193 			break;
1194 		}
1195 
1196 		if (ntohs(pip->ip_off) & IP_MF) {
1197 			struct alias_link *link;
1198 
1199 			link = FindFragmentIn1(la, pip->ip_src, alias_addr, pip->ip_id);
1200 			if (link != NULL) {
1201 				iresult = PKT_ALIAS_FOUND_HEADER_FRAGMENT;
1202 				SetFragmentAddr(link, pip->ip_dst);
1203 			} else {
1204 				iresult = PKT_ALIAS_ERROR;
1205 			}
1206 		}
1207 	} else {
1208 		iresult = FragmentIn(la, pip);
1209 	}
1210 
1211 	return (iresult);
1212 }
1213 
1214 
1215 
1216 /* Unregistered address ranges */
1217 
1218 /* 10.0.0.0   ->   10.255.255.255 */
1219 #define UNREG_ADDR_A_LOWER 0x0a000000
1220 #define UNREG_ADDR_A_UPPER 0x0affffff
1221 
1222 /* 172.16.0.0  ->  172.31.255.255 */
1223 #define UNREG_ADDR_B_LOWER 0xac100000
1224 #define UNREG_ADDR_B_UPPER 0xac1fffff
1225 
1226 /* 192.168.0.0 -> 192.168.255.255 */
1227 #define UNREG_ADDR_C_LOWER 0xc0a80000
1228 #define UNREG_ADDR_C_UPPER 0xc0a8ffff
1229 
1230 int
1231 LibAliasOut(struct libalias *la, char *ptr,	/* valid IP packet */
1232     int maxpacketsize		/* How much the packet data may grow (FTP
1233 				 * and IRC inline changes) */
1234 )
1235 {
1236 	int iresult;
1237 	struct in_addr addr_save;
1238 	struct ip *pip;
1239 
1240 	if (la->packetAliasMode & PKT_ALIAS_REVERSE) {
1241 		la->packetAliasMode &= ~PKT_ALIAS_REVERSE;
1242 		iresult = PacketAliasIn(ptr, maxpacketsize);
1243 		la->packetAliasMode |= PKT_ALIAS_REVERSE;
1244 		return iresult;
1245 	}
1246 	HouseKeeping(la);
1247 	ClearCheckNewLink(la);
1248 	pip = (struct ip *)ptr;
1249 
1250 	/* Defense against mangled packets */
1251 	if (ntohs(pip->ip_len) > maxpacketsize
1252 	    || (pip->ip_hl << 2) > maxpacketsize)
1253 		return PKT_ALIAS_IGNORED;
1254 
1255 	addr_save = GetDefaultAliasAddress(la);
1256 	if (la->packetAliasMode & PKT_ALIAS_UNREGISTERED_ONLY) {
1257 		u_long addr;
1258 		int iclass;
1259 
1260 		iclass = 0;
1261 		addr = ntohl(pip->ip_src.s_addr);
1262 		if (addr >= UNREG_ADDR_C_LOWER && addr <= UNREG_ADDR_C_UPPER)
1263 			iclass = 3;
1264 		else if (addr >= UNREG_ADDR_B_LOWER && addr <= UNREG_ADDR_B_UPPER)
1265 			iclass = 2;
1266 		else if (addr >= UNREG_ADDR_A_LOWER && addr <= UNREG_ADDR_A_UPPER)
1267 			iclass = 1;
1268 
1269 		if (iclass == 0) {
1270 			SetDefaultAliasAddress(la, pip->ip_src);
1271 		}
1272 	} else if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY) {
1273 		SetDefaultAliasAddress(la, pip->ip_src);
1274 	}
1275 	iresult = PKT_ALIAS_IGNORED;
1276 	if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
1277 		switch (pip->ip_p) {
1278 		case IPPROTO_ICMP:
1279 			iresult = IcmpAliasOut(la, pip);
1280 			break;
1281 		case IPPROTO_UDP:
1282 			iresult = UdpAliasOut(la, pip);
1283 			break;
1284 		case IPPROTO_TCP:
1285 			iresult = TcpAliasOut(la, pip, maxpacketsize);
1286 			break;
1287 		case IPPROTO_GRE:
1288 			if (AliasHandlePptpGreOut(la, pip) == 0)
1289 				iresult = PKT_ALIAS_OK;
1290 			else
1291 				iresult = ProtoAliasOut(la, pip);
1292 			break;
1293 		default:
1294 			iresult = ProtoAliasOut(la, pip);
1295 			break;
1296 		}
1297 	} else {
1298 		iresult = FragmentOut(la, pip);
1299 	}
1300 
1301 	SetDefaultAliasAddress(la, addr_save);
1302 	return (iresult);
1303 }
1304 
1305 int
1306 LibAliasUnaliasOut(struct libalias *la, char *ptr,	/* valid IP packet */
1307     int maxpacketsize		/* for error checking */
1308 )
1309 {
1310 	struct ip *pip;
1311 	struct icmp *ic;
1312 	struct udphdr *ud;
1313 	struct tcphdr *tc;
1314 	struct alias_link *link;
1315 	int iresult = PKT_ALIAS_IGNORED;
1316 
1317 	pip = (struct ip *)ptr;
1318 
1319 	/* Defense against mangled packets */
1320 	if (ntohs(pip->ip_len) > maxpacketsize
1321 	    || (pip->ip_hl << 2) > maxpacketsize)
1322 		return (iresult);
1323 
1324 	ud = (struct udphdr *)((char *)pip + (pip->ip_hl << 2));
1325 	tc = (struct tcphdr *)ud;
1326 	ic = (struct icmp *)ud;
1327 
1328 	/* Find a link */
1329 	if (pip->ip_p == IPPROTO_UDP)
1330 		link = FindUdpTcpIn(la, pip->ip_dst, pip->ip_src,
1331 		    ud->uh_dport, ud->uh_sport,
1332 		    IPPROTO_UDP, 0);
1333 	else if (pip->ip_p == IPPROTO_TCP)
1334 		link = FindUdpTcpIn(la, pip->ip_dst, pip->ip_src,
1335 		    tc->th_dport, tc->th_sport,
1336 		    IPPROTO_TCP, 0);
1337 	else if (pip->ip_p == IPPROTO_ICMP)
1338 		link = FindIcmpIn(la, pip->ip_dst, pip->ip_src, ic->icmp_id, 0);
1339 	else
1340 		link = NULL;
1341 
1342 	/* Change it from an aliased packet to an unaliased packet */
1343 	if (link != NULL) {
1344 		if (pip->ip_p == IPPROTO_UDP || pip->ip_p == IPPROTO_TCP) {
1345 			int accumulate;
1346 			struct in_addr original_address;
1347 			u_short original_port;
1348 
1349 			original_address = GetOriginalAddress(link);
1350 			original_port = GetOriginalPort(link);
1351 
1352 			/* Adjust TCP/UDP checksum */
1353 			accumulate = twowords(&pip->ip_src);
1354 			accumulate -= twowords(&original_address);
1355 
1356 			if (pip->ip_p == IPPROTO_UDP) {
1357 				accumulate += ud->uh_sport;
1358 				accumulate -= original_port;
1359 				ADJUST_CHECKSUM(accumulate, ud->uh_sum);
1360 			} else {
1361 				accumulate += tc->th_sport;
1362 				accumulate -= original_port;
1363 				ADJUST_CHECKSUM(accumulate, tc->th_sum);
1364 			}
1365 
1366 			/* Adjust IP checksum */
1367 			DifferentialChecksum(&pip->ip_sum,
1368 			    &original_address, &pip->ip_src, 2);
1369 
1370 			/* Un-alias source address and port number */
1371 			pip->ip_src = original_address;
1372 			if (pip->ip_p == IPPROTO_UDP)
1373 				ud->uh_sport = original_port;
1374 			else
1375 				tc->th_sport = original_port;
1376 
1377 			iresult = PKT_ALIAS_OK;
1378 
1379 		} else if (pip->ip_p == IPPROTO_ICMP) {
1380 
1381 			int accumulate;
1382 			struct in_addr original_address;
1383 			u_short original_id;
1384 
1385 			original_address = GetOriginalAddress(link);
1386 			original_id = GetOriginalPort(link);
1387 
1388 			/* Adjust ICMP checksum */
1389 			accumulate = twowords(&pip->ip_src);
1390 			accumulate -= twowords(&original_address);
1391 			accumulate += ic->icmp_id;
1392 			accumulate -= original_id;
1393 			ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
1394 
1395 			/* Adjust IP checksum */
1396 			DifferentialChecksum(&pip->ip_sum,
1397 			    &original_address, &pip->ip_src, 2);
1398 
1399 			/* Un-alias source address and port number */
1400 			pip->ip_src = original_address;
1401 			ic->icmp_id = original_id;
1402 
1403 			iresult = PKT_ALIAS_OK;
1404 		}
1405 	}
1406 	return (iresult);
1407 
1408 }
1409