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