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