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