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