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