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