xref: /freebsd/sys/netinet/libalias/alias.c (revision a2aef24aa3c8458e4036735dd6928b4ef77294e5)
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 
703 /* Return if proxy-only mode is enabled */
704 	if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
705 		return (PKT_ALIAS_OK);
706 
707 	if (!create)
708 		return (PKT_ALIAS_IGNORED);
709 
710 	lnk = FindProtoOut(la, *ip_src, ip_dst, ip_p);
711 	if (lnk != NULL) {
712 		struct in_addr alias_address;
713 
714 		alias_address = GetAliasAddress(lnk);
715 
716 /* Change source address */
717 		DifferentialChecksum(ip_sum,
718 		    &alias_address, ip_src, 2);
719 		*ip_src = alias_address;
720 
721 		return (PKT_ALIAS_OK);
722 	}
723 	return (PKT_ALIAS_IGNORED);
724 }
725 
726 
727 static int
728 UdpAliasIn(struct libalias *la, struct ip *pip)
729 {
730 	struct udphdr *ud;
731 	struct alias_link *lnk;
732 
733 	LIBALIAS_LOCK_ASSERT(la);
734 
735 	ud = (struct udphdr *)ip_next(pip);
736 
737 	lnk = FindUdpTcpIn(la, pip->ip_src, pip->ip_dst,
738 	    ud->uh_sport, ud->uh_dport,
739 	    IPPROTO_UDP, !(la->packetAliasMode & PKT_ALIAS_PROXY_ONLY));
740 	if (lnk != NULL) {
741 		struct in_addr alias_address;
742 		struct in_addr original_address;
743 		struct in_addr proxy_address;
744 		u_short alias_port;
745 		u_short proxy_port;
746 		int accumulate;
747 		int error;
748 		struct alias_data ad = {
749 			.lnk = lnk,
750 			.oaddr = &original_address,
751 			.aaddr = &alias_address,
752 			.aport = &alias_port,
753 			.sport = &ud->uh_sport,
754 			.dport = &ud->uh_dport,
755 			.maxpktsize = 0
756 		};
757 
758 		alias_address = GetAliasAddress(lnk);
759 		original_address = GetOriginalAddress(lnk);
760 		proxy_address = GetProxyAddress(lnk);
761 		alias_port = ud->uh_dport;
762 		ud->uh_dport = GetOriginalPort(lnk);
763 		proxy_port = GetProxyPort(lnk);
764 
765 		/* Walk out chain. */
766 		error = find_handler(IN, UDP, la, pip, &ad);
767 		/* If we cannot figure out the packet, ignore it. */
768 		if (error < 0)
769 			return (PKT_ALIAS_IGNORED);
770 
771 /* If UDP checksum is not zero, then adjust since destination port */
772 /* is being unaliased and destination address is being altered.    */
773 		if (ud->uh_sum != 0) {
774 			accumulate = alias_port;
775 			accumulate -= ud->uh_dport;
776 			accumulate += twowords(&alias_address);
777 			accumulate -= twowords(&original_address);
778 
779 /* If this is a proxy packet, modify checksum because of source change.*/
780         		if (proxy_port != 0) {
781 		                accumulate += ud->uh_sport;
782 		                accumulate -= proxy_port;
783 	                }
784 
785 	                if (proxy_address.s_addr != 0) {
786 				accumulate += twowords(&pip->ip_src);
787 				accumulate -= twowords(&proxy_address);
788 	                }
789 
790 			ADJUST_CHECKSUM(accumulate, ud->uh_sum);
791 		}
792 /* XXX: Could the two if's below be concatenated to one ? */
793 /* Restore source port and/or address in case of proxying*/
794 
795     		if (proxy_port != 0)
796         		ud->uh_sport = proxy_port;
797 
798     		if (proxy_address.s_addr != 0) {
799         		DifferentialChecksum(&pip->ip_sum,
800                 	    &proxy_address, &pip->ip_src, 2);
801 	        	pip->ip_src = proxy_address;
802     		}
803 
804 /* Restore original IP address */
805 		DifferentialChecksum(&pip->ip_sum,
806 		    &original_address, &pip->ip_dst, 2);
807 		pip->ip_dst = original_address;
808 
809 		return (PKT_ALIAS_OK);
810 	}
811 	return (PKT_ALIAS_IGNORED);
812 }
813 
814 static int
815 UdpAliasOut(struct libalias *la, struct ip *pip, int maxpacketsize, int create)
816 {
817 	struct udphdr *ud;
818 	struct alias_link *lnk;
819 	struct in_addr dest_address;
820 	struct in_addr proxy_server_address;
821 	u_short dest_port;
822 	u_short proxy_server_port;
823 	int proxy_type;
824 	int error;
825 
826 	LIBALIAS_LOCK_ASSERT(la);
827 
828 /* Return if proxy-only mode is enabled and not proxyrule found.*/
829 	ud = (struct udphdr *)ip_next(pip);
830 	proxy_type = ProxyCheck(la, &proxy_server_address,
831 		&proxy_server_port, pip->ip_src, pip->ip_dst,
832 		ud->uh_dport, pip->ip_p);
833 	if (proxy_type == 0 && (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY))
834 		return (PKT_ALIAS_OK);
835 
836 /* If this is a transparent proxy, save original destination,
837  * then alter the destination and adjust checksums */
838 	dest_port = ud->uh_dport;
839 	dest_address = pip->ip_dst;
840 
841 	if (proxy_type != 0) {
842 	        int accumulate;
843 
844 		accumulate = twowords(&pip->ip_dst);
845 		accumulate -= twowords(&proxy_server_address);
846 
847 	        ADJUST_CHECKSUM(accumulate, pip->ip_sum);
848 
849 		if (ud->uh_sum != 0) {
850 			accumulate = twowords(&pip->ip_dst);
851 			accumulate -= twowords(&proxy_server_address);
852     			accumulate += ud->uh_dport;
853 	        	accumulate -= proxy_server_port;
854 	    		ADJUST_CHECKSUM(accumulate, ud->uh_sum);
855 		}
856 	        pip->ip_dst = proxy_server_address;
857 	        ud->uh_dport = proxy_server_port;
858 	}
859 	lnk = FindUdpTcpOut(la, pip->ip_src, pip->ip_dst,
860 	    ud->uh_sport, ud->uh_dport,
861 	    IPPROTO_UDP, create);
862 	if (lnk != NULL) {
863 		u_short alias_port;
864 		struct in_addr alias_address;
865 		struct alias_data ad = {
866 			.lnk = lnk,
867 			.oaddr = NULL,
868 			.aaddr = &alias_address,
869 			.aport = &alias_port,
870 			.sport = &ud->uh_sport,
871 			.dport = &ud->uh_dport,
872 			.maxpktsize = 0
873 		};
874 
875 /* Save original destination address, if this is a proxy packet.
876  * Also modify packet to include destination encoding.  This may
877  * change the size of IP header. */
878 		if (proxy_type != 0) {
879 	                SetProxyPort(lnk, dest_port);
880 	                SetProxyAddress(lnk, dest_address);
881 	                ProxyModify(la, lnk, pip, maxpacketsize, proxy_type);
882 	                ud = (struct udphdr *)ip_next(pip);
883 	        }
884 
885 		alias_address = GetAliasAddress(lnk);
886 		alias_port = GetAliasPort(lnk);
887 
888 		/* Walk out chain. */
889 		error = find_handler(OUT, UDP, la, pip, &ad);
890 
891 /* If UDP checksum is not zero, adjust since source port is */
892 /* being aliased and source address is being altered        */
893 		if (ud->uh_sum != 0) {
894 			int accumulate;
895 
896 			accumulate = ud->uh_sport;
897 			accumulate -= alias_port;
898 			accumulate += twowords(&pip->ip_src);
899 			accumulate -= twowords(&alias_address);
900 			ADJUST_CHECKSUM(accumulate, ud->uh_sum);
901 		}
902 /* Put alias port in UDP header */
903 		ud->uh_sport = alias_port;
904 
905 /* Change source address */
906 		DifferentialChecksum(&pip->ip_sum,
907 		    &alias_address, &pip->ip_src, 2);
908 		pip->ip_src = alias_address;
909 
910 		return (PKT_ALIAS_OK);
911 	}
912 	return (PKT_ALIAS_IGNORED);
913 }
914 
915 
916 
917 static int
918 TcpAliasIn(struct libalias *la, struct ip *pip)
919 {
920 	struct tcphdr *tc;
921 	struct alias_link *lnk;
922 
923 	LIBALIAS_LOCK_ASSERT(la);
924 	tc = (struct tcphdr *)ip_next(pip);
925 
926 	lnk = FindUdpTcpIn(la, pip->ip_src, pip->ip_dst,
927 	    tc->th_sport, tc->th_dport,
928 	    IPPROTO_TCP,
929 	    !(la->packetAliasMode & PKT_ALIAS_PROXY_ONLY));
930 	if (lnk != NULL) {
931 		struct in_addr alias_address;
932 		struct in_addr original_address;
933 		struct in_addr proxy_address;
934 		u_short alias_port;
935 		u_short proxy_port;
936 		int accumulate, error;
937 
938 		/*
939 		 * The init of MANY vars is a bit below, but aliashandlepptpin
940 		 * seems to need the destination port that came within the
941 		 * packet and not the original one looks below [*].
942 		 */
943 
944 		struct alias_data ad = {
945 			.lnk = lnk,
946 			.oaddr = NULL,
947 			.aaddr = NULL,
948 			.aport = NULL,
949 			.sport = &tc->th_sport,
950 			.dport = &tc->th_dport,
951 			.maxpktsize = 0
952 		};
953 
954 		/* Walk out chain. */
955 		error = find_handler(IN, TCP, la, pip, &ad);
956 
957 		alias_address = GetAliasAddress(lnk);
958 		original_address = GetOriginalAddress(lnk);
959 		proxy_address = GetProxyAddress(lnk);
960 		alias_port = tc->th_dport;
961 		tc->th_dport = GetOriginalPort(lnk);
962 		proxy_port = GetProxyPort(lnk);
963 
964 		/*
965 		 * Look above, if anyone is going to add find_handler AFTER
966 		 * this aliashandlepptpin/point, please redo alias_data too.
967 		 * Uncommenting the piece here below should be enough.
968 		 */
969 #if 0
970 				 struct alias_data ad = {
971 					.lnk = lnk,
972 					.oaddr = &original_address,
973 					.aaddr = &alias_address,
974 					.aport = &alias_port,
975 					.sport = &ud->uh_sport,
976 					.dport = &ud->uh_dport,
977 					.maxpktsize = 0
978 				};
979 
980 				/* Walk out chain. */
981 				error = find_handler(la, pip, &ad);
982 				if (error == EHDNOF)
983 					printf("Protocol handler not found\n");
984 #endif
985 
986 /* Adjust TCP checksum since destination port is being unaliased */
987 /* and destination port is being altered.                        */
988 		accumulate = alias_port;
989 		accumulate -= tc->th_dport;
990 		accumulate += twowords(&alias_address);
991 		accumulate -= twowords(&original_address);
992 
993 /* If this is a proxy, then modify the TCP source port and
994    checksum accumulation */
995 		if (proxy_port != 0) {
996 			accumulate += tc->th_sport;
997 			tc->th_sport = proxy_port;
998 			accumulate -= tc->th_sport;
999 			accumulate += twowords(&pip->ip_src);
1000 			accumulate -= twowords(&proxy_address);
1001 		}
1002 /* See if ACK number needs to be modified */
1003 		if (GetAckModified(lnk) == 1) {
1004 			int delta;
1005 
1006 			tc = (struct tcphdr *)ip_next(pip);
1007 			delta = GetDeltaAckIn(tc->th_ack, lnk);
1008 			if (delta != 0) {
1009 				accumulate += twowords(&tc->th_ack);
1010 				tc->th_ack = htonl(ntohl(tc->th_ack) - delta);
1011 				accumulate -= twowords(&tc->th_ack);
1012 			}
1013 		}
1014 		ADJUST_CHECKSUM(accumulate, tc->th_sum);
1015 
1016 /* Restore original IP address */
1017 		accumulate = twowords(&pip->ip_dst);
1018 		pip->ip_dst = original_address;
1019 		accumulate -= twowords(&pip->ip_dst);
1020 
1021 /* If this is a transparent proxy packet, then modify the source
1022    address */
1023 		if (proxy_address.s_addr != 0) {
1024 			accumulate += twowords(&pip->ip_src);
1025 			pip->ip_src = proxy_address;
1026 			accumulate -= twowords(&pip->ip_src);
1027 		}
1028 		ADJUST_CHECKSUM(accumulate, pip->ip_sum);
1029 
1030 /* Monitor TCP connection state */
1031 		tc = (struct tcphdr *)ip_next(pip);
1032 		TcpMonitorIn(tc->th_flags, lnk);
1033 
1034 		return (PKT_ALIAS_OK);
1035 	}
1036 	return (PKT_ALIAS_IGNORED);
1037 }
1038 
1039 static int
1040 TcpAliasOut(struct libalias *la, struct ip *pip, int maxpacketsize, int create)
1041 {
1042 	int proxy_type, error;
1043 	u_short dest_port;
1044 	u_short proxy_server_port;
1045 	struct in_addr dest_address;
1046 	struct in_addr proxy_server_address;
1047 	struct tcphdr *tc;
1048 	struct alias_link *lnk;
1049 
1050 	LIBALIAS_LOCK_ASSERT(la);
1051 	tc = (struct tcphdr *)ip_next(pip);
1052 
1053 	if (create)
1054 		proxy_type = ProxyCheck(la, &proxy_server_address,
1055 		    &proxy_server_port, pip->ip_src, pip->ip_dst,
1056 		    tc->th_dport, pip->ip_p);
1057 	else
1058 		proxy_type = 0;
1059 
1060 	if (proxy_type == 0 && (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY))
1061 		return (PKT_ALIAS_OK);
1062 
1063 /* If this is a transparent proxy, save original destination,
1064    then alter the destination and adjust checksums */
1065 	dest_port = tc->th_dport;
1066 	dest_address = pip->ip_dst;
1067 	if (proxy_type != 0) {
1068 		int accumulate;
1069 
1070 		accumulate = tc->th_dport;
1071 		tc->th_dport = proxy_server_port;
1072 		accumulate -= tc->th_dport;
1073 		accumulate += twowords(&pip->ip_dst);
1074 		accumulate -= twowords(&proxy_server_address);
1075 		ADJUST_CHECKSUM(accumulate, tc->th_sum);
1076 
1077 		accumulate = twowords(&pip->ip_dst);
1078 		pip->ip_dst = proxy_server_address;
1079 		accumulate -= twowords(&pip->ip_dst);
1080 		ADJUST_CHECKSUM(accumulate, pip->ip_sum);
1081 	}
1082 	lnk = FindUdpTcpOut(la, pip->ip_src, pip->ip_dst,
1083 	    tc->th_sport, tc->th_dport,
1084 	    IPPROTO_TCP, create);
1085 	if (lnk == NULL)
1086 		return (PKT_ALIAS_IGNORED);
1087 	if (lnk != NULL) {
1088 		u_short alias_port;
1089 		struct in_addr alias_address;
1090 		int accumulate;
1091 		struct alias_data ad = {
1092 			.lnk = lnk,
1093 			.oaddr = NULL,
1094 			.aaddr = &alias_address,
1095 			.aport = &alias_port,
1096 			.sport = &tc->th_sport,
1097 			.dport = &tc->th_dport,
1098 			.maxpktsize = maxpacketsize
1099 		};
1100 
1101 /* Save original destination address, if this is a proxy packet.
1102    Also modify packet to include destination encoding.  This may
1103    change the size of IP header. */
1104 		if (proxy_type != 0) {
1105 			SetProxyPort(lnk, dest_port);
1106 			SetProxyAddress(lnk, dest_address);
1107 			ProxyModify(la, lnk, pip, maxpacketsize, proxy_type);
1108 			tc = (struct tcphdr *)ip_next(pip);
1109 		}
1110 /* Get alias address and port */
1111 		alias_port = GetAliasPort(lnk);
1112 		alias_address = GetAliasAddress(lnk);
1113 
1114 /* Monitor TCP connection state */
1115 		tc = (struct tcphdr *)ip_next(pip);
1116 		TcpMonitorOut(tc->th_flags, lnk);
1117 
1118 		/* Walk out chain. */
1119 		error = find_handler(OUT, TCP, la, pip, &ad);
1120 
1121 /* Adjust TCP checksum since source port is being aliased */
1122 /* and source address is being altered                    */
1123 		accumulate = tc->th_sport;
1124 		tc->th_sport = alias_port;
1125 		accumulate -= tc->th_sport;
1126 		accumulate += twowords(&pip->ip_src);
1127 		accumulate -= twowords(&alias_address);
1128 
1129 /* Modify sequence number if necessary */
1130 		if (GetAckModified(lnk) == 1) {
1131 			int delta;
1132 
1133 			tc = (struct tcphdr *)ip_next(pip);
1134 			delta = GetDeltaSeqOut(tc->th_seq, lnk);
1135 			if (delta != 0) {
1136 				accumulate += twowords(&tc->th_seq);
1137 				tc->th_seq = htonl(ntohl(tc->th_seq) + delta);
1138 				accumulate -= twowords(&tc->th_seq);
1139 			}
1140 		}
1141 		ADJUST_CHECKSUM(accumulate, tc->th_sum);
1142 
1143 /* Change source address */
1144 		accumulate = twowords(&pip->ip_src);
1145 		pip->ip_src = alias_address;
1146 		accumulate -= twowords(&pip->ip_src);
1147 		ADJUST_CHECKSUM(accumulate, pip->ip_sum);
1148 
1149 		return (PKT_ALIAS_OK);
1150 	}
1151 	return (PKT_ALIAS_IGNORED);
1152 }
1153 
1154 
1155 
1156 
1157 /* Fragment Handling
1158 
1159     FragmentIn()
1160     FragmentOut()
1161 
1162 The packet aliasing module has a limited ability for handling IP
1163 fragments.  If the ICMP, TCP or UDP header is in the first fragment
1164 received, then the ID number of the IP packet is saved, and other
1165 fragments are identified according to their ID number and IP address
1166 they were sent from.  Pointers to unresolved fragments can also be
1167 saved and recalled when a header fragment is seen.
1168 */
1169 
1170 /* Local prototypes */
1171 static int	FragmentIn(struct libalias *la, struct in_addr ip_src,
1172 		    struct in_addr *ip_dst, u_short ip_id, u_short *ip_sum);
1173 static int	FragmentOut(struct libalias *, struct in_addr *ip_src,
1174 		    u_short *ip_sum);
1175 
1176 static int
1177 FragmentIn(struct libalias *la, struct in_addr ip_src, struct in_addr *ip_dst,
1178     u_short ip_id, u_short *ip_sum)
1179 {
1180 	struct alias_link *lnk;
1181 
1182 	LIBALIAS_LOCK_ASSERT(la);
1183 	lnk = FindFragmentIn2(la, ip_src, *ip_dst, ip_id);
1184 	if (lnk != NULL) {
1185 		struct in_addr original_address;
1186 
1187 		GetFragmentAddr(lnk, &original_address);
1188 		DifferentialChecksum(ip_sum,
1189 		    &original_address, ip_dst, 2);
1190 		*ip_dst = original_address;
1191 
1192 		return (PKT_ALIAS_OK);
1193 	}
1194 	return (PKT_ALIAS_UNRESOLVED_FRAGMENT);
1195 }
1196 
1197 static int
1198 FragmentOut(struct libalias *la, struct in_addr *ip_src, u_short *ip_sum)
1199 {
1200 	struct in_addr alias_address;
1201 
1202 	LIBALIAS_LOCK_ASSERT(la);
1203 	alias_address = FindAliasAddress(la, *ip_src);
1204 	DifferentialChecksum(ip_sum,
1205 	    &alias_address, ip_src, 2);
1206 	*ip_src = alias_address;
1207 
1208 	return (PKT_ALIAS_OK);
1209 }
1210 
1211 
1212 
1213 
1214 
1215 
1216 /* Outside World Access
1217 
1218 	PacketAliasSaveFragment()
1219 	PacketAliasGetFragment()
1220 	PacketAliasFragmentIn()
1221 	PacketAliasIn()
1222 	PacketAliasOut()
1223 	PacketUnaliasOut()
1224 
1225 (prototypes in alias.h)
1226 */
1227 
1228 int
1229 LibAliasSaveFragment(struct libalias *la, char *ptr)
1230 {
1231 	int iresult;
1232 	struct alias_link *lnk;
1233 	struct ip *pip;
1234 
1235 	LIBALIAS_LOCK(la);
1236 	pip = (struct ip *)ptr;
1237 	lnk = AddFragmentPtrLink(la, pip->ip_src, pip->ip_id);
1238 	iresult = PKT_ALIAS_ERROR;
1239 	if (lnk != NULL) {
1240 		SetFragmentPtr(lnk, ptr);
1241 		iresult = PKT_ALIAS_OK;
1242 	}
1243 	LIBALIAS_UNLOCK(la);
1244 	return (iresult);
1245 }
1246 
1247 char           *
1248 LibAliasGetFragment(struct libalias *la, char *ptr)
1249 {
1250 	struct alias_link *lnk;
1251 	char *fptr;
1252 	struct ip *pip;
1253 
1254 	LIBALIAS_LOCK(la);
1255 	pip = (struct ip *)ptr;
1256 	lnk = FindFragmentPtr(la, pip->ip_src, pip->ip_id);
1257 	if (lnk != NULL) {
1258 		GetFragmentPtr(lnk, &fptr);
1259 		SetFragmentPtr(lnk, NULL);
1260 		SetExpire(lnk, 0);	/* Deletes link */
1261 	} else
1262 		fptr = NULL;
1263 
1264 	LIBALIAS_UNLOCK(la);
1265 	return (fptr);
1266 }
1267 
1268 void
1269 LibAliasFragmentIn(struct libalias *la, char *ptr,	/* Points to correctly
1270 							 * de-aliased header
1271 							 * fragment */
1272     char *ptr_fragment		/* Points to fragment which must be
1273 				 * de-aliased   */
1274 )
1275 {
1276 	struct ip *pip;
1277 	struct ip *fpip;
1278 
1279 	LIBALIAS_LOCK(la);
1280 	(void)la;
1281 	pip = (struct ip *)ptr;
1282 	fpip = (struct ip *)ptr_fragment;
1283 
1284 	DifferentialChecksum(&fpip->ip_sum,
1285 	    &pip->ip_dst, &fpip->ip_dst, 2);
1286 	fpip->ip_dst = pip->ip_dst;
1287 	LIBALIAS_UNLOCK(la);
1288 }
1289 
1290 /* Local prototypes */
1291 static int
1292 LibAliasOutLocked(struct libalias *la, char *ptr,
1293 		  int maxpacketsize, int create);
1294 static int
1295 LibAliasInLocked(struct libalias *la, char *ptr,
1296 		  int maxpacketsize);
1297 
1298 int
1299 LibAliasIn(struct libalias *la, char *ptr, int maxpacketsize)
1300 {
1301 	int res;
1302 
1303 	LIBALIAS_LOCK(la);
1304 	res = LibAliasInLocked(la, ptr, maxpacketsize);
1305 	LIBALIAS_UNLOCK(la);
1306 	return (res);
1307 }
1308 
1309 static int
1310 LibAliasInLocked(struct libalias *la, char *ptr, int maxpacketsize)
1311 {
1312 	struct in_addr alias_addr;
1313 	struct ip *pip;
1314 	int iresult;
1315 
1316 	if (la->packetAliasMode & PKT_ALIAS_REVERSE) {
1317 		la->packetAliasMode &= ~PKT_ALIAS_REVERSE;
1318 		iresult = LibAliasOutLocked(la, ptr, maxpacketsize, 1);
1319 		la->packetAliasMode |= PKT_ALIAS_REVERSE;
1320 		goto getout;
1321 	}
1322 	HouseKeeping(la);
1323 	ClearCheckNewLink(la);
1324 	pip = (struct ip *)ptr;
1325 	alias_addr = pip->ip_dst;
1326 
1327 	/* Defense against mangled packets */
1328 	if (ntohs(pip->ip_len) > maxpacketsize
1329 	    || (pip->ip_hl << 2) > maxpacketsize) {
1330 		iresult = PKT_ALIAS_IGNORED;
1331 		goto getout;
1332 	}
1333 
1334 	iresult = PKT_ALIAS_IGNORED;
1335 	if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
1336 		switch (pip->ip_p) {
1337 		case IPPROTO_ICMP:
1338 			iresult = IcmpAliasIn(la, pip);
1339 			break;
1340 		case IPPROTO_UDP:
1341 			iresult = UdpAliasIn(la, pip);
1342 			break;
1343 		case IPPROTO_TCP:
1344 			iresult = TcpAliasIn(la, pip);
1345 			break;
1346 #ifdef _KERNEL
1347 		case IPPROTO_SCTP:
1348 		  iresult = SctpAlias(la, pip, SN_TO_LOCAL);
1349 			break;
1350 #endif
1351  		case IPPROTO_GRE: {
1352 			int error;
1353 			struct alias_data ad = {
1354 				.lnk = NULL,
1355 				.oaddr = NULL,
1356 				.aaddr = NULL,
1357 				.aport = NULL,
1358 				.sport = NULL,
1359 				.dport = NULL,
1360 				.maxpktsize = 0
1361 			};
1362 
1363 			/* Walk out chain. */
1364 			error = find_handler(IN, IP, la, pip, &ad);
1365 			if (error ==  0)
1366 				iresult = PKT_ALIAS_OK;
1367 			else
1368 				iresult = ProtoAliasIn(la, pip->ip_src,
1369 				    &pip->ip_dst, pip->ip_p, &pip->ip_sum);
1370 		}
1371  			break;
1372 		default:
1373 			iresult = ProtoAliasIn(la, pip->ip_src, &pip->ip_dst,
1374 			    pip->ip_p, &pip->ip_sum);
1375 			break;
1376 		}
1377 
1378 		if (ntohs(pip->ip_off) & IP_MF) {
1379 			struct alias_link *lnk;
1380 
1381 			lnk = FindFragmentIn1(la, pip->ip_src, alias_addr, pip->ip_id);
1382 			if (lnk != NULL) {
1383 				iresult = PKT_ALIAS_FOUND_HEADER_FRAGMENT;
1384 				SetFragmentAddr(lnk, pip->ip_dst);
1385 			} else {
1386 				iresult = PKT_ALIAS_ERROR;
1387 			}
1388 		}
1389 	} else {
1390 		iresult = FragmentIn(la, pip->ip_src, &pip->ip_dst, pip->ip_id,
1391 		    &pip->ip_sum);
1392 	}
1393 
1394 getout:
1395 	return (iresult);
1396 }
1397 
1398 
1399 
1400 /* Unregistered address ranges */
1401 
1402 /* 10.0.0.0   ->   10.255.255.255 */
1403 #define UNREG_ADDR_A_LOWER 0x0a000000
1404 #define UNREG_ADDR_A_UPPER 0x0affffff
1405 
1406 /* 172.16.0.0  ->  172.31.255.255 */
1407 #define UNREG_ADDR_B_LOWER 0xac100000
1408 #define UNREG_ADDR_B_UPPER 0xac1fffff
1409 
1410 /* 192.168.0.0 -> 192.168.255.255 */
1411 #define UNREG_ADDR_C_LOWER 0xc0a80000
1412 #define UNREG_ADDR_C_UPPER 0xc0a8ffff
1413 
1414 int
1415 LibAliasOut(struct libalias *la, char *ptr, int maxpacketsize)
1416 {
1417 	int res;
1418 
1419 	LIBALIAS_LOCK(la);
1420 	res = LibAliasOutLocked(la, ptr, maxpacketsize, 1);
1421 	LIBALIAS_UNLOCK(la);
1422 	return (res);
1423 }
1424 
1425 int
1426 LibAliasOutTry(struct libalias *la, char *ptr, int maxpacketsize, int create)
1427 {
1428 	int res;
1429 
1430 	LIBALIAS_LOCK(la);
1431 	res = LibAliasOutLocked(la, ptr, maxpacketsize, create);
1432 	LIBALIAS_UNLOCK(la);
1433 	return (res);
1434 }
1435 
1436 static int
1437 LibAliasOutLocked(struct libalias *la, char *ptr,	/* valid IP packet */
1438     int maxpacketsize,		/* How much the packet data may grow (FTP
1439 				 * and IRC inline changes) */
1440     int create                  /* Create new entries ? */
1441 )
1442 {
1443 	int iresult;
1444 	struct in_addr addr_save;
1445 	struct ip *pip;
1446 
1447 	if (la->packetAliasMode & PKT_ALIAS_REVERSE) {
1448 		la->packetAliasMode &= ~PKT_ALIAS_REVERSE;
1449 		iresult = LibAliasInLocked(la, ptr, maxpacketsize);
1450 		la->packetAliasMode |= PKT_ALIAS_REVERSE;
1451 		goto getout;
1452 	}
1453 	HouseKeeping(la);
1454 	ClearCheckNewLink(la);
1455 	pip = (struct ip *)ptr;
1456 
1457 	/* Defense against mangled packets */
1458 	if (ntohs(pip->ip_len) > maxpacketsize
1459 	    || (pip->ip_hl << 2) > maxpacketsize) {
1460 		iresult = PKT_ALIAS_IGNORED;
1461 		goto getout;
1462 	}
1463 
1464 	addr_save = GetDefaultAliasAddress(la);
1465 	if (la->packetAliasMode & PKT_ALIAS_UNREGISTERED_ONLY) {
1466 		u_long addr;
1467 		int iclass;
1468 
1469 		iclass = 0;
1470 		addr = ntohl(pip->ip_src.s_addr);
1471 		if (addr >= UNREG_ADDR_C_LOWER && addr <= UNREG_ADDR_C_UPPER)
1472 			iclass = 3;
1473 		else if (addr >= UNREG_ADDR_B_LOWER && addr <= UNREG_ADDR_B_UPPER)
1474 			iclass = 2;
1475 		else if (addr >= UNREG_ADDR_A_LOWER && addr <= UNREG_ADDR_A_UPPER)
1476 			iclass = 1;
1477 
1478 		if (iclass == 0) {
1479 			SetDefaultAliasAddress(la, pip->ip_src);
1480 		}
1481 	} else if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY) {
1482 		SetDefaultAliasAddress(la, pip->ip_src);
1483 	}
1484 	iresult = PKT_ALIAS_IGNORED;
1485 	if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
1486 		switch (pip->ip_p) {
1487 		case IPPROTO_ICMP:
1488 			iresult = IcmpAliasOut(la, pip, create);
1489 			break;
1490 		case IPPROTO_UDP:
1491 			iresult = UdpAliasOut(la, pip, maxpacketsize, create);
1492 			break;
1493 		case IPPROTO_TCP:
1494 			iresult = TcpAliasOut(la, pip, maxpacketsize, create);
1495 			break;
1496 #ifdef _KERNEL
1497 		case IPPROTO_SCTP:
1498 		  iresult = SctpAlias(la, pip, SN_TO_GLOBAL);
1499 			break;
1500 #endif
1501 		case IPPROTO_GRE: {
1502 			int error;
1503 			struct alias_data ad = {
1504 				.lnk = NULL,
1505 				.oaddr = NULL,
1506 				.aaddr = NULL,
1507 				.aport = NULL,
1508 				.sport = NULL,
1509 				.dport = NULL,
1510 				.maxpktsize = 0
1511 			};
1512 			/* Walk out chain. */
1513 			error = find_handler(OUT, IP, la, pip, &ad);
1514 			if (error == 0)
1515  				iresult = PKT_ALIAS_OK;
1516  			else
1517  				iresult = ProtoAliasOut(la, &pip->ip_src,
1518 				    pip->ip_dst, pip->ip_p, &pip->ip_sum, create);
1519 		}
1520  			break;
1521 		default:
1522 			iresult = ProtoAliasOut(la, &pip->ip_src,
1523 			    pip->ip_dst, pip->ip_p, &pip->ip_sum, create);
1524 			break;
1525 		}
1526 	} else {
1527 		iresult = FragmentOut(la, &pip->ip_src, &pip->ip_sum);
1528 	}
1529 
1530 	SetDefaultAliasAddress(la, addr_save);
1531 getout:
1532 	return (iresult);
1533 }
1534 
1535 int
1536 LibAliasUnaliasOut(struct libalias *la, char *ptr,	/* valid IP packet */
1537     int maxpacketsize		/* for error checking */
1538 )
1539 {
1540 	struct ip *pip;
1541 	struct icmp *ic;
1542 	struct udphdr *ud;
1543 	struct tcphdr *tc;
1544 	struct alias_link *lnk;
1545 	int iresult = PKT_ALIAS_IGNORED;
1546 
1547 	LIBALIAS_LOCK(la);
1548 	pip = (struct ip *)ptr;
1549 
1550 	/* Defense against mangled packets */
1551 	if (ntohs(pip->ip_len) > maxpacketsize
1552 	    || (pip->ip_hl << 2) > maxpacketsize)
1553 		goto getout;
1554 
1555 	ud = (struct udphdr *)ip_next(pip);
1556 	tc = (struct tcphdr *)ip_next(pip);
1557 	ic = (struct icmp *)ip_next(pip);
1558 
1559 	/* Find a link */
1560 	if (pip->ip_p == IPPROTO_UDP)
1561 		lnk = FindUdpTcpIn(la, pip->ip_dst, pip->ip_src,
1562 		    ud->uh_dport, ud->uh_sport,
1563 		    IPPROTO_UDP, 0);
1564 	else if (pip->ip_p == IPPROTO_TCP)
1565 		lnk = FindUdpTcpIn(la, pip->ip_dst, pip->ip_src,
1566 		    tc->th_dport, tc->th_sport,
1567 		    IPPROTO_TCP, 0);
1568 	else if (pip->ip_p == IPPROTO_ICMP)
1569 		lnk = FindIcmpIn(la, pip->ip_dst, pip->ip_src, ic->icmp_id, 0);
1570 	else
1571 		lnk = NULL;
1572 
1573 	/* Change it from an aliased packet to an unaliased packet */
1574 	if (lnk != NULL) {
1575 		if (pip->ip_p == IPPROTO_UDP || pip->ip_p == IPPROTO_TCP) {
1576 			int accumulate;
1577 			struct in_addr original_address;
1578 			u_short original_port;
1579 
1580 			original_address = GetOriginalAddress(lnk);
1581 			original_port = GetOriginalPort(lnk);
1582 
1583 			/* Adjust TCP/UDP checksum */
1584 			accumulate = twowords(&pip->ip_src);
1585 			accumulate -= twowords(&original_address);
1586 
1587 			if (pip->ip_p == IPPROTO_UDP) {
1588 				accumulate += ud->uh_sport;
1589 				accumulate -= original_port;
1590 				ADJUST_CHECKSUM(accumulate, ud->uh_sum);
1591 			} else {
1592 				accumulate += tc->th_sport;
1593 				accumulate -= original_port;
1594 				ADJUST_CHECKSUM(accumulate, tc->th_sum);
1595 			}
1596 
1597 			/* Adjust IP checksum */
1598 			DifferentialChecksum(&pip->ip_sum,
1599 			    &original_address, &pip->ip_src, 2);
1600 
1601 			/* Un-alias source address and port number */
1602 			pip->ip_src = original_address;
1603 			if (pip->ip_p == IPPROTO_UDP)
1604 				ud->uh_sport = original_port;
1605 			else
1606 				tc->th_sport = original_port;
1607 
1608 			iresult = PKT_ALIAS_OK;
1609 
1610 		} else if (pip->ip_p == IPPROTO_ICMP) {
1611 
1612 			int accumulate;
1613 			struct in_addr original_address;
1614 			u_short original_id;
1615 
1616 			original_address = GetOriginalAddress(lnk);
1617 			original_id = GetOriginalPort(lnk);
1618 
1619 			/* Adjust ICMP checksum */
1620 			accumulate = twowords(&pip->ip_src);
1621 			accumulate -= twowords(&original_address);
1622 			accumulate += ic->icmp_id;
1623 			accumulate -= original_id;
1624 			ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
1625 
1626 			/* Adjust IP checksum */
1627 			DifferentialChecksum(&pip->ip_sum,
1628 			    &original_address, &pip->ip_src, 2);
1629 
1630 			/* Un-alias source address and port number */
1631 			pip->ip_src = original_address;
1632 			ic->icmp_id = original_id;
1633 
1634 			iresult = PKT_ALIAS_OK;
1635 		}
1636 	}
1637 getout:
1638 	LIBALIAS_UNLOCK(la);
1639 	return (iresult);
1640 
1641 }
1642 
1643 #ifndef _KERNEL
1644 
1645 int
1646 LibAliasRefreshModules(void)
1647 {
1648 	char buf[256], conf[] = "/etc/libalias.conf";
1649 	FILE *fd;
1650 	int i, len;
1651 
1652 	fd = fopen(conf, "r");
1653 	if (fd == NULL)
1654 		err(1, "fopen(%s)", conf);
1655 
1656 	LibAliasUnLoadAllModule();
1657 
1658 	for (;;) {
1659 		fgets(buf, 256, fd);
1660 		if (feof(fd))
1661 		        break;
1662 		len = strlen(buf);
1663 		if (len > 1) {
1664 			for (i = 0; i < len; i++)
1665 				if (!isspace(buf[i]))
1666 					break;
1667 			if (buf[i] == '#')
1668 				continue;
1669 			buf[len - 1] = '\0';
1670 			LibAliasLoadModule(buf);
1671 		}
1672 	}
1673 	fclose(fd);
1674 	return (0);
1675 }
1676 
1677 int
1678 LibAliasLoadModule(char *path)
1679 {
1680 	struct dll *t;
1681 	void *handle;
1682 	struct proto_handler *m;
1683         const char *error;
1684 	moduledata_t *p;
1685 
1686         handle = dlopen (path, RTLD_LAZY);
1687         if (!handle) {
1688 		fprintf(stderr, "%s\n", dlerror());
1689 		return (EINVAL);
1690         }
1691 
1692 	p = dlsym(handle, "alias_mod");
1693         if ((error = dlerror()) != NULL)  {
1694 		fprintf(stderr, "%s\n", dlerror());
1695 		return (EINVAL);
1696         }
1697 
1698 	t = malloc(sizeof(struct dll));
1699 	if (t == NULL)
1700 		return (ENOMEM);
1701 	strncpy(t->name, p->name, DLL_LEN);
1702 	t->handle = handle;
1703 	if (attach_dll(t) == EEXIST) {
1704 		free(t);
1705 		fprintf(stderr, "dll conflict\n");
1706 		return (EEXIST);
1707 	}
1708 
1709         m = dlsym(t->handle, "handlers");
1710         if ((error = dlerror()) != NULL)  {
1711 		fprintf(stderr, "%s\n", error);
1712 		return (EINVAL);
1713 	}
1714 
1715 	LibAliasAttachHandlers(m);
1716 	return (0);
1717 }
1718 
1719 int
1720 LibAliasUnLoadAllModule(void)
1721 {
1722 	struct dll *t;
1723 	struct proto_handler *p;
1724 
1725 	/* Unload all modules then reload everything. */
1726 	while ((p = first_handler()) != NULL) {
1727 		LibAliasDetachHandlers(p);
1728 	}
1729 	while ((t = walk_dll_chain()) != NULL) {
1730 		dlclose(t->handle);
1731 		free(t);
1732 	}
1733 	return (1);
1734 }
1735 
1736 #endif
1737 
1738 #ifdef _KERNEL
1739 /*
1740  * m_megapullup() - this function is a big hack.
1741  * Thankfully, it's only used in ng_nat and ipfw+nat.
1742  *
1743  * It allocates an mbuf with cluster and copies the specified part of the chain
1744  * into cluster, so that it is all contiguous and can be accessed via a plain
1745  * (char *) pointer. This is required, because libalias doesn't know how to
1746  * handle mbuf chains.
1747  *
1748  * On success, m_megapullup returns an mbuf (possibly with cluster) containing
1749  * the input packet, on failure NULL. The input packet is always consumed.
1750  */
1751 struct mbuf *
1752 m_megapullup(struct mbuf *m, int len) {
1753 	struct mbuf *mcl;
1754 
1755 	if (len > m->m_pkthdr.len)
1756 		goto bad;
1757 
1758 	if (m->m_next == NULL && M_WRITABLE(m))
1759 		return (m);
1760 
1761 	mcl = m_get2(len, M_NOWAIT, MT_DATA, M_PKTHDR);
1762 	if (mcl == NULL)
1763 		goto bad;
1764 	m_align(mcl, len);
1765 	m_move_pkthdr(mcl, m);
1766 	m_copydata(m, 0, len, mtod(mcl, caddr_t));
1767 	mcl->m_len = mcl->m_pkthdr.len = len;
1768 	m_freem(m);
1769 
1770 	return (mcl);
1771 bad:
1772 	m_freem(m);
1773 	return (NULL);
1774 }
1775 #endif
1776