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