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