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