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