xref: /freebsd/sys/netinet/libalias/alias.c (revision 0fc7bdc978366abb4351b0b76b50a5848cc5d982)
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 */
186*0fc7bdc9SRichard Scheffenegger static void	TcpMonitorIn(uint16_t, struct alias_link *);
1873b160b8bSBrian Somers 
188*0fc7bdc9SRichard Scheffenegger static void	TcpMonitorOut(uint16_t, struct alias_link *);
1893b160b8bSBrian Somers 
1903b160b8bSBrian Somers static void
TcpMonitorIn(uint16_t th_flags,struct alias_link * lnk)191*0fc7bdc9SRichard 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)208*0fc7bdc9SRichard 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;
2933b160b8bSBrian Somers 
2942e6b0786SLutz Donnerhacke 	LIBALIAS_LOCK_ASSERT(la);
2959fa0fd26SDag-Erling Smørgrav 	ic = (struct icmp *)ip_next(pip);
2963b160b8bSBrian Somers 
2973b160b8bSBrian Somers 	/* Get source address from ICMP data field and restore original data */
298ed01a582SDag-Erling Smørgrav 	lnk = FindIcmpIn(la, pip->ip_src, pip->ip_dst, ic->icmp_id, 1);
299ed01a582SDag-Erling Smørgrav 	if (lnk != NULL) {
3003b160b8bSBrian Somers 		u_short original_id;
3013b160b8bSBrian Somers 		int accumulate;
3023b160b8bSBrian Somers 
303ed01a582SDag-Erling Smørgrav 		original_id = GetOriginalPort(lnk);
3043b160b8bSBrian Somers 
3053b160b8bSBrian Somers 		/* Adjust ICMP checksum */
3063b160b8bSBrian Somers 		accumulate = ic->icmp_id;
3073b160b8bSBrian Somers 		accumulate -= original_id;
30871593f95SBrian Somers 		ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
3093b160b8bSBrian Somers 
3103b160b8bSBrian Somers 		/* Put original sequence number back in */
3113b160b8bSBrian Somers 		ic->icmp_id = original_id;
3123b160b8bSBrian Somers 
3133b160b8bSBrian Somers 		/* Put original address back into IP header */
3143b160b8bSBrian Somers 		{
3153b160b8bSBrian Somers 			struct in_addr original_address;
3163b160b8bSBrian Somers 
317ed01a582SDag-Erling Smørgrav 			original_address = GetOriginalAddress(lnk);
3183b160b8bSBrian Somers 			DifferentialChecksum(&pip->ip_sum,
3192871c501SDag-Erling Smørgrav 			    &original_address, &pip->ip_dst, 2);
3203b160b8bSBrian Somers 			pip->ip_dst = original_address;
3213b160b8bSBrian Somers 		}
3223b160b8bSBrian Somers 
3233b160b8bSBrian Somers 		return (PKT_ALIAS_OK);
3243b160b8bSBrian Somers 	}
3253b160b8bSBrian Somers 	return (PKT_ALIAS_IGNORED);
3263b160b8bSBrian Somers }
3273b160b8bSBrian Somers 
3283b160b8bSBrian Somers /*
3293b160b8bSBrian Somers     Alias incoming ICMP error messages containing
3303b160b8bSBrian Somers     IP header and first 64 bits of datagram.
3313b160b8bSBrian Somers */
332effc8e57SLutz Donnerhacke static int
IcmpAliasIn2(struct libalias * la,struct ip * pip)333effc8e57SLutz Donnerhacke IcmpAliasIn2(struct libalias *la, struct ip *pip)
334effc8e57SLutz Donnerhacke {
3353b160b8bSBrian Somers 	struct ip *ip;
3363b160b8bSBrian Somers 	struct icmp *ic, *ic2;
3373b160b8bSBrian Somers 	struct udphdr *ud;
3383b160b8bSBrian Somers 	struct tcphdr *tc;
339ed01a582SDag-Erling Smørgrav 	struct alias_link *lnk;
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 
3493b160b8bSBrian Somers 	if (ip->ip_p == IPPROTO_UDP)
350ed01a582SDag-Erling Smørgrav 		lnk = FindUdpTcpIn(la, ip->ip_dst, ip->ip_src,
3513b160b8bSBrian Somers 		    ud->uh_dport, ud->uh_sport,
352642cd09fSRuslan Ermilov 		    IPPROTO_UDP, 0);
3533b160b8bSBrian Somers 	else if (ip->ip_p == IPPROTO_TCP)
354ed01a582SDag-Erling Smørgrav 		lnk = FindUdpTcpIn(la, ip->ip_dst, ip->ip_src,
3553b160b8bSBrian Somers 		    tc->th_dport, tc->th_sport,
356642cd09fSRuslan Ermilov 		    IPPROTO_TCP, 0);
357dfcb634bSBrian Somers 	else if (ip->ip_p == IPPROTO_ICMP) {
3583b160b8bSBrian Somers 		if (ic2->icmp_type == ICMP_ECHO || ic2->icmp_type == ICMP_TSTAMP)
359ed01a582SDag-Erling Smørgrav 			lnk = FindIcmpIn(la, ip->ip_dst, ip->ip_src, ic2->icmp_id, 0);
3603b160b8bSBrian Somers 		else
361ed01a582SDag-Erling Smørgrav 			lnk = NULL;
362dfcb634bSBrian Somers 	} else
363ed01a582SDag-Erling Smørgrav 		lnk = NULL;
3643b160b8bSBrian Somers 
365ed01a582SDag-Erling Smørgrav 	if (lnk != NULL) {
366f0f93429SDag-Erling Smørgrav 		if (ip->ip_p == IPPROTO_UDP || ip->ip_p == IPPROTO_TCP) {
36761a875d7SRuslan Ermilov 			int accumulate, accumulate2;
3683b160b8bSBrian Somers 			struct in_addr original_address;
3693b160b8bSBrian Somers 			u_short original_port;
3703b160b8bSBrian Somers 
371ed01a582SDag-Erling Smørgrav 			original_address = GetOriginalAddress(lnk);
372ed01a582SDag-Erling Smørgrav 			original_port = GetOriginalPort(lnk);
3733b160b8bSBrian Somers 
3743b160b8bSBrian Somers 			/* Adjust ICMP checksum */
3752871c501SDag-Erling Smørgrav 			accumulate = twowords(&ip->ip_src);
3762871c501SDag-Erling Smørgrav 			accumulate -= twowords(&original_address);
3773b160b8bSBrian Somers 			accumulate += ud->uh_sport;
3783b160b8bSBrian Somers 			accumulate -= original_port;
37961a875d7SRuslan Ermilov 			accumulate2 = accumulate;
38061a875d7SRuslan Ermilov 			accumulate2 += ip->ip_sum;
38161a875d7SRuslan Ermilov 			ADJUST_CHECKSUM(accumulate, ip->ip_sum);
38261a875d7SRuslan Ermilov 			accumulate2 -= ip->ip_sum;
38361a875d7SRuslan Ermilov 			ADJUST_CHECKSUM(accumulate2, ic->icmp_cksum);
3843b160b8bSBrian Somers 
3853b160b8bSBrian Somers 			/* Un-alias address in IP header */
3863b160b8bSBrian Somers 			DifferentialChecksum(&pip->ip_sum,
3872871c501SDag-Erling Smørgrav 			    &original_address, &pip->ip_dst, 2);
3883b160b8bSBrian Somers 			pip->ip_dst = original_address;
3893b160b8bSBrian Somers 
390effc8e57SLutz Donnerhacke 			/* Un-alias address and port number of
391effc8e57SLutz Donnerhacke 			 * original IP packet fragment contained
392effc8e57SLutz Donnerhacke 			 * in ICMP data section */
3933b160b8bSBrian Somers 			ip->ip_src = original_address;
3943b160b8bSBrian Somers 			ud->uh_sport = original_port;
395f0f93429SDag-Erling Smørgrav 		} else if (ip->ip_p == IPPROTO_ICMP) {
39661a875d7SRuslan Ermilov 			int accumulate, accumulate2;
3973b160b8bSBrian Somers 			struct in_addr original_address;
3983b160b8bSBrian Somers 			u_short original_id;
3993b160b8bSBrian Somers 
400ed01a582SDag-Erling Smørgrav 			original_address = GetOriginalAddress(lnk);
401ed01a582SDag-Erling Smørgrav 			original_id = GetOriginalPort(lnk);
4023b160b8bSBrian Somers 
4033b160b8bSBrian Somers 			/* Adjust ICMP checksum */
4042871c501SDag-Erling Smørgrav 			accumulate = twowords(&ip->ip_src);
4052871c501SDag-Erling Smørgrav 			accumulate -= twowords(&original_address);
4063b160b8bSBrian Somers 			accumulate += ic2->icmp_id;
4073b160b8bSBrian Somers 			accumulate -= original_id;
40861a875d7SRuslan Ermilov 			accumulate2 = accumulate;
40961a875d7SRuslan Ermilov 			accumulate2 += ip->ip_sum;
41061a875d7SRuslan Ermilov 			ADJUST_CHECKSUM(accumulate, ip->ip_sum);
41161a875d7SRuslan Ermilov 			accumulate2 -= ip->ip_sum;
41261a875d7SRuslan Ermilov 			ADJUST_CHECKSUM(accumulate2, ic->icmp_cksum);
4133b160b8bSBrian Somers 
4143b160b8bSBrian Somers 			/* Un-alias address in IP header */
4153b160b8bSBrian Somers 			DifferentialChecksum(&pip->ip_sum,
4162871c501SDag-Erling Smørgrav 			    &original_address, &pip->ip_dst, 2);
4173b160b8bSBrian Somers 			pip->ip_dst = original_address;
4183b160b8bSBrian Somers 
419effc8e57SLutz Donnerhacke 			/* Un-alias address of original IP packet and
420effc8e57SLutz Donnerhacke 			 * sequence number of embedded ICMP datagram */
4213b160b8bSBrian Somers 			ip->ip_src = original_address;
4223b160b8bSBrian Somers 			ic2->icmp_id = original_id;
4233b160b8bSBrian Somers 		}
4243b160b8bSBrian Somers 		return (PKT_ALIAS_OK);
4253b160b8bSBrian Somers 	}
4263b160b8bSBrian Somers 	return (PKT_ALIAS_IGNORED);
4273b160b8bSBrian Somers }
4283b160b8bSBrian Somers 
4293b160b8bSBrian Somers static int
IcmpAliasIn(struct libalias * la,struct ip * pip)4305e289f9eSPoul-Henning Kamp IcmpAliasIn(struct libalias *la, struct ip *pip)
4313b160b8bSBrian Somers {
4323b160b8bSBrian Somers 	struct icmp *ic;
433be597269SAlex Richardson 	int iresult;
434be597269SAlex Richardson 	size_t dlen;
4353b160b8bSBrian Somers 
436ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK_ASSERT(la);
4376461c83eSEd Maste 
4386461c83eSEd Maste 	dlen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
4396461c83eSEd Maste 	if (dlen < ICMP_MINLEN)
4406461c83eSEd Maste 		return (PKT_ALIAS_IGNORED);
4416461c83eSEd Maste 
4427d96f4efSBrian Somers 	/* Return if proxy-only mode is enabled */
4435e289f9eSPoul-Henning Kamp 	if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
444ffcb611aSDag-Erling Smørgrav 		return (PKT_ALIAS_OK);
4457d96f4efSBrian Somers 
4469fa0fd26SDag-Erling Smørgrav 	ic = (struct icmp *)ip_next(pip);
4473b160b8bSBrian Somers 
4483b160b8bSBrian Somers 	iresult = PKT_ALIAS_IGNORED;
449f0f93429SDag-Erling Smørgrav 	switch (ic->icmp_type) {
4503b160b8bSBrian Somers 	case ICMP_ECHOREPLY:
4513b160b8bSBrian Somers 	case ICMP_TSTAMPREPLY:
452f0f93429SDag-Erling Smørgrav 		if (ic->icmp_code == 0) {
4535e289f9eSPoul-Henning Kamp 			iresult = IcmpAliasIn1(la, pip);
4543b160b8bSBrian Somers 		}
4553b160b8bSBrian Somers 		break;
4563b160b8bSBrian Somers 	case ICMP_UNREACH:
4573b160b8bSBrian Somers 	case ICMP_SOURCEQUENCH:
4583b160b8bSBrian Somers 	case ICMP_TIMXCEED:
4593b160b8bSBrian Somers 	case ICMP_PARAMPROB:
4606461c83eSEd Maste 		if (dlen < ICMP_ADVLENMIN ||
461be597269SAlex Richardson 		    dlen < (size_t)ICMP_ADVLEN(ic))
4626461c83eSEd Maste 			return (PKT_ALIAS_IGNORED);
4635e289f9eSPoul-Henning Kamp 		iresult = IcmpAliasIn2(la, pip);
4643b160b8bSBrian Somers 		break;
4653b160b8bSBrian Somers 	case ICMP_ECHO:
4663b160b8bSBrian Somers 	case ICMP_TSTAMP:
4675e289f9eSPoul-Henning Kamp 		iresult = IcmpAliasIn1(la, pip);
4683b160b8bSBrian Somers 		break;
4693b160b8bSBrian Somers 	}
4703b160b8bSBrian Somers 	return (iresult);
4713b160b8bSBrian Somers }
4723b160b8bSBrian Somers 
4733b160b8bSBrian Somers /*
474305d1069SRuslan Ermilov     Alias outgoing echo and timestamp requests.
475305d1069SRuslan Ermilov     De-alias outgoing echo and timestamp replies.
4763b160b8bSBrian Somers */
477effc8e57SLutz Donnerhacke static int
IcmpAliasOut1(struct libalias * la,struct ip * pip,int create)478effc8e57SLutz Donnerhacke IcmpAliasOut1(struct libalias *la, struct ip *pip, int create)
479effc8e57SLutz Donnerhacke {
480ed01a582SDag-Erling Smørgrav 	struct alias_link *lnk;
4813b160b8bSBrian Somers 	struct icmp *ic;
4823b160b8bSBrian Somers 
483ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK_ASSERT(la);
4849fa0fd26SDag-Erling Smørgrav 	ic = (struct icmp *)ip_next(pip);
4853b160b8bSBrian Somers 
4863b160b8bSBrian Somers 	/* Save overwritten data for when echo packet returns */
487e7581f0fSPoul-Henning Kamp 	lnk = FindIcmpOut(la, pip->ip_src, pip->ip_dst, ic->icmp_id, create);
488ed01a582SDag-Erling Smørgrav 	if (lnk != NULL) {
4893b160b8bSBrian Somers 		u_short alias_id;
4903b160b8bSBrian Somers 		int accumulate;
4913b160b8bSBrian Somers 
492ed01a582SDag-Erling Smørgrav 		alias_id = GetAliasPort(lnk);
4933b160b8bSBrian Somers 
4943b160b8bSBrian Somers 		/* Since data field is being modified, adjust ICMP checksum */
4953b160b8bSBrian Somers 		accumulate = ic->icmp_id;
4963b160b8bSBrian Somers 		accumulate -= alias_id;
49771593f95SBrian Somers 		ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
4983b160b8bSBrian Somers 
4993b160b8bSBrian Somers 		/* Alias sequence number */
5003b160b8bSBrian Somers 		ic->icmp_id = alias_id;
5013b160b8bSBrian Somers 
5023b160b8bSBrian Somers 		/* Change source address */
5033b160b8bSBrian Somers 		{
5043b160b8bSBrian Somers 			struct in_addr alias_address;
5053b160b8bSBrian Somers 
506ed01a582SDag-Erling Smørgrav 			alias_address = GetAliasAddress(lnk);
5073b160b8bSBrian Somers 			DifferentialChecksum(&pip->ip_sum,
5082871c501SDag-Erling Smørgrav 			    &alias_address, &pip->ip_src, 2);
5093b160b8bSBrian Somers 			pip->ip_src = alias_address;
5103b160b8bSBrian Somers 		}
5113b160b8bSBrian Somers 
5123b160b8bSBrian Somers 		return (PKT_ALIAS_OK);
5133b160b8bSBrian Somers 	}
5143b160b8bSBrian Somers 	return (PKT_ALIAS_IGNORED);
5153b160b8bSBrian Somers }
5163b160b8bSBrian Somers 
5173b160b8bSBrian Somers /*
5183b160b8bSBrian Somers     Alias outgoing ICMP error messages containing
5193b160b8bSBrian Somers     IP header and first 64 bits of datagram.
5203b160b8bSBrian Somers */
521effc8e57SLutz Donnerhacke static int
IcmpAliasOut2(struct libalias * la,struct ip * pip)522effc8e57SLutz Donnerhacke IcmpAliasOut2(struct libalias *la, struct ip *pip)
523effc8e57SLutz Donnerhacke {
5243b160b8bSBrian Somers 	struct ip *ip;
525680c8244SRuslan Ermilov 	struct icmp *ic, *ic2;
526680c8244SRuslan Ermilov 	struct udphdr *ud;
527680c8244SRuslan Ermilov 	struct tcphdr *tc;
528ed01a582SDag-Erling Smørgrav 	struct alias_link *lnk;
5293b160b8bSBrian Somers 
530ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK_ASSERT(la);
5319fa0fd26SDag-Erling Smørgrav 	ic = (struct icmp *)ip_next(pip);
532305d1069SRuslan Ermilov 	ip = &ic->icmp_ip;
5333b160b8bSBrian Somers 
5349fa0fd26SDag-Erling Smørgrav 	ud = (struct udphdr *)ip_next(ip);
5359fa0fd26SDag-Erling Smørgrav 	tc = (struct tcphdr *)ip_next(ip);
5369fa0fd26SDag-Erling Smørgrav 	ic2 = (struct icmp *)ip_next(ip);
5373b160b8bSBrian Somers 
538680c8244SRuslan Ermilov 	if (ip->ip_p == IPPROTO_UDP)
539ed01a582SDag-Erling Smørgrav 		lnk = FindUdpTcpOut(la, ip->ip_dst, ip->ip_src,
540680c8244SRuslan Ermilov 		    ud->uh_dport, ud->uh_sport,
541642cd09fSRuslan Ermilov 		    IPPROTO_UDP, 0);
542680c8244SRuslan Ermilov 	else if (ip->ip_p == IPPROTO_TCP)
543ed01a582SDag-Erling Smørgrav 		lnk = FindUdpTcpOut(la, ip->ip_dst, ip->ip_src,
544680c8244SRuslan Ermilov 		    tc->th_dport, tc->th_sport,
545642cd09fSRuslan Ermilov 		    IPPROTO_TCP, 0);
546680c8244SRuslan Ermilov 	else if (ip->ip_p == IPPROTO_ICMP) {
547680c8244SRuslan Ermilov 		if (ic2->icmp_type == ICMP_ECHO || ic2->icmp_type == ICMP_TSTAMP)
548ed01a582SDag-Erling Smørgrav 			lnk = FindIcmpOut(la, ip->ip_dst, ip->ip_src, ic2->icmp_id, 0);
549680c8244SRuslan Ermilov 		else
550ed01a582SDag-Erling Smørgrav 			lnk = NULL;
551680c8244SRuslan Ermilov 	} else
552ed01a582SDag-Erling Smørgrav 		lnk = NULL;
5533b160b8bSBrian Somers 
554ed01a582SDag-Erling Smørgrav 	if (lnk != NULL) {
555f0f93429SDag-Erling Smørgrav 		if (ip->ip_p == IPPROTO_UDP || ip->ip_p == IPPROTO_TCP) {
556680c8244SRuslan Ermilov 			int accumulate;
557680c8244SRuslan Ermilov 			struct in_addr alias_address;
558680c8244SRuslan Ermilov 			u_short alias_port;
559680c8244SRuslan Ermilov 
560ed01a582SDag-Erling Smørgrav 			alias_address = GetAliasAddress(lnk);
561ed01a582SDag-Erling Smørgrav 			alias_port = GetAliasPort(lnk);
562680c8244SRuslan Ermilov 
563680c8244SRuslan Ermilov 			/* Adjust ICMP checksum */
5642871c501SDag-Erling Smørgrav 			accumulate = twowords(&ip->ip_dst);
5652871c501SDag-Erling Smørgrav 			accumulate -= twowords(&alias_address);
566680c8244SRuslan Ermilov 			accumulate += ud->uh_dport;
567680c8244SRuslan Ermilov 			accumulate -= alias_port;
56871593f95SBrian Somers 			ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
569680c8244SRuslan Ermilov 
570816fa7feSRuslan Ermilov 			/*
571816fa7feSRuslan Ermilov 			 * Alias address in IP header if it comes from the host
572816fa7feSRuslan Ermilov 			 * the original TCP/UDP packet was destined for.
573816fa7feSRuslan Ermilov 			 */
574816fa7feSRuslan Ermilov 			if (pip->ip_src.s_addr == ip->ip_dst.s_addr) {
5753b160b8bSBrian Somers 				DifferentialChecksum(&pip->ip_sum,
5762871c501SDag-Erling Smørgrav 				    &alias_address, &pip->ip_src, 2);
577680c8244SRuslan Ermilov 				pip->ip_src = alias_address;
578816fa7feSRuslan Ermilov 			}
579680c8244SRuslan Ermilov 			/* Alias address and port number of original IP packet
580effc8e57SLutz Donnerhacke 			 * fragment contained in ICMP data section */
581680c8244SRuslan Ermilov 			ip->ip_dst = alias_address;
582680c8244SRuslan Ermilov 			ud->uh_dport = alias_port;
583f0f93429SDag-Erling Smørgrav 		} else if (ip->ip_p == IPPROTO_ICMP) {
584680c8244SRuslan Ermilov 			int accumulate;
585680c8244SRuslan Ermilov 			struct in_addr alias_address;
586680c8244SRuslan Ermilov 			u_short alias_id;
587680c8244SRuslan Ermilov 
588ed01a582SDag-Erling Smørgrav 			alias_address = GetAliasAddress(lnk);
589ed01a582SDag-Erling Smørgrav 			alias_id = GetAliasPort(lnk);
590680c8244SRuslan Ermilov 
591680c8244SRuslan Ermilov 			/* Adjust ICMP checksum */
5922871c501SDag-Erling Smørgrav 			accumulate = twowords(&ip->ip_dst);
5932871c501SDag-Erling Smørgrav 			accumulate -= twowords(&alias_address);
594680c8244SRuslan Ermilov 			accumulate += ic2->icmp_id;
595680c8244SRuslan Ermilov 			accumulate -= alias_id;
59671593f95SBrian Somers 			ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
597680c8244SRuslan Ermilov 
598816fa7feSRuslan Ermilov 			/*
599816fa7feSRuslan Ermilov 			 * Alias address in IP header if it comes from the host
600816fa7feSRuslan Ermilov 			 * the original ICMP message was destined for.
601816fa7feSRuslan Ermilov 			 */
602816fa7feSRuslan Ermilov 			if (pip->ip_src.s_addr == ip->ip_dst.s_addr) {
603680c8244SRuslan Ermilov 				DifferentialChecksum(&pip->ip_sum,
6042871c501SDag-Erling Smørgrav 				    &alias_address, &pip->ip_src, 2);
605680c8244SRuslan Ermilov 				pip->ip_src = alias_address;
606816fa7feSRuslan Ermilov 			}
607effc8e57SLutz Donnerhacke 			/* Alias address of original IP packet and
608effc8e57SLutz Donnerhacke 			 * sequence number of embedded ICMP datagram */
609680c8244SRuslan Ermilov 			ip->ip_dst = alias_address;
610680c8244SRuslan Ermilov 			ic2->icmp_id = alias_id;
611680c8244SRuslan Ermilov 		}
612680c8244SRuslan Ermilov 		return (PKT_ALIAS_OK);
613680c8244SRuslan Ermilov 	}
614680c8244SRuslan Ermilov 	return (PKT_ALIAS_IGNORED);
6153b160b8bSBrian Somers }
6163b160b8bSBrian Somers 
6173b160b8bSBrian Somers static int
IcmpAliasOut(struct libalias * la,struct ip * pip,int create)618e6bbb691SPoul-Henning Kamp IcmpAliasOut(struct libalias *la, struct ip *pip, int create)
6193b160b8bSBrian Somers {
6203b160b8bSBrian Somers 	int iresult;
6213b160b8bSBrian Somers 	struct icmp *ic;
6223b160b8bSBrian Somers 
623ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK_ASSERT(la);
624ed01a582SDag-Erling Smørgrav 	(void)create;
625ed01a582SDag-Erling Smørgrav 
6267d96f4efSBrian Somers 	/* Return if proxy-only mode is enabled */
6275e289f9eSPoul-Henning Kamp 	if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
628ffcb611aSDag-Erling Smørgrav 		return (PKT_ALIAS_OK);
6297d96f4efSBrian Somers 
6309fa0fd26SDag-Erling Smørgrav 	ic = (struct icmp *)ip_next(pip);
6313b160b8bSBrian Somers 
6323b160b8bSBrian Somers 	iresult = PKT_ALIAS_IGNORED;
633f0f93429SDag-Erling Smørgrav 	switch (ic->icmp_type) {
6343b160b8bSBrian Somers 	case ICMP_ECHO:
6353b160b8bSBrian Somers 	case ICMP_TSTAMP:
636f0f93429SDag-Erling Smørgrav 		if (ic->icmp_code == 0) {
637e7581f0fSPoul-Henning Kamp 			iresult = IcmpAliasOut1(la, pip, create);
6383b160b8bSBrian Somers 		}
6393b160b8bSBrian Somers 		break;
6403b160b8bSBrian Somers 	case ICMP_UNREACH:
6413b160b8bSBrian Somers 	case ICMP_SOURCEQUENCH:
6423b160b8bSBrian Somers 	case ICMP_TIMXCEED:
6433b160b8bSBrian Somers 	case ICMP_PARAMPROB:
6445e289f9eSPoul-Henning Kamp 		iresult = IcmpAliasOut2(la, pip);
6453b160b8bSBrian Somers 		break;
6463b160b8bSBrian Somers 	case ICMP_ECHOREPLY:
6473b160b8bSBrian Somers 	case ICMP_TSTAMPREPLY:
648e7581f0fSPoul-Henning Kamp 		iresult = IcmpAliasOut1(la, pip, create);
6493b160b8bSBrian Somers 	}
6503b160b8bSBrian Somers 	return (iresult);
6513b160b8bSBrian Somers }
6523b160b8bSBrian Somers 
6537d96f4efSBrian Somers /*
65480607605SRuslan Ermilov   Handle incoming IP packets. The
6557d96f4efSBrian Somers   only thing which is done in this case is to alias
6567d96f4efSBrian Somers   the dest IP address of the packet to our inside
6577d96f4efSBrian Somers   machine.
6587d96f4efSBrian Somers */
659effc8e57SLutz Donnerhacke static int
ProtoAliasIn(struct libalias * la,struct in_addr ip_src,struct ip * pip,u_char ip_p,u_short * ip_sum)660effc8e57SLutz Donnerhacke ProtoAliasIn(struct libalias *la, struct in_addr ip_src,
661effc8e57SLutz Donnerhacke     struct ip *pip, u_char ip_p, u_short *ip_sum)
662effc8e57SLutz Donnerhacke {
663ed01a582SDag-Erling Smørgrav 	struct alias_link *lnk;
6647d96f4efSBrian Somers 
665ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK_ASSERT(la);
666483d2f22SRuslan Ermilov 	/* Return if proxy-only mode is enabled */
6675e289f9eSPoul-Henning Kamp 	if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
668ffcb611aSDag-Erling Smørgrav 		return (PKT_ALIAS_OK);
669483d2f22SRuslan Ermilov 
670bc596e56SAlex Richardson 	lnk = FindProtoIn(la, ip_src, pip->ip_dst, ip_p);
671ed01a582SDag-Erling Smørgrav 	if (lnk != NULL) {
672483d2f22SRuslan Ermilov 		struct in_addr original_address;
6737d96f4efSBrian Somers 
674ed01a582SDag-Erling Smørgrav 		original_address = GetOriginalAddress(lnk);
675483d2f22SRuslan Ermilov 
676483d2f22SRuslan Ermilov 		/* Restore original IP address */
677ab0fcfd0SPaolo Pisati 		DifferentialChecksum(ip_sum,
678bc596e56SAlex Richardson 		    &original_address, &pip->ip_dst, 2);
679bc596e56SAlex Richardson 		pip->ip_dst = original_address;
6807d96f4efSBrian Somers 
681483d2f22SRuslan Ermilov 		return (PKT_ALIAS_OK);
682483d2f22SRuslan Ermilov 	}
683483d2f22SRuslan Ermilov 	return (PKT_ALIAS_IGNORED);
6847d96f4efSBrian Somers }
6857d96f4efSBrian Somers 
6867d96f4efSBrian Somers /*
68780607605SRuslan Ermilov   Handle outgoing IP packets. The
6887d96f4efSBrian Somers   only thing which is done in this case is to alias
6897d96f4efSBrian Somers   the source IP address of the packet.
6907d96f4efSBrian Somers */
691effc8e57SLutz 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)692effc8e57SLutz Donnerhacke ProtoAliasOut(struct libalias *la, struct ip *pip,
693effc8e57SLutz Donnerhacke     struct in_addr ip_dst, u_char ip_p, u_short *ip_sum, int create)
694effc8e57SLutz Donnerhacke {
695ed01a582SDag-Erling Smørgrav 	struct alias_link *lnk;
696ed01a582SDag-Erling Smørgrav 
697ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK_ASSERT(la);
6987d96f4efSBrian Somers 
699483d2f22SRuslan Ermilov 	/* Return if proxy-only mode is enabled */
7005e289f9eSPoul-Henning Kamp 	if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
701ffcb611aSDag-Erling Smørgrav 		return (PKT_ALIAS_OK);
702483d2f22SRuslan Ermilov 
7031a356b8bSEugene Grosbein 	if (!create)
7041a356b8bSEugene Grosbein 		return (PKT_ALIAS_IGNORED);
7051a356b8bSEugene Grosbein 
706bc596e56SAlex Richardson 	lnk = FindProtoOut(la, pip->ip_src, ip_dst, ip_p);
707ed01a582SDag-Erling Smørgrav 	if (lnk != NULL) {
708483d2f22SRuslan Ermilov 		struct in_addr alias_address;
7097d96f4efSBrian Somers 
710ed01a582SDag-Erling Smørgrav 		alias_address = GetAliasAddress(lnk);
711483d2f22SRuslan Ermilov 
712483d2f22SRuslan Ermilov 		/* Change source address */
713ab0fcfd0SPaolo Pisati 		DifferentialChecksum(ip_sum,
714bc596e56SAlex Richardson 		    &alias_address, &pip->ip_src, 2);
715bc596e56SAlex Richardson 		pip->ip_src = alias_address;
7167d96f4efSBrian Somers 
717483d2f22SRuslan Ermilov 		return (PKT_ALIAS_OK);
718483d2f22SRuslan Ermilov 	}
719483d2f22SRuslan Ermilov 	return (PKT_ALIAS_IGNORED);
7207d96f4efSBrian Somers }
7217d96f4efSBrian Somers 
722461e6f23SMaxim Sobolev #define MF_ISSET(_pip) (ntohs((_pip)->ip_off) & IP_MF)
723461e6f23SMaxim Sobolev #define FRAG_NO_HDR(_pip) (ntohs((_pip)->ip_off) & IP_OFFMASK)
724461e6f23SMaxim Sobolev 
725461e6f23SMaxim Sobolev static struct udphdr *
ValidateUdpLength(struct ip * pip)726461e6f23SMaxim Sobolev ValidateUdpLength(struct ip *pip)
727461e6f23SMaxim Sobolev {
728461e6f23SMaxim Sobolev 	struct udphdr *ud;
729461e6f23SMaxim Sobolev 	size_t dlen;
730461e6f23SMaxim Sobolev 
731461e6f23SMaxim Sobolev #ifdef _KERNEL
732461e6f23SMaxim Sobolev 	KASSERT(!FRAG_NO_HDR(pip), ("header-less fragment isn't expected here"));
733461e6f23SMaxim Sobolev #endif
734461e6f23SMaxim Sobolev 	dlen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
735461e6f23SMaxim Sobolev 	if (dlen < sizeof(struct udphdr))
736461e6f23SMaxim Sobolev 		return (NULL);
737461e6f23SMaxim Sobolev 	ud = (struct udphdr *)ip_next(pip);
738461e6f23SMaxim Sobolev 	if (!MF_ISSET(pip) && dlen < ntohs(ud->uh_ulen))
739461e6f23SMaxim Sobolev 		return (NULL);
740461e6f23SMaxim Sobolev 	return (ud);
741461e6f23SMaxim Sobolev }
742461e6f23SMaxim Sobolev 
74355a39fc5SRuslan Ermilov static int
UdpAliasIn(struct libalias * la,struct ip * pip)7445e289f9eSPoul-Henning Kamp UdpAliasIn(struct libalias *la, struct ip *pip)
7453b160b8bSBrian Somers {
7463b160b8bSBrian Somers 	struct udphdr *ud;
747ed01a582SDag-Erling Smørgrav 	struct alias_link *lnk;
7483b160b8bSBrian Somers 
749ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK_ASSERT(la);
7507d96f4efSBrian Somers 
751461e6f23SMaxim Sobolev 	ud = ValidateUdpLength(pip);
752461e6f23SMaxim Sobolev 	if (ud == NULL)
7536461c83eSEd Maste 		return (PKT_ALIAS_IGNORED);
7543b160b8bSBrian Somers 
755ed01a582SDag-Erling Smørgrav 	lnk = FindUdpTcpIn(la, pip->ip_src, pip->ip_dst,
7563b160b8bSBrian Somers 	    ud->uh_sport, ud->uh_dport,
757ea29dd92SAlexander Motin 	    IPPROTO_UDP, !(la->packetAliasMode & PKT_ALIAS_PROXY_ONLY));
758ed01a582SDag-Erling Smørgrav 	if (lnk != NULL) {
7593b160b8bSBrian Somers 		struct in_addr alias_address;
7603b160b8bSBrian Somers 		struct in_addr original_address;
761ea29dd92SAlexander Motin 		struct in_addr proxy_address;
7623b160b8bSBrian Somers 		u_short alias_port;
763ea29dd92SAlexander Motin 		u_short proxy_port;
7643b160b8bSBrian Somers 		int accumulate;
765ea80b0acSPaolo Pisati 		int error;
766be4f3cd0SPaolo Pisati 		struct alias_data ad = {
767be4f3cd0SPaolo Pisati 			.lnk = lnk,
768be4f3cd0SPaolo Pisati 			.oaddr = &original_address,
769be4f3cd0SPaolo Pisati 			.aaddr = &alias_address,
770be4f3cd0SPaolo Pisati 			.aport = &alias_port,
771be4f3cd0SPaolo Pisati 			.sport = &ud->uh_sport,
772be4f3cd0SPaolo Pisati 			.dport = &ud->uh_dport,
773be4f3cd0SPaolo Pisati 			.maxpktsize = 0
774be4f3cd0SPaolo Pisati 		};
7753b160b8bSBrian Somers 
776ed01a582SDag-Erling Smørgrav 		alias_address = GetAliasAddress(lnk);
777ed01a582SDag-Erling Smørgrav 		original_address = GetOriginalAddress(lnk);
778ea29dd92SAlexander Motin 		proxy_address = GetProxyAddress(lnk);
7793b160b8bSBrian Somers 		alias_port = ud->uh_dport;
780ed01a582SDag-Erling Smørgrav 		ud->uh_dport = GetOriginalPort(lnk);
781ea29dd92SAlexander Motin 		proxy_port = GetProxyPort(lnk);
7823b160b8bSBrian Somers 
783be4f3cd0SPaolo Pisati 		/* Walk out chain. */
784be4f3cd0SPaolo Pisati 		error = find_handler(IN, UDP, la, pip, &ad);
78550d25ddaSPaolo Pisati 		/* If we cannot figure out the packet, ignore it. */
78650d25ddaSPaolo Pisati 		if (error < 0)
78750d25ddaSPaolo Pisati 			return (PKT_ALIAS_IGNORED);
7880579bd71SBrian Somers 
789effc8e57SLutz Donnerhacke 		/* If UDP checksum is not zero, then adjust since
790effc8e57SLutz Donnerhacke 		 * destination port is being unaliased and
791effc8e57SLutz Donnerhacke 		 * destination address is being altered. */
792f0f93429SDag-Erling Smørgrav 		if (ud->uh_sum != 0) {
7933b160b8bSBrian Somers 			accumulate = alias_port;
7943b160b8bSBrian Somers 			accumulate -= ud->uh_dport;
7952871c501SDag-Erling Smørgrav 			accumulate += twowords(&alias_address);
7962871c501SDag-Erling Smørgrav 			accumulate -= twowords(&original_address);
797ea29dd92SAlexander Motin 
798effc8e57SLutz Donnerhacke 			/* If this is a proxy packet, modify checksum
799effc8e57SLutz Donnerhacke 			 * because of source change.*/
800ea29dd92SAlexander Motin 			if (proxy_port != 0) {
801ea29dd92SAlexander Motin 				accumulate += ud->uh_sport;
802ea29dd92SAlexander Motin 				accumulate -= proxy_port;
803ea29dd92SAlexander Motin 			}
804ea29dd92SAlexander Motin 
805ea29dd92SAlexander Motin 			if (proxy_address.s_addr != 0) {
806ea29dd92SAlexander Motin 				accumulate += twowords(&pip->ip_src);
807ea29dd92SAlexander Motin 				accumulate -= twowords(&proxy_address);
808ea29dd92SAlexander Motin 			}
809ea29dd92SAlexander Motin 
81071593f95SBrian Somers 			ADJUST_CHECKSUM(accumulate, ud->uh_sum);
8113b160b8bSBrian Somers 		}
812effc8e57SLutz Donnerhacke 
813ea29dd92SAlexander Motin 		/* XXX: Could the two if's below be concatenated to one ? */
814ea29dd92SAlexander Motin 		/* Restore source port and/or address in case of proxying*/
815ea29dd92SAlexander Motin 		if (proxy_port != 0)
816ea29dd92SAlexander Motin 			ud->uh_sport = proxy_port;
817ea29dd92SAlexander Motin 
818ea29dd92SAlexander Motin 		if (proxy_address.s_addr != 0) {
819ea29dd92SAlexander Motin 			DifferentialChecksum(&pip->ip_sum,
820ea29dd92SAlexander Motin 			    &proxy_address, &pip->ip_src, 2);
821ea29dd92SAlexander Motin 			pip->ip_src = proxy_address;
822ea29dd92SAlexander Motin 		}
823ea29dd92SAlexander Motin 
8243b160b8bSBrian Somers 		/* Restore original IP address */
8253b160b8bSBrian Somers 		DifferentialChecksum(&pip->ip_sum,
8262871c501SDag-Erling Smørgrav 		    &original_address, &pip->ip_dst, 2);
8273b160b8bSBrian Somers 		pip->ip_dst = original_address;
828374fad8bSMatthew Dillon 
8293b160b8bSBrian Somers 		return (PKT_ALIAS_OK);
8303b160b8bSBrian Somers 	}
8313b160b8bSBrian Somers 	return (PKT_ALIAS_IGNORED);
8323b160b8bSBrian Somers }
8333b160b8bSBrian Somers 
8343b160b8bSBrian Somers static int
UdpAliasOut(struct libalias * la,struct ip * pip,int maxpacketsize,int create)835ea29dd92SAlexander Motin UdpAliasOut(struct libalias *la, struct ip *pip, int maxpacketsize, int create)
8363b160b8bSBrian Somers {
8373b160b8bSBrian Somers 	struct udphdr *ud;
838ed01a582SDag-Erling Smørgrav 	struct alias_link *lnk;
839ea29dd92SAlexander Motin 	struct in_addr dest_address;
840ea29dd92SAlexander Motin 	struct in_addr proxy_server_address;
841ea29dd92SAlexander Motin 	u_short dest_port;
842ea29dd92SAlexander Motin 	u_short proxy_server_port;
843ea29dd92SAlexander Motin 	int proxy_type;
8443b160b8bSBrian Somers 
845ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK_ASSERT(la);
846ea29dd92SAlexander Motin 
847461e6f23SMaxim Sobolev 	ud = ValidateUdpLength(pip);
848461e6f23SMaxim Sobolev 	if (ud == NULL)
849461e6f23SMaxim Sobolev 		return (PKT_ALIAS_IGNORED);
850461e6f23SMaxim Sobolev 
851ea29dd92SAlexander Motin 	/* Return if proxy-only mode is enabled and not proxyrule found.*/
852effc8e57SLutz Donnerhacke 	proxy_type = ProxyCheck(la, &proxy_server_address, &proxy_server_port,
853effc8e57SLutz Donnerhacke 	    pip->ip_src, pip->ip_dst, ud->uh_dport, pip->ip_p);
854ea29dd92SAlexander Motin 	if (proxy_type == 0 && (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY))
855ffcb611aSDag-Erling Smørgrav 		return (PKT_ALIAS_OK);
8567d96f4efSBrian Somers 
857ea29dd92SAlexander Motin 	/* If this is a transparent proxy, save original destination,
858ea29dd92SAlexander Motin 	 * then alter the destination and adjust checksums */
859ea29dd92SAlexander Motin 	dest_port = ud->uh_dport;
860ea29dd92SAlexander Motin 	dest_address = pip->ip_dst;
8613b160b8bSBrian Somers 
862ea29dd92SAlexander Motin 	if (proxy_type != 0) {
863ea29dd92SAlexander Motin 		int accumulate;
864ea29dd92SAlexander Motin 
865ea29dd92SAlexander Motin 		accumulate = twowords(&pip->ip_dst);
866ea29dd92SAlexander Motin 		accumulate -= twowords(&proxy_server_address);
867ea29dd92SAlexander Motin 
868ea29dd92SAlexander Motin 		ADJUST_CHECKSUM(accumulate, pip->ip_sum);
869ea29dd92SAlexander Motin 
870ea29dd92SAlexander Motin 		if (ud->uh_sum != 0) {
871ea29dd92SAlexander Motin 			accumulate = twowords(&pip->ip_dst);
872ea29dd92SAlexander Motin 			accumulate -= twowords(&proxy_server_address);
873ea29dd92SAlexander Motin 			accumulate += ud->uh_dport;
874ea29dd92SAlexander Motin 			accumulate -= proxy_server_port;
875ea29dd92SAlexander Motin 			ADJUST_CHECKSUM(accumulate, ud->uh_sum);
876ea29dd92SAlexander Motin 		}
877ea29dd92SAlexander Motin 		pip->ip_dst = proxy_server_address;
878ea29dd92SAlexander Motin 		ud->uh_dport = proxy_server_port;
879ea29dd92SAlexander Motin 	}
880ed01a582SDag-Erling Smørgrav 	lnk = FindUdpTcpOut(la, pip->ip_src, pip->ip_dst,
8813b160b8bSBrian Somers 	    ud->uh_sport, ud->uh_dport,
882e6bbb691SPoul-Henning Kamp 	    IPPROTO_UDP, create);
883ed01a582SDag-Erling Smørgrav 	if (lnk != NULL) {
8843b160b8bSBrian Somers 		u_short alias_port;
8853b160b8bSBrian Somers 		struct in_addr alias_address;
886be4f3cd0SPaolo Pisati 		struct alias_data ad = {
887be4f3cd0SPaolo Pisati 			.lnk = lnk,
888be4f3cd0SPaolo Pisati 			.oaddr = NULL,
889be4f3cd0SPaolo Pisati 			.aaddr = &alias_address,
890be4f3cd0SPaolo Pisati 			.aport = &alias_port,
891be4f3cd0SPaolo Pisati 			.sport = &ud->uh_sport,
892be4f3cd0SPaolo Pisati 			.dport = &ud->uh_dport,
893be4f3cd0SPaolo Pisati 			.maxpktsize = 0
894be4f3cd0SPaolo Pisati 		};
8953b160b8bSBrian Somers 
896ea29dd92SAlexander Motin 		/* Save original destination address, if this is a proxy packet.
897ea29dd92SAlexander Motin 		 * Also modify packet to include destination encoding.  This may
898ea29dd92SAlexander Motin 		 * change the size of IP header. */
899ea29dd92SAlexander Motin 		if (proxy_type != 0) {
900ea29dd92SAlexander Motin 			SetProxyPort(lnk, dest_port);
901ea29dd92SAlexander Motin 			SetProxyAddress(lnk, dest_address);
902ea29dd92SAlexander Motin 			ProxyModify(la, lnk, pip, maxpacketsize, proxy_type);
903ea29dd92SAlexander Motin 			ud = (struct udphdr *)ip_next(pip);
904ea29dd92SAlexander Motin 		}
905ea29dd92SAlexander Motin 
906ed01a582SDag-Erling Smørgrav 		alias_address = GetAliasAddress(lnk);
907ed01a582SDag-Erling Smørgrav 		alias_port = GetAliasPort(lnk);
9083b160b8bSBrian Somers 
909be4f3cd0SPaolo Pisati 		/* Walk out chain. */
9106454d0c8SJohn Baldwin 		find_handler(OUT, UDP, la, pip, &ad);
911fb9cd36dSAtsushi Murai 
9123b160b8bSBrian Somers 		/* If UDP checksum is not zero, adjust since source port is */
9133b160b8bSBrian Somers 		/* being aliased and source address is being altered	*/
914f0f93429SDag-Erling Smørgrav 		if (ud->uh_sum != 0) {
9153b160b8bSBrian Somers 			int accumulate;
9163b160b8bSBrian Somers 
9173b160b8bSBrian Somers 			accumulate = ud->uh_sport;
9183b160b8bSBrian Somers 			accumulate -= alias_port;
9192871c501SDag-Erling Smørgrav 			accumulate += twowords(&pip->ip_src);
9202871c501SDag-Erling Smørgrav 			accumulate -= twowords(&alias_address);
92171593f95SBrian Somers 			ADJUST_CHECKSUM(accumulate, ud->uh_sum);
9223b160b8bSBrian Somers 		}
923fb9cd36dSAtsushi Murai 		/* Put alias port in UDP header */
9243b160b8bSBrian Somers 		ud->uh_sport = alias_port;
9253b160b8bSBrian Somers 
9263b160b8bSBrian Somers 		/* Change source address */
9273b160b8bSBrian Somers 		DifferentialChecksum(&pip->ip_sum,
9282871c501SDag-Erling Smørgrav 		    &alias_address, &pip->ip_src, 2);
9293b160b8bSBrian Somers 		pip->ip_src = alias_address;
9303b160b8bSBrian Somers 
9313b160b8bSBrian Somers 		return (PKT_ALIAS_OK);
9323b160b8bSBrian Somers 	}
9333b160b8bSBrian Somers 	return (PKT_ALIAS_IGNORED);
9343b160b8bSBrian Somers }
9353b160b8bSBrian Somers 
9363b160b8bSBrian Somers static int
TcpAliasIn(struct libalias * la,struct ip * pip)9375e289f9eSPoul-Henning Kamp TcpAliasIn(struct libalias *la, struct ip *pip)
9383b160b8bSBrian Somers {
9393b160b8bSBrian Somers 	struct tcphdr *tc;
940ed01a582SDag-Erling Smørgrav 	struct alias_link *lnk;
941be597269SAlex Richardson 	size_t dlen;
9423b160b8bSBrian Somers 
943ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK_ASSERT(la);
9446461c83eSEd Maste 
9456461c83eSEd Maste 	dlen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
9466461c83eSEd Maste 	if (dlen < sizeof(struct tcphdr))
9476461c83eSEd Maste 		return (PKT_ALIAS_IGNORED);
9489fa0fd26SDag-Erling Smørgrav 	tc = (struct tcphdr *)ip_next(pip);
9493b160b8bSBrian Somers 
950ed01a582SDag-Erling Smørgrav 	lnk = FindUdpTcpIn(la, pip->ip_src, pip->ip_dst,
9513b160b8bSBrian Somers 	    tc->th_sport, tc->th_dport,
952642cd09fSRuslan Ermilov 	    IPPROTO_TCP,
9535e289f9eSPoul-Henning Kamp 	    !(la->packetAliasMode & PKT_ALIAS_PROXY_ONLY));
954ed01a582SDag-Erling Smørgrav 	if (lnk != NULL) {
9553b160b8bSBrian Somers 		struct in_addr alias_address;
9563b160b8bSBrian Somers 		struct in_addr original_address;
9577d96f4efSBrian Somers 		struct in_addr proxy_address;
9583b160b8bSBrian Somers 		u_short alias_port;
9597d96f4efSBrian Somers 		u_short proxy_port;
9606454d0c8SJohn Baldwin 		int accumulate;
9613b160b8bSBrian Somers 
962be4f3cd0SPaolo Pisati 		/*
963be4f3cd0SPaolo Pisati 		 * The init of MANY vars is a bit below, but aliashandlepptpin
964be4f3cd0SPaolo Pisati 		 * seems to need the destination port that came within the
965be4f3cd0SPaolo Pisati 		 * packet and not the original one looks below [*].
966be4f3cd0SPaolo Pisati 		 */
967be4f3cd0SPaolo Pisati 
968be4f3cd0SPaolo Pisati 		struct alias_data ad = {
969be4f3cd0SPaolo Pisati 			.lnk = lnk,
970be4f3cd0SPaolo Pisati 			.oaddr = NULL,
971be4f3cd0SPaolo Pisati 			.aaddr = NULL,
972be4f3cd0SPaolo Pisati 			.aport = NULL,
973be4f3cd0SPaolo Pisati 			.sport = &tc->th_sport,
974be4f3cd0SPaolo Pisati 			.dport = &tc->th_dport,
975be4f3cd0SPaolo Pisati 			.maxpktsize = 0
976be4f3cd0SPaolo Pisati 		};
977be4f3cd0SPaolo Pisati 
978be4f3cd0SPaolo Pisati 		/* Walk out chain. */
9796454d0c8SJohn Baldwin 		find_handler(IN, TCP, la, pip, &ad);
98055a39fc5SRuslan Ermilov 
981ed01a582SDag-Erling Smørgrav 		alias_address = GetAliasAddress(lnk);
982ed01a582SDag-Erling Smørgrav 		original_address = GetOriginalAddress(lnk);
983ed01a582SDag-Erling Smørgrav 		proxy_address = GetProxyAddress(lnk);
9843b160b8bSBrian Somers 		alias_port = tc->th_dport;
985ed01a582SDag-Erling Smørgrav 		tc->th_dport = GetOriginalPort(lnk);
986ed01a582SDag-Erling Smørgrav 		proxy_port = GetProxyPort(lnk);
9873b160b8bSBrian Somers 
988be4f3cd0SPaolo Pisati 		/*
989be4f3cd0SPaolo Pisati 		 * Look above, if anyone is going to add find_handler AFTER
990be4f3cd0SPaolo Pisati 		 * this aliashandlepptpin/point, please redo alias_data too.
991be4f3cd0SPaolo Pisati 		 * Uncommenting the piece here below should be enough.
992be4f3cd0SPaolo Pisati 		 */
993be4f3cd0SPaolo Pisati #if 0
994be4f3cd0SPaolo Pisati 				 struct alias_data ad = {
995be4f3cd0SPaolo Pisati 					.lnk = lnk,
996be4f3cd0SPaolo Pisati 					.oaddr = &original_address,
997be4f3cd0SPaolo Pisati 					.aaddr = &alias_address,
998be4f3cd0SPaolo Pisati 					.aport = &alias_port,
999be4f3cd0SPaolo Pisati 					.sport = &ud->uh_sport,
1000be4f3cd0SPaolo Pisati 					.dport = &ud->uh_dport,
1001be4f3cd0SPaolo Pisati 					.maxpktsize = 0
1002be4f3cd0SPaolo Pisati 				};
1003be4f3cd0SPaolo Pisati 
1004be4f3cd0SPaolo Pisati 				/* Walk out chain. */
1005be4f3cd0SPaolo Pisati 				error = find_handler(la, pip, &ad);
1006be4f3cd0SPaolo Pisati 				if (error == EHDNOF)
1007be4f3cd0SPaolo Pisati 					printf("Protocol handler not found\n");
1008be4f3cd0SPaolo Pisati #endif
1009be4f3cd0SPaolo Pisati 
1010effc8e57SLutz Donnerhacke 		/* Adjust TCP checksum since destination port is being
1011effc8e57SLutz Donnerhacke 		 * unaliased and destination port is being altered. */
10123b160b8bSBrian Somers 		accumulate = alias_port;
10133b160b8bSBrian Somers 		accumulate -= tc->th_dport;
10142871c501SDag-Erling Smørgrav 		accumulate += twowords(&alias_address);
10152871c501SDag-Erling Smørgrav 		accumulate -= twowords(&original_address);
10163b160b8bSBrian Somers 
1017effc8e57SLutz Donnerhacke 		/* If this is a proxy, then modify the TCP source port
1018effc8e57SLutz Donnerhacke 		 * and checksum accumulation */
1019f0f93429SDag-Erling Smørgrav 		if (proxy_port != 0) {
10207d96f4efSBrian Somers 			accumulate += tc->th_sport;
10217d96f4efSBrian Somers 			tc->th_sport = proxy_port;
10227d96f4efSBrian Somers 			accumulate -= tc->th_sport;
10232871c501SDag-Erling Smørgrav 			accumulate += twowords(&pip->ip_src);
10242871c501SDag-Erling Smørgrav 			accumulate -= twowords(&proxy_address);
10257d96f4efSBrian Somers 		}
1026483d2f22SRuslan Ermilov 		/* See if ACK number needs to be modified */
1027ed01a582SDag-Erling Smørgrav 		if (GetAckModified(lnk) == 1) {
10283b160b8bSBrian Somers 			int delta;
10293b160b8bSBrian Somers 
10304741f3a1SPaolo Pisati 			tc = (struct tcphdr *)ip_next(pip);
10314741f3a1SPaolo Pisati 			delta = GetDeltaAckIn(tc->th_ack, lnk);
1032f0f93429SDag-Erling Smørgrav 			if (delta != 0) {
10332871c501SDag-Erling Smørgrav 				accumulate += twowords(&tc->th_ack);
10343b160b8bSBrian Somers 				tc->th_ack = htonl(ntohl(tc->th_ack) - delta);
10352871c501SDag-Erling Smørgrav 				accumulate -= twowords(&tc->th_ack);
10363b160b8bSBrian Somers 			}
10373b160b8bSBrian Somers 		}
10383b160b8bSBrian Somers 		ADJUST_CHECKSUM(accumulate, tc->th_sum);
10393b160b8bSBrian Somers 
10403b160b8bSBrian Somers 		/* Restore original IP address */
10412871c501SDag-Erling Smørgrav 		accumulate = twowords(&pip->ip_dst);
1042ab39bc9aSDaniel Eischen 		pip->ip_dst = original_address;
10432871c501SDag-Erling Smørgrav 		accumulate -= twowords(&pip->ip_dst);
10447d96f4efSBrian Somers 
1045effc8e57SLutz Donnerhacke 		/* If this is a transparent proxy packet,
1046effc8e57SLutz Donnerhacke 		 * then modify the source address */
1047f0f93429SDag-Erling Smørgrav 		if (proxy_address.s_addr != 0) {
10482871c501SDag-Erling Smørgrav 			accumulate += twowords(&pip->ip_src);
10497d96f4efSBrian Somers 			pip->ip_src = proxy_address;
10502871c501SDag-Erling Smørgrav 			accumulate -= twowords(&pip->ip_src);
10517d96f4efSBrian Somers 		}
10527d96f4efSBrian Somers 		ADJUST_CHECKSUM(accumulate, pip->ip_sum);
10533b160b8bSBrian Somers 
10543b160b8bSBrian Somers 		/* Monitor TCP connection state */
10554741f3a1SPaolo Pisati 		tc = (struct tcphdr *)ip_next(pip);
1056*0fc7bdc9SRichard Scheffenegger 		TcpMonitorIn(__tcp_get_flags(tc), lnk);
10573b160b8bSBrian Somers 
10583b160b8bSBrian Somers 		return (PKT_ALIAS_OK);
10593b160b8bSBrian Somers 	}
10603b160b8bSBrian Somers 	return (PKT_ALIAS_IGNORED);
10613b160b8bSBrian Somers }
10623b160b8bSBrian Somers 
10633b160b8bSBrian Somers static int
TcpAliasOut(struct libalias * la,struct ip * pip,int maxpacketsize,int create)1064e6bbb691SPoul-Henning Kamp TcpAliasOut(struct libalias *la, struct ip *pip, int maxpacketsize, int create)
10653b160b8bSBrian Somers {
10666454d0c8SJohn Baldwin 	int proxy_type;
10677d96f4efSBrian Somers 	u_short dest_port;
10687d96f4efSBrian Somers 	u_short proxy_server_port;
1069be597269SAlex Richardson 	size_t dlen;
10707d96f4efSBrian Somers 	struct in_addr dest_address;
10717d96f4efSBrian Somers 	struct in_addr proxy_server_address;
10723b160b8bSBrian Somers 	struct tcphdr *tc;
1073ed01a582SDag-Erling Smørgrav 	struct alias_link *lnk;
10743b160b8bSBrian Somers 
1075ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK_ASSERT(la);
10766461c83eSEd Maste 
10776461c83eSEd Maste 	dlen = ntohs(pip->ip_len) - (pip->ip_hl << 2);
10786461c83eSEd Maste 	if (dlen < sizeof(struct tcphdr))
10796461c83eSEd Maste 		return (PKT_ALIAS_IGNORED);
10809fa0fd26SDag-Erling Smørgrav 	tc = (struct tcphdr *)ip_next(pip);
10813b160b8bSBrian Somers 
1082dca9c930SPoul-Henning Kamp 	if (create)
10834741f3a1SPaolo Pisati 		proxy_type = ProxyCheck(la, &proxy_server_address,
10844741f3a1SPaolo Pisati 		    &proxy_server_port, pip->ip_src, pip->ip_dst,
10854741f3a1SPaolo Pisati 		    tc->th_dport, pip->ip_p);
1086dca9c930SPoul-Henning Kamp 	else
1087dca9c930SPoul-Henning Kamp 		proxy_type = 0;
10887d96f4efSBrian Somers 
10895e289f9eSPoul-Henning Kamp 	if (proxy_type == 0 && (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY))
1090ffcb611aSDag-Erling Smørgrav 		return (PKT_ALIAS_OK);
10917d96f4efSBrian Somers 
10927d96f4efSBrian Somers 	/* If this is a transparent proxy, save original destination,
1093effc8e57SLutz Donnerhacke 	 * then alter the destination and adjust checksums */
10947d96f4efSBrian Somers 	dest_port = tc->th_dport;
10957d96f4efSBrian Somers 	dest_address = pip->ip_dst;
1096f0f93429SDag-Erling Smørgrav 	if (proxy_type != 0) {
10977d96f4efSBrian Somers 		int accumulate;
10987d96f4efSBrian Somers 
10997d96f4efSBrian Somers 		accumulate = tc->th_dport;
11007d96f4efSBrian Somers 		tc->th_dport = proxy_server_port;
11017d96f4efSBrian Somers 		accumulate -= tc->th_dport;
11022871c501SDag-Erling Smørgrav 		accumulate += twowords(&pip->ip_dst);
11032871c501SDag-Erling Smørgrav 		accumulate -= twowords(&proxy_server_address);
11047d96f4efSBrian Somers 		ADJUST_CHECKSUM(accumulate, tc->th_sum);
11057d96f4efSBrian Somers 
11062871c501SDag-Erling Smørgrav 		accumulate = twowords(&pip->ip_dst);
11077d96f4efSBrian Somers 		pip->ip_dst = proxy_server_address;
11082871c501SDag-Erling Smørgrav 		accumulate -= twowords(&pip->ip_dst);
11097d96f4efSBrian Somers 		ADJUST_CHECKSUM(accumulate, pip->ip_sum);
11107d96f4efSBrian Somers 	}
1111ed01a582SDag-Erling Smørgrav 	lnk = FindUdpTcpOut(la, pip->ip_src, pip->ip_dst,
11123b160b8bSBrian Somers 	    tc->th_sport, tc->th_dport,
1113e6bbb691SPoul-Henning Kamp 	    IPPROTO_TCP, create);
1114ed01a582SDag-Erling Smørgrav 	if (lnk == NULL)
1115e6bbb691SPoul-Henning Kamp 		return (PKT_ALIAS_IGNORED);
1116ed01a582SDag-Erling Smørgrav 	if (lnk != NULL) {
11173b160b8bSBrian Somers 		u_short alias_port;
11187d96f4efSBrian Somers 		struct in_addr alias_address;
11193b160b8bSBrian Somers 		int accumulate;
1120be4f3cd0SPaolo Pisati 		struct alias_data ad = {
1121be4f3cd0SPaolo Pisati 			.lnk = lnk,
1122be4f3cd0SPaolo Pisati 			.oaddr = NULL,
1123be4f3cd0SPaolo Pisati 			.aaddr = &alias_address,
1124be4f3cd0SPaolo Pisati 			.aport = &alias_port,
1125be4f3cd0SPaolo Pisati 			.sport = &tc->th_sport,
1126be4f3cd0SPaolo Pisati 			.dport = &tc->th_dport,
1127be4f3cd0SPaolo Pisati 			.maxpktsize = maxpacketsize
1128be4f3cd0SPaolo Pisati 		};
11293b160b8bSBrian Somers 
11307d96f4efSBrian Somers 		/* Save original destination address, if this is a proxy packet.
1131effc8e57SLutz Donnerhacke 		 * Also modify packet to include destination
1132effc8e57SLutz Donnerhacke 		 * encoding.  This may change the size of IP header. */
1133f0f93429SDag-Erling Smørgrav 		if (proxy_type != 0) {
1134ed01a582SDag-Erling Smørgrav 			SetProxyPort(lnk, dest_port);
1135ed01a582SDag-Erling Smørgrav 			SetProxyAddress(lnk, dest_address);
1136ed01a582SDag-Erling Smørgrav 			ProxyModify(la, lnk, pip, maxpacketsize, proxy_type);
11379fa0fd26SDag-Erling Smørgrav 			tc = (struct tcphdr *)ip_next(pip);
11387d96f4efSBrian Somers 		}
11397d96f4efSBrian Somers 		/* Get alias address and port */
1140ed01a582SDag-Erling Smørgrav 		alias_port = GetAliasPort(lnk);
1141ed01a582SDag-Erling Smørgrav 		alias_address = GetAliasAddress(lnk);
11423b160b8bSBrian Somers 
1143483d2f22SRuslan Ermilov 		/* Monitor TCP connection state */
11444741f3a1SPaolo Pisati 		tc = (struct tcphdr *)ip_next(pip);
1145*0fc7bdc9SRichard Scheffenegger 		TcpMonitorOut(__tcp_get_flags(tc), lnk);
11463b160b8bSBrian Somers 
1147be4f3cd0SPaolo Pisati 		/* Walk out chain. */
11486454d0c8SJohn Baldwin 		find_handler(OUT, TCP, la, pip, &ad);
11493b160b8bSBrian Somers 
1150effc8e57SLutz Donnerhacke 		/* Adjust TCP checksum since source port is being aliased
1151effc8e57SLutz Donnerhacke 		 * and source address is being altered */
11523b160b8bSBrian Somers 		accumulate = tc->th_sport;
11537d96f4efSBrian Somers 		tc->th_sport = alias_port;
11547d96f4efSBrian Somers 		accumulate -= tc->th_sport;
11552871c501SDag-Erling Smørgrav 		accumulate += twowords(&pip->ip_src);
11562871c501SDag-Erling Smørgrav 		accumulate -= twowords(&alias_address);
11573b160b8bSBrian Somers 
11583b160b8bSBrian Somers 		/* Modify sequence number if necessary */
1159ed01a582SDag-Erling Smørgrav 		if (GetAckModified(lnk) == 1) {
11603b160b8bSBrian Somers 			int delta;
11613b160b8bSBrian Somers 
11624741f3a1SPaolo Pisati 			tc = (struct tcphdr *)ip_next(pip);
11634741f3a1SPaolo Pisati 			delta = GetDeltaSeqOut(tc->th_seq, lnk);
1164f0f93429SDag-Erling Smørgrav 			if (delta != 0) {
11652871c501SDag-Erling Smørgrav 				accumulate += twowords(&tc->th_seq);
11663b160b8bSBrian Somers 				tc->th_seq = htonl(ntohl(tc->th_seq) + delta);
11672871c501SDag-Erling Smørgrav 				accumulate -= twowords(&tc->th_seq);
11683b160b8bSBrian Somers 			}
11693b160b8bSBrian Somers 		}
117071593f95SBrian Somers 		ADJUST_CHECKSUM(accumulate, tc->th_sum);
11713b160b8bSBrian Somers 
11723b160b8bSBrian Somers 		/* Change source address */
11732871c501SDag-Erling Smørgrav 		accumulate = twowords(&pip->ip_src);
11743b160b8bSBrian Somers 		pip->ip_src = alias_address;
11752871c501SDag-Erling Smørgrav 		accumulate -= twowords(&pip->ip_src);
117671593f95SBrian Somers 		ADJUST_CHECKSUM(accumulate, pip->ip_sum);
11773b160b8bSBrian Somers 
11783b160b8bSBrian Somers 		return (PKT_ALIAS_OK);
11793b160b8bSBrian Somers 	}
11803b160b8bSBrian Somers 	return (PKT_ALIAS_IGNORED);
11813b160b8bSBrian Somers }
11823b160b8bSBrian Somers 
11833b160b8bSBrian Somers /* Fragment Handling
11843b160b8bSBrian Somers 
11853b160b8bSBrian Somers     FragmentIn()
11863b160b8bSBrian Somers     FragmentOut()
11873b160b8bSBrian Somers 
11883b160b8bSBrian Somers The packet aliasing module has a limited ability for handling IP
11893b160b8bSBrian Somers fragments.  If the ICMP, TCP or UDP header is in the first fragment
1190483d2f22SRuslan Ermilov received, then the ID number of the IP packet is saved, and other
11913b160b8bSBrian Somers fragments are identified according to their ID number and IP address
11923b160b8bSBrian Somers they were sent from.  Pointers to unresolved fragments can also be
11933b160b8bSBrian Somers saved and recalled when a header fragment is seen.
11943b160b8bSBrian Somers */
11953b160b8bSBrian Somers 
11963b160b8bSBrian Somers /* Local prototypes */
1197ab0fcfd0SPaolo Pisati static int	FragmentIn(struct libalias *la, struct in_addr ip_src,
1198bc596e56SAlex Richardson 		    struct ip *pip, u_short ip_id, u_short *ip_sum);
1199bc596e56SAlex Richardson static int	FragmentOut(struct libalias *, struct ip *pip,
1200ab0fcfd0SPaolo Pisati 		    u_short *ip_sum);
12013b160b8bSBrian Somers 
12023b160b8bSBrian Somers static int
FragmentIn(struct libalias * la,struct in_addr ip_src,struct ip * pip,u_short ip_id,u_short * ip_sum)1203bc596e56SAlex Richardson FragmentIn(struct libalias *la, struct in_addr ip_src, struct ip *pip,
1204aac54f0aSAlexander Motin     u_short ip_id, u_short *ip_sum)
12053b160b8bSBrian Somers {
1206ed01a582SDag-Erling Smørgrav 	struct alias_link *lnk;
12073b160b8bSBrian Somers 
1208ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK_ASSERT(la);
1209bc596e56SAlex Richardson 	lnk = FindFragmentIn2(la, ip_src, pip->ip_dst, ip_id);
1210ed01a582SDag-Erling Smørgrav 	if (lnk != NULL) {
12113b160b8bSBrian Somers 		struct in_addr original_address;
12123b160b8bSBrian Somers 
1213ed01a582SDag-Erling Smørgrav 		GetFragmentAddr(lnk, &original_address);
1214ab0fcfd0SPaolo Pisati 		DifferentialChecksum(ip_sum,
1215bc596e56SAlex Richardson 		    &original_address, &pip->ip_dst, 2);
1216bc596e56SAlex Richardson 		pip->ip_dst = original_address;
12173b160b8bSBrian Somers 
12183b160b8bSBrian Somers 		return (PKT_ALIAS_OK);
12193b160b8bSBrian Somers 	}
12203b160b8bSBrian Somers 	return (PKT_ALIAS_UNRESOLVED_FRAGMENT);
12213b160b8bSBrian Somers }
12223b160b8bSBrian Somers 
12233b160b8bSBrian Somers static int
FragmentOut(struct libalias * la,struct ip * pip,u_short * ip_sum)1224bc596e56SAlex Richardson FragmentOut(struct libalias *la, struct ip *pip, u_short *ip_sum)
12253b160b8bSBrian Somers {
12263b160b8bSBrian Somers 	struct in_addr alias_address;
12273b160b8bSBrian Somers 
1228ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK_ASSERT(la);
1229bc596e56SAlex Richardson 	alias_address = FindAliasAddress(la, pip->ip_src);
1230ab0fcfd0SPaolo Pisati 	DifferentialChecksum(ip_sum,
1231bc596e56SAlex Richardson 	    &alias_address, &pip->ip_src, 2);
1232bc596e56SAlex Richardson 	pip->ip_src = alias_address;
12333b160b8bSBrian Somers 
12343b160b8bSBrian Somers 	return (PKT_ALIAS_OK);
12353b160b8bSBrian Somers }
12363b160b8bSBrian Somers 
12373b160b8bSBrian Somers /* Outside World Access
12383b160b8bSBrian Somers 
12393efa11bbSBrian Somers 	PacketAliasSaveFragment()
12403efa11bbSBrian Somers 	PacketAliasGetFragment()
12413efa11bbSBrian Somers 	PacketAliasFragmentIn()
12423b160b8bSBrian Somers 	PacketAliasIn()
12433b160b8bSBrian Somers 	PacketAliasOut()
1244642e43b3SArchie Cobbs 	PacketUnaliasOut()
12453b160b8bSBrian Somers 
12463b160b8bSBrian Somers (prototypes in alias.h)
12473b160b8bSBrian Somers */
12483b160b8bSBrian Somers 
12493b160b8bSBrian Somers int
LibAliasSaveFragment(struct libalias * la,void * ptr)1250bc596e56SAlex Richardson LibAliasSaveFragment(struct libalias *la, void *ptr)
12513b160b8bSBrian Somers {
12523b160b8bSBrian Somers 	int iresult;
1253ed01a582SDag-Erling Smørgrav 	struct alias_link *lnk;
12543b160b8bSBrian Somers 	struct ip *pip;
12553b160b8bSBrian Somers 
1256ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK(la);
12573b160b8bSBrian Somers 	pip = (struct ip *)ptr;
1258ed01a582SDag-Erling Smørgrav 	lnk = AddFragmentPtrLink(la, pip->ip_src, pip->ip_id);
12593b160b8bSBrian Somers 	iresult = PKT_ALIAS_ERROR;
1260ed01a582SDag-Erling Smørgrav 	if (lnk != NULL) {
1261ed01a582SDag-Erling Smørgrav 		SetFragmentPtr(lnk, ptr);
12623b160b8bSBrian Somers 		iresult = PKT_ALIAS_OK;
12633b160b8bSBrian Somers 	}
1264ccd57eeaSPaolo Pisati 	LIBALIAS_UNLOCK(la);
12653b160b8bSBrian Somers 	return (iresult);
12663b160b8bSBrian Somers }
12673b160b8bSBrian Somers 
1268bc596e56SAlex Richardson void *
LibAliasGetFragment(struct libalias * la,void * ptr)1269bc596e56SAlex Richardson LibAliasGetFragment(struct libalias *la, void *ptr)
12703b160b8bSBrian Somers {
1271ed01a582SDag-Erling Smørgrav 	struct alias_link *lnk;
1272bc596e56SAlex Richardson 	void *fptr;
12733b160b8bSBrian Somers 	struct ip *pip;
12743b160b8bSBrian Somers 
1275ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK(la);
12763b160b8bSBrian Somers 	pip = (struct ip *)ptr;
1277ed01a582SDag-Erling Smørgrav 	lnk = FindFragmentPtr(la, pip->ip_src, pip->ip_id);
1278ed01a582SDag-Erling Smørgrav 	if (lnk != NULL) {
1279ed01a582SDag-Erling Smørgrav 		GetFragmentPtr(lnk, &fptr);
1280ed01a582SDag-Erling Smørgrav 		SetFragmentPtr(lnk, NULL);
1281ed01a582SDag-Erling Smørgrav 		SetExpire(lnk, 0);	/* Deletes link */
1282ccd57eeaSPaolo Pisati 	} else
1283ccd57eeaSPaolo Pisati 		fptr = NULL;
12843b160b8bSBrian Somers 
1285ccd57eeaSPaolo Pisati 	LIBALIAS_UNLOCK(la);
12863b160b8bSBrian Somers 	return (fptr);
12873b160b8bSBrian Somers }
12883b160b8bSBrian Somers 
12893b160b8bSBrian Somers void
LibAliasFragmentIn(struct libalias * la,void * ptr,void * ptr_fragment)1290effc8e57SLutz Donnerhacke LibAliasFragmentIn(struct libalias *la,
1291effc8e57SLutz Donnerhacke     void *ptr,	/* Points to correctly de-aliased header fragment */
1292effc8e57SLutz Donnerhacke     void *ptr_fragment	/* fragment which must be de-aliased   */
12933b160b8bSBrian Somers )
12943b160b8bSBrian Somers {
12953b160b8bSBrian Somers 	struct ip *pip;
12963b160b8bSBrian Somers 	struct ip *fpip;
12973b160b8bSBrian Somers 
1298ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK(la);
1299ed01a582SDag-Erling Smørgrav 	(void)la;
13003b160b8bSBrian Somers 	pip = (struct ip *)ptr;
13013b160b8bSBrian Somers 	fpip = (struct ip *)ptr_fragment;
13023b160b8bSBrian Somers 
13033b160b8bSBrian Somers 	DifferentialChecksum(&fpip->ip_sum,
13042871c501SDag-Erling Smørgrav 	    &pip->ip_dst, &fpip->ip_dst, 2);
13053b160b8bSBrian Somers 	fpip->ip_dst = pip->ip_dst;
1306ccd57eeaSPaolo Pisati 	LIBALIAS_UNLOCK(la);
13073b160b8bSBrian Somers }
13083b160b8bSBrian Somers 
1309ccd57eeaSPaolo Pisati /* Local prototypes */
1310ccd57eeaSPaolo Pisati static int
1311bc596e56SAlex Richardson LibAliasOutLocked(struct libalias *la, struct ip *pip,
1312ccd57eeaSPaolo Pisati     int maxpacketsize, int create);
1313ccd57eeaSPaolo Pisati static int
1314bc596e56SAlex Richardson LibAliasInLocked(struct libalias *la, struct ip *pip,
1315ccd57eeaSPaolo Pisati     int maxpacketsize);
13163b160b8bSBrian Somers 
13173b160b8bSBrian Somers int
LibAliasIn(struct libalias * la,void * ptr,int maxpacketsize)1318bc596e56SAlex Richardson LibAliasIn(struct libalias *la, void *ptr, int maxpacketsize)
13193b160b8bSBrian Somers {
1320ccd57eeaSPaolo Pisati 	int res;
1321ccd57eeaSPaolo Pisati 
1322ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK(la);
1323bc596e56SAlex Richardson 	res = LibAliasInLocked(la, (struct ip *)ptr, maxpacketsize);
1324ccd57eeaSPaolo Pisati 	LIBALIAS_UNLOCK(la);
1325ccd57eeaSPaolo Pisati 	return (res);
1326ccd57eeaSPaolo Pisati }
1327ccd57eeaSPaolo Pisati 
1328ccd57eeaSPaolo Pisati static int
LibAliasInLocked(struct libalias * la,struct ip * pip,int maxpacketsize)1329bc596e56SAlex Richardson LibAliasInLocked(struct libalias *la, struct ip *pip, int maxpacketsize)
1330ccd57eeaSPaolo Pisati {
13313b160b8bSBrian Somers 	struct in_addr alias_addr;
13323b160b8bSBrian Somers 	int iresult;
13333b160b8bSBrian Somers 
13345e289f9eSPoul-Henning Kamp 	if (la->packetAliasMode & PKT_ALIAS_REVERSE) {
13355e289f9eSPoul-Henning Kamp 		la->packetAliasMode &= ~PKT_ALIAS_REVERSE;
1336bc596e56SAlex Richardson 		iresult = LibAliasOutLocked(la, pip, maxpacketsize, 1);
13375e289f9eSPoul-Henning Kamp 		la->packetAliasMode |= PKT_ALIAS_REVERSE;
1338ccd57eeaSPaolo Pisati 		goto getout;
13390622eafcSBrian Somers 	}
13405e289f9eSPoul-Henning Kamp 	HouseKeeping(la);
13413b160b8bSBrian Somers 	alias_addr = pip->ip_dst;
13423b160b8bSBrian Somers 
13438ddc51bcSEivind Eklund 	/* Defense against mangled packets */
13448ddc51bcSEivind Eklund 	if (ntohs(pip->ip_len) > maxpacketsize
1345ccd57eeaSPaolo Pisati 	    || (pip->ip_hl << 2) > maxpacketsize) {
1346ccd57eeaSPaolo Pisati 		iresult = PKT_ALIAS_IGNORED;
1347ccd57eeaSPaolo Pisati 		goto getout;
1348ccd57eeaSPaolo Pisati 	}
13498ddc51bcSEivind Eklund 
1350461e6f23SMaxim Sobolev 	if (FRAG_NO_HDR(pip)) {
1351461e6f23SMaxim Sobolev 		iresult = FragmentIn(la, pip->ip_src, pip, pip->ip_id,
1352461e6f23SMaxim Sobolev 		    &pip->ip_sum);
1353461e6f23SMaxim Sobolev 		goto getout;
1354461e6f23SMaxim Sobolev 	}
1355461e6f23SMaxim Sobolev 
13563b160b8bSBrian Somers 	iresult = PKT_ALIAS_IGNORED;
1357f0f93429SDag-Erling Smørgrav 	switch (pip->ip_p) {
13583b160b8bSBrian Somers 	case IPPROTO_ICMP:
13595e289f9eSPoul-Henning Kamp 		iresult = IcmpAliasIn(la, pip);
13603b160b8bSBrian Somers 		break;
13613b160b8bSBrian Somers 	case IPPROTO_UDP:
13625e289f9eSPoul-Henning Kamp 		iresult = UdpAliasIn(la, pip);
13633b160b8bSBrian Somers 		break;
13643b160b8bSBrian Somers 	case IPPROTO_TCP:
13655e289f9eSPoul-Henning Kamp 		iresult = TcpAliasIn(la, pip);
13663b160b8bSBrian Somers 		break;
136737ce2656SPaolo Pisati #ifdef _KERNEL
136837ce2656SPaolo Pisati 	case IPPROTO_SCTP:
136937ce2656SPaolo Pisati 		iresult = SctpAlias(la, pip, SN_TO_LOCAL);
137037ce2656SPaolo Pisati 		break;
137137ce2656SPaolo Pisati #endif
1372be4f3cd0SPaolo Pisati 	case IPPROTO_GRE: {
1373be4f3cd0SPaolo Pisati 		int error;
1374be4f3cd0SPaolo Pisati 		struct alias_data ad = {
1375be4f3cd0SPaolo Pisati 			.lnk = NULL,
1376be4f3cd0SPaolo Pisati 			.oaddr = NULL,
1377be4f3cd0SPaolo Pisati 			.aaddr = NULL,
1378be4f3cd0SPaolo Pisati 			.aport = NULL,
1379be4f3cd0SPaolo Pisati 			.sport = NULL,
1380be4f3cd0SPaolo Pisati 			.dport = NULL,
1381be4f3cd0SPaolo Pisati 			.maxpktsize = 0
1382be4f3cd0SPaolo Pisati 		};
1383be4f3cd0SPaolo Pisati 
1384be4f3cd0SPaolo Pisati 		/* Walk out chain. */
1385be4f3cd0SPaolo Pisati 		error = find_handler(IN, IP, la, pip, &ad);
1386be4f3cd0SPaolo Pisati 		if (error == 0)
138703453c5eSRuslan Ermilov 			iresult = PKT_ALIAS_OK;
138803453c5eSRuslan Ermilov 		else
1389ab0fcfd0SPaolo Pisati 			iresult = ProtoAliasIn(la, pip->ip_src,
1390bc596e56SAlex Richardson 			    pip, pip->ip_p, &pip->ip_sum);
139155a39fc5SRuslan Ermilov 		break;
1392effc8e57SLutz Donnerhacke 	}
139380607605SRuslan Ermilov 	default:
1394bc596e56SAlex Richardson 		iresult = ProtoAliasIn(la, pip->ip_src, pip,
1395ab0fcfd0SPaolo Pisati 		    pip->ip_p, &pip->ip_sum);
13967d96f4efSBrian Somers 		break;
13973b160b8bSBrian Somers 	}
13983b160b8bSBrian Somers 
1399461e6f23SMaxim Sobolev 	if (MF_ISSET(pip)) {
1400ed01a582SDag-Erling Smørgrav 		struct alias_link *lnk;
14013b160b8bSBrian Somers 
1402ed01a582SDag-Erling Smørgrav 		lnk = FindFragmentIn1(la, pip->ip_src, alias_addr, pip->ip_id);
1403ed01a582SDag-Erling Smørgrav 		if (lnk != NULL) {
14043b160b8bSBrian Somers 			iresult = PKT_ALIAS_FOUND_HEADER_FRAGMENT;
1405ed01a582SDag-Erling Smørgrav 			SetFragmentAddr(lnk, pip->ip_dst);
1406f0f93429SDag-Erling Smørgrav 		} else {
14073b160b8bSBrian Somers 			iresult = PKT_ALIAS_ERROR;
14083b160b8bSBrian Somers 		}
14093b160b8bSBrian Somers 	}
14103b160b8bSBrian Somers 
1411ccd57eeaSPaolo Pisati getout:
14123b160b8bSBrian Somers 	return (iresult);
14133b160b8bSBrian Somers }
14143b160b8bSBrian Somers 
14153b160b8bSBrian Somers /* Unregistered address ranges */
14163b160b8bSBrian Somers 
14173b160b8bSBrian Somers /* 10.0.0.0   ->   10.255.255.255 */
14183b160b8bSBrian Somers #define UNREG_ADDR_A_LOWER 0x0a000000
14193b160b8bSBrian Somers #define UNREG_ADDR_A_UPPER 0x0affffff
14203b160b8bSBrian Somers 
14213b160b8bSBrian Somers /* 172.16.0.0  ->  172.31.255.255 */
14223b160b8bSBrian Somers #define UNREG_ADDR_B_LOWER 0xac100000
14233b160b8bSBrian Somers #define UNREG_ADDR_B_UPPER 0xac1fffff
14243b160b8bSBrian Somers 
14253b160b8bSBrian Somers /* 192.168.0.0 -> 192.168.255.255 */
14263b160b8bSBrian Somers #define UNREG_ADDR_C_LOWER 0xc0a80000
14273b160b8bSBrian Somers #define UNREG_ADDR_C_UPPER 0xc0a8ffff
14283b160b8bSBrian Somers 
142975b89337SAlexander V. Chernikov /* 100.64.0.0  -> 100.127.255.255 (RFC 6598 - Carrier Grade NAT) */
143075b89337SAlexander V. Chernikov #define UNREG_ADDR_CGN_LOWER 0x64400000
143175b89337SAlexander V. Chernikov #define UNREG_ADDR_CGN_UPPER 0x647fffff
143275b89337SAlexander V. Chernikov 
14333b160b8bSBrian Somers int
LibAliasOut(struct libalias * la,void * ptr,int maxpacketsize)1434bc596e56SAlex Richardson LibAliasOut(struct libalias *la, void *ptr, int maxpacketsize)
14353b160b8bSBrian Somers {
1436ccd57eeaSPaolo Pisati 	int res;
1437ccd57eeaSPaolo Pisati 
1438ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK(la);
1439bc596e56SAlex Richardson 	res = LibAliasOutLocked(la, (struct ip *)ptr, maxpacketsize, 1);
1440ccd57eeaSPaolo Pisati 	LIBALIAS_UNLOCK(la);
1441ccd57eeaSPaolo Pisati 	return (res);
1442e6bbb691SPoul-Henning Kamp }
1443e6bbb691SPoul-Henning Kamp 
1444e6bbb691SPoul-Henning Kamp int
LibAliasOutTry(struct libalias * la,void * ptr,int maxpacketsize,int create)1445bc596e56SAlex Richardson LibAliasOutTry(struct libalias *la, void *ptr, int maxpacketsize, int create)
1446ccd57eeaSPaolo Pisati {
1447ccd57eeaSPaolo Pisati 	int res;
1448ccd57eeaSPaolo Pisati 
1449ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK(la);
1450bc596e56SAlex Richardson 	res = LibAliasOutLocked(la, (struct ip *)ptr, maxpacketsize, create);
1451ccd57eeaSPaolo Pisati 	LIBALIAS_UNLOCK(la);
1452ccd57eeaSPaolo Pisati 	return (res);
1453ccd57eeaSPaolo Pisati }
1454ccd57eeaSPaolo Pisati 
1455ccd57eeaSPaolo Pisati static int
LibAliasOutLocked(struct libalias * la,struct ip * pip,int maxpacketsize,int create)1456effc8e57SLutz Donnerhacke LibAliasOutLocked(struct libalias *la,
1457effc8e57SLutz Donnerhacke     struct ip *pip,	/* valid IP packet */
1458effc8e57SLutz Donnerhacke     int maxpacketsize,	/* How much the packet data may grow (FTP and IRC inline changes) */
1459e6bbb691SPoul-Henning Kamp     int create		/* Create new entries ? */
1460e6bbb691SPoul-Henning Kamp )
1461e6bbb691SPoul-Henning Kamp {
14623b160b8bSBrian Somers 	int iresult;
14633b160b8bSBrian Somers 	struct in_addr addr_save;
14643b160b8bSBrian Somers 
14655e289f9eSPoul-Henning Kamp 	if (la->packetAliasMode & PKT_ALIAS_REVERSE) {
14665e289f9eSPoul-Henning Kamp 		la->packetAliasMode &= ~PKT_ALIAS_REVERSE;
1467bc596e56SAlex Richardson 		iresult = LibAliasInLocked(la, pip, maxpacketsize);
14685e289f9eSPoul-Henning Kamp 		la->packetAliasMode |= PKT_ALIAS_REVERSE;
1469ccd57eeaSPaolo Pisati 		goto getout;
14700622eafcSBrian Somers 	}
14715e289f9eSPoul-Henning Kamp 	HouseKeeping(la);
14723b160b8bSBrian Somers 
14738ddc51bcSEivind Eklund 	/* Defense against mangled packets */
14748ddc51bcSEivind Eklund 	if (ntohs(pip->ip_len) > maxpacketsize
1475ccd57eeaSPaolo Pisati 	    || (pip->ip_hl << 2) > maxpacketsize) {
1476ccd57eeaSPaolo Pisati 		iresult = PKT_ALIAS_IGNORED;
1477ccd57eeaSPaolo Pisati 		goto getout;
1478ccd57eeaSPaolo Pisati 	}
14798ddc51bcSEivind Eklund 
14805e289f9eSPoul-Henning Kamp 	addr_save = GetDefaultAliasAddress(la);
148175b89337SAlexander V. Chernikov 	if (la->packetAliasMode & PKT_ALIAS_UNREGISTERED_ONLY ||
148275b89337SAlexander V. Chernikov 	    la->packetAliasMode & PKT_ALIAS_UNREGISTERED_CGN) {
1483483d2f22SRuslan Ermilov 		u_long addr;
14843b160b8bSBrian Somers 		int iclass;
14853b160b8bSBrian Somers 
14863b160b8bSBrian Somers 		iclass = 0;
14873b160b8bSBrian Somers 		addr = ntohl(pip->ip_src.s_addr);
14883b160b8bSBrian Somers 		if (addr >= UNREG_ADDR_C_LOWER && addr <= UNREG_ADDR_C_UPPER)
14893b160b8bSBrian Somers 			iclass = 3;
14903b160b8bSBrian Somers 		else if (addr >= UNREG_ADDR_B_LOWER && addr <= UNREG_ADDR_B_UPPER)
14913b160b8bSBrian Somers 			iclass = 2;
14923b160b8bSBrian Somers 		else if (addr >= UNREG_ADDR_A_LOWER && addr <= UNREG_ADDR_A_UPPER)
14933b160b8bSBrian Somers 			iclass = 1;
149475b89337SAlexander V. Chernikov 		else if (addr >= UNREG_ADDR_CGN_LOWER && addr <= UNREG_ADDR_CGN_UPPER &&
149575b89337SAlexander V. Chernikov 		    la->packetAliasMode & PKT_ALIAS_UNREGISTERED_CGN)
149675b89337SAlexander V. Chernikov 			iclass = 4;
14973b160b8bSBrian Somers 
1498f0f93429SDag-Erling Smørgrav 		if (iclass == 0) {
14995e289f9eSPoul-Henning Kamp 			SetDefaultAliasAddress(la, pip->ip_src);
15003b160b8bSBrian Somers 		}
1501f0f93429SDag-Erling Smørgrav 	} else if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY) {
15025e289f9eSPoul-Henning Kamp 		SetDefaultAliasAddress(la, pip->ip_src);
1503ada24e69SRuslan Ermilov 	}
1504461e6f23SMaxim Sobolev 
1505461e6f23SMaxim Sobolev 	if (FRAG_NO_HDR(pip)) {
1506461e6f23SMaxim Sobolev 		iresult = FragmentOut(la, pip, &pip->ip_sum);
1507461e6f23SMaxim Sobolev 		goto getout_restore;
1508461e6f23SMaxim Sobolev 	}
1509461e6f23SMaxim Sobolev 
15103b160b8bSBrian Somers 	iresult = PKT_ALIAS_IGNORED;
1511f0f93429SDag-Erling Smørgrav 	switch (pip->ip_p) {
15123b160b8bSBrian Somers 	case IPPROTO_ICMP:
1513e6bbb691SPoul-Henning Kamp 		iresult = IcmpAliasOut(la, pip, create);
15143b160b8bSBrian Somers 		break;
15153b160b8bSBrian Somers 	case IPPROTO_UDP:
1516ea29dd92SAlexander Motin 		iresult = UdpAliasOut(la, pip, maxpacketsize, create);
15173b160b8bSBrian Somers 		break;
15183b160b8bSBrian Somers 	case IPPROTO_TCP:
1519e6bbb691SPoul-Henning Kamp 		iresult = TcpAliasOut(la, pip, maxpacketsize, create);
15203b160b8bSBrian Somers 		break;
152137ce2656SPaolo Pisati #ifdef _KERNEL
152237ce2656SPaolo Pisati 	case IPPROTO_SCTP:
152337ce2656SPaolo Pisati 		iresult = SctpAlias(la, pip, SN_TO_GLOBAL);
152437ce2656SPaolo Pisati 		break;
152537ce2656SPaolo Pisati #endif
1526be4f3cd0SPaolo Pisati 	case IPPROTO_GRE: {
1527be4f3cd0SPaolo Pisati 		int error;
1528be4f3cd0SPaolo Pisati 		struct alias_data ad = {
1529be4f3cd0SPaolo Pisati 			.lnk = NULL,
1530be4f3cd0SPaolo Pisati 			.oaddr = NULL,
1531be4f3cd0SPaolo Pisati 			.aaddr = NULL,
1532be4f3cd0SPaolo Pisati 			.aport = NULL,
1533be4f3cd0SPaolo Pisati 			.sport = NULL,
1534be4f3cd0SPaolo Pisati 			.dport = NULL,
1535be4f3cd0SPaolo Pisati 			.maxpktsize = 0
1536be4f3cd0SPaolo Pisati 		};
1537be4f3cd0SPaolo Pisati 		/* Walk out chain. */
1538be4f3cd0SPaolo Pisati 		error = find_handler(OUT, IP, la, pip, &ad);
1539be4f3cd0SPaolo Pisati 		if (error == 0)
154003453c5eSRuslan Ermilov 			iresult = PKT_ALIAS_OK;
154103453c5eSRuslan Ermilov 		else
1542bc596e56SAlex Richardson 			iresult = ProtoAliasOut(la, pip,
1543ab0fcfd0SPaolo Pisati 			    pip->ip_dst, pip->ip_p, &pip->ip_sum, create);
154403453c5eSRuslan Ermilov 		break;
1545effc8e57SLutz Donnerhacke 		}
154680607605SRuslan Ermilov 	default:
1547bc596e56SAlex Richardson 		iresult = ProtoAliasOut(la, pip,
1548ab0fcfd0SPaolo Pisati 		    pip->ip_dst, pip->ip_p, &pip->ip_sum, create);
15497d96f4efSBrian Somers 		break;
15503b160b8bSBrian Somers 	}
15513b160b8bSBrian Somers 
1552461e6f23SMaxim Sobolev getout_restore:
15535e289f9eSPoul-Henning Kamp 	SetDefaultAliasAddress(la, addr_save);
1554ccd57eeaSPaolo Pisati getout:
15553b160b8bSBrian Somers 	return (iresult);
15563b160b8bSBrian Somers }
1557642e43b3SArchie Cobbs 
1558642e43b3SArchie Cobbs int
LibAliasUnaliasOut(struct libalias * la,void * ptr,int maxpacketsize)1559effc8e57SLutz Donnerhacke LibAliasUnaliasOut(struct libalias *la,
1560effc8e57SLutz Donnerhacke     void *ptr,		/* valid IP packet */
1561642e43b3SArchie Cobbs     int maxpacketsize	/* for error checking */
1562642e43b3SArchie Cobbs )
1563642e43b3SArchie Cobbs {
1564642e43b3SArchie Cobbs 	struct ip *pip;
1565642e43b3SArchie Cobbs 	struct icmp *ic;
1566642e43b3SArchie Cobbs 	struct udphdr *ud;
1567642e43b3SArchie Cobbs 	struct tcphdr *tc;
1568ed01a582SDag-Erling Smørgrav 	struct alias_link *lnk;
1569642e43b3SArchie Cobbs 	int iresult = PKT_ALIAS_IGNORED;
1570642e43b3SArchie Cobbs 
1571ccd57eeaSPaolo Pisati 	LIBALIAS_LOCK(la);
1572642e43b3SArchie Cobbs 	pip = (struct ip *)ptr;
1573642e43b3SArchie Cobbs 
1574642e43b3SArchie Cobbs 	/* Defense against mangled packets */
1575642e43b3SArchie Cobbs 	if (ntohs(pip->ip_len) > maxpacketsize
1576642e43b3SArchie Cobbs 	    || (pip->ip_hl << 2) > maxpacketsize)
1577ccd57eeaSPaolo Pisati 		goto getout;
1578642e43b3SArchie Cobbs 
15799fa0fd26SDag-Erling Smørgrav 	ud = (struct udphdr *)ip_next(pip);
15809fa0fd26SDag-Erling Smørgrav 	tc = (struct tcphdr *)ip_next(pip);
15819fa0fd26SDag-Erling Smørgrav 	ic = (struct icmp *)ip_next(pip);
1582642e43b3SArchie Cobbs 
1583642e43b3SArchie Cobbs 	/* Find a link */
1584642e43b3SArchie Cobbs 	if (pip->ip_p == IPPROTO_UDP)
1585ed01a582SDag-Erling Smørgrav 		lnk = FindUdpTcpIn(la, pip->ip_dst, pip->ip_src,
1586642e43b3SArchie Cobbs 		    ud->uh_dport, ud->uh_sport,
1587642cd09fSRuslan Ermilov 		    IPPROTO_UDP, 0);
1588642e43b3SArchie Cobbs 	else if (pip->ip_p == IPPROTO_TCP)
1589ed01a582SDag-Erling Smørgrav 		lnk = FindUdpTcpIn(la, pip->ip_dst, pip->ip_src,
1590642e43b3SArchie Cobbs 		    tc->th_dport, tc->th_sport,
1591642cd09fSRuslan Ermilov 		    IPPROTO_TCP, 0);
1592642e43b3SArchie Cobbs 	else if (pip->ip_p == IPPROTO_ICMP)
1593ed01a582SDag-Erling Smørgrav 		lnk = FindIcmpIn(la, pip->ip_dst, pip->ip_src, ic->icmp_id, 0);
1594642e43b3SArchie Cobbs 	else
1595ed01a582SDag-Erling Smørgrav 		lnk = NULL;
1596642e43b3SArchie Cobbs 
1597642e43b3SArchie Cobbs 	/* Change it from an aliased packet to an unaliased packet */
1598ed01a582SDag-Erling Smørgrav 	if (lnk != NULL) {
1599f0f93429SDag-Erling Smørgrav 		if (pip->ip_p == IPPROTO_UDP || pip->ip_p == IPPROTO_TCP) {
1600642e43b3SArchie Cobbs 			int accumulate;
1601642e43b3SArchie Cobbs 			struct in_addr original_address;
1602642e43b3SArchie Cobbs 			u_short original_port;
1603642e43b3SArchie Cobbs 
1604ed01a582SDag-Erling Smørgrav 			original_address = GetOriginalAddress(lnk);
1605ed01a582SDag-Erling Smørgrav 			original_port = GetOriginalPort(lnk);
1606642e43b3SArchie Cobbs 
1607642e43b3SArchie Cobbs 			/* Adjust TCP/UDP checksum */
16082871c501SDag-Erling Smørgrav 			accumulate = twowords(&pip->ip_src);
16092871c501SDag-Erling Smørgrav 			accumulate -= twowords(&original_address);
1610642e43b3SArchie Cobbs 
1611642e43b3SArchie Cobbs 			if (pip->ip_p == IPPROTO_UDP) {
1612642e43b3SArchie Cobbs 				accumulate += ud->uh_sport;
1613642e43b3SArchie Cobbs 				accumulate -= original_port;
161471593f95SBrian Somers 				ADJUST_CHECKSUM(accumulate, ud->uh_sum);
1615642e43b3SArchie Cobbs 			} else {
1616642e43b3SArchie Cobbs 				accumulate += tc->th_sport;
1617642e43b3SArchie Cobbs 				accumulate -= original_port;
161871593f95SBrian Somers 				ADJUST_CHECKSUM(accumulate, tc->th_sum);
1619642e43b3SArchie Cobbs 			}
1620642e43b3SArchie Cobbs 
1621642e43b3SArchie Cobbs 			/* Adjust IP checksum */
1622642e43b3SArchie Cobbs 			DifferentialChecksum(&pip->ip_sum,
16232871c501SDag-Erling Smørgrav 			    &original_address, &pip->ip_src, 2);
1624642e43b3SArchie Cobbs 
1625642e43b3SArchie Cobbs 			/* Un-alias source address and port number */
1626642e43b3SArchie Cobbs 			pip->ip_src = original_address;
1627642e43b3SArchie Cobbs 			if (pip->ip_p == IPPROTO_UDP)
1628642e43b3SArchie Cobbs 				ud->uh_sport = original_port;
1629642e43b3SArchie Cobbs 			else
1630642e43b3SArchie Cobbs 				tc->th_sport = original_port;
1631642e43b3SArchie Cobbs 
1632642e43b3SArchie Cobbs 			iresult = PKT_ALIAS_OK;
1633642e43b3SArchie Cobbs 		} else if (pip->ip_p == IPPROTO_ICMP) {
1634642e43b3SArchie Cobbs 			int accumulate;
1635642e43b3SArchie Cobbs 			struct in_addr original_address;
1636642e43b3SArchie Cobbs 			u_short original_id;
1637642e43b3SArchie Cobbs 
1638ed01a582SDag-Erling Smørgrav 			original_address = GetOriginalAddress(lnk);
1639ed01a582SDag-Erling Smørgrav 			original_id = GetOriginalPort(lnk);
1640642e43b3SArchie Cobbs 
1641642e43b3SArchie Cobbs 			/* Adjust ICMP checksum */
16422871c501SDag-Erling Smørgrav 			accumulate = twowords(&pip->ip_src);
16432871c501SDag-Erling Smørgrav 			accumulate -= twowords(&original_address);
1644642e43b3SArchie Cobbs 			accumulate += ic->icmp_id;
1645642e43b3SArchie Cobbs 			accumulate -= original_id;
164671593f95SBrian Somers 			ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
1647642e43b3SArchie Cobbs 
1648642e43b3SArchie Cobbs 			/* Adjust IP checksum */
1649642e43b3SArchie Cobbs 			DifferentialChecksum(&pip->ip_sum,
16502871c501SDag-Erling Smørgrav 			    &original_address, &pip->ip_src, 2);
1651642e43b3SArchie Cobbs 
1652642e43b3SArchie Cobbs 			/* Un-alias source address and port number */
1653642e43b3SArchie Cobbs 			pip->ip_src = original_address;
1654642e43b3SArchie Cobbs 			ic->icmp_id = original_id;
1655642e43b3SArchie Cobbs 
1656642e43b3SArchie Cobbs 			iresult = PKT_ALIAS_OK;
1657642e43b3SArchie Cobbs 		}
1658642e43b3SArchie Cobbs 	}
1659ccd57eeaSPaolo Pisati getout:
1660ccd57eeaSPaolo Pisati 	LIBALIAS_UNLOCK(la);
1661642e43b3SArchie Cobbs 	return (iresult);
1662642e43b3SArchie Cobbs }
1663be4f3cd0SPaolo Pisati 
1664be4f3cd0SPaolo Pisati #ifndef _KERNEL
1665be4f3cd0SPaolo Pisati 
1666be4f3cd0SPaolo Pisati int
LibAliasRefreshModules(void)1667be4f3cd0SPaolo Pisati LibAliasRefreshModules(void)
1668be4f3cd0SPaolo Pisati {
1669be4f3cd0SPaolo Pisati 	char buf[256], conf[] = "/etc/libalias.conf";
1670be4f3cd0SPaolo Pisati 	FILE *fd;
16715910c1c1SPaolo Pisati 	int i, len;
1672be4f3cd0SPaolo Pisati 
1673be4f3cd0SPaolo Pisati 	fd = fopen(conf, "r");
1674be4f3cd0SPaolo Pisati 	if (fd == NULL)
1675be4f3cd0SPaolo Pisati 		err(1, "fopen(%s)", conf);
1676be4f3cd0SPaolo Pisati 
1677be4f3cd0SPaolo Pisati 	LibAliasUnLoadAllModule();
1678be4f3cd0SPaolo Pisati 
1679be4f3cd0SPaolo Pisati 	for (;;) {
1680be4f3cd0SPaolo Pisati 		fgets(buf, 256, fd);
168103bc210eSDmitry Morozovsky 		if (feof(fd))
1682be4f3cd0SPaolo Pisati 			break;
1683be4f3cd0SPaolo Pisati 		len = strlen(buf);
1684be4f3cd0SPaolo Pisati 		if (len > 1) {
16855910c1c1SPaolo Pisati 			for (i = 0; i < len; i++)
16865910c1c1SPaolo Pisati 				if (!isspace(buf[i]))
16875910c1c1SPaolo Pisati 					break;
16885910c1c1SPaolo Pisati 			if (buf[i] == '#')
16895910c1c1SPaolo Pisati 				continue;
1690be4f3cd0SPaolo Pisati 			buf[len - 1] = '\0';
1691be4f3cd0SPaolo Pisati 			LibAliasLoadModule(buf);
1692be4f3cd0SPaolo Pisati 		}
1693be4f3cd0SPaolo Pisati 	}
1694621882f0SChristian Brueffer 	fclose(fd);
1695be4f3cd0SPaolo Pisati 	return (0);
1696be4f3cd0SPaolo Pisati }
1697be4f3cd0SPaolo Pisati 
1698be4f3cd0SPaolo Pisati int
LibAliasLoadModule(char * path)1699be4f3cd0SPaolo Pisati LibAliasLoadModule(char *path)
1700be4f3cd0SPaolo Pisati {
1701be4f3cd0SPaolo Pisati 	struct dll *t;
1702be4f3cd0SPaolo Pisati 	void *handle;
1703be4f3cd0SPaolo Pisati 	struct proto_handler *m;
1704be4f3cd0SPaolo Pisati 	const char *error;
1705be4f3cd0SPaolo Pisati 	moduledata_t *p;
1706be4f3cd0SPaolo Pisati 
1707be4f3cd0SPaolo Pisati 	handle = dlopen (path, RTLD_LAZY);
1708be4f3cd0SPaolo Pisati 	if (!handle) {
17095910c1c1SPaolo Pisati 		fprintf(stderr, "%s\n", dlerror());
1710be4f3cd0SPaolo Pisati 		return (EINVAL);
1711be4f3cd0SPaolo Pisati 	}
1712be4f3cd0SPaolo Pisati 
1713be4f3cd0SPaolo Pisati 	p = dlsym(handle, "alias_mod");
1714be4f3cd0SPaolo Pisati 	if ((error = dlerror()) != NULL)  {
17155910c1c1SPaolo Pisati 		fprintf(stderr, "%s\n", dlerror());
1716be4f3cd0SPaolo Pisati 		return (EINVAL);
1717be4f3cd0SPaolo Pisati 	}
1718be4f3cd0SPaolo Pisati 
1719be4f3cd0SPaolo Pisati 	t = malloc(sizeof(struct dll));
1720be4f3cd0SPaolo Pisati 	if (t == NULL)
1721be4f3cd0SPaolo Pisati 		return (ENOMEM);
1722be4f3cd0SPaolo Pisati 	strncpy(t->name, p->name, DLL_LEN);
1723be4f3cd0SPaolo Pisati 	t->handle = handle;
1724be4f3cd0SPaolo Pisati 	if (attach_dll(t) == EEXIST) {
1725be4f3cd0SPaolo Pisati 		free(t);
17265910c1c1SPaolo Pisati 		fprintf(stderr, "dll conflict\n");
1727be4f3cd0SPaolo Pisati 		return (EEXIST);
1728be4f3cd0SPaolo Pisati 	}
1729be4f3cd0SPaolo Pisati 
1730be4f3cd0SPaolo Pisati 	m = dlsym(t->handle, "handlers");
1731be4f3cd0SPaolo Pisati 	if ((error = dlerror()) != NULL)  {
17325910c1c1SPaolo Pisati 		fprintf(stderr, "%s\n", error);
1733be4f3cd0SPaolo Pisati 		return (EINVAL);
1734be4f3cd0SPaolo Pisati 	}
1735be4f3cd0SPaolo Pisati 
1736be4f3cd0SPaolo Pisati 	LibAliasAttachHandlers(m);
1737be4f3cd0SPaolo Pisati 	return (0);
1738be4f3cd0SPaolo Pisati }
1739be4f3cd0SPaolo Pisati 
1740be4f3cd0SPaolo Pisati int
LibAliasUnLoadAllModule(void)1741be4f3cd0SPaolo Pisati LibAliasUnLoadAllModule(void)
1742be4f3cd0SPaolo Pisati {
1743be4f3cd0SPaolo Pisati 	struct dll *t;
1744be4f3cd0SPaolo Pisati 	struct proto_handler *p;
1745be4f3cd0SPaolo Pisati 
1746be4f3cd0SPaolo Pisati 	/* Unload all modules then reload everything. */
1747be4f3cd0SPaolo Pisati 	while ((p = first_handler()) != NULL) {
1748ec5df3a7SGleb Smirnoff 		LibAliasDetachHandlers(p);
1749be4f3cd0SPaolo Pisati 	}
1750be4f3cd0SPaolo Pisati 	while ((t = walk_dll_chain()) != NULL) {
1751be4f3cd0SPaolo Pisati 		dlclose(t->handle);
1752be4f3cd0SPaolo Pisati 		free(t);
1753be4f3cd0SPaolo Pisati 	}
1754be4f3cd0SPaolo Pisati 	return (1);
1755be4f3cd0SPaolo Pisati }
1756be4f3cd0SPaolo Pisati 
1757be4f3cd0SPaolo Pisati #endif
1758e876228eSPaolo Pisati 
1759e876228eSPaolo Pisati #ifdef _KERNEL
1760e876228eSPaolo Pisati /*
1761ccd57eeaSPaolo Pisati  * m_megapullup() - this function is a big hack.
1762ccd57eeaSPaolo Pisati  * Thankfully, it's only used in ng_nat and ipfw+nat.
1763e876228eSPaolo Pisati  *
1764efc66711SAlexander Motin  * It allocates an mbuf with cluster and copies the specified part of the chain
1765efc66711SAlexander Motin  * into cluster, so that it is all contiguous and can be accessed via a plain
1766efc66711SAlexander Motin  * (char *) pointer. This is required, because libalias doesn't know how to
1767efc66711SAlexander Motin  * handle mbuf chains.
1768e876228eSPaolo Pisati  *
1769efc66711SAlexander Motin  * On success, m_megapullup returns an mbuf (possibly with cluster) containing
1770efc66711SAlexander Motin  * the input packet, on failure NULL. The input packet is always consumed.
1771e876228eSPaolo Pisati  */
1772e876228eSPaolo Pisati struct mbuf *
m_megapullup(struct mbuf * m,int len)1773eb548a1aSAndrey V. Elsukov m_megapullup(struct mbuf *m, int len)
1774eb548a1aSAndrey V. Elsukov {
1775e876228eSPaolo Pisati 	struct mbuf *mcl;
1776e876228eSPaolo Pisati 
1777efc66711SAlexander Motin 	if (len > m->m_pkthdr.len)
1778e876228eSPaolo Pisati 		goto bad;
1779e876228eSPaolo Pisati 
17807525c481SGleb Smirnoff 	if (m->m_next == NULL && M_WRITABLE(m))
1781efc66711SAlexander Motin 		return (m);
1782efc66711SAlexander Motin 
1783eb548a1aSAndrey V. Elsukov 	if (len <= MJUMPAGESIZE)
17847525c481SGleb Smirnoff 		mcl = m_get2(len, M_NOWAIT, MT_DATA, M_PKTHDR);
1785eb548a1aSAndrey V. Elsukov 	else if (len <= MJUM9BYTES)
1786eb548a1aSAndrey V. Elsukov 		mcl = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUM9BYTES);
1787eb548a1aSAndrey V. Elsukov 	else if (len <= MJUM16BYTES)
1788eb548a1aSAndrey V. Elsukov 		mcl = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUM16BYTES);
1789eb548a1aSAndrey V. Elsukov 	else
1790eb548a1aSAndrey V. Elsukov 		goto bad;
1791efc66711SAlexander Motin 	if (mcl == NULL)
1792e876228eSPaolo Pisati 		goto bad;
17937525c481SGleb Smirnoff 	m_align(mcl, len);
1794e876228eSPaolo Pisati 	m_move_pkthdr(mcl, m);
1795efc66711SAlexander Motin 	m_copydata(m, 0, len, mtod(mcl, caddr_t));
1796efc66711SAlexander Motin 	mcl->m_len = mcl->m_pkthdr.len = len;
1797e876228eSPaolo Pisati 	m_freem(m);
1798e876228eSPaolo Pisati 
1799e876228eSPaolo Pisati 	return (mcl);
1800e876228eSPaolo Pisati bad:
1801e876228eSPaolo Pisati 	m_freem(m);
1802e876228eSPaolo Pisati 	return (NULL);
1803e876228eSPaolo Pisati }
1804e876228eSPaolo Pisati #endif
1805