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