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