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