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