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