xref: /freebsd/sys/netinet/libalias/alias.c (revision fb2ea26f3c3681f5ef639af9c798a631d800864b)
1f987e1bdSBrian Somers /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3fe267a55SPedro F. Giffuni  *
4e83aaae3SBrian Somers  * Copyright (c) 2001 Charles Mott <cm@linktel.net>
5f987e1bdSBrian Somers  * All rights reserved.
6f987e1bdSBrian Somers  *
7f987e1bdSBrian Somers  * Redistribution and use in source and binary forms, with or without
8f987e1bdSBrian Somers  * modification, are permitted provided that the following conditions
9f987e1bdSBrian Somers  * are met:
10f987e1bdSBrian Somers  * 1. Redistributions of source code must retain the above copyright
11f987e1bdSBrian Somers  *    notice, this list of conditions and the following disclaimer.
12f987e1bdSBrian Somers  * 2. Redistributions in binary form must reproduce the above copyright
13f987e1bdSBrian Somers  *    notice, this list of conditions and the following disclaimer in the
14f987e1bdSBrian Somers  *    documentation and/or other materials provided with the distribution.
15f987e1bdSBrian Somers  *
16f987e1bdSBrian Somers  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17f987e1bdSBrian Somers  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18f987e1bdSBrian Somers  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19f987e1bdSBrian Somers  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20f987e1bdSBrian Somers  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21f987e1bdSBrian Somers  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22f987e1bdSBrian Somers  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23f987e1bdSBrian Somers  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24f987e1bdSBrian Somers  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25f987e1bdSBrian Somers  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26f987e1bdSBrian Somers  * SUCH DAMAGE.
27f987e1bdSBrian Somers  */
28f987e1bdSBrian Somers 
29e2505aa6SMatthew Dillon #include <sys/cdefs.h>
303b160b8bSBrian Somers /*
313b160b8bSBrian Somers     Alias.c provides supervisory control for the functions of the
323b160b8bSBrian Somers     packet aliasing software.  It consists of routines to monitor
333b160b8bSBrian Somers     TCP connection state, protocol-specific aliasing routines,
343b160b8bSBrian Somers     fragment handling and the following outside world functional
353b160b8bSBrian Somers     interfaces: SaveFragmentPtr, GetFragmentPtr, FragmentAliasIn,
363b160b8bSBrian Somers     PacketAliasIn and PacketAliasOut.
373b160b8bSBrian Somers 
383b160b8bSBrian Somers     The other C program files are briefly described. The data
393b160b8bSBrian Somers     structure framework which holds information needed to translate
403b160b8bSBrian Somers     packets is encapsulated in alias_db.c.  Data is accessed by
413b160b8bSBrian Somers     function calls, so other segments of the program need not know
423b160b8bSBrian Somers     about the underlying data structures.  Alias_ftp.c contains
433b160b8bSBrian Somers     special code for modifying the ftp PORT command used to establish
44680c8244SRuslan Ermilov     data connections, while alias_irc.c does the same for IRC
453b160b8bSBrian Somers     DCC. Alias_util.c contains a few utility routines.
463b160b8bSBrian Somers 
473b160b8bSBrian Somers     Version 1.0 August, 1996  (cjm)
483b160b8bSBrian Somers 
493b160b8bSBrian Somers     Version 1.1 August 20, 1996  (cjm)
503b160b8bSBrian Somers 	PPP host accepts incoming connections for ports 0 to 1023.
513b160b8bSBrian Somers 	(Gary Roberts pointed out the need to handle incoming
523b160b8bSBrian Somers 	 connections.)
533b160b8bSBrian Somers 
543b160b8bSBrian Somers     Version 1.2 September 7, 1996 (cjm)
553b160b8bSBrian Somers 	Fragment handling error in alias_db.c corrected.
563b160b8bSBrian Somers 	(Tom Torrance helped fix this problem.)
573b160b8bSBrian Somers 
583b160b8bSBrian Somers     Version 1.4 September 16, 1996 (cjm)
593b160b8bSBrian Somers 	- A more generalized method for handling incoming
603b160b8bSBrian Somers 	  connections, without the 0-1023 restriction, is
613b160b8bSBrian Somers 	  implemented in alias_db.c
623b160b8bSBrian Somers 	- Improved ICMP support in alias.c.  Traceroute
633b160b8bSBrian Somers 	  packet streams can now be correctly aliased.
643b160b8bSBrian Somers 	- TCP connection closing logic simplified in
653b160b8bSBrian Somers 	  alias.c and now allows for additional 1 minute
663b160b8bSBrian Somers 	  "grace period" after FIN or RST is observed.
673b160b8bSBrian Somers 
683b160b8bSBrian Somers     Version 1.5 September 17, 1996 (cjm)
693b160b8bSBrian Somers 	Corrected error in handling incoming UDP packets with 0 checksum.
703b160b8bSBrian Somers 	(Tom Torrance helped fix this problem.)
713b160b8bSBrian Somers 
723b160b8bSBrian Somers     Version 1.6 September 18, 1996 (cjm)
733b160b8bSBrian Somers 	Simplified ICMP aliasing scheme.  Should now support
743b160b8bSBrian Somers 	traceroute from Win95 as well as FreeBSD.
753b160b8bSBrian Somers 
763b160b8bSBrian Somers     Version 1.7 January 9, 1997 (cjm)
773b160b8bSBrian Somers 	- Out-of-order fragment handling.
783b160b8bSBrian Somers 	- IP checksum error fixed for ftp transfers
793b160b8bSBrian Somers 	  from aliasing host.
803b160b8bSBrian Somers 	- Integer return codes added to all
813b160b8bSBrian Somers 	  aliasing/de-aliasing functions.
823b160b8bSBrian Somers 	- Some obsolete comments cleaned up.
833b160b8bSBrian Somers 	- Differential checksum computations for
843b160b8bSBrian Somers 	  IP header (TCP, UDP and ICMP were already
853b160b8bSBrian Somers 	  differential).
863b160b8bSBrian Somers 
873b160b8bSBrian Somers     Version 2.1 May 1997 (cjm)
883b160b8bSBrian Somers 	- Added support for outgoing ICMP error
893b160b8bSBrian Somers 	  messages.
903b160b8bSBrian Somers 	- Added two functions PacketAliasIn2()
913b160b8bSBrian Somers 	  and PacketAliasOut2() for dynamic address
923b160b8bSBrian Somers 	  control (e.g. round-robin allocation of
933b160b8bSBrian Somers 	  incoming packets).
943efa11bbSBrian Somers 
953efa11bbSBrian Somers     Version 2.2 July 1997 (cjm)
963efa11bbSBrian Somers 	- Rationalized API function names to begin
973efa11bbSBrian Somers 	  with "PacketAlias..."
983efa11bbSBrian Somers 	- Eliminated PacketAliasIn2() and
993efa11bbSBrian Somers 	  PacketAliasOut2() as poorly conceived.
1003efa11bbSBrian Somers 
101374fad8bSMatthew Dillon     Version 2.3 Dec 1998 (dillon)
102374fad8bSMatthew Dillon 	- Major bounds checking additions, see FreeBSD/CVS
103374fad8bSMatthew Dillon 
104642e43b3SArchie Cobbs     Version 3.1 May, 2000 (salander)
10555a39fc5SRuslan Ermilov 	- Added hooks to handle PPTP.
10655a39fc5SRuslan Ermilov 
107642e43b3SArchie Cobbs     Version 3.2 July, 2000 (salander and satoh)
108642e43b3SArchie Cobbs 	- Added PacketUnaliasOut routine.
109642e43b3SArchie Cobbs 	- Added hooks to handle RTSP/RTP.
110642e43b3SArchie Cobbs 
1118ddc51bcSEivind Eklund     See HISTORY file for additional revisions.
1123b160b8bSBrian Somers */
1133b160b8bSBrian Somers 
114c649a2e0SGleb Smirnoff #ifdef _KERNEL
115c649a2e0SGleb Smirnoff #include <sys/param.h>
1165910c1c1SPaolo Pisati #include <sys/systm.h>
1175910c1c1SPaolo Pisati #include <sys/mbuf.h>
11837ce2656SPaolo Pisati #include <sys/sysctl.h>
119c649a2e0SGleb Smirnoff #else
1203b160b8bSBrian Somers #include <sys/types.h>
121be4f3cd0SPaolo Pisati #include <stdlib.h>
122c649a2e0SGleb Smirnoff #include <stdio.h>
1235910c1c1SPaolo Pisati #include <ctype.h>
124be4f3cd0SPaolo Pisati #include <dlfcn.h>
125be4f3cd0SPaolo Pisati #include <errno.h>
126be4f3cd0SPaolo Pisati #include <string.h>
127c649a2e0SGleb Smirnoff #endif
1283b160b8bSBrian Somers 
1293b160b8bSBrian Somers #include <netinet/in_systm.h>
1303b160b8bSBrian Somers #include <netinet/in.h>
1313b160b8bSBrian Somers #include <netinet/ip.h>
1323b160b8bSBrian Somers #include <netinet/ip_icmp.h>
1333b160b8bSBrian Somers #include <netinet/tcp.h>
1343b160b8bSBrian Somers #include <netinet/udp.h>
1353b160b8bSBrian Somers 
136c649a2e0SGleb Smirnoff #ifdef _KERNEL
137c649a2e0SGleb Smirnoff #include <netinet/libalias/alias.h>
13875bc2620SGleb Smirnoff #include <netinet/libalias/alias_local.h>
139be4f3cd0SPaolo Pisati #include <netinet/libalias/alias_mod.h>
140c649a2e0SGleb Smirnoff #else
141be4f3cd0SPaolo Pisati #include <err.h>
1423b160b8bSBrian Somers #include "alias.h"
14375bc2620SGleb Smirnoff #include "alias_local.h"
144be4f3cd0SPaolo Pisati #include "alias_mod.h"
145c649a2e0SGleb Smirnoff #endif
1463b160b8bSBrian Somers 
14737ce2656SPaolo Pisati /*
14837ce2656SPaolo Pisati  * Define libalias SYSCTL Node
14937ce2656SPaolo Pisati  */
15037ce2656SPaolo Pisati #ifdef SYSCTL_NODE
15137ce2656SPaolo Pisati 
15237ce2656SPaolo Pisati SYSCTL_DECL(_net_inet);
15337ce2656SPaolo Pisati SYSCTL_DECL(_net_inet_ip);
1547029da5cSPawel Biernacki SYSCTL_NODE(_net_inet_ip, OID_AUTO, alias, CTLFLAG_RW | CTLFLAG_MPSAFE, NULL,
1557029da5cSPawel Biernacki     "Libalias sysctl API");
15637ce2656SPaolo Pisati 
15737ce2656SPaolo Pisati #endif
15837ce2656SPaolo Pisati 
1592871c501SDag-Erling Smørgrav static __inline int
twowords(void * p)1602871c501SDag-Erling Smørgrav twowords(void *p)
1612871c501SDag-Erling Smørgrav {
162e3e2c216SDag-Erling Smørgrav 	uint8_t *c = p;
1633b160b8bSBrian Somers 
164e3e2c216SDag-Erling Smørgrav #if BYTE_ORDER == LITTLE_ENDIAN
165e3e2c216SDag-Erling Smørgrav 	uint16_t s1 = ((uint16_t)c[1] << 8) + (uint16_t)c[0];
166e3e2c216SDag-Erling Smørgrav 	uint16_t s2 = ((uint16_t)c[3] << 8) + (uint16_t)c[2];
167e3e2c216SDag-Erling Smørgrav #else
168e3e2c216SDag-Erling Smørgrav 	uint16_t s1 = ((uint16_t)c[0] << 8) + (uint16_t)c[1];
169e3e2c216SDag-Erling Smørgrav 	uint16_t s2 = ((uint16_t)c[2] << 8) + (uint16_t)c[3];
170e3e2c216SDag-Erling Smørgrav #endif
171e3e2c216SDag-Erling Smørgrav 	return (s1 + s2);
1722871c501SDag-Erling Smørgrav }
1733b160b8bSBrian Somers 
1743b160b8bSBrian Somers /* TCP Handling Routines
1753b160b8bSBrian Somers 
1763b160b8bSBrian Somers     TcpMonitorIn()  -- These routines monitor TCP connections, and
1777d96f4efSBrian Somers     TcpMonitorOut()    delete a link when a connection is closed.
1783b160b8bSBrian Somers 
17992da29a0SRuslan Ermilov These routines look for SYN, FIN and RST flags to determine when TCP
1803b160b8bSBrian Somers connections open and close.  When a TCP connection closes, the data
1813b160b8bSBrian Somers structure containing packet aliasing information is deleted after
1823b160b8bSBrian Somers a timeout period.
1833b160b8bSBrian Somers */
1843b160b8bSBrian Somers 
1853b160b8bSBrian Somers /* Local prototypes */
1860fc7bdc9SRichard Scheffenegger static void	TcpMonitorIn(uint16_t, struct alias_link *);
1873b160b8bSBrian Somers 
1880fc7bdc9SRichard Scheffenegger static void	TcpMonitorOut(uint16_t, struct alias_link *);
1893b160b8bSBrian Somers 
1903b160b8bSBrian Somers static void
TcpMonitorIn(uint16_t th_flags,struct alias_link * lnk)1910fc7bdc9SRichard Scheffenegger TcpMonitorIn(uint16_t th_flags, struct alias_link *lnk)
1923b160b8bSBrian Somers {
193ed01a582SDag-Erling Smørgrav 	switch (GetStateIn(lnk)) {
1948ddc51bcSEivind Eklund 	case ALIAS_TCP_STATE_NOT_CONNECTED:
1954741f3a1SPaolo Pisati 		if (th_flags & TH_RST)
196ed01a582SDag-Erling Smørgrav 			SetStateIn(lnk, ALIAS_TCP_STATE_DISCONNECTED);
1974741f3a1SPaolo Pisati 		else if (th_flags & TH_SYN)
198ed01a582SDag-Erling Smørgrav 			SetStateIn(lnk, ALIAS_TCP_STATE_CONNECTED);
19992da29a0SRuslan Ermilov 		break;
2008ddc51bcSEivind Eklund 	case ALIAS_TCP_STATE_CONNECTED:
2014741f3a1SPaolo Pisati 		if (th_flags & (TH_FIN | TH_RST))
202ed01a582SDag-Erling Smørgrav 			SetStateIn(lnk, ALIAS_TCP_STATE_DISCONNECTED);
2038ddc51bcSEivind Eklund 		break;
2043b160b8bSBrian Somers 	}
2053b160b8bSBrian Somers }
2063b160b8bSBrian Somers 
2073b160b8bSBrian Somers static void
TcpMonitorOut(uint16_t th_flags,struct alias_link * lnk)2080fc7bdc9SRichard Scheffenegger TcpMonitorOut(uint16_t th_flags, struct alias_link *lnk)
2093b160b8bSBrian Somers {
210ed01a582SDag-Erling Smørgrav 	switch (GetStateOut(lnk)) {
2118ddc51bcSEivind Eklund 	case ALIAS_TCP_STATE_NOT_CONNECTED:
2124741f3a1SPaolo Pisati 		if (th_flags & TH_RST)
213ed01a582SDag-Erling Smørgrav 			SetStateOut(lnk, ALIAS_TCP_STATE_DISCONNECTED);
2144741f3a1SPaolo Pisati 		else if (th_flags & TH_SYN)
215ed01a582SDag-Erling Smørgrav 			SetStateOut(lnk, ALIAS_TCP_STATE_CONNECTED);
21692da29a0SRuslan Ermilov 		break;
2178ddc51bcSEivind Eklund 	case ALIAS_TCP_STATE_CONNECTED:
2184741f3a1SPaolo Pisati 		if (th_flags & (TH_FIN | TH_RST))
219ed01a582SDag-Erling Smørgrav 			SetStateOut(lnk, ALIAS_TCP_STATE_DISCONNECTED);
2208ddc51bcSEivind Eklund 		break;
2213b160b8bSBrian Somers 	}
2223b160b8bSBrian Somers }
2233b160b8bSBrian Somers 
2243b160b8bSBrian Somers /* Protocol Specific Packet Aliasing Routines
2253b160b8bSBrian Somers 
226305d1069SRuslan Ermilov     IcmpAliasIn(), IcmpAliasIn1(), IcmpAliasIn2()
227305d1069SRuslan Ermilov     IcmpAliasOut(), IcmpAliasOut1(), IcmpAliasOut2()
22880607605SRuslan Ermilov     ProtoAliasIn(), ProtoAliasOut()
2293b160b8bSBrian Somers     UdpAliasIn(), UdpAliasOut()
2303b160b8bSBrian Somers     TcpAliasIn(), TcpAliasOut()
2313b160b8bSBrian Somers 
2323b160b8bSBrian Somers These routines handle protocol specific details of packet aliasing.
2333b160b8bSBrian Somers One may observe a certain amount of repetitive arithmetic in these
2343b160b8bSBrian Somers functions, the purpose of which is to compute a revised checksum
2353b160b8bSBrian Somers without actually summing over the entire data packet, which could be
2363b160b8bSBrian Somers unnecessarily time consuming.
2373b160b8bSBrian Somers 
2383b160b8bSBrian Somers The purpose of the packet aliasing routines is to replace the source
2393b160b8bSBrian Somers address of the outgoing packet and then correctly put it back for
2403b160b8bSBrian Somers any incoming packets.  For TCP and UDP, ports are also re-mapped.
2413b160b8bSBrian Somers 
2423b160b8bSBrian Somers For ICMP echo/timestamp requests and replies, the following scheme
243483d2f22SRuslan Ermilov is used: the ID number is replaced by an alias for the outgoing
2443b160b8bSBrian Somers packet.
2453b160b8bSBrian Somers 
2463b160b8bSBrian Somers ICMP error messages are handled by looking at the IP fragment
2473b160b8bSBrian Somers in the data section of the message.
2483b160b8bSBrian Somers 
2493b160b8bSBrian Somers For TCP and UDP protocols, a port number is chosen for an outgoing
2503b160b8bSBrian Somers packet, and then incoming packets are identified by IP address and
2513b160b8bSBrian Somers port numbers.  For TCP packets, there is additional logic in the event
252483d2f22SRuslan Ermilov that sequence and ACK numbers have been altered (as in the case for
2533b160b8bSBrian Somers FTP data port commands).
2543b160b8bSBrian Somers 
2553b160b8bSBrian Somers The port numbers used by the packet aliasing module are not true
2563b160b8bSBrian Somers ports in the Unix sense.  No sockets are actually bound to ports.
2573b160b8bSBrian Somers They are more correctly thought of as placeholders.
2583b160b8bSBrian Somers 
2593b160b8bSBrian Somers All packets go through the aliasing mechanism, whether they come from
2603b160b8bSBrian Somers the gateway machine or other machines on a local area network.
2613b160b8bSBrian Somers */
2623b160b8bSBrian Somers 
2633b160b8bSBrian Somers /* Local prototypes */
2645e289f9eSPoul-Henning Kamp static int	IcmpAliasIn1(struct libalias *, struct ip *);
2655e289f9eSPoul-Henning Kamp static int	IcmpAliasIn2(struct libalias *, struct ip *);
2665e289f9eSPoul-Henning Kamp static int	IcmpAliasIn(struct libalias *, struct ip *);
2673b160b8bSBrian Somers 
268e7581f0fSPoul-Henning Kamp static int	IcmpAliasOut1(struct libalias *, struct ip *, int create);
2695e289f9eSPoul-Henning Kamp static int	IcmpAliasOut2(struct libalias *, struct ip *);
270e6bbb691SPoul-Henning Kamp static int	IcmpAliasOut(struct libalias *, struct ip *, int create);
2713b160b8bSBrian Somers 
272ab0fcfd0SPaolo Pisati static int	ProtoAliasIn(struct libalias *la, struct in_addr ip_src,
273bc596e56SAlex Richardson 		    struct ip *pip, u_char ip_p, u_short *ip_sum);
274bc596e56SAlex Richardson static int	ProtoAliasOut(struct libalias *la, struct ip *pip,
275ab0fcfd0SPaolo Pisati 		    struct in_addr ip_dst, u_char ip_p, u_short *ip_sum,
276ab0fcfd0SPaolo Pisati 		    int create);
27780607605SRuslan Ermilov 
2785e289f9eSPoul-Henning Kamp static int	UdpAliasIn(struct libalias *, struct ip *);
279ea29dd92SAlexander Motin static int	UdpAliasOut(struct libalias *, struct ip *, int, int create);
2803b160b8bSBrian Somers 
2815e289f9eSPoul-Henning Kamp static int	TcpAliasIn(struct libalias *, struct ip *);
282e6bbb691SPoul-Henning Kamp static int	TcpAliasOut(struct libalias *, struct ip *, int, int create);
2833b160b8bSBrian Somers 
2843b160b8bSBrian Somers /*
285305d1069SRuslan Ermilov     De-alias incoming echo and timestamp replies.
286305d1069SRuslan Ermilov     Alias incoming echo and timestamp requests.
2873b160b8bSBrian Somers */
288effc8e57SLutz Donnerhacke static int
IcmpAliasIn1(struct libalias * la,struct ip * pip)289effc8e57SLutz Donnerhacke IcmpAliasIn1(struct libalias *la, struct ip *pip)
290effc8e57SLutz Donnerhacke {
291ed01a582SDag-Erling Smørgrav 	struct alias_link *lnk;
2923b160b8bSBrian Somers 	struct icmp *ic;
293*fb2ea26fSMark Johnston 	int ret;
2943b160b8bSBrian Somers 
2952e6b0786SLutz Donnerhacke 	LIBALIAS_LOCK_ASSERT(la);
2969fa0fd26SDag-Erling Smørgrav 	ic = (struct icmp *)ip_next(pip);
2973b160b8bSBrian Somers 
2983b160b8bSBrian Somers 	/* Get source address from ICMP data field and restore original data */
299*fb2ea26fSMark Johnston 	ret = FindIcmpIn(la, pip->ip_src, pip->ip_dst, ic->icmp_id, 1, &lnk);
300*fb2ea26fSMark Johnston 	if (ret == PKT_ALIAS_OK) {
3013b160b8bSBrian Somers 		u_short original_id;
3023b160b8bSBrian Somers 		int accumulate;
3033b160b8bSBrian Somers 
304ed01a582SDag-Erling Smørgrav 		original_id = GetOriginalPort(lnk);
3053b160b8bSBrian Somers 
3063b160b8bSBrian Somers 		/* Adjust ICMP checksum */
3073b160b8bSBrian Somers 		accumulate = ic->icmp_id;
3083b160b8bSBrian Somers 		accumulate -= original_id;
30971593f95SBrian Somers 		ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
3103b160b8bSBrian Somers 
3113b160b8bSBrian Somers 		/* Put original sequence number back in */
3123b160b8bSBrian Somers 		ic->icmp_id = original_id;
3133b160b8bSBrian Somers 
3143b160b8bSBrian Somers 		/* Put original address back into IP header */
3153b160b8bSBrian Somers 		{
3163b160b8bSBrian Somers 			struct in_addr original_address;
3173b160b8bSBrian Somers 
318ed01a582SDag-Erling Smørgrav 			original_address = GetOriginalAddress(lnk);
3193b160b8bSBrian Somers 			DifferentialChecksum(&pip->ip_sum,
3202871c501SDag-Erling Smørgrav 			    &original_address, &pip->ip_dst, 2);
3213b160b8bSBrian Somers 			pip->ip_dst = original_address;
3223b160b8bSBrian Somers 		}
3233b160b8bSBrian Somers 	}
324*fb2ea26fSMark Johnston 	return (ret);
3253b160b8bSBrian Somers }
3263b160b8bSBrian Somers 
3273b160b8bSBrian Somers /*
3283b160b8bSBrian Somers     Alias incoming ICMP error messages containing
3293b160b8bSBrian Somers     IP header and first 64 bits of datagram.
3303b160b8bSBrian Somers */
331effc8e57SLutz Donnerhacke static int
IcmpAliasIn2(struct libalias * la,struct ip * pip)332effc8e57SLutz Donnerhacke IcmpAliasIn2(struct libalias *la, struct ip *pip)
333effc8e57SLutz Donnerhacke {
3343b160b8bSBrian Somers 	struct ip *ip;
3353b160b8bSBrian Somers 	struct icmp *ic, *ic2;
3363b160b8bSBrian Somers 	struct udphdr *ud;
3373b160b8bSBrian Somers 	struct tcphdr *tc;
338ed01a582SDag-Erling Smørgrav 	struct alias_link *lnk;
339*fb2ea26fSMark Johnston 	int ret;
3403b160b8bSBrian Somers 
3412e6b0786SLutz Donnerhacke 	LIBALIAS_LOCK_ASSERT(la);
3429fa0fd26SDag-Erling Smørgrav 	ic = (struct icmp *)ip_next(pip);
343305d1069SRuslan Ermilov 	ip = &ic->icmp_ip;
3443b160b8bSBrian Somers 
3459fa0fd26SDag-Erling Smørgrav 	ud = (struct udphdr *)ip_next(ip);
3469fa0fd26SDag-Erling Smørgrav 	tc = (struct tcphdr *)ip_next(ip);
3479fa0fd26SDag-Erling Smørgrav 	ic2 = (struct icmp *)ip_next(ip);
3483b160b8bSBrian Somers 
349*fb2ea26fSMark Johnston 	if (ip->ip_p == IPPROTO_UDP) {
350*fb2ea26fSMark Johnston 		ret = FindUdpTcpIn(la, ip->ip_dst, ip->ip_src,
3513b160b8bSBrian Somers 		    ud->uh_dport, ud->uh_sport,
352*fb2ea26fSMark Johnston 		    IPPROTO_UDP, 0, &lnk);
353*fb2ea26fSMark Johnston 		if (ret != PKT_ALIAS_OK)
354*fb2ea26fSMark Johnston 			return (ret);
355*fb2ea26fSMark Johnston 	} else if (ip->ip_p == IPPROTO_TCP) {
356*fb2ea26fSMark Johnston 		ret = FindUdpTcpIn(la, ip->ip_dst, ip->ip_src,
3573b160b8bSBrian Somers 		    tc->th_dport, tc->th_sport,
358*fb2ea26fSMark Johnston 		    IPPROTO_TCP, 0, &lnk);
359*fb2ea26fSMark Johnston 		if (ret != PKT_ALIAS_OK)
360*fb2ea26fSMark Johnston 			return (ret);
361*fb2ea26fSMark Johnston 	} else if (ip->ip_p == IPPROTO_ICMP) {
362*fb2ea26fSMark Johnston 		if (ic2->icmp_type == ICMP_ECHO ||
363*fb2ea26fSMark Johnston 		    ic2->icmp_type == ICMP_TSTAMP) {
364*fb2ea26fSMark Johnston 			ret = FindIcmpIn(la, ip->ip_dst, ip->ip_src,
365*fb2ea26fSMark Johnston 			    ic2->icmp_id, 0, &lnk);
366*fb2ea26fSMark Johnston 			if (ret != PKT_ALIAS_OK)
367*fb2ea26fSMark Johnston 				return (ret);
368*fb2ea26fSMark Johnston 		} else
369ed01a582SDag-Erling Smørgrav 			lnk = NULL;
370dfcb634bSBrian Somers 	} else
371ed01a582SDag-Erling Smørgrav 		lnk = NULL;
3723b160b8bSBrian Somers 
373ed01a582SDag-Erling Smørgrav 	if (lnk != NULL) {
374f0f93429SDag-Erling Smørgrav 		if (ip->ip_p == IPPROTO_UDP || ip->ip_p == IPPROTO_TCP) {
37561a875d7SRuslan Ermilov 			int accumulate, accumulate2;
3763b160b8bSBrian Somers 			struct in_addr original_address;
3773b160b8bSBrian Somers 			u_short original_port;
3783b160b8bSBrian Somers 
379ed01a582SDag-Erling Smørgrav 			original_address = GetOriginalAddress(lnk);
380ed01a582SDag-Erling Smørgrav 			original_port = GetOriginalPort(lnk);
3813b160b8bSBrian Somers 
3823b160b8bSBrian Somers 			/* Adjust ICMP checksum */
3832871c501SDag-Erling Smørgrav 			accumulate = twowords(&ip->ip_src);
3842871c501SDag-Erling Smørgrav 			accumulate -= twowords(&original_address);
3853b160b8bSBrian Somers 			accumulate += ud->uh_sport;
3863b160b8bSBrian Somers 			accumulate -= original_port;
38761a875d7SRuslan Ermilov 			accumulate2 = accumulate;
38861a875d7SRuslan Ermilov 			accumulate2 += ip->ip_sum;
38961a875d7SRuslan Ermilov 			ADJUST_CHECKSUM(accumulate, ip->ip_sum);
39061a875d7SRuslan Ermilov 			accumulate2 -= ip->ip_sum;
39161a875d7SRuslan Ermilov 			ADJUST_CHECKSUM(accumulate2, ic->icmp_cksum);
3923b160b8bSBrian Somers 
3933b160b8bSBrian Somers 			/* Un-alias address in IP header */
3943b160b8bSBrian Somers 			DifferentialChecksum(&pip->ip_sum,
3952871c501SDag-Erling Smørgrav 			    &original_address, &pip->ip_dst, 2);
3963b160b8bSBrian Somers 			pip->ip_dst = original_address;
3973b160b8bSBrian Somers 
398effc8e57SLutz Donnerhacke 			/* Un-alias address and port number of
399effc8e57SLutz Donnerhacke 			 * original IP packet fragment contained
400effc8e57SLutz Donnerhacke 			 * in ICMP data section */
4013b160b8bSBrian Somers 			ip->ip_src = original_address;
4023b160b8bSBrian Somers 			ud->uh_sport = original_port;
403f0f93429SDag-Erling Smørgrav 		} else if (ip->ip_p == IPPROTO_ICMP) {
40461a875d7SRuslan Ermilov 			int accumulate, accumulate2;
4053b160b8bSBrian Somers 			struct in_addr original_address;
4063b160b8bSBrian Somers 			u_short original_id;
4073b160b8bSBrian Somers 
408ed01a582SDag-Erling Smørgrav 			original_address = GetOriginalAddress(lnk);
409ed01a582SDag-Erling Smørgrav 			original_id = GetOriginalPort(lnk);
4103b160b8bSBrian Somers 
4113b160b8bSBrian Somers 			/* Adjust ICMP checksum */
4122871c501SDag-Erling Smørgrav 			accumulate = twowords(&ip->ip_src);
4132871c501SDag-Erling Smørgrav 			accumulate -= twowords(&original_address);
4143b160b8bSBrian Somers 			accumulate += ic2->icmp_id;
4153b160b8bSBrian Somers 			accumulate -= original_id;
41661a875d7SRuslan Ermilov 			accumulate2 = accumulate;
41761a875d7SRuslan Ermilov 			accumulate2 += ip->ip_sum;
41861a875d7SRuslan Ermilov 			ADJUST_CHECKSUM(accumulate, ip->ip_sum);
41961a875d7SRuslan Ermilov 			accumulate2 -= ip->ip_sum;
42061a875d7SRuslan Ermilov 			ADJUST_CHECKSUM(accumulate2, ic->icmp_cksum);
4213b160b8bSBrian Somers 
4223b160b8bSBrian Somers 			/* Un-alias address in IP header */
4233b160b8bSBrian Somers 			DifferentialChecksum(&pip->ip_sum,
4242871c501SDag-Erling Smørgrav 			    &original_address, &pip->ip_dst, 2);
4253b160b8bSBrian Somers 			pip->ip_dst = original_address;
4263b160b8bSBrian Somers 
427effc8e57SLutz Donnerhacke 			/* Un-alias address of original IP packet and
428effc8e57SLutz Donnerhacke 			 * sequence number of embedded ICMP datagram */
4293b160b8bSBrian Somers 			ip->ip_src = original_address;
4303b160b8bSBrian Somers 			ic2->icmp_id = original_id;
4313b160b8bSBrian Somers 		}
4323b160b8bSBrian Somers 		return (PKT_ALIAS_OK);
4333b160b8bSBrian Somers 	}
4343b160b8bSBrian Somers 	return (PKT_ALIAS_IGNORED);
4353b160b8bSBrian Somers }
4363b160b8bSBrian Somers 
4373b160b8bSBrian Somers static int
IcmpAliasIn(struct libalias * la,struct ip * pip)4385e289f9eSPoul-Henning Kamp IcmpAliasIn(struct libalias *la, struct ip *pip)
4393b160b8bSBrian Somers {
4403b160b8bSBrian Somers 	struct icmp *ic;
441be597269SAlex Richardson 	int iresult;
442be597269SAlex Richardson 	size_t dlen;
4433b160b8bSBrian Somers 
444ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK_ASSERT(la);
4456461c83eSEd Maste 
4466461c83eSEd Maste 	dlen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
4476461c83eSEd Maste 	if (dlen < ICMP_MINLEN)
4486461c83eSEd Maste 		return (PKT_ALIAS_IGNORED);
4496461c83eSEd Maste 
4507d96f4efSBrian Somers 	/* Return if proxy-only mode is enabled */
4515e289f9eSPoul-Henning Kamp 	if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
452ffcb611aSDag-Erling Smørgrav 		return (PKT_ALIAS_OK);
4537d96f4efSBrian Somers 
4549fa0fd26SDag-Erling Smørgrav 	ic = (struct icmp *)ip_next(pip);
4553b160b8bSBrian Somers 
4563b160b8bSBrian Somers 	iresult = PKT_ALIAS_IGNORED;
457f0f93429SDag-Erling Smørgrav 	switch (ic->icmp_type) {
4583b160b8bSBrian Somers 	case ICMP_ECHOREPLY:
4593b160b8bSBrian Somers 	case ICMP_TSTAMPREPLY:
460f0f93429SDag-Erling Smørgrav 		if (ic->icmp_code == 0) {
4615e289f9eSPoul-Henning Kamp 			iresult = IcmpAliasIn1(la, pip);
4623b160b8bSBrian Somers 		}
4633b160b8bSBrian Somers 		break;
4643b160b8bSBrian Somers 	case ICMP_UNREACH:
4653b160b8bSBrian Somers 	case ICMP_SOURCEQUENCH:
4663b160b8bSBrian Somers 	case ICMP_TIMXCEED:
4673b160b8bSBrian Somers 	case ICMP_PARAMPROB:
4686461c83eSEd Maste 		if (dlen < ICMP_ADVLENMIN ||
469be597269SAlex Richardson 		    dlen < (size_t)ICMP_ADVLEN(ic))
4706461c83eSEd Maste 			return (PKT_ALIAS_IGNORED);
4715e289f9eSPoul-Henning Kamp 		iresult = IcmpAliasIn2(la, pip);
4723b160b8bSBrian Somers 		break;
4733b160b8bSBrian Somers 	case ICMP_ECHO:
4743b160b8bSBrian Somers 	case ICMP_TSTAMP:
4755e289f9eSPoul-Henning Kamp 		iresult = IcmpAliasIn1(la, pip);
4763b160b8bSBrian Somers 		break;
4773b160b8bSBrian Somers 	}
4783b160b8bSBrian Somers 	return (iresult);
4793b160b8bSBrian Somers }
4803b160b8bSBrian Somers 
4813b160b8bSBrian Somers /*
482305d1069SRuslan Ermilov     Alias outgoing echo and timestamp requests.
483305d1069SRuslan Ermilov     De-alias outgoing echo and timestamp replies.
4843b160b8bSBrian Somers */
485effc8e57SLutz Donnerhacke static int
IcmpAliasOut1(struct libalias * la,struct ip * pip,int create)486effc8e57SLutz Donnerhacke IcmpAliasOut1(struct libalias *la, struct ip *pip, int create)
487effc8e57SLutz Donnerhacke {
488ed01a582SDag-Erling Smørgrav 	struct alias_link *lnk;
4893b160b8bSBrian Somers 	struct icmp *ic;
490*fb2ea26fSMark Johnston 	int ret;
4913b160b8bSBrian Somers 
492ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK_ASSERT(la);
4939fa0fd26SDag-Erling Smørgrav 	ic = (struct icmp *)ip_next(pip);
4943b160b8bSBrian Somers 
4953b160b8bSBrian Somers 	/* Save overwritten data for when echo packet returns */
496*fb2ea26fSMark Johnston 	ret = FindIcmpOut(la, pip->ip_src, pip->ip_dst, ic->icmp_id, create,
497*fb2ea26fSMark Johnston 	    &lnk);
498*fb2ea26fSMark Johnston 	if (ret == PKT_ALIAS_OK) {
4993b160b8bSBrian Somers 		u_short alias_id;
5003b160b8bSBrian Somers 		int accumulate;
5013b160b8bSBrian Somers 
502ed01a582SDag-Erling Smørgrav 		alias_id = GetAliasPort(lnk);
5033b160b8bSBrian Somers 
5043b160b8bSBrian Somers 		/* Since data field is being modified, adjust ICMP checksum */
5053b160b8bSBrian Somers 		accumulate = ic->icmp_id;
5063b160b8bSBrian Somers 		accumulate -= alias_id;
50771593f95SBrian Somers 		ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
5083b160b8bSBrian Somers 
5093b160b8bSBrian Somers 		/* Alias sequence number */
5103b160b8bSBrian Somers 		ic->icmp_id = alias_id;
5113b160b8bSBrian Somers 
5123b160b8bSBrian Somers 		/* Change source address */
5133b160b8bSBrian Somers 		{
5143b160b8bSBrian Somers 			struct in_addr alias_address;
5153b160b8bSBrian Somers 
516ed01a582SDag-Erling Smørgrav 			alias_address = GetAliasAddress(lnk);
5173b160b8bSBrian Somers 			DifferentialChecksum(&pip->ip_sum,
5182871c501SDag-Erling Smørgrav 			    &alias_address, &pip->ip_src, 2);
5193b160b8bSBrian Somers 			pip->ip_src = alias_address;
5203b160b8bSBrian Somers 		}
5213b160b8bSBrian Somers 	}
522*fb2ea26fSMark Johnston 	return (ret);
5233b160b8bSBrian Somers }
5243b160b8bSBrian Somers 
5253b160b8bSBrian Somers /*
5263b160b8bSBrian Somers     Alias outgoing ICMP error messages containing
5273b160b8bSBrian Somers     IP header and first 64 bits of datagram.
5283b160b8bSBrian Somers */
529effc8e57SLutz Donnerhacke static int
IcmpAliasOut2(struct libalias * la,struct ip * pip)530effc8e57SLutz Donnerhacke IcmpAliasOut2(struct libalias *la, struct ip *pip)
531effc8e57SLutz Donnerhacke {
5323b160b8bSBrian Somers 	struct ip *ip;
533680c8244SRuslan Ermilov 	struct icmp *ic, *ic2;
534680c8244SRuslan Ermilov 	struct udphdr *ud;
535680c8244SRuslan Ermilov 	struct tcphdr *tc;
536ed01a582SDag-Erling Smørgrav 	struct alias_link *lnk;
537*fb2ea26fSMark Johnston 	int ret;
5383b160b8bSBrian Somers 
539ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK_ASSERT(la);
5409fa0fd26SDag-Erling Smørgrav 	ic = (struct icmp *)ip_next(pip);
541305d1069SRuslan Ermilov 	ip = &ic->icmp_ip;
5423b160b8bSBrian Somers 
5439fa0fd26SDag-Erling Smørgrav 	ud = (struct udphdr *)ip_next(ip);
5449fa0fd26SDag-Erling Smørgrav 	tc = (struct tcphdr *)ip_next(ip);
5459fa0fd26SDag-Erling Smørgrav 	ic2 = (struct icmp *)ip_next(ip);
5463b160b8bSBrian Somers 
547*fb2ea26fSMark Johnston 	if (ip->ip_p == IPPROTO_UDP) {
548*fb2ea26fSMark Johnston 		ret = FindUdpTcpOut(la, ip->ip_dst, ip->ip_src,
549680c8244SRuslan Ermilov 		    ud->uh_dport, ud->uh_sport,
550*fb2ea26fSMark Johnston 		    IPPROTO_UDP, 0, &lnk);
551*fb2ea26fSMark Johnston 		if (ret != PKT_ALIAS_OK)
552*fb2ea26fSMark Johnston 			return (ret);
553*fb2ea26fSMark Johnston 	} else if (ip->ip_p == IPPROTO_TCP) {
554*fb2ea26fSMark Johnston 		ret = FindUdpTcpOut(la, ip->ip_dst, ip->ip_src,
555680c8244SRuslan Ermilov 		    tc->th_dport, tc->th_sport,
556*fb2ea26fSMark Johnston 		    IPPROTO_TCP, 0, &lnk);
557*fb2ea26fSMark Johnston 		if (ret != PKT_ALIAS_OK)
558*fb2ea26fSMark Johnston 			return (ret);
559*fb2ea26fSMark Johnston 	} else if (ip->ip_p == IPPROTO_ICMP) {
560*fb2ea26fSMark Johnston 		if (ic2->icmp_type == ICMP_ECHO ||
561*fb2ea26fSMark Johnston 		    ic2->icmp_type == ICMP_TSTAMP) {
562*fb2ea26fSMark Johnston 			ret = FindIcmpOut(la, ip->ip_dst, ip->ip_src,
563*fb2ea26fSMark Johnston 			    ic2->icmp_id, 0, &lnk);
564*fb2ea26fSMark Johnston 			if (ret != PKT_ALIAS_OK)
565*fb2ea26fSMark Johnston 				return (ret);
566*fb2ea26fSMark Johnston 		} else
567ed01a582SDag-Erling Smørgrav 			lnk = NULL;
568680c8244SRuslan Ermilov 	} else
569ed01a582SDag-Erling Smørgrav 		lnk = NULL;
5703b160b8bSBrian Somers 
571ed01a582SDag-Erling Smørgrav 	if (lnk != NULL) {
572f0f93429SDag-Erling Smørgrav 		if (ip->ip_p == IPPROTO_UDP || ip->ip_p == IPPROTO_TCP) {
573680c8244SRuslan Ermilov 			int accumulate;
574680c8244SRuslan Ermilov 			struct in_addr alias_address;
575680c8244SRuslan Ermilov 			u_short alias_port;
576680c8244SRuslan Ermilov 
577ed01a582SDag-Erling Smørgrav 			alias_address = GetAliasAddress(lnk);
578ed01a582SDag-Erling Smørgrav 			alias_port = GetAliasPort(lnk);
579680c8244SRuslan Ermilov 
580680c8244SRuslan Ermilov 			/* Adjust ICMP checksum */
5812871c501SDag-Erling Smørgrav 			accumulate = twowords(&ip->ip_dst);
5822871c501SDag-Erling Smørgrav 			accumulate -= twowords(&alias_address);
583680c8244SRuslan Ermilov 			accumulate += ud->uh_dport;
584680c8244SRuslan Ermilov 			accumulate -= alias_port;
58571593f95SBrian Somers 			ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
586680c8244SRuslan Ermilov 
587816fa7feSRuslan Ermilov 			/*
588816fa7feSRuslan Ermilov 			 * Alias address in IP header if it comes from the host
589816fa7feSRuslan Ermilov 			 * the original TCP/UDP packet was destined for.
590816fa7feSRuslan Ermilov 			 */
591816fa7feSRuslan Ermilov 			if (pip->ip_src.s_addr == ip->ip_dst.s_addr) {
5923b160b8bSBrian Somers 				DifferentialChecksum(&pip->ip_sum,
5932871c501SDag-Erling Smørgrav 				    &alias_address, &pip->ip_src, 2);
594680c8244SRuslan Ermilov 				pip->ip_src = alias_address;
595816fa7feSRuslan Ermilov 			}
596680c8244SRuslan Ermilov 			/* Alias address and port number of original IP packet
597effc8e57SLutz Donnerhacke 			 * fragment contained in ICMP data section */
598680c8244SRuslan Ermilov 			ip->ip_dst = alias_address;
599680c8244SRuslan Ermilov 			ud->uh_dport = alias_port;
600f0f93429SDag-Erling Smørgrav 		} else if (ip->ip_p == IPPROTO_ICMP) {
601680c8244SRuslan Ermilov 			int accumulate;
602680c8244SRuslan Ermilov 			struct in_addr alias_address;
603680c8244SRuslan Ermilov 			u_short alias_id;
604680c8244SRuslan Ermilov 
605ed01a582SDag-Erling Smørgrav 			alias_address = GetAliasAddress(lnk);
606ed01a582SDag-Erling Smørgrav 			alias_id = GetAliasPort(lnk);
607680c8244SRuslan Ermilov 
608680c8244SRuslan Ermilov 			/* Adjust ICMP checksum */
6092871c501SDag-Erling Smørgrav 			accumulate = twowords(&ip->ip_dst);
6102871c501SDag-Erling Smørgrav 			accumulate -= twowords(&alias_address);
611680c8244SRuslan Ermilov 			accumulate += ic2->icmp_id;
612680c8244SRuslan Ermilov 			accumulate -= alias_id;
61371593f95SBrian Somers 			ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
614680c8244SRuslan Ermilov 
615816fa7feSRuslan Ermilov 			/*
616816fa7feSRuslan Ermilov 			 * Alias address in IP header if it comes from the host
617816fa7feSRuslan Ermilov 			 * the original ICMP message was destined for.
618816fa7feSRuslan Ermilov 			 */
619816fa7feSRuslan Ermilov 			if (pip->ip_src.s_addr == ip->ip_dst.s_addr) {
620680c8244SRuslan Ermilov 				DifferentialChecksum(&pip->ip_sum,
6212871c501SDag-Erling Smørgrav 				    &alias_address, &pip->ip_src, 2);
622680c8244SRuslan Ermilov 				pip->ip_src = alias_address;
623816fa7feSRuslan Ermilov 			}
624effc8e57SLutz Donnerhacke 			/* Alias address of original IP packet and
625effc8e57SLutz Donnerhacke 			 * sequence number of embedded ICMP datagram */
626680c8244SRuslan Ermilov 			ip->ip_dst = alias_address;
627680c8244SRuslan Ermilov 			ic2->icmp_id = alias_id;
628680c8244SRuslan Ermilov 		}
629680c8244SRuslan Ermilov 		return (PKT_ALIAS_OK);
630680c8244SRuslan Ermilov 	}
631680c8244SRuslan Ermilov 	return (PKT_ALIAS_IGNORED);
6323b160b8bSBrian Somers }
6333b160b8bSBrian Somers 
6343b160b8bSBrian Somers static int
IcmpAliasOut(struct libalias * la,struct ip * pip,int create)635e6bbb691SPoul-Henning Kamp IcmpAliasOut(struct libalias *la, struct ip *pip, int create)
6363b160b8bSBrian Somers {
6373b160b8bSBrian Somers 	int iresult;
6383b160b8bSBrian Somers 	struct icmp *ic;
6393b160b8bSBrian Somers 
640ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK_ASSERT(la);
641ed01a582SDag-Erling Smørgrav 	(void)create;
642ed01a582SDag-Erling Smørgrav 
6437d96f4efSBrian Somers 	/* Return if proxy-only mode is enabled */
6445e289f9eSPoul-Henning Kamp 	if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
645ffcb611aSDag-Erling Smørgrav 		return (PKT_ALIAS_OK);
6467d96f4efSBrian Somers 
6479fa0fd26SDag-Erling Smørgrav 	ic = (struct icmp *)ip_next(pip);
6483b160b8bSBrian Somers 
6493b160b8bSBrian Somers 	iresult = PKT_ALIAS_IGNORED;
650f0f93429SDag-Erling Smørgrav 	switch (ic->icmp_type) {
6513b160b8bSBrian Somers 	case ICMP_ECHO:
6523b160b8bSBrian Somers 	case ICMP_TSTAMP:
653f0f93429SDag-Erling Smørgrav 		if (ic->icmp_code == 0) {
654e7581f0fSPoul-Henning Kamp 			iresult = IcmpAliasOut1(la, pip, create);
6553b160b8bSBrian Somers 		}
6563b160b8bSBrian Somers 		break;
6573b160b8bSBrian Somers 	case ICMP_UNREACH:
6583b160b8bSBrian Somers 	case ICMP_SOURCEQUENCH:
6593b160b8bSBrian Somers 	case ICMP_TIMXCEED:
6603b160b8bSBrian Somers 	case ICMP_PARAMPROB:
6615e289f9eSPoul-Henning Kamp 		iresult = IcmpAliasOut2(la, pip);
6623b160b8bSBrian Somers 		break;
6633b160b8bSBrian Somers 	case ICMP_ECHOREPLY:
6643b160b8bSBrian Somers 	case ICMP_TSTAMPREPLY:
665e7581f0fSPoul-Henning Kamp 		iresult = IcmpAliasOut1(la, pip, create);
6663b160b8bSBrian Somers 	}
6673b160b8bSBrian Somers 	return (iresult);
6683b160b8bSBrian Somers }
6693b160b8bSBrian Somers 
6707d96f4efSBrian Somers /*
67180607605SRuslan Ermilov   Handle incoming IP packets. The
6727d96f4efSBrian Somers   only thing which is done in this case is to alias
6737d96f4efSBrian Somers   the dest IP address of the packet to our inside
6747d96f4efSBrian Somers   machine.
6757d96f4efSBrian Somers */
676effc8e57SLutz Donnerhacke static int
ProtoAliasIn(struct libalias * la,struct in_addr ip_src,struct ip * pip,u_char ip_p,u_short * ip_sum)677effc8e57SLutz Donnerhacke ProtoAliasIn(struct libalias *la, struct in_addr ip_src,
678effc8e57SLutz Donnerhacke     struct ip *pip, u_char ip_p, u_short *ip_sum)
679effc8e57SLutz Donnerhacke {
680ed01a582SDag-Erling Smørgrav 	struct alias_link *lnk;
681*fb2ea26fSMark Johnston 	int ret;
6827d96f4efSBrian Somers 
683ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK_ASSERT(la);
684483d2f22SRuslan Ermilov 	/* Return if proxy-only mode is enabled */
6855e289f9eSPoul-Henning Kamp 	if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
686ffcb611aSDag-Erling Smørgrav 		return (PKT_ALIAS_OK);
687483d2f22SRuslan Ermilov 
688*fb2ea26fSMark Johnston 	ret = FindProtoIn(la, ip_src, pip->ip_dst, ip_p, &lnk);
689*fb2ea26fSMark Johnston 	if (ret == PKT_ALIAS_OK) {
690483d2f22SRuslan Ermilov 		struct in_addr original_address;
6917d96f4efSBrian Somers 
692ed01a582SDag-Erling Smørgrav 		original_address = GetOriginalAddress(lnk);
693483d2f22SRuslan Ermilov 
694483d2f22SRuslan Ermilov 		/* Restore original IP address */
695ab0fcfd0SPaolo Pisati 		DifferentialChecksum(ip_sum,
696bc596e56SAlex Richardson 		    &original_address, &pip->ip_dst, 2);
697bc596e56SAlex Richardson 		pip->ip_dst = original_address;
698483d2f22SRuslan Ermilov 	}
699*fb2ea26fSMark Johnston 	return (ret);
7007d96f4efSBrian Somers }
7017d96f4efSBrian Somers 
7027d96f4efSBrian Somers /*
70380607605SRuslan Ermilov   Handle outgoing IP packets. The
7047d96f4efSBrian Somers   only thing which is done in this case is to alias
7057d96f4efSBrian Somers   the source IP address of the packet.
7067d96f4efSBrian Somers */
707effc8e57SLutz Donnerhacke static int
ProtoAliasOut(struct libalias * la,struct ip * pip,struct in_addr ip_dst,u_char ip_p,u_short * ip_sum,int create)708effc8e57SLutz Donnerhacke ProtoAliasOut(struct libalias *la, struct ip *pip,
709effc8e57SLutz Donnerhacke     struct in_addr ip_dst, u_char ip_p, u_short *ip_sum, int create)
710effc8e57SLutz Donnerhacke {
711ed01a582SDag-Erling Smørgrav 	struct alias_link *lnk;
712*fb2ea26fSMark Johnston 	int ret;
713ed01a582SDag-Erling Smørgrav 
714ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK_ASSERT(la);
7157d96f4efSBrian Somers 
716483d2f22SRuslan Ermilov 	/* Return if proxy-only mode is enabled */
7175e289f9eSPoul-Henning Kamp 	if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
718ffcb611aSDag-Erling Smørgrav 		return (PKT_ALIAS_OK);
719483d2f22SRuslan Ermilov 
7201a356b8bSEugene Grosbein 	if (!create)
7211a356b8bSEugene Grosbein 		return (PKT_ALIAS_IGNORED);
7221a356b8bSEugene Grosbein 
723*fb2ea26fSMark Johnston 	ret = FindProtoOut(la, pip->ip_src, ip_dst, ip_p, &lnk);
724*fb2ea26fSMark Johnston 	if (ret == PKT_ALIAS_OK) {
725483d2f22SRuslan Ermilov 		struct in_addr alias_address;
7267d96f4efSBrian Somers 
727ed01a582SDag-Erling Smørgrav 		alias_address = GetAliasAddress(lnk);
728483d2f22SRuslan Ermilov 
729483d2f22SRuslan Ermilov 		/* Change source address */
730ab0fcfd0SPaolo Pisati 		DifferentialChecksum(ip_sum,
731bc596e56SAlex Richardson 		    &alias_address, &pip->ip_src, 2);
732bc596e56SAlex Richardson 		pip->ip_src = alias_address;
733483d2f22SRuslan Ermilov 	}
734*fb2ea26fSMark Johnston 	return (ret);
7357d96f4efSBrian Somers }
7367d96f4efSBrian Somers 
737461e6f23SMaxim Sobolev #define MF_ISSET(_pip) (ntohs((_pip)->ip_off) & IP_MF)
738461e6f23SMaxim Sobolev #define FRAG_NO_HDR(_pip) (ntohs((_pip)->ip_off) & IP_OFFMASK)
739461e6f23SMaxim Sobolev 
740461e6f23SMaxim Sobolev static struct udphdr *
ValidateUdpLength(struct ip * pip)741461e6f23SMaxim Sobolev ValidateUdpLength(struct ip *pip)
742461e6f23SMaxim Sobolev {
743461e6f23SMaxim Sobolev 	struct udphdr *ud;
744461e6f23SMaxim Sobolev 	size_t dlen;
745461e6f23SMaxim Sobolev 
746461e6f23SMaxim Sobolev #ifdef _KERNEL
747461e6f23SMaxim Sobolev 	KASSERT(!FRAG_NO_HDR(pip), ("header-less fragment isn't expected here"));
748461e6f23SMaxim Sobolev #endif
749461e6f23SMaxim Sobolev 	dlen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
750461e6f23SMaxim Sobolev 	if (dlen < sizeof(struct udphdr))
751461e6f23SMaxim Sobolev 		return (NULL);
752461e6f23SMaxim Sobolev 	ud = (struct udphdr *)ip_next(pip);
753461e6f23SMaxim Sobolev 	if (!MF_ISSET(pip) && dlen < ntohs(ud->uh_ulen))
754461e6f23SMaxim Sobolev 		return (NULL);
755461e6f23SMaxim Sobolev 	return (ud);
756461e6f23SMaxim Sobolev }
757461e6f23SMaxim Sobolev 
75855a39fc5SRuslan Ermilov static int
UdpAliasIn(struct libalias * la,struct ip * pip)7595e289f9eSPoul-Henning Kamp UdpAliasIn(struct libalias *la, struct ip *pip)
7603b160b8bSBrian Somers {
7613b160b8bSBrian Somers 	struct udphdr *ud;
762ed01a582SDag-Erling Smørgrav 	struct alias_link *lnk;
763*fb2ea26fSMark Johnston 	int ret;
7643b160b8bSBrian Somers 
765ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK_ASSERT(la);
7667d96f4efSBrian Somers 
767461e6f23SMaxim Sobolev 	ud = ValidateUdpLength(pip);
768461e6f23SMaxim Sobolev 	if (ud == NULL)
7696461c83eSEd Maste 		return (PKT_ALIAS_IGNORED);
7703b160b8bSBrian Somers 
771*fb2ea26fSMark Johnston 	ret = FindUdpTcpIn(la, pip->ip_src, pip->ip_dst,
7723b160b8bSBrian Somers 	    ud->uh_sport, ud->uh_dport,
773*fb2ea26fSMark Johnston 	    IPPROTO_UDP, !(la->packetAliasMode & PKT_ALIAS_PROXY_ONLY), &lnk);
774*fb2ea26fSMark Johnston 	if (ret != PKT_ALIAS_OK)
775*fb2ea26fSMark Johnston 		return (ret);
776*fb2ea26fSMark Johnston 	{
7773b160b8bSBrian Somers 		struct in_addr alias_address;
7783b160b8bSBrian Somers 		struct in_addr original_address;
779ea29dd92SAlexander Motin 		struct in_addr proxy_address;
7803b160b8bSBrian Somers 		u_short alias_port;
781ea29dd92SAlexander Motin 		u_short proxy_port;
7823b160b8bSBrian Somers 		int accumulate;
783ea80b0acSPaolo Pisati 		int error;
784be4f3cd0SPaolo Pisati 		struct alias_data ad = {
785be4f3cd0SPaolo Pisati 			.lnk = lnk,
786be4f3cd0SPaolo Pisati 			.oaddr = &original_address,
787be4f3cd0SPaolo Pisati 			.aaddr = &alias_address,
788be4f3cd0SPaolo Pisati 			.aport = &alias_port,
789be4f3cd0SPaolo Pisati 			.sport = &ud->uh_sport,
790be4f3cd0SPaolo Pisati 			.dport = &ud->uh_dport,
791be4f3cd0SPaolo Pisati 			.maxpktsize = 0
792be4f3cd0SPaolo Pisati 		};
7933b160b8bSBrian Somers 
794ed01a582SDag-Erling Smørgrav 		alias_address = GetAliasAddress(lnk);
795ed01a582SDag-Erling Smørgrav 		original_address = GetOriginalAddress(lnk);
796ea29dd92SAlexander Motin 		proxy_address = GetProxyAddress(lnk);
7973b160b8bSBrian Somers 		alias_port = ud->uh_dport;
798ed01a582SDag-Erling Smørgrav 		ud->uh_dport = GetOriginalPort(lnk);
799ea29dd92SAlexander Motin 		proxy_port = GetProxyPort(lnk);
8003b160b8bSBrian Somers 
801be4f3cd0SPaolo Pisati 		/* Walk out chain. */
802be4f3cd0SPaolo Pisati 		error = find_handler(IN, UDP, la, pip, &ad);
80350d25ddaSPaolo Pisati 		/* If we cannot figure out the packet, ignore it. */
80450d25ddaSPaolo Pisati 		if (error < 0)
80550d25ddaSPaolo Pisati 			return (PKT_ALIAS_IGNORED);
8060579bd71SBrian Somers 
807effc8e57SLutz Donnerhacke 		/* If UDP checksum is not zero, then adjust since
808effc8e57SLutz Donnerhacke 		 * destination port is being unaliased and
809effc8e57SLutz Donnerhacke 		 * destination address is being altered. */
810f0f93429SDag-Erling Smørgrav 		if (ud->uh_sum != 0) {
8113b160b8bSBrian Somers 			accumulate = alias_port;
8123b160b8bSBrian Somers 			accumulate -= ud->uh_dport;
8132871c501SDag-Erling Smørgrav 			accumulate += twowords(&alias_address);
8142871c501SDag-Erling Smørgrav 			accumulate -= twowords(&original_address);
815ea29dd92SAlexander Motin 
816effc8e57SLutz Donnerhacke 			/* If this is a proxy packet, modify checksum
817effc8e57SLutz Donnerhacke 			 * because of source change.*/
818ea29dd92SAlexander Motin 			if (proxy_port != 0) {
819ea29dd92SAlexander Motin 				accumulate += ud->uh_sport;
820ea29dd92SAlexander Motin 				accumulate -= proxy_port;
821ea29dd92SAlexander Motin 			}
822ea29dd92SAlexander Motin 
823ea29dd92SAlexander Motin 			if (proxy_address.s_addr != 0) {
824ea29dd92SAlexander Motin 				accumulate += twowords(&pip->ip_src);
825ea29dd92SAlexander Motin 				accumulate -= twowords(&proxy_address);
826ea29dd92SAlexander Motin 			}
827ea29dd92SAlexander Motin 
82871593f95SBrian Somers 			ADJUST_CHECKSUM(accumulate, ud->uh_sum);
8293b160b8bSBrian Somers 		}
830effc8e57SLutz Donnerhacke 
831ea29dd92SAlexander Motin 		/* XXX: Could the two if's below be concatenated to one ? */
832ea29dd92SAlexander Motin 		/* Restore source port and/or address in case of proxying*/
833ea29dd92SAlexander Motin 		if (proxy_port != 0)
834ea29dd92SAlexander Motin 			ud->uh_sport = proxy_port;
835ea29dd92SAlexander Motin 
836ea29dd92SAlexander Motin 		if (proxy_address.s_addr != 0) {
837ea29dd92SAlexander Motin 			DifferentialChecksum(&pip->ip_sum,
838ea29dd92SAlexander Motin 			    &proxy_address, &pip->ip_src, 2);
839ea29dd92SAlexander Motin 			pip->ip_src = proxy_address;
840ea29dd92SAlexander Motin 		}
841ea29dd92SAlexander Motin 
8423b160b8bSBrian Somers 		/* Restore original IP address */
8433b160b8bSBrian Somers 		DifferentialChecksum(&pip->ip_sum,
8442871c501SDag-Erling Smørgrav 		    &original_address, &pip->ip_dst, 2);
8453b160b8bSBrian Somers 		pip->ip_dst = original_address;
846374fad8bSMatthew Dillon 
8473b160b8bSBrian Somers 		return (PKT_ALIAS_OK);
8483b160b8bSBrian Somers 	}
8493b160b8bSBrian Somers }
8503b160b8bSBrian Somers 
8513b160b8bSBrian Somers static int
UdpAliasOut(struct libalias * la,struct ip * pip,int maxpacketsize,int create)852ea29dd92SAlexander Motin UdpAliasOut(struct libalias *la, struct ip *pip, int maxpacketsize, int create)
8533b160b8bSBrian Somers {
8543b160b8bSBrian Somers 	struct udphdr *ud;
855ed01a582SDag-Erling Smørgrav 	struct alias_link *lnk;
856ea29dd92SAlexander Motin 	struct in_addr dest_address;
857ea29dd92SAlexander Motin 	struct in_addr proxy_server_address;
858ea29dd92SAlexander Motin 	u_short dest_port;
859ea29dd92SAlexander Motin 	u_short proxy_server_port;
860*fb2ea26fSMark Johnston 	int proxy_type, ret;
8613b160b8bSBrian Somers 
862ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK_ASSERT(la);
863ea29dd92SAlexander Motin 
864461e6f23SMaxim Sobolev 	ud = ValidateUdpLength(pip);
865461e6f23SMaxim Sobolev 	if (ud == NULL)
866461e6f23SMaxim Sobolev 		return (PKT_ALIAS_IGNORED);
867461e6f23SMaxim Sobolev 
868ea29dd92SAlexander Motin 	/* Return if proxy-only mode is enabled and not proxyrule found.*/
869effc8e57SLutz Donnerhacke 	proxy_type = ProxyCheck(la, &proxy_server_address, &proxy_server_port,
870effc8e57SLutz Donnerhacke 	    pip->ip_src, pip->ip_dst, ud->uh_dport, pip->ip_p);
871ea29dd92SAlexander Motin 	if (proxy_type == 0 && (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY))
872ffcb611aSDag-Erling Smørgrav 		return (PKT_ALIAS_OK);
8737d96f4efSBrian Somers 
874ea29dd92SAlexander Motin 	/* If this is a transparent proxy, save original destination,
875ea29dd92SAlexander Motin 	 * then alter the destination and adjust checksums */
876ea29dd92SAlexander Motin 	dest_port = ud->uh_dport;
877ea29dd92SAlexander Motin 	dest_address = pip->ip_dst;
8783b160b8bSBrian Somers 
879ea29dd92SAlexander Motin 	if (proxy_type != 0) {
880ea29dd92SAlexander Motin 		int accumulate;
881ea29dd92SAlexander Motin 
882ea29dd92SAlexander Motin 		accumulate = twowords(&pip->ip_dst);
883ea29dd92SAlexander Motin 		accumulate -= twowords(&proxy_server_address);
884ea29dd92SAlexander Motin 
885ea29dd92SAlexander Motin 		ADJUST_CHECKSUM(accumulate, pip->ip_sum);
886ea29dd92SAlexander Motin 
887ea29dd92SAlexander Motin 		if (ud->uh_sum != 0) {
888ea29dd92SAlexander Motin 			accumulate = twowords(&pip->ip_dst);
889ea29dd92SAlexander Motin 			accumulate -= twowords(&proxy_server_address);
890ea29dd92SAlexander Motin 			accumulate += ud->uh_dport;
891ea29dd92SAlexander Motin 			accumulate -= proxy_server_port;
892ea29dd92SAlexander Motin 			ADJUST_CHECKSUM(accumulate, ud->uh_sum);
893ea29dd92SAlexander Motin 		}
894ea29dd92SAlexander Motin 		pip->ip_dst = proxy_server_address;
895ea29dd92SAlexander Motin 		ud->uh_dport = proxy_server_port;
896ea29dd92SAlexander Motin 	}
897*fb2ea26fSMark Johnston 	ret = FindUdpTcpOut(la, pip->ip_src, pip->ip_dst,
8983b160b8bSBrian Somers 	    ud->uh_sport, ud->uh_dport,
899*fb2ea26fSMark Johnston 	    IPPROTO_UDP, create, &lnk);
900*fb2ea26fSMark Johnston 	if (ret != PKT_ALIAS_OK)
901*fb2ea26fSMark Johnston 		return (ret);
902*fb2ea26fSMark Johnston 	{
9033b160b8bSBrian Somers 		u_short alias_port;
9043b160b8bSBrian Somers 		struct in_addr alias_address;
905be4f3cd0SPaolo Pisati 		struct alias_data ad = {
906be4f3cd0SPaolo Pisati 			.lnk = lnk,
907be4f3cd0SPaolo Pisati 			.oaddr = NULL,
908be4f3cd0SPaolo Pisati 			.aaddr = &alias_address,
909be4f3cd0SPaolo Pisati 			.aport = &alias_port,
910be4f3cd0SPaolo Pisati 			.sport = &ud->uh_sport,
911be4f3cd0SPaolo Pisati 			.dport = &ud->uh_dport,
912be4f3cd0SPaolo Pisati 			.maxpktsize = 0
913be4f3cd0SPaolo Pisati 		};
9143b160b8bSBrian Somers 
915ea29dd92SAlexander Motin 		/* Save original destination address, if this is a proxy packet.
916ea29dd92SAlexander Motin 		 * Also modify packet to include destination encoding.  This may
917ea29dd92SAlexander Motin 		 * change the size of IP header. */
918ea29dd92SAlexander Motin 		if (proxy_type != 0) {
919ea29dd92SAlexander Motin 			SetProxyPort(lnk, dest_port);
920ea29dd92SAlexander Motin 			SetProxyAddress(lnk, dest_address);
921ea29dd92SAlexander Motin 			ProxyModify(la, lnk, pip, maxpacketsize, proxy_type);
922ea29dd92SAlexander Motin 			ud = (struct udphdr *)ip_next(pip);
923ea29dd92SAlexander Motin 		}
924ea29dd92SAlexander Motin 
925ed01a582SDag-Erling Smørgrav 		alias_address = GetAliasAddress(lnk);
926ed01a582SDag-Erling Smørgrav 		alias_port = GetAliasPort(lnk);
9273b160b8bSBrian Somers 
928be4f3cd0SPaolo Pisati 		/* Walk out chain. */
9296454d0c8SJohn Baldwin 		find_handler(OUT, UDP, la, pip, &ad);
930fb9cd36dSAtsushi Murai 
9313b160b8bSBrian Somers 		/* If UDP checksum is not zero, adjust since source port is */
9323b160b8bSBrian Somers 		/* being aliased and source address is being altered	*/
933f0f93429SDag-Erling Smørgrav 		if (ud->uh_sum != 0) {
9343b160b8bSBrian Somers 			int accumulate;
9353b160b8bSBrian Somers 
9363b160b8bSBrian Somers 			accumulate = ud->uh_sport;
9373b160b8bSBrian Somers 			accumulate -= alias_port;
9382871c501SDag-Erling Smørgrav 			accumulate += twowords(&pip->ip_src);
9392871c501SDag-Erling Smørgrav 			accumulate -= twowords(&alias_address);
94071593f95SBrian Somers 			ADJUST_CHECKSUM(accumulate, ud->uh_sum);
9413b160b8bSBrian Somers 		}
942fb9cd36dSAtsushi Murai 		/* Put alias port in UDP header */
9433b160b8bSBrian Somers 		ud->uh_sport = alias_port;
9443b160b8bSBrian Somers 
9453b160b8bSBrian Somers 		/* Change source address */
9463b160b8bSBrian Somers 		DifferentialChecksum(&pip->ip_sum,
9472871c501SDag-Erling Smørgrav 		    &alias_address, &pip->ip_src, 2);
9483b160b8bSBrian Somers 		pip->ip_src = alias_address;
9493b160b8bSBrian Somers 
9503b160b8bSBrian Somers 		return (PKT_ALIAS_OK);
9513b160b8bSBrian Somers 	}
9523b160b8bSBrian Somers }
9533b160b8bSBrian Somers 
9543b160b8bSBrian Somers static int
TcpAliasIn(struct libalias * la,struct ip * pip)9555e289f9eSPoul-Henning Kamp TcpAliasIn(struct libalias *la, struct ip *pip)
9563b160b8bSBrian Somers {
9573b160b8bSBrian Somers 	struct tcphdr *tc;
958ed01a582SDag-Erling Smørgrav 	struct alias_link *lnk;
959be597269SAlex Richardson 	size_t dlen;
960*fb2ea26fSMark Johnston 	int ret;
9613b160b8bSBrian Somers 
962ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK_ASSERT(la);
9636461c83eSEd Maste 
9646461c83eSEd Maste 	dlen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
9656461c83eSEd Maste 	if (dlen < sizeof(struct tcphdr))
9666461c83eSEd Maste 		return (PKT_ALIAS_IGNORED);
9679fa0fd26SDag-Erling Smørgrav 	tc = (struct tcphdr *)ip_next(pip);
9683b160b8bSBrian Somers 
969*fb2ea26fSMark Johnston 	ret = FindUdpTcpIn(la, pip->ip_src, pip->ip_dst,
9703b160b8bSBrian Somers 	    tc->th_sport, tc->th_dport,
971642cd09fSRuslan Ermilov 	    IPPROTO_TCP,
972*fb2ea26fSMark Johnston 	    !(la->packetAliasMode & PKT_ALIAS_PROXY_ONLY),
973*fb2ea26fSMark Johnston 	    &lnk);
974*fb2ea26fSMark Johnston 	if (ret == PKT_ALIAS_OK) {
9753b160b8bSBrian Somers 		struct in_addr alias_address;
9763b160b8bSBrian Somers 		struct in_addr original_address;
9777d96f4efSBrian Somers 		struct in_addr proxy_address;
9783b160b8bSBrian Somers 		u_short alias_port;
9797d96f4efSBrian Somers 		u_short proxy_port;
9806454d0c8SJohn Baldwin 		int accumulate;
9813b160b8bSBrian Somers 
982be4f3cd0SPaolo Pisati 		/*
983be4f3cd0SPaolo Pisati 		 * The init of MANY vars is a bit below, but aliashandlepptpin
984be4f3cd0SPaolo Pisati 		 * seems to need the destination port that came within the
985be4f3cd0SPaolo Pisati 		 * packet and not the original one looks below [*].
986be4f3cd0SPaolo Pisati 		 */
987be4f3cd0SPaolo Pisati 
988be4f3cd0SPaolo Pisati 		struct alias_data ad = {
989be4f3cd0SPaolo Pisati 			.lnk = lnk,
990be4f3cd0SPaolo Pisati 			.oaddr = NULL,
991be4f3cd0SPaolo Pisati 			.aaddr = NULL,
992be4f3cd0SPaolo Pisati 			.aport = NULL,
993be4f3cd0SPaolo Pisati 			.sport = &tc->th_sport,
994be4f3cd0SPaolo Pisati 			.dport = &tc->th_dport,
995be4f3cd0SPaolo Pisati 			.maxpktsize = 0
996be4f3cd0SPaolo Pisati 		};
997be4f3cd0SPaolo Pisati 
998be4f3cd0SPaolo Pisati 		/* Walk out chain. */
9996454d0c8SJohn Baldwin 		find_handler(IN, TCP, la, pip, &ad);
100055a39fc5SRuslan Ermilov 
1001ed01a582SDag-Erling Smørgrav 		alias_address = GetAliasAddress(lnk);
1002ed01a582SDag-Erling Smørgrav 		original_address = GetOriginalAddress(lnk);
1003ed01a582SDag-Erling Smørgrav 		proxy_address = GetProxyAddress(lnk);
10043b160b8bSBrian Somers 		alias_port = tc->th_dport;
1005ed01a582SDag-Erling Smørgrav 		tc->th_dport = GetOriginalPort(lnk);
1006ed01a582SDag-Erling Smørgrav 		proxy_port = GetProxyPort(lnk);
10073b160b8bSBrian Somers 
1008be4f3cd0SPaolo Pisati 		/*
1009be4f3cd0SPaolo Pisati 		 * Look above, if anyone is going to add find_handler AFTER
1010be4f3cd0SPaolo Pisati 		 * this aliashandlepptpin/point, please redo alias_data too.
1011be4f3cd0SPaolo Pisati 		 * Uncommenting the piece here below should be enough.
1012be4f3cd0SPaolo Pisati 		 */
1013be4f3cd0SPaolo Pisati #if 0
1014be4f3cd0SPaolo Pisati 				 struct alias_data ad = {
1015be4f3cd0SPaolo Pisati 					.lnk = lnk,
1016be4f3cd0SPaolo Pisati 					.oaddr = &original_address,
1017be4f3cd0SPaolo Pisati 					.aaddr = &alias_address,
1018be4f3cd0SPaolo Pisati 					.aport = &alias_port,
1019be4f3cd0SPaolo Pisati 					.sport = &ud->uh_sport,
1020be4f3cd0SPaolo Pisati 					.dport = &ud->uh_dport,
1021be4f3cd0SPaolo Pisati 					.maxpktsize = 0
1022be4f3cd0SPaolo Pisati 				};
1023be4f3cd0SPaolo Pisati 
1024be4f3cd0SPaolo Pisati 				/* Walk out chain. */
1025be4f3cd0SPaolo Pisati 				error = find_handler(la, pip, &ad);
1026be4f3cd0SPaolo Pisati 				if (error == EHDNOF)
1027be4f3cd0SPaolo Pisati 					printf("Protocol handler not found\n");
1028be4f3cd0SPaolo Pisati #endif
1029be4f3cd0SPaolo Pisati 
1030effc8e57SLutz Donnerhacke 		/* Adjust TCP checksum since destination port is being
1031effc8e57SLutz Donnerhacke 		 * unaliased and destination port is being altered. */
10323b160b8bSBrian Somers 		accumulate = alias_port;
10333b160b8bSBrian Somers 		accumulate -= tc->th_dport;
10342871c501SDag-Erling Smørgrav 		accumulate += twowords(&alias_address);
10352871c501SDag-Erling Smørgrav 		accumulate -= twowords(&original_address);
10363b160b8bSBrian Somers 
1037effc8e57SLutz Donnerhacke 		/* If this is a proxy, then modify the TCP source port
1038effc8e57SLutz Donnerhacke 		 * and checksum accumulation */
1039f0f93429SDag-Erling Smørgrav 		if (proxy_port != 0) {
10407d96f4efSBrian Somers 			accumulate += tc->th_sport;
10417d96f4efSBrian Somers 			tc->th_sport = proxy_port;
10427d96f4efSBrian Somers 			accumulate -= tc->th_sport;
10432871c501SDag-Erling Smørgrav 			accumulate += twowords(&pip->ip_src);
10442871c501SDag-Erling Smørgrav 			accumulate -= twowords(&proxy_address);
10457d96f4efSBrian Somers 		}
1046483d2f22SRuslan Ermilov 		/* See if ACK number needs to be modified */
1047ed01a582SDag-Erling Smørgrav 		if (GetAckModified(lnk) == 1) {
10483b160b8bSBrian Somers 			int delta;
10493b160b8bSBrian Somers 
10504741f3a1SPaolo Pisati 			tc = (struct tcphdr *)ip_next(pip);
10514741f3a1SPaolo Pisati 			delta = GetDeltaAckIn(tc->th_ack, lnk);
1052f0f93429SDag-Erling Smørgrav 			if (delta != 0) {
10532871c501SDag-Erling Smørgrav 				accumulate += twowords(&tc->th_ack);
10543b160b8bSBrian Somers 				tc->th_ack = htonl(ntohl(tc->th_ack) - delta);
10552871c501SDag-Erling Smørgrav 				accumulate -= twowords(&tc->th_ack);
10563b160b8bSBrian Somers 			}
10573b160b8bSBrian Somers 		}
10583b160b8bSBrian Somers 		ADJUST_CHECKSUM(accumulate, tc->th_sum);
10593b160b8bSBrian Somers 
10603b160b8bSBrian Somers 		/* Restore original IP address */
10612871c501SDag-Erling Smørgrav 		accumulate = twowords(&pip->ip_dst);
1062ab39bc9aSDaniel Eischen 		pip->ip_dst = original_address;
10632871c501SDag-Erling Smørgrav 		accumulate -= twowords(&pip->ip_dst);
10647d96f4efSBrian Somers 
1065effc8e57SLutz Donnerhacke 		/* If this is a transparent proxy packet,
1066effc8e57SLutz Donnerhacke 		 * then modify the source address */
1067f0f93429SDag-Erling Smørgrav 		if (proxy_address.s_addr != 0) {
10682871c501SDag-Erling Smørgrav 			accumulate += twowords(&pip->ip_src);
10697d96f4efSBrian Somers 			pip->ip_src = proxy_address;
10702871c501SDag-Erling Smørgrav 			accumulate -= twowords(&pip->ip_src);
10717d96f4efSBrian Somers 		}
10727d96f4efSBrian Somers 		ADJUST_CHECKSUM(accumulate, pip->ip_sum);
10733b160b8bSBrian Somers 
10743b160b8bSBrian Somers 		/* Monitor TCP connection state */
10754741f3a1SPaolo Pisati 		tc = (struct tcphdr *)ip_next(pip);
10760fc7bdc9SRichard Scheffenegger 		TcpMonitorIn(__tcp_get_flags(tc), lnk);
10773b160b8bSBrian Somers 
10783b160b8bSBrian Somers 		return (PKT_ALIAS_OK);
10793b160b8bSBrian Somers 	}
1080*fb2ea26fSMark Johnston 	return (ret);
10813b160b8bSBrian Somers }
10823b160b8bSBrian Somers 
10833b160b8bSBrian Somers static int
TcpAliasOut(struct libalias * la,struct ip * pip,int maxpacketsize,int create)1084e6bbb691SPoul-Henning Kamp TcpAliasOut(struct libalias *la, struct ip *pip, int maxpacketsize, int create)
10853b160b8bSBrian Somers {
1086*fb2ea26fSMark Johnston 	int proxy_type, ret;
10877d96f4efSBrian Somers 	u_short dest_port;
10887d96f4efSBrian Somers 	u_short proxy_server_port;
1089be597269SAlex Richardson 	size_t dlen;
10907d96f4efSBrian Somers 	struct in_addr dest_address;
10917d96f4efSBrian Somers 	struct in_addr proxy_server_address;
10923b160b8bSBrian Somers 	struct tcphdr *tc;
1093ed01a582SDag-Erling Smørgrav 	struct alias_link *lnk;
10943b160b8bSBrian Somers 
1095ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK_ASSERT(la);
10966461c83eSEd Maste 
10976461c83eSEd Maste 	dlen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
10986461c83eSEd Maste 	if (dlen < sizeof(struct tcphdr))
10996461c83eSEd Maste 		return (PKT_ALIAS_IGNORED);
11009fa0fd26SDag-Erling Smørgrav 	tc = (struct tcphdr *)ip_next(pip);
11013b160b8bSBrian Somers 
1102dca9c930SPoul-Henning Kamp 	if (create)
11034741f3a1SPaolo Pisati 		proxy_type = ProxyCheck(la, &proxy_server_address,
11044741f3a1SPaolo Pisati 		    &proxy_server_port, pip->ip_src, pip->ip_dst,
11054741f3a1SPaolo Pisati 		    tc->th_dport, pip->ip_p);
1106dca9c930SPoul-Henning Kamp 	else
1107dca9c930SPoul-Henning Kamp 		proxy_type = 0;
11087d96f4efSBrian Somers 
11095e289f9eSPoul-Henning Kamp 	if (proxy_type == 0 && (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY))
1110ffcb611aSDag-Erling Smørgrav 		return (PKT_ALIAS_OK);
11117d96f4efSBrian Somers 
11127d96f4efSBrian Somers 	/* If this is a transparent proxy, save original destination,
1113effc8e57SLutz Donnerhacke 	 * then alter the destination and adjust checksums */
11147d96f4efSBrian Somers 	dest_port = tc->th_dport;
11157d96f4efSBrian Somers 	dest_address = pip->ip_dst;
1116f0f93429SDag-Erling Smørgrav 	if (proxy_type != 0) {
11177d96f4efSBrian Somers 		int accumulate;
11187d96f4efSBrian Somers 
11197d96f4efSBrian Somers 		accumulate = tc->th_dport;
11207d96f4efSBrian Somers 		tc->th_dport = proxy_server_port;
11217d96f4efSBrian Somers 		accumulate -= tc->th_dport;
11222871c501SDag-Erling Smørgrav 		accumulate += twowords(&pip->ip_dst);
11232871c501SDag-Erling Smørgrav 		accumulate -= twowords(&proxy_server_address);
11247d96f4efSBrian Somers 		ADJUST_CHECKSUM(accumulate, tc->th_sum);
11257d96f4efSBrian Somers 
11262871c501SDag-Erling Smørgrav 		accumulate = twowords(&pip->ip_dst);
11277d96f4efSBrian Somers 		pip->ip_dst = proxy_server_address;
11282871c501SDag-Erling Smørgrav 		accumulate -= twowords(&pip->ip_dst);
11297d96f4efSBrian Somers 		ADJUST_CHECKSUM(accumulate, pip->ip_sum);
11307d96f4efSBrian Somers 	}
1131*fb2ea26fSMark Johnston 	ret = FindUdpTcpOut(la, pip->ip_src, pip->ip_dst,
11323b160b8bSBrian Somers 	    tc->th_sport, tc->th_dport,
1133*fb2ea26fSMark Johnston 	    IPPROTO_TCP, create, &lnk);
1134*fb2ea26fSMark Johnston 	if (ret != PKT_ALIAS_OK)
1135*fb2ea26fSMark Johnston 		return (ret);
1136*fb2ea26fSMark Johnston 	{
11373b160b8bSBrian Somers 		u_short alias_port;
11387d96f4efSBrian Somers 		struct in_addr alias_address;
11393b160b8bSBrian Somers 		int accumulate;
1140be4f3cd0SPaolo Pisati 		struct alias_data ad = {
1141be4f3cd0SPaolo Pisati 			.lnk = lnk,
1142be4f3cd0SPaolo Pisati 			.oaddr = NULL,
1143be4f3cd0SPaolo Pisati 			.aaddr = &alias_address,
1144be4f3cd0SPaolo Pisati 			.aport = &alias_port,
1145be4f3cd0SPaolo Pisati 			.sport = &tc->th_sport,
1146be4f3cd0SPaolo Pisati 			.dport = &tc->th_dport,
1147be4f3cd0SPaolo Pisati 			.maxpktsize = maxpacketsize
1148be4f3cd0SPaolo Pisati 		};
11493b160b8bSBrian Somers 
11507d96f4efSBrian Somers 		/* Save original destination address, if this is a proxy packet.
1151effc8e57SLutz Donnerhacke 		 * Also modify packet to include destination
1152effc8e57SLutz Donnerhacke 		 * encoding.  This may change the size of IP header. */
1153f0f93429SDag-Erling Smørgrav 		if (proxy_type != 0) {
1154ed01a582SDag-Erling Smørgrav 			SetProxyPort(lnk, dest_port);
1155ed01a582SDag-Erling Smørgrav 			SetProxyAddress(lnk, dest_address);
1156ed01a582SDag-Erling Smørgrav 			ProxyModify(la, lnk, pip, maxpacketsize, proxy_type);
11579fa0fd26SDag-Erling Smørgrav 			tc = (struct tcphdr *)ip_next(pip);
11587d96f4efSBrian Somers 		}
11597d96f4efSBrian Somers 		/* Get alias address and port */
1160ed01a582SDag-Erling Smørgrav 		alias_port = GetAliasPort(lnk);
1161ed01a582SDag-Erling Smørgrav 		alias_address = GetAliasAddress(lnk);
11623b160b8bSBrian Somers 
1163483d2f22SRuslan Ermilov 		/* Monitor TCP connection state */
11644741f3a1SPaolo Pisati 		tc = (struct tcphdr *)ip_next(pip);
11650fc7bdc9SRichard Scheffenegger 		TcpMonitorOut(__tcp_get_flags(tc), lnk);
11663b160b8bSBrian Somers 
1167be4f3cd0SPaolo Pisati 		/* Walk out chain. */
11686454d0c8SJohn Baldwin 		find_handler(OUT, TCP, la, pip, &ad);
11693b160b8bSBrian Somers 
1170effc8e57SLutz Donnerhacke 		/* Adjust TCP checksum since source port is being aliased
1171effc8e57SLutz Donnerhacke 		 * and source address is being altered */
11723b160b8bSBrian Somers 		accumulate = tc->th_sport;
11737d96f4efSBrian Somers 		tc->th_sport = alias_port;
11747d96f4efSBrian Somers 		accumulate -= tc->th_sport;
11752871c501SDag-Erling Smørgrav 		accumulate += twowords(&pip->ip_src);
11762871c501SDag-Erling Smørgrav 		accumulate -= twowords(&alias_address);
11773b160b8bSBrian Somers 
11783b160b8bSBrian Somers 		/* Modify sequence number if necessary */
1179ed01a582SDag-Erling Smørgrav 		if (GetAckModified(lnk) == 1) {
11803b160b8bSBrian Somers 			int delta;
11813b160b8bSBrian Somers 
11824741f3a1SPaolo Pisati 			tc = (struct tcphdr *)ip_next(pip);
11834741f3a1SPaolo Pisati 			delta = GetDeltaSeqOut(tc->th_seq, lnk);
1184f0f93429SDag-Erling Smørgrav 			if (delta != 0) {
11852871c501SDag-Erling Smørgrav 				accumulate += twowords(&tc->th_seq);
11863b160b8bSBrian Somers 				tc->th_seq = htonl(ntohl(tc->th_seq) + delta);
11872871c501SDag-Erling Smørgrav 				accumulate -= twowords(&tc->th_seq);
11883b160b8bSBrian Somers 			}
11893b160b8bSBrian Somers 		}
119071593f95SBrian Somers 		ADJUST_CHECKSUM(accumulate, tc->th_sum);
11913b160b8bSBrian Somers 
11923b160b8bSBrian Somers 		/* Change source address */
11932871c501SDag-Erling Smørgrav 		accumulate = twowords(&pip->ip_src);
11943b160b8bSBrian Somers 		pip->ip_src = alias_address;
11952871c501SDag-Erling Smørgrav 		accumulate -= twowords(&pip->ip_src);
119671593f95SBrian Somers 		ADJUST_CHECKSUM(accumulate, pip->ip_sum);
11973b160b8bSBrian Somers 
11983b160b8bSBrian Somers 		return (PKT_ALIAS_OK);
11993b160b8bSBrian Somers 	}
12003b160b8bSBrian Somers }
12013b160b8bSBrian Somers 
12023b160b8bSBrian Somers /* Fragment Handling
12033b160b8bSBrian Somers 
12043b160b8bSBrian Somers     FragmentIn()
12053b160b8bSBrian Somers     FragmentOut()
12063b160b8bSBrian Somers 
12073b160b8bSBrian Somers The packet aliasing module has a limited ability for handling IP
12083b160b8bSBrian Somers fragments.  If the ICMP, TCP or UDP header is in the first fragment
1209483d2f22SRuslan Ermilov received, then the ID number of the IP packet is saved, and other
12103b160b8bSBrian Somers fragments are identified according to their ID number and IP address
12113b160b8bSBrian Somers they were sent from.  Pointers to unresolved fragments can also be
12123b160b8bSBrian Somers saved and recalled when a header fragment is seen.
12133b160b8bSBrian Somers */
12143b160b8bSBrian Somers 
12153b160b8bSBrian Somers /* Local prototypes */
1216ab0fcfd0SPaolo Pisati static int	FragmentIn(struct libalias *la, struct in_addr ip_src,
1217bc596e56SAlex Richardson 		    struct ip *pip, u_short ip_id, u_short *ip_sum);
1218bc596e56SAlex Richardson static int	FragmentOut(struct libalias *, struct ip *pip,
1219ab0fcfd0SPaolo Pisati 		    u_short *ip_sum);
12203b160b8bSBrian Somers 
12213b160b8bSBrian Somers static int
FragmentIn(struct libalias * la,struct in_addr ip_src,struct ip * pip,u_short ip_id,u_short * ip_sum)1222bc596e56SAlex Richardson FragmentIn(struct libalias *la, struct in_addr ip_src, struct ip *pip,
1223aac54f0aSAlexander Motin     u_short ip_id, u_short *ip_sum)
12243b160b8bSBrian Somers {
1225ed01a582SDag-Erling Smørgrav 	struct alias_link *lnk;
12263b160b8bSBrian Somers 
1227ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK_ASSERT(la);
1228bc596e56SAlex Richardson 	lnk = FindFragmentIn2(la, ip_src, pip->ip_dst, ip_id);
1229ed01a582SDag-Erling Smørgrav 	if (lnk != NULL) {
12303b160b8bSBrian Somers 		struct in_addr original_address;
12313b160b8bSBrian Somers 
1232ed01a582SDag-Erling Smørgrav 		GetFragmentAddr(lnk, &original_address);
1233ab0fcfd0SPaolo Pisati 		DifferentialChecksum(ip_sum,
1234bc596e56SAlex Richardson 		    &original_address, &pip->ip_dst, 2);
1235bc596e56SAlex Richardson 		pip->ip_dst = original_address;
12363b160b8bSBrian Somers 
12373b160b8bSBrian Somers 		return (PKT_ALIAS_OK);
12383b160b8bSBrian Somers 	}
12393b160b8bSBrian Somers 	return (PKT_ALIAS_UNRESOLVED_FRAGMENT);
12403b160b8bSBrian Somers }
12413b160b8bSBrian Somers 
12423b160b8bSBrian Somers static int
FragmentOut(struct libalias * la,struct ip * pip,u_short * ip_sum)1243bc596e56SAlex Richardson FragmentOut(struct libalias *la, struct ip *pip, u_short *ip_sum)
12443b160b8bSBrian Somers {
12453b160b8bSBrian Somers 	struct in_addr alias_address;
12463b160b8bSBrian Somers 
1247ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK_ASSERT(la);
1248bc596e56SAlex Richardson 	alias_address = FindAliasAddress(la, pip->ip_src);
1249ab0fcfd0SPaolo Pisati 	DifferentialChecksum(ip_sum,
1250bc596e56SAlex Richardson 	    &alias_address, &pip->ip_src, 2);
1251bc596e56SAlex Richardson 	pip->ip_src = alias_address;
12523b160b8bSBrian Somers 
12533b160b8bSBrian Somers 	return (PKT_ALIAS_OK);
12543b160b8bSBrian Somers }
12553b160b8bSBrian Somers 
12563b160b8bSBrian Somers /* Outside World Access
12573b160b8bSBrian Somers 
12583efa11bbSBrian Somers 	PacketAliasSaveFragment()
12593efa11bbSBrian Somers 	PacketAliasGetFragment()
12603efa11bbSBrian Somers 	PacketAliasFragmentIn()
12613b160b8bSBrian Somers 	PacketAliasIn()
12623b160b8bSBrian Somers 	PacketAliasOut()
1263642e43b3SArchie Cobbs 	PacketUnaliasOut()
12643b160b8bSBrian Somers 
12653b160b8bSBrian Somers (prototypes in alias.h)
12663b160b8bSBrian Somers */
12673b160b8bSBrian Somers 
12683b160b8bSBrian Somers int
LibAliasSaveFragment(struct libalias * la,void * ptr)1269bc596e56SAlex Richardson LibAliasSaveFragment(struct libalias *la, void *ptr)
12703b160b8bSBrian Somers {
12713b160b8bSBrian Somers 	int iresult;
1272ed01a582SDag-Erling Smørgrav 	struct alias_link *lnk;
12733b160b8bSBrian Somers 	struct ip *pip;
12743b160b8bSBrian Somers 
1275ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK(la);
12763b160b8bSBrian Somers 	pip = (struct ip *)ptr;
1277ed01a582SDag-Erling Smørgrav 	lnk = AddFragmentPtrLink(la, pip->ip_src, pip->ip_id);
12783b160b8bSBrian Somers 	iresult = PKT_ALIAS_ERROR;
1279ed01a582SDag-Erling Smørgrav 	if (lnk != NULL) {
1280ed01a582SDag-Erling Smørgrav 		SetFragmentPtr(lnk, ptr);
12813b160b8bSBrian Somers 		iresult = PKT_ALIAS_OK;
12823b160b8bSBrian Somers 	}
1283ccd57eeaSPaolo Pisati 	LIBALIAS_UNLOCK(la);
12843b160b8bSBrian Somers 	return (iresult);
12853b160b8bSBrian Somers }
12863b160b8bSBrian Somers 
1287bc596e56SAlex Richardson void *
LibAliasGetFragment(struct libalias * la,void * ptr)1288bc596e56SAlex Richardson LibAliasGetFragment(struct libalias *la, void *ptr)
12893b160b8bSBrian Somers {
1290ed01a582SDag-Erling Smørgrav 	struct alias_link *lnk;
1291bc596e56SAlex Richardson 	void *fptr;
12923b160b8bSBrian Somers 	struct ip *pip;
12933b160b8bSBrian Somers 
1294ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK(la);
12953b160b8bSBrian Somers 	pip = (struct ip *)ptr;
1296ed01a582SDag-Erling Smørgrav 	lnk = FindFragmentPtr(la, pip->ip_src, pip->ip_id);
1297ed01a582SDag-Erling Smørgrav 	if (lnk != NULL) {
1298ed01a582SDag-Erling Smørgrav 		GetFragmentPtr(lnk, &fptr);
1299ed01a582SDag-Erling Smørgrav 		SetFragmentPtr(lnk, NULL);
1300ed01a582SDag-Erling Smørgrav 		SetExpire(lnk, 0);	/* Deletes link */
1301ccd57eeaSPaolo Pisati 	} else
1302ccd57eeaSPaolo Pisati 		fptr = NULL;
13033b160b8bSBrian Somers 
1304ccd57eeaSPaolo Pisati 	LIBALIAS_UNLOCK(la);
13053b160b8bSBrian Somers 	return (fptr);
13063b160b8bSBrian Somers }
13073b160b8bSBrian Somers 
13083b160b8bSBrian Somers void
LibAliasFragmentIn(struct libalias * la,void * ptr,void * ptr_fragment)1309effc8e57SLutz Donnerhacke LibAliasFragmentIn(struct libalias *la,
1310effc8e57SLutz Donnerhacke     void *ptr,	/* Points to correctly de-aliased header fragment */
1311effc8e57SLutz Donnerhacke     void *ptr_fragment	/* fragment which must be de-aliased   */
13123b160b8bSBrian Somers )
13133b160b8bSBrian Somers {
13143b160b8bSBrian Somers 	struct ip *pip;
13153b160b8bSBrian Somers 	struct ip *fpip;
13163b160b8bSBrian Somers 
1317ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK(la);
1318ed01a582SDag-Erling Smørgrav 	(void)la;
13193b160b8bSBrian Somers 	pip = (struct ip *)ptr;
13203b160b8bSBrian Somers 	fpip = (struct ip *)ptr_fragment;
13213b160b8bSBrian Somers 
13223b160b8bSBrian Somers 	DifferentialChecksum(&fpip->ip_sum,
13232871c501SDag-Erling Smørgrav 	    &pip->ip_dst, &fpip->ip_dst, 2);
13243b160b8bSBrian Somers 	fpip->ip_dst = pip->ip_dst;
1325ccd57eeaSPaolo Pisati 	LIBALIAS_UNLOCK(la);
13263b160b8bSBrian Somers }
13273b160b8bSBrian Somers 
1328ccd57eeaSPaolo Pisati /* Local prototypes */
1329ccd57eeaSPaolo Pisati static int
1330bc596e56SAlex Richardson LibAliasOutLocked(struct libalias *la, struct ip *pip,
1331ccd57eeaSPaolo Pisati     int maxpacketsize, int create);
1332ccd57eeaSPaolo Pisati static int
1333bc596e56SAlex Richardson LibAliasInLocked(struct libalias *la, struct ip *pip,
1334ccd57eeaSPaolo Pisati     int maxpacketsize);
13353b160b8bSBrian Somers 
13363b160b8bSBrian Somers int
LibAliasIn(struct libalias * la,void * ptr,int maxpacketsize)1337bc596e56SAlex Richardson LibAliasIn(struct libalias *la, void *ptr, int maxpacketsize)
13383b160b8bSBrian Somers {
1339ccd57eeaSPaolo Pisati 	int res;
1340ccd57eeaSPaolo Pisati 
1341ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK(la);
1342bc596e56SAlex Richardson 	res = LibAliasInLocked(la, (struct ip *)ptr, maxpacketsize);
1343ccd57eeaSPaolo Pisati 	LIBALIAS_UNLOCK(la);
1344ccd57eeaSPaolo Pisati 	return (res);
1345ccd57eeaSPaolo Pisati }
1346ccd57eeaSPaolo Pisati 
1347ccd57eeaSPaolo Pisati static int
LibAliasInLocked(struct libalias * la,struct ip * pip,int maxpacketsize)1348bc596e56SAlex Richardson LibAliasInLocked(struct libalias *la, struct ip *pip, int maxpacketsize)
1349ccd57eeaSPaolo Pisati {
13503b160b8bSBrian Somers 	struct in_addr alias_addr;
13513b160b8bSBrian Somers 	int iresult;
13523b160b8bSBrian Somers 
13535e289f9eSPoul-Henning Kamp 	if (la->packetAliasMode & PKT_ALIAS_REVERSE) {
13545e289f9eSPoul-Henning Kamp 		la->packetAliasMode &= ~PKT_ALIAS_REVERSE;
1355bc596e56SAlex Richardson 		iresult = LibAliasOutLocked(la, pip, maxpacketsize, 1);
13565e289f9eSPoul-Henning Kamp 		la->packetAliasMode |= PKT_ALIAS_REVERSE;
1357ccd57eeaSPaolo Pisati 		goto getout;
13580622eafcSBrian Somers 	}
13595e289f9eSPoul-Henning Kamp 	HouseKeeping(la);
13603b160b8bSBrian Somers 	alias_addr = pip->ip_dst;
13613b160b8bSBrian Somers 
13628ddc51bcSEivind Eklund 	/* Defense against mangled packets */
13638ddc51bcSEivind Eklund 	if (ntohs(pip->ip_len) > maxpacketsize
1364ccd57eeaSPaolo Pisati 	    || (pip->ip_hl << 2) > maxpacketsize) {
1365ccd57eeaSPaolo Pisati 		iresult = PKT_ALIAS_IGNORED;
1366ccd57eeaSPaolo Pisati 		goto getout;
1367ccd57eeaSPaolo Pisati 	}
13688ddc51bcSEivind Eklund 
1369461e6f23SMaxim Sobolev 	if (FRAG_NO_HDR(pip)) {
1370461e6f23SMaxim Sobolev 		iresult = FragmentIn(la, pip->ip_src, pip, pip->ip_id,
1371461e6f23SMaxim Sobolev 		    &pip->ip_sum);
1372461e6f23SMaxim Sobolev 		goto getout;
1373461e6f23SMaxim Sobolev 	}
1374461e6f23SMaxim Sobolev 
13753b160b8bSBrian Somers 	iresult = PKT_ALIAS_IGNORED;
1376f0f93429SDag-Erling Smørgrav 	switch (pip->ip_p) {
13773b160b8bSBrian Somers 	case IPPROTO_ICMP:
13785e289f9eSPoul-Henning Kamp 		iresult = IcmpAliasIn(la, pip);
13793b160b8bSBrian Somers 		break;
13803b160b8bSBrian Somers 	case IPPROTO_UDP:
13815e289f9eSPoul-Henning Kamp 		iresult = UdpAliasIn(la, pip);
13823b160b8bSBrian Somers 		break;
13833b160b8bSBrian Somers 	case IPPROTO_TCP:
13845e289f9eSPoul-Henning Kamp 		iresult = TcpAliasIn(la, pip);
13853b160b8bSBrian Somers 		break;
138637ce2656SPaolo Pisati #ifdef _KERNEL
138737ce2656SPaolo Pisati 	case IPPROTO_SCTP:
138837ce2656SPaolo Pisati 		iresult = SctpAlias(la, pip, SN_TO_LOCAL);
138937ce2656SPaolo Pisati 		break;
139037ce2656SPaolo Pisati #endif
1391be4f3cd0SPaolo Pisati 	case IPPROTO_GRE: {
1392be4f3cd0SPaolo Pisati 		int error;
1393be4f3cd0SPaolo Pisati 		struct alias_data ad = {
1394be4f3cd0SPaolo Pisati 			.lnk = NULL,
1395be4f3cd0SPaolo Pisati 			.oaddr = NULL,
1396be4f3cd0SPaolo Pisati 			.aaddr = NULL,
1397be4f3cd0SPaolo Pisati 			.aport = NULL,
1398be4f3cd0SPaolo Pisati 			.sport = NULL,
1399be4f3cd0SPaolo Pisati 			.dport = NULL,
1400be4f3cd0SPaolo Pisati 			.maxpktsize = 0
1401be4f3cd0SPaolo Pisati 		};
1402be4f3cd0SPaolo Pisati 
1403be4f3cd0SPaolo Pisati 		/* Walk out chain. */
1404be4f3cd0SPaolo Pisati 		error = find_handler(IN, IP, la, pip, &ad);
1405be4f3cd0SPaolo Pisati 		if (error == 0)
140603453c5eSRuslan Ermilov 			iresult = PKT_ALIAS_OK;
140703453c5eSRuslan Ermilov 		else
1408ab0fcfd0SPaolo Pisati 			iresult = ProtoAliasIn(la, pip->ip_src,
1409bc596e56SAlex Richardson 			    pip, pip->ip_p, &pip->ip_sum);
141055a39fc5SRuslan Ermilov 		break;
1411effc8e57SLutz Donnerhacke 	}
141280607605SRuslan Ermilov 	default:
1413bc596e56SAlex Richardson 		iresult = ProtoAliasIn(la, pip->ip_src, pip,
1414ab0fcfd0SPaolo Pisati 		    pip->ip_p, &pip->ip_sum);
14157d96f4efSBrian Somers 		break;
14163b160b8bSBrian Somers 	}
14173b160b8bSBrian Somers 
1418461e6f23SMaxim Sobolev 	if (MF_ISSET(pip)) {
1419ed01a582SDag-Erling Smørgrav 		struct alias_link *lnk;
14203b160b8bSBrian Somers 
1421ed01a582SDag-Erling Smørgrav 		lnk = FindFragmentIn1(la, pip->ip_src, alias_addr, pip->ip_id);
1422ed01a582SDag-Erling Smørgrav 		if (lnk != NULL) {
14233b160b8bSBrian Somers 			iresult = PKT_ALIAS_FOUND_HEADER_FRAGMENT;
1424ed01a582SDag-Erling Smørgrav 			SetFragmentAddr(lnk, pip->ip_dst);
1425f0f93429SDag-Erling Smørgrav 		} else {
14263b160b8bSBrian Somers 			iresult = PKT_ALIAS_ERROR;
14273b160b8bSBrian Somers 		}
14283b160b8bSBrian Somers 	}
14293b160b8bSBrian Somers 
1430ccd57eeaSPaolo Pisati getout:
14313b160b8bSBrian Somers 	return (iresult);
14323b160b8bSBrian Somers }
14333b160b8bSBrian Somers 
14343b160b8bSBrian Somers /* Unregistered address ranges */
14353b160b8bSBrian Somers 
14363b160b8bSBrian Somers /* 10.0.0.0   ->   10.255.255.255 */
14373b160b8bSBrian Somers #define UNREG_ADDR_A_LOWER 0x0a000000
14383b160b8bSBrian Somers #define UNREG_ADDR_A_UPPER 0x0affffff
14393b160b8bSBrian Somers 
14403b160b8bSBrian Somers /* 172.16.0.0  ->  172.31.255.255 */
14413b160b8bSBrian Somers #define UNREG_ADDR_B_LOWER 0xac100000
14423b160b8bSBrian Somers #define UNREG_ADDR_B_UPPER 0xac1fffff
14433b160b8bSBrian Somers 
14443b160b8bSBrian Somers /* 192.168.0.0 -> 192.168.255.255 */
14453b160b8bSBrian Somers #define UNREG_ADDR_C_LOWER 0xc0a80000
14463b160b8bSBrian Somers #define UNREG_ADDR_C_UPPER 0xc0a8ffff
14473b160b8bSBrian Somers 
144875b89337SAlexander V. Chernikov /* 100.64.0.0  -> 100.127.255.255 (RFC 6598 - Carrier Grade NAT) */
144975b89337SAlexander V. Chernikov #define UNREG_ADDR_CGN_LOWER 0x64400000
145075b89337SAlexander V. Chernikov #define UNREG_ADDR_CGN_UPPER 0x647fffff
145175b89337SAlexander V. Chernikov 
14523b160b8bSBrian Somers int
LibAliasOut(struct libalias * la,void * ptr,int maxpacketsize)1453bc596e56SAlex Richardson LibAliasOut(struct libalias *la, void *ptr, int maxpacketsize)
14543b160b8bSBrian Somers {
1455ccd57eeaSPaolo Pisati 	int res;
1456ccd57eeaSPaolo Pisati 
1457ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK(la);
1458bc596e56SAlex Richardson 	res = LibAliasOutLocked(la, (struct ip *)ptr, maxpacketsize, 1);
1459ccd57eeaSPaolo Pisati 	LIBALIAS_UNLOCK(la);
1460ccd57eeaSPaolo Pisati 	return (res);
1461e6bbb691SPoul-Henning Kamp }
1462e6bbb691SPoul-Henning Kamp 
1463e6bbb691SPoul-Henning Kamp int
LibAliasOutTry(struct libalias * la,void * ptr,int maxpacketsize,int create)1464bc596e56SAlex Richardson LibAliasOutTry(struct libalias *la, void *ptr, int maxpacketsize, int create)
1465ccd57eeaSPaolo Pisati {
1466ccd57eeaSPaolo Pisati 	int res;
1467ccd57eeaSPaolo Pisati 
1468ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK(la);
1469bc596e56SAlex Richardson 	res = LibAliasOutLocked(la, (struct ip *)ptr, maxpacketsize, create);
1470ccd57eeaSPaolo Pisati 	LIBALIAS_UNLOCK(la);
1471ccd57eeaSPaolo Pisati 	return (res);
1472ccd57eeaSPaolo Pisati }
1473ccd57eeaSPaolo Pisati 
1474ccd57eeaSPaolo Pisati static int
LibAliasOutLocked(struct libalias * la,struct ip * pip,int maxpacketsize,int create)1475effc8e57SLutz Donnerhacke LibAliasOutLocked(struct libalias *la,
1476effc8e57SLutz Donnerhacke     struct ip *pip,	/* valid IP packet */
1477effc8e57SLutz Donnerhacke     int maxpacketsize,	/* How much the packet data may grow (FTP and IRC inline changes) */
1478e6bbb691SPoul-Henning Kamp     int create		/* Create new entries ? */
1479e6bbb691SPoul-Henning Kamp )
1480e6bbb691SPoul-Henning Kamp {
14813b160b8bSBrian Somers 	int iresult;
14823b160b8bSBrian Somers 	struct in_addr addr_save;
14833b160b8bSBrian Somers 
14845e289f9eSPoul-Henning Kamp 	if (la->packetAliasMode & PKT_ALIAS_REVERSE) {
14855e289f9eSPoul-Henning Kamp 		la->packetAliasMode &= ~PKT_ALIAS_REVERSE;
1486bc596e56SAlex Richardson 		iresult = LibAliasInLocked(la, pip, maxpacketsize);
14875e289f9eSPoul-Henning Kamp 		la->packetAliasMode |= PKT_ALIAS_REVERSE;
1488ccd57eeaSPaolo Pisati 		goto getout;
14890622eafcSBrian Somers 	}
14905e289f9eSPoul-Henning Kamp 	HouseKeeping(la);
14913b160b8bSBrian Somers 
14928ddc51bcSEivind Eklund 	/* Defense against mangled packets */
14938ddc51bcSEivind Eklund 	if (ntohs(pip->ip_len) > maxpacketsize
1494ccd57eeaSPaolo Pisati 	    || (pip->ip_hl << 2) > maxpacketsize) {
1495ccd57eeaSPaolo Pisati 		iresult = PKT_ALIAS_IGNORED;
1496ccd57eeaSPaolo Pisati 		goto getout;
1497ccd57eeaSPaolo Pisati 	}
14988ddc51bcSEivind Eklund 
14995e289f9eSPoul-Henning Kamp 	addr_save = GetDefaultAliasAddress(la);
150075b89337SAlexander V. Chernikov 	if (la->packetAliasMode & PKT_ALIAS_UNREGISTERED_ONLY ||
150175b89337SAlexander V. Chernikov 	    la->packetAliasMode & PKT_ALIAS_UNREGISTERED_CGN) {
1502483d2f22SRuslan Ermilov 		u_long addr;
15033b160b8bSBrian Somers 		int iclass;
15043b160b8bSBrian Somers 
15053b160b8bSBrian Somers 		iclass = 0;
15063b160b8bSBrian Somers 		addr = ntohl(pip->ip_src.s_addr);
15073b160b8bSBrian Somers 		if (addr >= UNREG_ADDR_C_LOWER && addr <= UNREG_ADDR_C_UPPER)
15083b160b8bSBrian Somers 			iclass = 3;
15093b160b8bSBrian Somers 		else if (addr >= UNREG_ADDR_B_LOWER && addr <= UNREG_ADDR_B_UPPER)
15103b160b8bSBrian Somers 			iclass = 2;
15113b160b8bSBrian Somers 		else if (addr >= UNREG_ADDR_A_LOWER && addr <= UNREG_ADDR_A_UPPER)
15123b160b8bSBrian Somers 			iclass = 1;
151375b89337SAlexander V. Chernikov 		else if (addr >= UNREG_ADDR_CGN_LOWER && addr <= UNREG_ADDR_CGN_UPPER &&
151475b89337SAlexander V. Chernikov 		    la->packetAliasMode & PKT_ALIAS_UNREGISTERED_CGN)
151575b89337SAlexander V. Chernikov 			iclass = 4;
15163b160b8bSBrian Somers 
1517f0f93429SDag-Erling Smørgrav 		if (iclass == 0) {
15185e289f9eSPoul-Henning Kamp 			SetDefaultAliasAddress(la, pip->ip_src);
15193b160b8bSBrian Somers 		}
1520f0f93429SDag-Erling Smørgrav 	} else if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY) {
15215e289f9eSPoul-Henning Kamp 		SetDefaultAliasAddress(la, pip->ip_src);
1522ada24e69SRuslan Ermilov 	}
1523461e6f23SMaxim Sobolev 
1524461e6f23SMaxim Sobolev 	if (FRAG_NO_HDR(pip)) {
1525461e6f23SMaxim Sobolev 		iresult = FragmentOut(la, pip, &pip->ip_sum);
1526461e6f23SMaxim Sobolev 		goto getout_restore;
1527461e6f23SMaxim Sobolev 	}
1528461e6f23SMaxim Sobolev 
15293b160b8bSBrian Somers 	iresult = PKT_ALIAS_IGNORED;
1530f0f93429SDag-Erling Smørgrav 	switch (pip->ip_p) {
15313b160b8bSBrian Somers 	case IPPROTO_ICMP:
1532e6bbb691SPoul-Henning Kamp 		iresult = IcmpAliasOut(la, pip, create);
15333b160b8bSBrian Somers 		break;
15343b160b8bSBrian Somers 	case IPPROTO_UDP:
1535ea29dd92SAlexander Motin 		iresult = UdpAliasOut(la, pip, maxpacketsize, create);
15363b160b8bSBrian Somers 		break;
15373b160b8bSBrian Somers 	case IPPROTO_TCP:
1538e6bbb691SPoul-Henning Kamp 		iresult = TcpAliasOut(la, pip, maxpacketsize, create);
15393b160b8bSBrian Somers 		break;
154037ce2656SPaolo Pisati #ifdef _KERNEL
154137ce2656SPaolo Pisati 	case IPPROTO_SCTP:
154237ce2656SPaolo Pisati 		iresult = SctpAlias(la, pip, SN_TO_GLOBAL);
154337ce2656SPaolo Pisati 		break;
154437ce2656SPaolo Pisati #endif
1545be4f3cd0SPaolo Pisati 	case IPPROTO_GRE: {
1546be4f3cd0SPaolo Pisati 		int error;
1547be4f3cd0SPaolo Pisati 		struct alias_data ad = {
1548be4f3cd0SPaolo Pisati 			.lnk = NULL,
1549be4f3cd0SPaolo Pisati 			.oaddr = NULL,
1550be4f3cd0SPaolo Pisati 			.aaddr = NULL,
1551be4f3cd0SPaolo Pisati 			.aport = NULL,
1552be4f3cd0SPaolo Pisati 			.sport = NULL,
1553be4f3cd0SPaolo Pisati 			.dport = NULL,
1554be4f3cd0SPaolo Pisati 			.maxpktsize = 0
1555be4f3cd0SPaolo Pisati 		};
1556be4f3cd0SPaolo Pisati 		/* Walk out chain. */
1557be4f3cd0SPaolo Pisati 		error = find_handler(OUT, IP, la, pip, &ad);
1558be4f3cd0SPaolo Pisati 		if (error == 0)
155903453c5eSRuslan Ermilov 			iresult = PKT_ALIAS_OK;
156003453c5eSRuslan Ermilov 		else
1561bc596e56SAlex Richardson 			iresult = ProtoAliasOut(la, pip,
1562ab0fcfd0SPaolo Pisati 			    pip->ip_dst, pip->ip_p, &pip->ip_sum, create);
156303453c5eSRuslan Ermilov 		break;
1564effc8e57SLutz Donnerhacke 		}
156580607605SRuslan Ermilov 	default:
1566bc596e56SAlex Richardson 		iresult = ProtoAliasOut(la, pip,
1567ab0fcfd0SPaolo Pisati 		    pip->ip_dst, pip->ip_p, &pip->ip_sum, create);
15687d96f4efSBrian Somers 		break;
15693b160b8bSBrian Somers 	}
15703b160b8bSBrian Somers 
1571461e6f23SMaxim Sobolev getout_restore:
15725e289f9eSPoul-Henning Kamp 	SetDefaultAliasAddress(la, addr_save);
1573ccd57eeaSPaolo Pisati getout:
15743b160b8bSBrian Somers 	return (iresult);
15753b160b8bSBrian Somers }
1576642e43b3SArchie Cobbs 
1577642e43b3SArchie Cobbs int
LibAliasUnaliasOut(struct libalias * la,void * ptr,int maxpacketsize)1578effc8e57SLutz Donnerhacke LibAliasUnaliasOut(struct libalias *la,
1579effc8e57SLutz Donnerhacke     void *ptr,		/* valid IP packet */
1580642e43b3SArchie Cobbs     int maxpacketsize	/* for error checking */
1581642e43b3SArchie Cobbs )
1582642e43b3SArchie Cobbs {
1583642e43b3SArchie Cobbs 	struct ip *pip;
1584642e43b3SArchie Cobbs 	struct icmp *ic;
1585642e43b3SArchie Cobbs 	struct udphdr *ud;
1586642e43b3SArchie Cobbs 	struct tcphdr *tc;
1587ed01a582SDag-Erling Smørgrav 	struct alias_link *lnk;
1588642e43b3SArchie Cobbs 	int iresult = PKT_ALIAS_IGNORED;
1589642e43b3SArchie Cobbs 
1590ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK(la);
1591642e43b3SArchie Cobbs 	pip = (struct ip *)ptr;
1592642e43b3SArchie Cobbs 
1593642e43b3SArchie Cobbs 	/* Defense against mangled packets */
1594642e43b3SArchie Cobbs 	if (ntohs(pip->ip_len) > maxpacketsize
1595642e43b3SArchie Cobbs 	    || (pip->ip_hl << 2) > maxpacketsize)
1596ccd57eeaSPaolo Pisati 		goto getout;
1597642e43b3SArchie Cobbs 
15989fa0fd26SDag-Erling Smørgrav 	ud = (struct udphdr *)ip_next(pip);
15999fa0fd26SDag-Erling Smørgrav 	tc = (struct tcphdr *)ip_next(pip);
16009fa0fd26SDag-Erling Smørgrav 	ic = (struct icmp *)ip_next(pip);
1601642e43b3SArchie Cobbs 
1602642e43b3SArchie Cobbs 	/* Find a link */
1603*fb2ea26fSMark Johnston 	if (pip->ip_p == IPPROTO_UDP) {
1604*fb2ea26fSMark Johnston 		iresult = FindUdpTcpIn(la, pip->ip_dst, pip->ip_src,
1605642e43b3SArchie Cobbs 		    ud->uh_dport, ud->uh_sport,
1606*fb2ea26fSMark Johnston 		    IPPROTO_UDP, 0, &lnk);
1607*fb2ea26fSMark Johnston 		if (iresult != PKT_ALIAS_OK)
1608*fb2ea26fSMark Johnston 			goto getout;
1609*fb2ea26fSMark Johnston 	} else if (pip->ip_p == IPPROTO_TCP) {
1610*fb2ea26fSMark Johnston 		iresult = FindUdpTcpIn(la, pip->ip_dst, pip->ip_src,
1611642e43b3SArchie Cobbs 		    tc->th_dport, tc->th_sport,
1612*fb2ea26fSMark Johnston 		    IPPROTO_TCP, 0, &lnk);
1613*fb2ea26fSMark Johnston 		if (iresult != PKT_ALIAS_OK)
1614*fb2ea26fSMark Johnston 			goto getout;
1615*fb2ea26fSMark Johnston 	} else if (pip->ip_p == IPPROTO_ICMP) {
1616*fb2ea26fSMark Johnston 		iresult = FindIcmpIn(la, pip->ip_dst, pip->ip_src,
1617*fb2ea26fSMark Johnston 		    ic->icmp_id, 0, &lnk);
1618*fb2ea26fSMark Johnston 		if (iresult != PKT_ALIAS_OK)
1619*fb2ea26fSMark Johnston 			goto getout;
1620*fb2ea26fSMark Johnston 	} else
1621ed01a582SDag-Erling Smørgrav 		lnk = NULL;
1622642e43b3SArchie Cobbs 
1623642e43b3SArchie Cobbs 	/* Change it from an aliased packet to an unaliased packet */
1624ed01a582SDag-Erling Smørgrav 	if (lnk != NULL) {
1625f0f93429SDag-Erling Smørgrav 		if (pip->ip_p == IPPROTO_UDP || pip->ip_p == IPPROTO_TCP) {
1626642e43b3SArchie Cobbs 			int accumulate;
1627642e43b3SArchie Cobbs 			struct in_addr original_address;
1628642e43b3SArchie Cobbs 			u_short original_port;
1629642e43b3SArchie Cobbs 
1630ed01a582SDag-Erling Smørgrav 			original_address = GetOriginalAddress(lnk);
1631ed01a582SDag-Erling Smørgrav 			original_port = GetOriginalPort(lnk);
1632642e43b3SArchie Cobbs 
1633642e43b3SArchie Cobbs 			/* Adjust TCP/UDP checksum */
16342871c501SDag-Erling Smørgrav 			accumulate = twowords(&pip->ip_src);
16352871c501SDag-Erling Smørgrav 			accumulate -= twowords(&original_address);
1636642e43b3SArchie Cobbs 
1637642e43b3SArchie Cobbs 			if (pip->ip_p == IPPROTO_UDP) {
1638642e43b3SArchie Cobbs 				accumulate += ud->uh_sport;
1639642e43b3SArchie Cobbs 				accumulate -= original_port;
164071593f95SBrian Somers 				ADJUST_CHECKSUM(accumulate, ud->uh_sum);
1641642e43b3SArchie Cobbs 			} else {
1642642e43b3SArchie Cobbs 				accumulate += tc->th_sport;
1643642e43b3SArchie Cobbs 				accumulate -= original_port;
164471593f95SBrian Somers 				ADJUST_CHECKSUM(accumulate, tc->th_sum);
1645642e43b3SArchie Cobbs 			}
1646642e43b3SArchie Cobbs 
1647642e43b3SArchie Cobbs 			/* Adjust IP checksum */
1648642e43b3SArchie Cobbs 			DifferentialChecksum(&pip->ip_sum,
16492871c501SDag-Erling Smørgrav 			    &original_address, &pip->ip_src, 2);
1650642e43b3SArchie Cobbs 
1651642e43b3SArchie Cobbs 			/* Un-alias source address and port number */
1652642e43b3SArchie Cobbs 			pip->ip_src = original_address;
1653642e43b3SArchie Cobbs 			if (pip->ip_p == IPPROTO_UDP)
1654642e43b3SArchie Cobbs 				ud->uh_sport = original_port;
1655642e43b3SArchie Cobbs 			else
1656642e43b3SArchie Cobbs 				tc->th_sport = original_port;
1657642e43b3SArchie Cobbs 
1658642e43b3SArchie Cobbs 			iresult = PKT_ALIAS_OK;
1659642e43b3SArchie Cobbs 		} else if (pip->ip_p == IPPROTO_ICMP) {
1660642e43b3SArchie Cobbs 			int accumulate;
1661642e43b3SArchie Cobbs 			struct in_addr original_address;
1662642e43b3SArchie Cobbs 			u_short original_id;
1663642e43b3SArchie Cobbs 
1664ed01a582SDag-Erling Smørgrav 			original_address = GetOriginalAddress(lnk);
1665ed01a582SDag-Erling Smørgrav 			original_id = GetOriginalPort(lnk);
1666642e43b3SArchie Cobbs 
1667642e43b3SArchie Cobbs 			/* Adjust ICMP checksum */
16682871c501SDag-Erling Smørgrav 			accumulate = twowords(&pip->ip_src);
16692871c501SDag-Erling Smørgrav 			accumulate -= twowords(&original_address);
1670642e43b3SArchie Cobbs 			accumulate += ic->icmp_id;
1671642e43b3SArchie Cobbs 			accumulate -= original_id;
167271593f95SBrian Somers 			ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
1673642e43b3SArchie Cobbs 
1674642e43b3SArchie Cobbs 			/* Adjust IP checksum */
1675642e43b3SArchie Cobbs 			DifferentialChecksum(&pip->ip_sum,
16762871c501SDag-Erling Smørgrav 			    &original_address, &pip->ip_src, 2);
1677642e43b3SArchie Cobbs 
1678642e43b3SArchie Cobbs 			/* Un-alias source address and port number */
1679642e43b3SArchie Cobbs 			pip->ip_src = original_address;
1680642e43b3SArchie Cobbs 			ic->icmp_id = original_id;
1681642e43b3SArchie Cobbs 
1682642e43b3SArchie Cobbs 			iresult = PKT_ALIAS_OK;
1683642e43b3SArchie Cobbs 		}
1684642e43b3SArchie Cobbs 	}
1685ccd57eeaSPaolo Pisati getout:
1686ccd57eeaSPaolo Pisati 	LIBALIAS_UNLOCK(la);
1687642e43b3SArchie Cobbs 	return (iresult);
1688642e43b3SArchie Cobbs }
1689be4f3cd0SPaolo Pisati 
1690be4f3cd0SPaolo Pisati #ifndef _KERNEL
1691be4f3cd0SPaolo Pisati 
1692be4f3cd0SPaolo Pisati int
LibAliasRefreshModules(void)1693be4f3cd0SPaolo Pisati LibAliasRefreshModules(void)
1694be4f3cd0SPaolo Pisati {
1695be4f3cd0SPaolo Pisati 	char buf[256], conf[] = "/etc/libalias.conf";
1696be4f3cd0SPaolo Pisati 	FILE *fd;
16975910c1c1SPaolo Pisati 	int i, len;
1698be4f3cd0SPaolo Pisati 
1699be4f3cd0SPaolo Pisati 	fd = fopen(conf, "r");
1700be4f3cd0SPaolo Pisati 	if (fd == NULL)
1701be4f3cd0SPaolo Pisati 		err(1, "fopen(%s)", conf);
1702be4f3cd0SPaolo Pisati 
1703be4f3cd0SPaolo Pisati 	LibAliasUnLoadAllModule();
1704be4f3cd0SPaolo Pisati 
1705be4f3cd0SPaolo Pisati 	for (;;) {
1706be4f3cd0SPaolo Pisati 		fgets(buf, 256, fd);
170703bc210eSDmitry Morozovsky 		if (feof(fd))
1708be4f3cd0SPaolo Pisati 			break;
1709be4f3cd0SPaolo Pisati 		len = strlen(buf);
1710be4f3cd0SPaolo Pisati 		if (len > 1) {
17115910c1c1SPaolo Pisati 			for (i = 0; i < len; i++)
17125910c1c1SPaolo Pisati 				if (!isspace(buf[i]))
17135910c1c1SPaolo Pisati 					break;
17145910c1c1SPaolo Pisati 			if (buf[i] == '#')
17155910c1c1SPaolo Pisati 				continue;
1716be4f3cd0SPaolo Pisati 			buf[len - 1] = '\0';
1717be4f3cd0SPaolo Pisati 			LibAliasLoadModule(buf);
1718be4f3cd0SPaolo Pisati 		}
1719be4f3cd0SPaolo Pisati 	}
1720621882f0SChristian Brueffer 	fclose(fd);
1721be4f3cd0SPaolo Pisati 	return (0);
1722be4f3cd0SPaolo Pisati }
1723be4f3cd0SPaolo Pisati 
1724be4f3cd0SPaolo Pisati int
LibAliasLoadModule(char * path)1725be4f3cd0SPaolo Pisati LibAliasLoadModule(char *path)
1726be4f3cd0SPaolo Pisati {
1727be4f3cd0SPaolo Pisati 	struct dll *t;
1728be4f3cd0SPaolo Pisati 	void *handle;
1729be4f3cd0SPaolo Pisati 	struct proto_handler *m;
1730be4f3cd0SPaolo Pisati 	const char *error;
1731be4f3cd0SPaolo Pisati 	moduledata_t *p;
1732be4f3cd0SPaolo Pisati 
1733be4f3cd0SPaolo Pisati 	handle = dlopen (path, RTLD_LAZY);
1734be4f3cd0SPaolo Pisati 	if (!handle) {
17355910c1c1SPaolo Pisati 		fprintf(stderr, "%s\n", dlerror());
1736be4f3cd0SPaolo Pisati 		return (EINVAL);
1737be4f3cd0SPaolo Pisati 	}
1738be4f3cd0SPaolo Pisati 
1739be4f3cd0SPaolo Pisati 	p = dlsym(handle, "alias_mod");
1740be4f3cd0SPaolo Pisati 	if ((error = dlerror()) != NULL)  {
17415910c1c1SPaolo Pisati 		fprintf(stderr, "%s\n", dlerror());
1742be4f3cd0SPaolo Pisati 		return (EINVAL);
1743be4f3cd0SPaolo Pisati 	}
1744be4f3cd0SPaolo Pisati 
1745be4f3cd0SPaolo Pisati 	t = malloc(sizeof(struct dll));
1746be4f3cd0SPaolo Pisati 	if (t == NULL)
1747be4f3cd0SPaolo Pisati 		return (ENOMEM);
1748be4f3cd0SPaolo Pisati 	strncpy(t->name, p->name, DLL_LEN);
1749be4f3cd0SPaolo Pisati 	t->handle = handle;
1750be4f3cd0SPaolo Pisati 	if (attach_dll(t) == EEXIST) {
1751be4f3cd0SPaolo Pisati 		free(t);
17525910c1c1SPaolo Pisati 		fprintf(stderr, "dll conflict\n");
1753be4f3cd0SPaolo Pisati 		return (EEXIST);
1754be4f3cd0SPaolo Pisati 	}
1755be4f3cd0SPaolo Pisati 
1756be4f3cd0SPaolo Pisati 	m = dlsym(t->handle, "handlers");
1757be4f3cd0SPaolo Pisati 	if ((error = dlerror()) != NULL)  {
17585910c1c1SPaolo Pisati 		fprintf(stderr, "%s\n", error);
1759be4f3cd0SPaolo Pisati 		return (EINVAL);
1760be4f3cd0SPaolo Pisati 	}
1761be4f3cd0SPaolo Pisati 
1762be4f3cd0SPaolo Pisati 	LibAliasAttachHandlers(m);
1763be4f3cd0SPaolo Pisati 	return (0);
1764be4f3cd0SPaolo Pisati }
1765be4f3cd0SPaolo Pisati 
1766be4f3cd0SPaolo Pisati int
LibAliasUnLoadAllModule(void)1767be4f3cd0SPaolo Pisati LibAliasUnLoadAllModule(void)
1768be4f3cd0SPaolo Pisati {
1769be4f3cd0SPaolo Pisati 	struct dll *t;
1770be4f3cd0SPaolo Pisati 	struct proto_handler *p;
1771be4f3cd0SPaolo Pisati 
1772be4f3cd0SPaolo Pisati 	/* Unload all modules then reload everything. */
1773be4f3cd0SPaolo Pisati 	while ((p = first_handler()) != NULL) {
1774ec5df3a7SGleb Smirnoff 		LibAliasDetachHandlers(p);
1775be4f3cd0SPaolo Pisati 	}
1776be4f3cd0SPaolo Pisati 	while ((t = walk_dll_chain()) != NULL) {
1777be4f3cd0SPaolo Pisati 		dlclose(t->handle);
1778be4f3cd0SPaolo Pisati 		free(t);
1779be4f3cd0SPaolo Pisati 	}
1780be4f3cd0SPaolo Pisati 	return (1);
1781be4f3cd0SPaolo Pisati }
1782be4f3cd0SPaolo Pisati 
1783be4f3cd0SPaolo Pisati #endif
1784e876228eSPaolo Pisati 
1785e876228eSPaolo Pisati #ifdef _KERNEL
1786e876228eSPaolo Pisati /*
1787ccd57eeaSPaolo Pisati  * m_megapullup() - this function is a big hack.
1788ccd57eeaSPaolo Pisati  * Thankfully, it's only used in ng_nat and ipfw+nat.
1789e876228eSPaolo Pisati  *
1790efc66711SAlexander Motin  * It allocates an mbuf with cluster and copies the specified part of the chain
1791efc66711SAlexander Motin  * into cluster, so that it is all contiguous and can be accessed via a plain
1792efc66711SAlexander Motin  * (char *) pointer. This is required, because libalias doesn't know how to
1793efc66711SAlexander Motin  * handle mbuf chains.
1794e876228eSPaolo Pisati  *
1795efc66711SAlexander Motin  * On success, m_megapullup returns an mbuf (possibly with cluster) containing
1796efc66711SAlexander Motin  * the input packet, on failure NULL. The input packet is always consumed.
1797e876228eSPaolo Pisati  */
1798e876228eSPaolo Pisati struct mbuf *
m_megapullup(struct mbuf * m,int len)1799eb548a1aSAndrey V. Elsukov m_megapullup(struct mbuf *m, int len)
1800eb548a1aSAndrey V. Elsukov {
1801e876228eSPaolo Pisati 	struct mbuf *mcl;
1802e876228eSPaolo Pisati 
1803efc66711SAlexander Motin 	if (len > m->m_pkthdr.len)
1804e876228eSPaolo Pisati 		goto bad;
1805e876228eSPaolo Pisati 
18067525c481SGleb Smirnoff 	if (m->m_next == NULL && M_WRITABLE(m))
1807efc66711SAlexander Motin 		return (m);
1808efc66711SAlexander Motin 
1809eb548a1aSAndrey V. Elsukov 	if (len <= MJUMPAGESIZE)
18107525c481SGleb Smirnoff 		mcl = m_get2(len, M_NOWAIT, MT_DATA, M_PKTHDR);
1811eb548a1aSAndrey V. Elsukov 	else if (len <= MJUM9BYTES)
1812eb548a1aSAndrey V. Elsukov 		mcl = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUM9BYTES);
1813eb548a1aSAndrey V. Elsukov 	else if (len <= MJUM16BYTES)
1814eb548a1aSAndrey V. Elsukov 		mcl = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUM16BYTES);
1815eb548a1aSAndrey V. Elsukov 	else
1816eb548a1aSAndrey V. Elsukov 		goto bad;
1817efc66711SAlexander Motin 	if (mcl == NULL)
1818e876228eSPaolo Pisati 		goto bad;
18197525c481SGleb Smirnoff 	m_align(mcl, len);
1820e876228eSPaolo Pisati 	m_move_pkthdr(mcl, m);
1821efc66711SAlexander Motin 	m_copydata(m, 0, len, mtod(mcl, caddr_t));
1822efc66711SAlexander Motin 	mcl->m_len = mcl->m_pkthdr.len = len;
1823e876228eSPaolo Pisati 	m_freem(m);
1824e876228eSPaolo Pisati 
1825e876228eSPaolo Pisati 	return (mcl);
1826e876228eSPaolo Pisati bad:
1827e876228eSPaolo Pisati 	m_freem(m);
1828e876228eSPaolo Pisati 	return (NULL);
1829e876228eSPaolo Pisati }
1830e876228eSPaolo Pisati #endif
1831