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