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