177701Sbrian/*-
285964Sbrian * Copyright (c) 2001 Charles Mott <cm@linktel.net>
377701Sbrian * All rights reserved.
477701Sbrian *
577701Sbrian * Redistribution and use in source and binary forms, with or without
677701Sbrian * modification, are permitted provided that the following conditions
777701Sbrian * are met:
877701Sbrian * 1. Redistributions of source code must retain the above copyright
977701Sbrian *    notice, this list of conditions and the following disclaimer.
1077701Sbrian * 2. Redistributions in binary form must reproduce the above copyright
1177701Sbrian *    notice, this list of conditions and the following disclaimer in the
1277701Sbrian *    documentation and/or other materials provided with the distribution.
1377701Sbrian *
1477701Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1577701Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1677701Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1777701Sbrian * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1877701Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1977701Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2077701Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2177701Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2277701Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2377701Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2477701Sbrian * SUCH DAMAGE.
2577701Sbrian */
2677701Sbrian
2784195Sdillon#include <sys/cdefs.h>
2884195Sdillon__FBSDID("$FreeBSD: stable/10/sys/netinet/libalias/alias.c 335474 2018-06-21 11:24:20Z ae $");
2984195Sdillon
3026026Sbrian/*
3126026Sbrian    Alias.c provides supervisory control for the functions of the
3226026Sbrian    packet aliasing software.  It consists of routines to monitor
3326026Sbrian    TCP connection state, protocol-specific aliasing routines,
3426026Sbrian    fragment handling and the following outside world functional
3526026Sbrian    interfaces: SaveFragmentPtr, GetFragmentPtr, FragmentAliasIn,
3626026Sbrian    PacketAliasIn and PacketAliasOut.
3726026Sbrian
3826026Sbrian    The other C program files are briefly described. The data
3926026Sbrian    structure framework which holds information needed to translate
4026026Sbrian    packets is encapsulated in alias_db.c.  Data is accessed by
4126026Sbrian    function calls, so other segments of the program need not know
4226026Sbrian    about the underlying data structures.  Alias_ftp.c contains
4326026Sbrian    special code for modifying the ftp PORT command used to establish
4459047Sru    data connections, while alias_irc.c does the same for IRC
4526026Sbrian    DCC. Alias_util.c contains a few utility routines.
4626026Sbrian
4726026Sbrian    Version 1.0 August, 1996  (cjm)
4826026Sbrian
4926026Sbrian    Version 1.1 August 20, 1996  (cjm)
50131612Sdes	PPP host accepts incoming connections for ports 0 to 1023.
51131612Sdes	(Gary Roberts pointed out the need to handle incoming
52131612Sdes	 connections.)
5326026Sbrian
5426026Sbrian    Version 1.2 September 7, 1996 (cjm)
55131612Sdes	Fragment handling error in alias_db.c corrected.
56131612Sdes	(Tom Torrance helped fix this problem.)
5726026Sbrian
5826026Sbrian    Version 1.4 September 16, 1996 (cjm)
59131612Sdes	- A more generalized method for handling incoming
60131612Sdes	  connections, without the 0-1023 restriction, is
61131612Sdes	  implemented in alias_db.c
62131612Sdes	- Improved ICMP support in alias.c.  Traceroute
63131612Sdes	  packet streams can now be correctly aliased.
64131612Sdes	- TCP connection closing logic simplified in
65131612Sdes	  alias.c and now allows for additional 1 minute
66131612Sdes	  "grace period" after FIN or RST is observed.
6726026Sbrian
6826026Sbrian    Version 1.5 September 17, 1996 (cjm)
69131612Sdes	Corrected error in handling incoming UDP packets with 0 checksum.
70131612Sdes	(Tom Torrance helped fix this problem.)
7126026Sbrian
7226026Sbrian    Version 1.6 September 18, 1996 (cjm)
73131612Sdes	Simplified ICMP aliasing scheme.  Should now support
74131612Sdes	traceroute from Win95 as well as FreeBSD.
7526026Sbrian
7626026Sbrian    Version 1.7 January 9, 1997 (cjm)
77131612Sdes	- Out-of-order fragment handling.
78131612Sdes	- IP checksum error fixed for ftp transfers
79131612Sdes	  from aliasing host.
80131612Sdes	- Integer return codes added to all
81131612Sdes	  aliasing/de-aliasing functions.
82131612Sdes	- Some obsolete comments cleaned up.
83131612Sdes	- Differential checksum computations for
84131612Sdes	  IP header (TCP, UDP and ICMP were already
85131612Sdes	  differential).
8626026Sbrian
8726026Sbrian    Version 2.1 May 1997 (cjm)
88131612Sdes	- Added support for outgoing ICMP error
89131612Sdes	  messages.
90131612Sdes	- Added two functions PacketAliasIn2()
91131612Sdes	  and PacketAliasOut2() for dynamic address
92131612Sdes	  control (e.g. round-robin allocation of
93131612Sdes	  incoming packets).
9427864Sbrian
9527864Sbrian    Version 2.2 July 1997 (cjm)
96131612Sdes	- Rationalized API function names to begin
97131612Sdes	  with "PacketAlias..."
98131612Sdes	- Eliminated PacketAliasIn2() and
99131612Sdes	  PacketAliasOut2() as poorly conceived.
10027864Sbrian
10141759Sdillon    Version 2.3 Dec 1998 (dillon)
10241759Sdillon	- Major bounds checking additions, see FreeBSD/CVS
10341759Sdillon
10499207Sbrian    Version 3.1 May, 2000 (salander)
10561861Sru	- Added hooks to handle PPTP.
10661861Sru
10763899Sarchie    Version 3.2 July, 2000 (salander and satoh)
10863899Sarchie	- Added PacketUnaliasOut routine.
10963899Sarchie	- Added hooks to handle RTSP/RTP.
11063899Sarchie
11132377Seivind    See HISTORY file for additional revisions.
11226026Sbrian*/
11326026Sbrian
114145921Sglebius#ifdef _KERNEL
115145921Sglebius#include <sys/param.h>
116164798Spiso#include <sys/systm.h>
117164798Spiso#include <sys/mbuf.h>
118188294Spiso#include <sys/sysctl.h>
119145921Sglebius#else
12026026Sbrian#include <sys/types.h>
121162674Spiso#include <stdlib.h>
122145921Sglebius#include <stdio.h>
123164798Spiso#include <ctype.h>
124162674Spiso#include <dlfcn.h>
125162674Spiso#include <errno.h>
126162674Spiso#include <string.h>
127145921Sglebius#endif
12826026Sbrian
12926026Sbrian#include <netinet/in_systm.h>
13026026Sbrian#include <netinet/in.h>
13126026Sbrian#include <netinet/ip.h>
13226026Sbrian#include <netinet/ip_icmp.h>
13326026Sbrian#include <netinet/tcp.h>
13426026Sbrian#include <netinet/udp.h>
13526026Sbrian
136145921Sglebius#ifdef _KERNEL
137145932Sglebius#include <netinet/libalias/alias.h>
138145921Sglebius#include <netinet/libalias/alias_local.h>
139162674Spiso#include <netinet/libalias/alias_mod.h>
140145921Sglebius#else
141162674Spiso#include <err.h>
142145932Sglebius#include "alias.h"
14326026Sbrian#include "alias_local.h"
144162674Spiso#include "alias_mod.h"
145145921Sglebius#endif
14626026Sbrian
147188294Spiso/*
148188294Spiso * Define libalias SYSCTL Node
149188294Spiso */
150188294Spiso#ifdef SYSCTL_NODE
151188294Spiso
152188294SpisoSYSCTL_DECL(_net_inet);
153188294SpisoSYSCTL_DECL(_net_inet_ip);
154188294SpisoSYSCTL_NODE(_net_inet_ip, OID_AUTO, alias, CTLFLAG_RW, NULL, "Libalias sysctl API");
155188294Spiso
156188294Spiso#endif
157188294Spiso
158127689Sdesstatic __inline int
159127689Sdestwowords(void *p)
160127689Sdes{
161131693Sdes	uint8_t *c = p;
16226026Sbrian
163131693Sdes#if BYTE_ORDER == LITTLE_ENDIAN
164131693Sdes	uint16_t s1 = ((uint16_t)c[1] << 8) + (uint16_t)c[0];
165131693Sdes	uint16_t s2 = ((uint16_t)c[3] << 8) + (uint16_t)c[2];
166131693Sdes#else
167131693Sdes	uint16_t s1 = ((uint16_t)c[0] << 8) + (uint16_t)c[1];
168131693Sdes	uint16_t s2 = ((uint16_t)c[2] << 8) + (uint16_t)c[3];
169131693Sdes#endif
170131693Sdes	return (s1 + s2);
171127689Sdes}
17226026Sbrian
17326026Sbrian/* TCP Handling Routines
17426026Sbrian
17526026Sbrian    TcpMonitorIn()  -- These routines monitor TCP connections, and
17644307Sbrian    TcpMonitorOut()    delete a link when a connection is closed.
17726026Sbrian
17851125SruThese routines look for SYN, FIN and RST flags to determine when TCP
17926026Sbrianconnections open and close.  When a TCP connection closes, the data
18026026Sbrianstructure containing packet aliasing information is deleted after
18126026Sbriana timeout period.
18226026Sbrian*/
18326026Sbrian
18426026Sbrian/* Local prototypes */
185176884Spisostatic void	TcpMonitorIn(u_char, struct alias_link *);
18626026Sbrian
187176884Spisostatic void	TcpMonitorOut(u_char, struct alias_link *);
18826026Sbrian
18926026Sbrian
19026026Sbrianstatic void
191176884SpisoTcpMonitorIn(u_char th_flags, struct alias_link *lnk)
19226026Sbrian{
19326026Sbrian
194131614Sdes	switch (GetStateIn(lnk)) {
195127094Sdes	case ALIAS_TCP_STATE_NOT_CONNECTED:
196176884Spiso		if (th_flags & TH_RST)
197131614Sdes			SetStateIn(lnk, ALIAS_TCP_STATE_DISCONNECTED);
198176884Spiso		else if (th_flags & TH_SYN)
199131614Sdes			SetStateIn(lnk, ALIAS_TCP_STATE_CONNECTED);
200127094Sdes		break;
201127094Sdes	case ALIAS_TCP_STATE_CONNECTED:
202176884Spiso		if (th_flags & (TH_FIN | TH_RST))
203131614Sdes			SetStateIn(lnk, ALIAS_TCP_STATE_DISCONNECTED);
204127094Sdes		break;
205127094Sdes	}
20626026Sbrian}
20726026Sbrian
20826026Sbrianstatic void
209176884SpisoTcpMonitorOut(u_char th_flags, struct alias_link *lnk)
21026026Sbrian{
21126026Sbrian
212131614Sdes	switch (GetStateOut(lnk)) {
213127094Sdes	case ALIAS_TCP_STATE_NOT_CONNECTED:
214176884Spiso		if (th_flags & TH_RST)
215131614Sdes			SetStateOut(lnk, ALIAS_TCP_STATE_DISCONNECTED);
216176884Spiso		else if (th_flags & TH_SYN)
217131614Sdes			SetStateOut(lnk, ALIAS_TCP_STATE_CONNECTED);
218127094Sdes		break;
219127094Sdes	case ALIAS_TCP_STATE_CONNECTED:
220176884Spiso		if (th_flags & (TH_FIN | TH_RST))
221131614Sdes			SetStateOut(lnk, ALIAS_TCP_STATE_DISCONNECTED);
222127094Sdes		break;
223127094Sdes	}
22426026Sbrian}
22526026Sbrian
22626026Sbrian
22726026Sbrian
22826026Sbrian
22926026Sbrian
23099207Sbrian/* Protocol Specific Packet Aliasing Routines
23126026Sbrian
23265280Sru    IcmpAliasIn(), IcmpAliasIn1(), IcmpAliasIn2()
23365280Sru    IcmpAliasOut(), IcmpAliasOut1(), IcmpAliasOut2()
23459726Sru    ProtoAliasIn(), ProtoAliasOut()
23526026Sbrian    UdpAliasIn(), UdpAliasOut()
23626026Sbrian    TcpAliasIn(), TcpAliasOut()
23726026Sbrian
23826026SbrianThese routines handle protocol specific details of packet aliasing.
23926026SbrianOne may observe a certain amount of repetitive arithmetic in these
24026026Sbrianfunctions, the purpose of which is to compute a revised checksum
24126026Sbrianwithout actually summing over the entire data packet, which could be
24226026Sbrianunnecessarily time consuming.
24326026Sbrian
24426026SbrianThe purpose of the packet aliasing routines is to replace the source
24526026Sbrianaddress of the outgoing packet and then correctly put it back for
24626026Sbrianany incoming packets.  For TCP and UDP, ports are also re-mapped.
24726026Sbrian
24826026SbrianFor ICMP echo/timestamp requests and replies, the following scheme
24959356Sruis used: the ID number is replaced by an alias for the outgoing
25026026Sbrianpacket.
25126026Sbrian
25226026SbrianICMP error messages are handled by looking at the IP fragment
25326026Sbrianin the data section of the message.
25426026Sbrian
25526026SbrianFor TCP and UDP protocols, a port number is chosen for an outgoing
25626026Sbrianpacket, and then incoming packets are identified by IP address and
25726026Sbrianport numbers.  For TCP packets, there is additional logic in the event
25859356Sruthat sequence and ACK numbers have been altered (as in the case for
25926026SbrianFTP data port commands).
26026026Sbrian
26126026SbrianThe port numbers used by the packet aliasing module are not true
26226026Sbrianports in the Unix sense.  No sockets are actually bound to ports.
26326026SbrianThey are more correctly thought of as placeholders.
26426026Sbrian
26526026SbrianAll packets go through the aliasing mechanism, whether they come from
26626026Sbrianthe gateway machine or other machines on a local area network.
26726026Sbrian*/
26826026Sbrian
26926026Sbrian
27026026Sbrian/* Local prototypes */
271127094Sdesstatic int	IcmpAliasIn1(struct libalias *, struct ip *);
272127094Sdesstatic int	IcmpAliasIn2(struct libalias *, struct ip *);
273127094Sdesstatic int	IcmpAliasIn(struct libalias *, struct ip *);
27426026Sbrian
275133719Sphkstatic int	IcmpAliasOut1(struct libalias *, struct ip *, int create);
276127094Sdesstatic int	IcmpAliasOut2(struct libalias *, struct ip *);
277131566Sphkstatic int	IcmpAliasOut(struct libalias *, struct ip *, int create);
27826026Sbrian
279177098Spisostatic int	ProtoAliasIn(struct libalias *la, struct in_addr ip_src,
280177098Spiso		    struct in_addr *ip_dst, u_char ip_p, u_short *ip_sum);
281177098Spisostatic int	ProtoAliasOut(struct libalias *la, struct in_addr *ip_src,
282177098Spiso		    struct in_addr ip_dst, u_char ip_p, u_short *ip_sum,
283177098Spiso		    int create);
28459726Sru
285127094Sdesstatic int	UdpAliasIn(struct libalias *, struct ip *);
286179920Smavstatic int	UdpAliasOut(struct libalias *, struct ip *, int, int create);
28726026Sbrian
288127094Sdesstatic int	TcpAliasIn(struct libalias *, struct ip *);
289131566Sphkstatic int	TcpAliasOut(struct libalias *, struct ip *, int, int create);
29026026Sbrian
29126026Sbrian
29226026Sbrianstatic int
293124621SphkIcmpAliasIn1(struct libalias *la, struct ip *pip)
29426026Sbrian{
295165243Spiso
296165243Spiso	LIBALIAS_LOCK_ASSERT(la);
29726026Sbrian/*
29865280Sru    De-alias incoming echo and timestamp replies.
29965280Sru    Alias incoming echo and timestamp requests.
30026026Sbrian*/
301131614Sdes	struct alias_link *lnk;
302127094Sdes	struct icmp *ic;
30326026Sbrian
304131699Sdes	ic = (struct icmp *)ip_next(pip);
30526026Sbrian
30626026Sbrian/* Get source address from ICMP data field and restore original data */
307131614Sdes	lnk = FindIcmpIn(la, pip->ip_src, pip->ip_dst, ic->icmp_id, 1);
308131614Sdes	if (lnk != NULL) {
309127094Sdes		u_short original_id;
310127094Sdes		int accumulate;
31126026Sbrian
312131614Sdes		original_id = GetOriginalPort(lnk);
31326026Sbrian
31426026Sbrian/* Adjust ICMP checksum */
315127094Sdes		accumulate = ic->icmp_id;
316127094Sdes		accumulate -= original_id;
317127094Sdes		ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
31826026Sbrian
31926026Sbrian/* Put original sequence number back in */
320127094Sdes		ic->icmp_id = original_id;
32126026Sbrian
32226026Sbrian/* Put original address back into IP header */
323127094Sdes		{
324127094Sdes			struct in_addr original_address;
32526026Sbrian
326131614Sdes			original_address = GetOriginalAddress(lnk);
327127094Sdes			DifferentialChecksum(&pip->ip_sum,
328127689Sdes			    &original_address, &pip->ip_dst, 2);
329127094Sdes			pip->ip_dst = original_address;
330127094Sdes		}
33126026Sbrian
332127094Sdes		return (PKT_ALIAS_OK);
333127094Sdes	}
334127094Sdes	return (PKT_ALIAS_IGNORED);
33526026Sbrian}
33626026Sbrian
33726026Sbrianstatic int
338124621SphkIcmpAliasIn2(struct libalias *la, struct ip *pip)
33926026Sbrian{
340165243Spiso
341165243Spiso	LIBALIAS_LOCK_ASSERT(la);
34226026Sbrian/*
34326026Sbrian    Alias incoming ICMP error messages containing
34426026Sbrian    IP header and first 64 bits of datagram.
34526026Sbrian*/
346127094Sdes	struct ip *ip;
347127094Sdes	struct icmp *ic, *ic2;
348127094Sdes	struct udphdr *ud;
349127094Sdes	struct tcphdr *tc;
350131614Sdes	struct alias_link *lnk;
35126026Sbrian
352131699Sdes	ic = (struct icmp *)ip_next(pip);
353127094Sdes	ip = &ic->icmp_ip;
35426026Sbrian
355131699Sdes	ud = (struct udphdr *)ip_next(ip);
356131699Sdes	tc = (struct tcphdr *)ip_next(ip);
357131699Sdes	ic2 = (struct icmp *)ip_next(ip);
35826026Sbrian
359127094Sdes	if (ip->ip_p == IPPROTO_UDP)
360131614Sdes		lnk = FindUdpTcpIn(la, ip->ip_dst, ip->ip_src,
361127094Sdes		    ud->uh_dport, ud->uh_sport,
362127094Sdes		    IPPROTO_UDP, 0);
363127094Sdes	else if (ip->ip_p == IPPROTO_TCP)
364131614Sdes		lnk = FindUdpTcpIn(la, ip->ip_dst, ip->ip_src,
365127094Sdes		    tc->th_dport, tc->th_sport,
366127094Sdes		    IPPROTO_TCP, 0);
367127094Sdes	else if (ip->ip_p == IPPROTO_ICMP) {
368127094Sdes		if (ic2->icmp_type == ICMP_ECHO || ic2->icmp_type == ICMP_TSTAMP)
369131614Sdes			lnk = FindIcmpIn(la, ip->ip_dst, ip->ip_src, ic2->icmp_id, 0);
370127094Sdes		else
371131614Sdes			lnk = NULL;
372127094Sdes	} else
373131614Sdes		lnk = NULL;
37426026Sbrian
375131614Sdes	if (lnk != NULL) {
376127094Sdes		if (ip->ip_p == IPPROTO_UDP || ip->ip_p == IPPROTO_TCP) {
377127094Sdes			int accumulate, accumulate2;
378127094Sdes			struct in_addr original_address;
379127094Sdes			u_short original_port;
38026026Sbrian
381131614Sdes			original_address = GetOriginalAddress(lnk);
382131614Sdes			original_port = GetOriginalPort(lnk);
38399207Sbrian
38426026Sbrian/* Adjust ICMP checksum */
385127689Sdes			accumulate = twowords(&ip->ip_src);
386127689Sdes			accumulate -= twowords(&original_address);
387127094Sdes			accumulate += ud->uh_sport;
388127094Sdes			accumulate -= original_port;
389127094Sdes			accumulate2 = accumulate;
390127094Sdes			accumulate2 += ip->ip_sum;
391127094Sdes			ADJUST_CHECKSUM(accumulate, ip->ip_sum);
392127094Sdes			accumulate2 -= ip->ip_sum;
393127094Sdes			ADJUST_CHECKSUM(accumulate2, ic->icmp_cksum);
39426026Sbrian
39526026Sbrian/* Un-alias address in IP header */
396127094Sdes			DifferentialChecksum(&pip->ip_sum,
397127689Sdes			    &original_address, &pip->ip_dst, 2);
398127094Sdes			pip->ip_dst = original_address;
39926026Sbrian
40026026Sbrian/* Un-alias address and port number of original IP packet
40126026Sbrianfragment contained in ICMP data section */
402127094Sdes			ip->ip_src = original_address;
403127094Sdes			ud->uh_sport = original_port;
404127094Sdes		} else if (ip->ip_p == IPPROTO_ICMP) {
405127094Sdes			int accumulate, accumulate2;
406127094Sdes			struct in_addr original_address;
407127094Sdes			u_short original_id;
40826026Sbrian
409131614Sdes			original_address = GetOriginalAddress(lnk);
410131614Sdes			original_id = GetOriginalPort(lnk);
41126026Sbrian
41226026Sbrian/* Adjust ICMP checksum */
413127689Sdes			accumulate = twowords(&ip->ip_src);
414127689Sdes			accumulate -= twowords(&original_address);
415127094Sdes			accumulate += ic2->icmp_id;
416127094Sdes			accumulate -= original_id;
417127094Sdes			accumulate2 = accumulate;
418127094Sdes			accumulate2 += ip->ip_sum;
419127094Sdes			ADJUST_CHECKSUM(accumulate, ip->ip_sum);
420127094Sdes			accumulate2 -= ip->ip_sum;
421127094Sdes			ADJUST_CHECKSUM(accumulate2, ic->icmp_cksum);
42226026Sbrian
42326026Sbrian/* Un-alias address in IP header */
424127094Sdes			DifferentialChecksum(&pip->ip_sum,
425127689Sdes			    &original_address, &pip->ip_dst, 2);
426127094Sdes			pip->ip_dst = original_address;
42726026Sbrian
42899207Sbrian/* Un-alias address of original IP packet and sequence number of
42959047Sru   embedded ICMP datagram */
430127094Sdes			ip->ip_src = original_address;
431127094Sdes			ic2->icmp_id = original_id;
432127094Sdes		}
433127094Sdes		return (PKT_ALIAS_OK);
434127094Sdes	}
435127094Sdes	return (PKT_ALIAS_IGNORED);
43626026Sbrian}
43726026Sbrian
43826026Sbrian
43926026Sbrianstatic int
440124621SphkIcmpAliasIn(struct libalias *la, struct ip *pip)
44126026Sbrian{
442127094Sdes	int iresult;
443127094Sdes	struct icmp *ic;
44426026Sbrian
445165243Spiso	LIBALIAS_LOCK_ASSERT(la);
44644307Sbrian/* Return if proxy-only mode is enabled */
447127094Sdes	if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
448131613Sdes		return (PKT_ALIAS_OK);
44944307Sbrian
450131699Sdes	ic = (struct icmp *)ip_next(pip);
45126026Sbrian
452127094Sdes	iresult = PKT_ALIAS_IGNORED;
453127094Sdes	switch (ic->icmp_type) {
454127094Sdes	case ICMP_ECHOREPLY:
455127094Sdes	case ICMP_TSTAMPREPLY:
456127094Sdes		if (ic->icmp_code == 0) {
457127094Sdes			iresult = IcmpAliasIn1(la, pip);
458127094Sdes		}
459127094Sdes		break;
460127094Sdes	case ICMP_UNREACH:
461127094Sdes	case ICMP_SOURCEQUENCH:
462127094Sdes	case ICMP_TIMXCEED:
463127094Sdes	case ICMP_PARAMPROB:
464127094Sdes		iresult = IcmpAliasIn2(la, pip);
465127094Sdes		break;
466127094Sdes	case ICMP_ECHO:
467127094Sdes	case ICMP_TSTAMP:
468127094Sdes		iresult = IcmpAliasIn1(la, pip);
469127094Sdes		break;
470127094Sdes	}
471127094Sdes	return (iresult);
47226026Sbrian}
47326026Sbrian
47426026Sbrian
47526026Sbrianstatic int
476133719SphkIcmpAliasOut1(struct libalias *la, struct ip *pip, int create)
47726026Sbrian{
47826026Sbrian/*
47965280Sru    Alias outgoing echo and timestamp requests.
48065280Sru    De-alias outgoing echo and timestamp replies.
48126026Sbrian*/
482131614Sdes	struct alias_link *lnk;
483127094Sdes	struct icmp *ic;
48426026Sbrian
485165243Spiso	LIBALIAS_LOCK_ASSERT(la);
486131699Sdes	ic = (struct icmp *)ip_next(pip);
48726026Sbrian
48826026Sbrian/* Save overwritten data for when echo packet returns */
489133719Sphk	lnk = FindIcmpOut(la, pip->ip_src, pip->ip_dst, ic->icmp_id, create);
490131614Sdes	if (lnk != NULL) {
491127094Sdes		u_short alias_id;
492127094Sdes		int accumulate;
49326026Sbrian
494131614Sdes		alias_id = GetAliasPort(lnk);
49526026Sbrian
49626026Sbrian/* Since data field is being modified, adjust ICMP checksum */
497127094Sdes		accumulate = ic->icmp_id;
498127094Sdes		accumulate -= alias_id;
499127094Sdes		ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
50026026Sbrian
50126026Sbrian/* Alias sequence number */
502127094Sdes		ic->icmp_id = alias_id;
50326026Sbrian
50426026Sbrian/* Change source address */
505127094Sdes		{
506127094Sdes			struct in_addr alias_address;
50726026Sbrian
508131614Sdes			alias_address = GetAliasAddress(lnk);
509127094Sdes			DifferentialChecksum(&pip->ip_sum,
510127689Sdes			    &alias_address, &pip->ip_src, 2);
511127094Sdes			pip->ip_src = alias_address;
512127094Sdes		}
51326026Sbrian
514127094Sdes		return (PKT_ALIAS_OK);
515127094Sdes	}
516127094Sdes	return (PKT_ALIAS_IGNORED);
51726026Sbrian}
51826026Sbrian
51926026Sbrian
52026026Sbrianstatic int
521124621SphkIcmpAliasOut2(struct libalias *la, struct ip *pip)
52226026Sbrian{
52326026Sbrian/*
52426026Sbrian    Alias outgoing ICMP error messages containing
52526026Sbrian    IP header and first 64 bits of datagram.
52626026Sbrian*/
527127094Sdes	struct ip *ip;
528127094Sdes	struct icmp *ic, *ic2;
529127094Sdes	struct udphdr *ud;
530127094Sdes	struct tcphdr *tc;
531131614Sdes	struct alias_link *lnk;
53226026Sbrian
533165243Spiso	LIBALIAS_LOCK_ASSERT(la);
534131699Sdes	ic = (struct icmp *)ip_next(pip);
535127094Sdes	ip = &ic->icmp_ip;
53626026Sbrian
537131699Sdes	ud = (struct udphdr *)ip_next(ip);
538131699Sdes	tc = (struct tcphdr *)ip_next(ip);
539131699Sdes	ic2 = (struct icmp *)ip_next(ip);
54026026Sbrian
541127094Sdes	if (ip->ip_p == IPPROTO_UDP)
542131614Sdes		lnk = FindUdpTcpOut(la, ip->ip_dst, ip->ip_src,
543127094Sdes		    ud->uh_dport, ud->uh_sport,
544127094Sdes		    IPPROTO_UDP, 0);
545127094Sdes	else if (ip->ip_p == IPPROTO_TCP)
546131614Sdes		lnk = FindUdpTcpOut(la, ip->ip_dst, ip->ip_src,
547127094Sdes		    tc->th_dport, tc->th_sport,
548127094Sdes		    IPPROTO_TCP, 0);
549127094Sdes	else if (ip->ip_p == IPPROTO_ICMP) {
550127094Sdes		if (ic2->icmp_type == ICMP_ECHO || ic2->icmp_type == ICMP_TSTAMP)
551131614Sdes			lnk = FindIcmpOut(la, ip->ip_dst, ip->ip_src, ic2->icmp_id, 0);
552127094Sdes		else
553131614Sdes			lnk = NULL;
554127094Sdes	} else
555131614Sdes		lnk = NULL;
55626026Sbrian
557131614Sdes	if (lnk != NULL) {
558127094Sdes		if (ip->ip_p == IPPROTO_UDP || ip->ip_p == IPPROTO_TCP) {
559127094Sdes			int accumulate;
560127094Sdes			struct in_addr alias_address;
561127094Sdes			u_short alias_port;
56226026Sbrian
563131614Sdes			alias_address = GetAliasAddress(lnk);
564131614Sdes			alias_port = GetAliasPort(lnk);
56599207Sbrian
56659047Sru/* Adjust ICMP checksum */
567127689Sdes			accumulate = twowords(&ip->ip_dst);
568127689Sdes			accumulate -= twowords(&alias_address);
569127094Sdes			accumulate += ud->uh_dport;
570127094Sdes			accumulate -= alias_port;
571127094Sdes			ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
57259047Sru
57365317Sru/*
57465317Sru * Alias address in IP header if it comes from the host
57565317Sru * the original TCP/UDP packet was destined for.
57665317Sru */
577127094Sdes			if (pip->ip_src.s_addr == ip->ip_dst.s_addr) {
578127094Sdes				DifferentialChecksum(&pip->ip_sum,
579127689Sdes				    &alias_address, &pip->ip_src, 2);
580127094Sdes				pip->ip_src = alias_address;
581127094Sdes			}
58259047Sru/* Alias address and port number of original IP packet
58359047Srufragment contained in ICMP data section */
584127094Sdes			ip->ip_dst = alias_address;
585127094Sdes			ud->uh_dport = alias_port;
586127094Sdes		} else if (ip->ip_p == IPPROTO_ICMP) {
587127094Sdes			int accumulate;
588127094Sdes			struct in_addr alias_address;
589127094Sdes			u_short alias_id;
59059047Sru
591131614Sdes			alias_address = GetAliasAddress(lnk);
592131614Sdes			alias_id = GetAliasPort(lnk);
59359047Sru
59459047Sru/* Adjust ICMP checksum */
595127689Sdes			accumulate = twowords(&ip->ip_dst);
596127689Sdes			accumulate -= twowords(&alias_address);
597127094Sdes			accumulate += ic2->icmp_id;
598127094Sdes			accumulate -= alias_id;
599127094Sdes			ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
60059047Sru
60165317Sru/*
60265317Sru * Alias address in IP header if it comes from the host
60365317Sru * the original ICMP message was destined for.
60465317Sru */
605127094Sdes			if (pip->ip_src.s_addr == ip->ip_dst.s_addr) {
606127094Sdes				DifferentialChecksum(&pip->ip_sum,
607127689Sdes				    &alias_address, &pip->ip_src, 2);
608127094Sdes				pip->ip_src = alias_address;
609127094Sdes			}
61099207Sbrian/* Alias address of original IP packet and sequence number of
61159047Sru   embedded ICMP datagram */
612127094Sdes			ip->ip_dst = alias_address;
613127094Sdes			ic2->icmp_id = alias_id;
614127094Sdes		}
615127094Sdes		return (PKT_ALIAS_OK);
616127094Sdes	}
617127094Sdes	return (PKT_ALIAS_IGNORED);
61826026Sbrian}
61926026Sbrian
62026026Sbrian
62126026Sbrianstatic int
622131566SphkIcmpAliasOut(struct libalias *la, struct ip *pip, int create)
62326026Sbrian{
624127094Sdes	int iresult;
625127094Sdes	struct icmp *ic;
62626026Sbrian
627165243Spiso	LIBALIAS_LOCK_ASSERT(la);
628131614Sdes	(void)create;
629131614Sdes
63044307Sbrian/* Return if proxy-only mode is enabled */
631127094Sdes	if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
632131613Sdes		return (PKT_ALIAS_OK);
63344307Sbrian
634131699Sdes	ic = (struct icmp *)ip_next(pip);
63526026Sbrian
636127094Sdes	iresult = PKT_ALIAS_IGNORED;
637127094Sdes	switch (ic->icmp_type) {
638127094Sdes	case ICMP_ECHO:
639127094Sdes	case ICMP_TSTAMP:
640127094Sdes		if (ic->icmp_code == 0) {
641133719Sphk			iresult = IcmpAliasOut1(la, pip, create);
642127094Sdes		}
643127094Sdes		break;
644127094Sdes	case ICMP_UNREACH:
645127094Sdes	case ICMP_SOURCEQUENCH:
646127094Sdes	case ICMP_TIMXCEED:
647127094Sdes	case ICMP_PARAMPROB:
648127094Sdes		iresult = IcmpAliasOut2(la, pip);
649127094Sdes		break;
650127094Sdes	case ICMP_ECHOREPLY:
651127094Sdes	case ICMP_TSTAMPREPLY:
652133719Sphk		iresult = IcmpAliasOut1(la, pip, create);
653127094Sdes	}
654127094Sdes	return (iresult);
65526026Sbrian}
65626026Sbrian
65726026Sbrianstatic int
658177098SpisoProtoAliasIn(struct libalias *la, struct in_addr ip_src,
659177098Spiso    struct in_addr *ip_dst, u_char ip_p, u_short *ip_sum)
66044307Sbrian{
66144307Sbrian/*
66259726Sru  Handle incoming IP packets. The
66344307Sbrian  only thing which is done in this case is to alias
66444307Sbrian  the dest IP address of the packet to our inside
66544307Sbrian  machine.
66644307Sbrian*/
667131614Sdes	struct alias_link *lnk;
66844307Sbrian
669165243Spiso	LIBALIAS_LOCK_ASSERT(la);
67059356Sru/* Return if proxy-only mode is enabled */
671127094Sdes	if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
672131613Sdes		return (PKT_ALIAS_OK);
67344307Sbrian
674177098Spiso	lnk = FindProtoIn(la, ip_src, *ip_dst, ip_p);
675131614Sdes	if (lnk != NULL) {
676127094Sdes		struct in_addr original_address;
67759356Sru
678131614Sdes		original_address = GetOriginalAddress(lnk);
67959356Sru
68059356Sru/* Restore original IP address */
681177098Spiso		DifferentialChecksum(ip_sum,
682177098Spiso		    &original_address, ip_dst, 2);
683177098Spiso		*ip_dst = original_address;
68459356Sru
685127094Sdes		return (PKT_ALIAS_OK);
686127094Sdes	}
687127094Sdes	return (PKT_ALIAS_IGNORED);
68844307Sbrian}
68944307Sbrian
69044307Sbrianstatic int
691177098SpisoProtoAliasOut(struct libalias *la, struct in_addr *ip_src,
692177098Spiso    struct in_addr ip_dst, u_char ip_p, u_short *ip_sum, int create)
69344307Sbrian{
69444307Sbrian/*
69559726Sru  Handle outgoing IP packets. The
69644307Sbrian  only thing which is done in this case is to alias
69744307Sbrian  the source IP address of the packet.
69844307Sbrian*/
699131614Sdes	struct alias_link *lnk;
70044307Sbrian
701165243Spiso	LIBALIAS_LOCK_ASSERT(la);
702131614Sdes
70359356Sru/* Return if proxy-only mode is enabled */
704127094Sdes	if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
705131613Sdes		return (PKT_ALIAS_OK);
70644307Sbrian
707318519Seugen	if (!create)
708318519Seugen		return (PKT_ALIAS_IGNORED);
709318519Seugen
710177098Spiso	lnk = FindProtoOut(la, *ip_src, ip_dst, ip_p);
711131614Sdes	if (lnk != NULL) {
712127094Sdes		struct in_addr alias_address;
71359356Sru
714131614Sdes		alias_address = GetAliasAddress(lnk);
71559356Sru
71659356Sru/* Change source address */
717177098Spiso		DifferentialChecksum(ip_sum,
718177098Spiso		    &alias_address, ip_src, 2);
719177098Spiso		*ip_src = alias_address;
72059356Sru
721127094Sdes		return (PKT_ALIAS_OK);
722127094Sdes	}
723127094Sdes	return (PKT_ALIAS_IGNORED);
72444307Sbrian}
72544307Sbrian
72644307Sbrian
72761861Srustatic int
728124621SphkUdpAliasIn(struct libalias *la, struct ip *pip)
72926026Sbrian{
730127094Sdes	struct udphdr *ud;
731131614Sdes	struct alias_link *lnk;
73226026Sbrian
733165243Spiso	LIBALIAS_LOCK_ASSERT(la);
73444307Sbrian
735131699Sdes	ud = (struct udphdr *)ip_next(pip);
73626026Sbrian
737131614Sdes	lnk = FindUdpTcpIn(la, pip->ip_src, pip->ip_dst,
738127094Sdes	    ud->uh_sport, ud->uh_dport,
739179920Smav	    IPPROTO_UDP, !(la->packetAliasMode & PKT_ALIAS_PROXY_ONLY));
740131614Sdes	if (lnk != NULL) {
741127094Sdes		struct in_addr alias_address;
742127094Sdes		struct in_addr original_address;
743179920Smav		struct in_addr proxy_address;
744127094Sdes		u_short alias_port;
745179920Smav		u_short proxy_port;
746127094Sdes		int accumulate;
747190938Spiso		int error;
748162674Spiso		struct alias_data ad = {
749162674Spiso			.lnk = lnk,
750162674Spiso			.oaddr = &original_address,
751162674Spiso			.aaddr = &alias_address,
752162674Spiso			.aport = &alias_port,
753162674Spiso			.sport = &ud->uh_sport,
754162674Spiso			.dport = &ud->uh_dport,
755162674Spiso			.maxpktsize = 0
756162674Spiso		};
75726026Sbrian
758131614Sdes		alias_address = GetAliasAddress(lnk);
759131614Sdes		original_address = GetOriginalAddress(lnk);
760179920Smav		proxy_address = GetProxyAddress(lnk);
761127094Sdes		alias_port = ud->uh_dport;
762131614Sdes		ud->uh_dport = GetOriginalPort(lnk);
763179920Smav		proxy_port = GetProxyPort(lnk);
76426026Sbrian
765162674Spiso		/* Walk out chain. */
766162674Spiso		error = find_handler(IN, UDP, la, pip, &ad);
767190941Spiso		/* If we cannot figure out the packet, ignore it. */
768190941Spiso		if (error < 0)
769190941Spiso			return (PKT_ALIAS_IGNORED);
77036321Samurai
77126026Sbrian/* If UDP checksum is not zero, then adjust since destination port */
77266545Sru/* is being unaliased and destination address is being altered.    */
773127094Sdes		if (ud->uh_sum != 0) {
774127094Sdes			accumulate = alias_port;
775127094Sdes			accumulate -= ud->uh_dport;
776127689Sdes			accumulate += twowords(&alias_address);
777127689Sdes			accumulate -= twowords(&original_address);
778179920Smav
779179920Smav/* If this is a proxy packet, modify checksum because of source change.*/
780179920Smav        		if (proxy_port != 0) {
781179920Smav		                accumulate += ud->uh_sport;
782179920Smav		                accumulate -= proxy_port;
783179920Smav	                }
784179920Smav
785179920Smav	                if (proxy_address.s_addr != 0) {
786179920Smav				accumulate += twowords(&pip->ip_src);
787179920Smav				accumulate -= twowords(&proxy_address);
788179920Smav	                }
789179920Smav
790127094Sdes			ADJUST_CHECKSUM(accumulate, ud->uh_sum);
791127094Sdes		}
792179920Smav/* XXX: Could the two if's below be concatenated to one ? */
793179920Smav/* Restore source port and/or address in case of proxying*/
794179920Smav
795179920Smav    		if (proxy_port != 0)
796179920Smav        		ud->uh_sport = proxy_port;
797179920Smav
798179920Smav    		if (proxy_address.s_addr != 0) {
799179920Smav        		DifferentialChecksum(&pip->ip_sum,
800179920Smav                	    &proxy_address, &pip->ip_src, 2);
801179920Smav	        	pip->ip_src = proxy_address;
802179920Smav    		}
803179920Smav
80426026Sbrian/* Restore original IP address */
805127094Sdes		DifferentialChecksum(&pip->ip_sum,
806127689Sdes		    &original_address, &pip->ip_dst, 2);
807127094Sdes		pip->ip_dst = original_address;
80841759Sdillon
809190941Spiso		return (PKT_ALIAS_OK);
810127094Sdes	}
811127094Sdes	return (PKT_ALIAS_IGNORED);
81226026Sbrian}
81326026Sbrian
81426026Sbrianstatic int
815179920SmavUdpAliasOut(struct libalias *la, struct ip *pip, int maxpacketsize, int create)
81626026Sbrian{
817127094Sdes	struct udphdr *ud;
818131614Sdes	struct alias_link *lnk;
819179920Smav	struct in_addr dest_address;
820179920Smav	struct in_addr proxy_server_address;
821179920Smav	u_short dest_port;
822179920Smav	u_short proxy_server_port;
823179920Smav	int proxy_type;
824162674Spiso	int error;
82526026Sbrian
826165243Spiso	LIBALIAS_LOCK_ASSERT(la);
82744307Sbrian
828179920Smav/* Return if proxy-only mode is enabled and not proxyrule found.*/
829131699Sdes	ud = (struct udphdr *)ip_next(pip);
830179920Smav	proxy_type = ProxyCheck(la, &proxy_server_address,
831179920Smav		&proxy_server_port, pip->ip_src, pip->ip_dst,
832179920Smav		ud->uh_dport, pip->ip_p);
833179920Smav	if (proxy_type == 0 && (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY))
834179920Smav		return (PKT_ALIAS_OK);
83526026Sbrian
836179920Smav/* If this is a transparent proxy, save original destination,
837179920Smav * then alter the destination and adjust checksums */
838179920Smav	dest_port = ud->uh_dport;
839179920Smav	dest_address = pip->ip_dst;
840179920Smav
841179920Smav	if (proxy_type != 0) {
842179920Smav	        int accumulate;
843179920Smav
844179920Smav		accumulate = twowords(&pip->ip_dst);
845179920Smav		accumulate -= twowords(&proxy_server_address);
846179920Smav
847179920Smav	        ADJUST_CHECKSUM(accumulate, pip->ip_sum);
848179920Smav
849179920Smav		if (ud->uh_sum != 0) {
850179920Smav			accumulate = twowords(&pip->ip_dst);
851179920Smav			accumulate -= twowords(&proxy_server_address);
852179920Smav    			accumulate += ud->uh_dport;
853179920Smav	        	accumulate -= proxy_server_port;
854179920Smav	    		ADJUST_CHECKSUM(accumulate, ud->uh_sum);
855179920Smav		}
856179920Smav	        pip->ip_dst = proxy_server_address;
857179920Smav	        ud->uh_dport = proxy_server_port;
858179920Smav	}
859131614Sdes	lnk = FindUdpTcpOut(la, pip->ip_src, pip->ip_dst,
860127094Sdes	    ud->uh_sport, ud->uh_dport,
861131566Sphk	    IPPROTO_UDP, create);
862131614Sdes	if (lnk != NULL) {
863127094Sdes		u_short alias_port;
864127094Sdes		struct in_addr alias_address;
865162674Spiso		struct alias_data ad = {
866162674Spiso			.lnk = lnk,
867162674Spiso			.oaddr = NULL,
868162674Spiso			.aaddr = &alias_address,
869162674Spiso			.aport = &alias_port,
870162674Spiso			.sport = &ud->uh_sport,
871162674Spiso			.dport = &ud->uh_dport,
872162674Spiso			.maxpktsize = 0
873162674Spiso		};
87426026Sbrian
875179920Smav/* Save original destination address, if this is a proxy packet.
876179920Smav * Also modify packet to include destination encoding.  This may
877179920Smav * change the size of IP header. */
878179920Smav		if (proxy_type != 0) {
879179920Smav	                SetProxyPort(lnk, dest_port);
880179920Smav	                SetProxyAddress(lnk, dest_address);
881179920Smav	                ProxyModify(la, lnk, pip, maxpacketsize, proxy_type);
882179920Smav	                ud = (struct udphdr *)ip_next(pip);
883179920Smav	        }
884179920Smav
885131614Sdes		alias_address = GetAliasAddress(lnk);
886131614Sdes		alias_port = GetAliasPort(lnk);
88726026Sbrian
888162674Spiso		/* Walk out chain. */
889162674Spiso		error = find_handler(OUT, UDP, la, pip, &ad);
89036321Samurai
89126026Sbrian/* If UDP checksum is not zero, adjust since source port is */
89226026Sbrian/* being aliased and source address is being altered        */
893127094Sdes		if (ud->uh_sum != 0) {
894127094Sdes			int accumulate;
89526026Sbrian
896127094Sdes			accumulate = ud->uh_sport;
897127094Sdes			accumulate -= alias_port;
898127689Sdes			accumulate += twowords(&pip->ip_src);
899127689Sdes			accumulate -= twowords(&alias_address);
900127094Sdes			ADJUST_CHECKSUM(accumulate, ud->uh_sum);
901127094Sdes		}
90236321Samurai/* Put alias port in UDP header */
903127094Sdes		ud->uh_sport = alias_port;
90426026Sbrian
90526026Sbrian/* Change source address */
906127094Sdes		DifferentialChecksum(&pip->ip_sum,
907127689Sdes		    &alias_address, &pip->ip_src, 2);
908127094Sdes		pip->ip_src = alias_address;
90926026Sbrian
910127094Sdes		return (PKT_ALIAS_OK);
911127094Sdes	}
912127094Sdes	return (PKT_ALIAS_IGNORED);
91326026Sbrian}
91426026Sbrian
91526026Sbrian
91626026Sbrian
91726026Sbrianstatic int
918124621SphkTcpAliasIn(struct libalias *la, struct ip *pip)
91926026Sbrian{
920127094Sdes	struct tcphdr *tc;
921131614Sdes	struct alias_link *lnk;
92226026Sbrian
923165243Spiso	LIBALIAS_LOCK_ASSERT(la);
924131699Sdes	tc = (struct tcphdr *)ip_next(pip);
92526026Sbrian
926131614Sdes	lnk = FindUdpTcpIn(la, pip->ip_src, pip->ip_dst,
927127094Sdes	    tc->th_sport, tc->th_dport,
928127094Sdes	    IPPROTO_TCP,
929127094Sdes	    !(la->packetAliasMode & PKT_ALIAS_PROXY_ONLY));
930131614Sdes	if (lnk != NULL) {
931127094Sdes		struct in_addr alias_address;
932127094Sdes		struct in_addr original_address;
933127094Sdes		struct in_addr proxy_address;
934127094Sdes		u_short alias_port;
935127094Sdes		u_short proxy_port;
936162674Spiso		int accumulate, error;
93726026Sbrian
938162674Spiso		/*
939162674Spiso		 * The init of MANY vars is a bit below, but aliashandlepptpin
940162674Spiso		 * seems to need the destination port that came within the
941162674Spiso		 * packet and not the original one looks below [*].
942162674Spiso		 */
94361861Sru
944162674Spiso		struct alias_data ad = {
945162674Spiso			.lnk = lnk,
946162674Spiso			.oaddr = NULL,
947162674Spiso			.aaddr = NULL,
948162674Spiso			.aport = NULL,
949162674Spiso			.sport = &tc->th_sport,
950162674Spiso			.dport = &tc->th_dport,
951162674Spiso			.maxpktsize = 0
952162674Spiso		};
953162674Spiso
954162674Spiso		/* Walk out chain. */
955162674Spiso		error = find_handler(IN, TCP, la, pip, &ad);
956162674Spiso
957131614Sdes		alias_address = GetAliasAddress(lnk);
958131614Sdes		original_address = GetOriginalAddress(lnk);
959131614Sdes		proxy_address = GetProxyAddress(lnk);
960127094Sdes		alias_port = tc->th_dport;
961131614Sdes		tc->th_dport = GetOriginalPort(lnk);
962131614Sdes		proxy_port = GetProxyPort(lnk);
96326026Sbrian
964162674Spiso		/*
965162674Spiso		 * Look above, if anyone is going to add find_handler AFTER
966162674Spiso		 * this aliashandlepptpin/point, please redo alias_data too.
967162674Spiso		 * Uncommenting the piece here below should be enough.
968162674Spiso		 */
969162674Spiso#if 0
970162674Spiso				 struct alias_data ad = {
971162674Spiso					.lnk = lnk,
972162674Spiso					.oaddr = &original_address,
973162674Spiso					.aaddr = &alias_address,
974162674Spiso					.aport = &alias_port,
975162674Spiso					.sport = &ud->uh_sport,
976162674Spiso					.dport = &ud->uh_dport,
977162674Spiso					.maxpktsize = 0
978162674Spiso				};
979162674Spiso
980162674Spiso				/* Walk out chain. */
981162674Spiso				error = find_handler(la, pip, &ad);
982162674Spiso				if (error == EHDNOF)
983162674Spiso					printf("Protocol handler not found\n");
984162674Spiso#endif
985162674Spiso
98626026Sbrian/* Adjust TCP checksum since destination port is being unaliased */
98726026Sbrian/* and destination port is being altered.                        */
988127094Sdes		accumulate = alias_port;
989127094Sdes		accumulate -= tc->th_dport;
990127689Sdes		accumulate += twowords(&alias_address);
991127689Sdes		accumulate -= twowords(&original_address);
99226026Sbrian
99359356Sru/* If this is a proxy, then modify the TCP source port and
99444307Sbrian   checksum accumulation */
995127094Sdes		if (proxy_port != 0) {
996127094Sdes			accumulate += tc->th_sport;
997127094Sdes			tc->th_sport = proxy_port;
998127094Sdes			accumulate -= tc->th_sport;
999127689Sdes			accumulate += twowords(&pip->ip_src);
1000127689Sdes			accumulate -= twowords(&proxy_address);
1001127094Sdes		}
100259356Sru/* See if ACK number needs to be modified */
1003131614Sdes		if (GetAckModified(lnk) == 1) {
1004127094Sdes			int delta;
100526026Sbrian
1006176884Spiso			tc = (struct tcphdr *)ip_next(pip);
1007176884Spiso			delta = GetDeltaAckIn(tc->th_ack, lnk);
1008127094Sdes			if (delta != 0) {
1009127689Sdes				accumulate += twowords(&tc->th_ack);
1010127094Sdes				tc->th_ack = htonl(ntohl(tc->th_ack) - delta);
1011127689Sdes				accumulate -= twowords(&tc->th_ack);
1012127094Sdes			}
1013127094Sdes		}
1014127094Sdes		ADJUST_CHECKSUM(accumulate, tc->th_sum);
101526026Sbrian
101626026Sbrian/* Restore original IP address */
1017127689Sdes		accumulate = twowords(&pip->ip_dst);
1018127757Sdeischen		pip->ip_dst = original_address;
1019127689Sdes		accumulate -= twowords(&pip->ip_dst);
102026026Sbrian
102144307Sbrian/* If this is a transparent proxy packet, then modify the source
102244307Sbrian   address */
1023127094Sdes		if (proxy_address.s_addr != 0) {
1024127689Sdes			accumulate += twowords(&pip->ip_src);
1025127094Sdes			pip->ip_src = proxy_address;
1026127689Sdes			accumulate -= twowords(&pip->ip_src);
1027127094Sdes		}
1028127094Sdes		ADJUST_CHECKSUM(accumulate, pip->ip_sum);
102944307Sbrian
103026026Sbrian/* Monitor TCP connection state */
1031176884Spiso		tc = (struct tcphdr *)ip_next(pip);
1032176884Spiso		TcpMonitorIn(tc->th_flags, lnk);
103326026Sbrian
1034127094Sdes		return (PKT_ALIAS_OK);
1035127094Sdes	}
1036127094Sdes	return (PKT_ALIAS_IGNORED);
103726026Sbrian}
103826026Sbrian
103926026Sbrianstatic int
1040131566SphkTcpAliasOut(struct libalias *la, struct ip *pip, int maxpacketsize, int create)
104126026Sbrian{
1042162674Spiso	int proxy_type, error;
1043127094Sdes	u_short dest_port;
1044127094Sdes	u_short proxy_server_port;
1045127094Sdes	struct in_addr dest_address;
1046127094Sdes	struct in_addr proxy_server_address;
1047127094Sdes	struct tcphdr *tc;
1048131614Sdes	struct alias_link *lnk;
104926026Sbrian
1050165243Spiso	LIBALIAS_LOCK_ASSERT(la);
1051131699Sdes	tc = (struct tcphdr *)ip_next(pip);
105226026Sbrian
1053147636Sphk	if (create)
1054176884Spiso		proxy_type = ProxyCheck(la, &proxy_server_address,
1055176884Spiso		    &proxy_server_port, pip->ip_src, pip->ip_dst,
1056176884Spiso		    tc->th_dport, pip->ip_p);
1057147636Sphk	else
1058147636Sphk		proxy_type = 0;
105944307Sbrian
1060127094Sdes	if (proxy_type == 0 && (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY))
1061131613Sdes		return (PKT_ALIAS_OK);
106244307Sbrian
106344307Sbrian/* If this is a transparent proxy, save original destination,
106459356Sru   then alter the destination and adjust checksums */
1065127094Sdes	dest_port = tc->th_dport;
1066127094Sdes	dest_address = pip->ip_dst;
1067127094Sdes	if (proxy_type != 0) {
1068127094Sdes		int accumulate;
106944307Sbrian
1070127094Sdes		accumulate = tc->th_dport;
1071127094Sdes		tc->th_dport = proxy_server_port;
1072127094Sdes		accumulate -= tc->th_dport;
1073127689Sdes		accumulate += twowords(&pip->ip_dst);
1074127689Sdes		accumulate -= twowords(&proxy_server_address);
1075127094Sdes		ADJUST_CHECKSUM(accumulate, tc->th_sum);
107644307Sbrian
1077127689Sdes		accumulate = twowords(&pip->ip_dst);
1078127094Sdes		pip->ip_dst = proxy_server_address;
1079127689Sdes		accumulate -= twowords(&pip->ip_dst);
1080127094Sdes		ADJUST_CHECKSUM(accumulate, pip->ip_sum);
1081127094Sdes	}
1082131614Sdes	lnk = FindUdpTcpOut(la, pip->ip_src, pip->ip_dst,
1083127094Sdes	    tc->th_sport, tc->th_dport,
1084131566Sphk	    IPPROTO_TCP, create);
1085131614Sdes	if (lnk == NULL)
1086131566Sphk		return (PKT_ALIAS_IGNORED);
1087131614Sdes	if (lnk != NULL) {
1088127094Sdes		u_short alias_port;
1089127094Sdes		struct in_addr alias_address;
1090127094Sdes		int accumulate;
1091162674Spiso		struct alias_data ad = {
1092162674Spiso			.lnk = lnk,
1093162674Spiso			.oaddr = NULL,
1094162674Spiso			.aaddr = &alias_address,
1095162674Spiso			.aport = &alias_port,
1096162674Spiso			.sport = &tc->th_sport,
1097162674Spiso			.dport = &tc->th_dport,
1098162674Spiso			.maxpktsize = maxpacketsize
1099162674Spiso		};
110044307Sbrian
110144307Sbrian/* Save original destination address, if this is a proxy packet.
110288132Sru   Also modify packet to include destination encoding.  This may
110388132Sru   change the size of IP header. */
1104127094Sdes		if (proxy_type != 0) {
1105131614Sdes			SetProxyPort(lnk, dest_port);
1106131614Sdes			SetProxyAddress(lnk, dest_address);
1107131614Sdes			ProxyModify(la, lnk, pip, maxpacketsize, proxy_type);
1108131699Sdes			tc = (struct tcphdr *)ip_next(pip);
1109127094Sdes		}
111044307Sbrian/* Get alias address and port */
1111131614Sdes		alias_port = GetAliasPort(lnk);
1112131614Sdes		alias_address = GetAliasAddress(lnk);
111326026Sbrian
111459356Sru/* Monitor TCP connection state */
1115176884Spiso		tc = (struct tcphdr *)ip_next(pip);
1116176884Spiso		TcpMonitorOut(tc->th_flags, lnk);
1117162674Spiso
1118162674Spiso		/* Walk out chain. */
1119162674Spiso		error = find_handler(OUT, TCP, la, pip, &ad);
112026026Sbrian
112126026Sbrian/* Adjust TCP checksum since source port is being aliased */
112226026Sbrian/* and source address is being altered                    */
1123127094Sdes		accumulate = tc->th_sport;
1124127094Sdes		tc->th_sport = alias_port;
1125127094Sdes		accumulate -= tc->th_sport;
1126127689Sdes		accumulate += twowords(&pip->ip_src);
1127127689Sdes		accumulate -= twowords(&alias_address);
112844307Sbrian
112926026Sbrian/* Modify sequence number if necessary */
1130131614Sdes		if (GetAckModified(lnk) == 1) {
1131127094Sdes			int delta;
1132176884Spiso
1133176884Spiso			tc = (struct tcphdr *)ip_next(pip);
1134176884Spiso			delta = GetDeltaSeqOut(tc->th_seq, lnk);
1135127094Sdes			if (delta != 0) {
1136127689Sdes				accumulate += twowords(&tc->th_seq);
1137127094Sdes				tc->th_seq = htonl(ntohl(tc->th_seq) + delta);
1138127689Sdes				accumulate -= twowords(&tc->th_seq);
1139127094Sdes			}
1140127094Sdes		}
1141127094Sdes		ADJUST_CHECKSUM(accumulate, tc->th_sum);
114226026Sbrian
114326026Sbrian/* Change source address */
1144127689Sdes		accumulate = twowords(&pip->ip_src);
1145127094Sdes		pip->ip_src = alias_address;
1146127689Sdes		accumulate -= twowords(&pip->ip_src);
1147127094Sdes		ADJUST_CHECKSUM(accumulate, pip->ip_sum);
114844307Sbrian
1149127094Sdes		return (PKT_ALIAS_OK);
1150127094Sdes	}
1151127094Sdes	return (PKT_ALIAS_IGNORED);
115226026Sbrian}
115326026Sbrian
115426026Sbrian
115526026Sbrian
115626026Sbrian
115726026Sbrian/* Fragment Handling
115826026Sbrian
115926026Sbrian    FragmentIn()
116026026Sbrian    FragmentOut()
116126026Sbrian
116226026SbrianThe packet aliasing module has a limited ability for handling IP
116326026Sbrianfragments.  If the ICMP, TCP or UDP header is in the first fragment
116459356Srureceived, then the ID number of the IP packet is saved, and other
116526026Sbrianfragments are identified according to their ID number and IP address
116626026Sbrianthey were sent from.  Pointers to unresolved fragments can also be
116726026Sbriansaved and recalled when a header fragment is seen.
116826026Sbrian*/
116926026Sbrian
117026026Sbrian/* Local prototypes */
1171177098Spisostatic int	FragmentIn(struct libalias *la, struct in_addr ip_src,
1172179472Smav		    struct in_addr *ip_dst, u_short ip_id, u_short *ip_sum);
1173177098Spisostatic int	FragmentOut(struct libalias *, struct in_addr *ip_src,
1174177098Spiso		    u_short *ip_sum);
117526026Sbrian
117626026Sbrianstatic int
1177177098SpisoFragmentIn(struct libalias *la, struct in_addr ip_src, struct in_addr *ip_dst,
1178179472Smav    u_short ip_id, u_short *ip_sum)
117926026Sbrian{
1180131614Sdes	struct alias_link *lnk;
118126026Sbrian
1182165243Spiso	LIBALIAS_LOCK_ASSERT(la);
1183177098Spiso	lnk = FindFragmentIn2(la, ip_src, *ip_dst, ip_id);
1184131614Sdes	if (lnk != NULL) {
1185127094Sdes		struct in_addr original_address;
118626026Sbrian
1187131614Sdes		GetFragmentAddr(lnk, &original_address);
1188177098Spiso		DifferentialChecksum(ip_sum,
1189177098Spiso		    &original_address, ip_dst, 2);
1190177098Spiso		*ip_dst = original_address;
119199207Sbrian
1192127094Sdes		return (PKT_ALIAS_OK);
1193127094Sdes	}
1194127094Sdes	return (PKT_ALIAS_UNRESOLVED_FRAGMENT);
119526026Sbrian}
119626026Sbrian
119726026Sbrianstatic int
1198177098SpisoFragmentOut(struct libalias *la, struct in_addr *ip_src, u_short *ip_sum)
119926026Sbrian{
1200127094Sdes	struct in_addr alias_address;
120126026Sbrian
1202165243Spiso	LIBALIAS_LOCK_ASSERT(la);
1203177098Spiso	alias_address = FindAliasAddress(la, *ip_src);
1204177098Spiso	DifferentialChecksum(ip_sum,
1205177098Spiso	    &alias_address, ip_src, 2);
1206177098Spiso	*ip_src = alias_address;
120726026Sbrian
1208127094Sdes	return (PKT_ALIAS_OK);
120926026Sbrian}
121026026Sbrian
121126026Sbrian
121226026Sbrian
121326026Sbrian
121426026Sbrian
121526026Sbrian
121626026Sbrian/* Outside World Access
121726026Sbrian
1218131612Sdes	PacketAliasSaveFragment()
1219131612Sdes	PacketAliasGetFragment()
1220131612Sdes	PacketAliasFragmentIn()
1221131612Sdes	PacketAliasIn()
1222131612Sdes	PacketAliasOut()
1223131612Sdes	PacketUnaliasOut()
122426026Sbrian
122526026Sbrian(prototypes in alias.h)
122626026Sbrian*/
122726026Sbrian
122826026Sbrianint
1229124621SphkLibAliasSaveFragment(struct libalias *la, char *ptr)
123026026Sbrian{
1231127094Sdes	int iresult;
1232131614Sdes	struct alias_link *lnk;
1233127094Sdes	struct ip *pip;
123426026Sbrian
1235165243Spiso	LIBALIAS_LOCK(la);
1236127094Sdes	pip = (struct ip *)ptr;
1237131614Sdes	lnk = AddFragmentPtrLink(la, pip->ip_src, pip->ip_id);
1238127094Sdes	iresult = PKT_ALIAS_ERROR;
1239131614Sdes	if (lnk != NULL) {
1240131614Sdes		SetFragmentPtr(lnk, ptr);
1241127094Sdes		iresult = PKT_ALIAS_OK;
1242127094Sdes	}
1243165243Spiso	LIBALIAS_UNLOCK(la);
1244127094Sdes	return (iresult);
124526026Sbrian}
124626026Sbrian
1247127094Sdeschar           *
1248124621SphkLibAliasGetFragment(struct libalias *la, char *ptr)
124926026Sbrian{
1250131614Sdes	struct alias_link *lnk;
1251127094Sdes	char *fptr;
1252127094Sdes	struct ip *pip;
125326026Sbrian
1254165243Spiso	LIBALIAS_LOCK(la);
1255127094Sdes	pip = (struct ip *)ptr;
1256131614Sdes	lnk = FindFragmentPtr(la, pip->ip_src, pip->ip_id);
1257131614Sdes	if (lnk != NULL) {
1258131614Sdes		GetFragmentPtr(lnk, &fptr);
1259131614Sdes		SetFragmentPtr(lnk, NULL);
1260131614Sdes		SetExpire(lnk, 0);	/* Deletes link */
1261165243Spiso	} else
1262165243Spiso		fptr = NULL;
126326026Sbrian
1264165243Spiso	LIBALIAS_UNLOCK(la);
1265165243Spiso	return (fptr);
126626026Sbrian}
126726026Sbrian
126826026Sbrianvoid
1269127094SdesLibAliasFragmentIn(struct libalias *la, char *ptr,	/* Points to correctly
1270127094Sdes							 * de-aliased header
1271127094Sdes							 * fragment */
1272127094Sdes    char *ptr_fragment		/* Points to fragment which must be
1273127094Sdes				 * de-aliased   */
1274127094Sdes)
127526026Sbrian{
1276127094Sdes	struct ip *pip;
1277127094Sdes	struct ip *fpip;
127826026Sbrian
1279165243Spiso	LIBALIAS_LOCK(la);
1280131614Sdes	(void)la;
1281127094Sdes	pip = (struct ip *)ptr;
1282127094Sdes	fpip = (struct ip *)ptr_fragment;
128326026Sbrian
1284127094Sdes	DifferentialChecksum(&fpip->ip_sum,
1285127689Sdes	    &pip->ip_dst, &fpip->ip_dst, 2);
1286127094Sdes	fpip->ip_dst = pip->ip_dst;
1287165243Spiso	LIBALIAS_UNLOCK(la);
128826026Sbrian}
128926026Sbrian
1290165243Spiso/* Local prototypes */
1291165243Spisostatic int
1292165243SpisoLibAliasOutLocked(struct libalias *la, char *ptr,
1293165243Spiso		  int maxpacketsize, int create);
1294165243Spisostatic int
1295165243SpisoLibAliasInLocked(struct libalias *la, char *ptr,
1296165243Spiso		  int maxpacketsize);
129726026Sbrian
129826026Sbrianint
1299124621SphkLibAliasIn(struct libalias *la, char *ptr, int maxpacketsize)
130026026Sbrian{
1301165243Spiso	int res;
1302165243Spiso
1303165243Spiso	LIBALIAS_LOCK(la);
1304165243Spiso	res = LibAliasInLocked(la, ptr, maxpacketsize);
1305165243Spiso	LIBALIAS_UNLOCK(la);
1306165243Spiso	return (res);
1307165243Spiso}
1308165243Spiso
1309165243Spisostatic int
1310165243SpisoLibAliasInLocked(struct libalias *la, char *ptr, int maxpacketsize)
1311165243Spiso{
1312127094Sdes	struct in_addr alias_addr;
1313127094Sdes	struct ip *pip;
1314127094Sdes	int iresult;
131526026Sbrian
1316127094Sdes	if (la->packetAliasMode & PKT_ALIAS_REVERSE) {
1317127094Sdes		la->packetAliasMode &= ~PKT_ALIAS_REVERSE;
1318165243Spiso		iresult = LibAliasOutLocked(la, ptr, maxpacketsize, 1);
1319127094Sdes		la->packetAliasMode |= PKT_ALIAS_REVERSE;
1320165243Spiso		goto getout;
1321127094Sdes	}
1322127094Sdes	HouseKeeping(la);
1323127094Sdes	ClearCheckNewLink(la);
1324127094Sdes	pip = (struct ip *)ptr;
1325127094Sdes	alias_addr = pip->ip_dst;
132644307Sbrian
1327127094Sdes	/* Defense against mangled packets */
1328127094Sdes	if (ntohs(pip->ip_len) > maxpacketsize
1329165243Spiso	    || (pip->ip_hl << 2) > maxpacketsize) {
1330165243Spiso		iresult = PKT_ALIAS_IGNORED;
1331165243Spiso		goto getout;
1332165243Spiso	}
133399207Sbrian
1334127094Sdes	iresult = PKT_ALIAS_IGNORED;
1335127094Sdes	if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
1336127094Sdes		switch (pip->ip_p) {
1337127094Sdes		case IPPROTO_ICMP:
1338127094Sdes			iresult = IcmpAliasIn(la, pip);
1339127094Sdes			break;
1340127094Sdes		case IPPROTO_UDP:
1341127094Sdes			iresult = UdpAliasIn(la, pip);
1342127094Sdes			break;
1343127094Sdes		case IPPROTO_TCP:
1344127094Sdes			iresult = TcpAliasIn(la, pip);
1345127094Sdes			break;
1346188294Spiso#ifdef _KERNEL
1347188294Spiso		case IPPROTO_SCTP:
1348188294Spiso		  iresult = SctpAlias(la, pip, SN_TO_LOCAL);
1349188294Spiso			break;
1350188294Spiso#endif
1351162674Spiso 		case IPPROTO_GRE: {
1352162674Spiso			int error;
1353162674Spiso			struct alias_data ad = {
1354162674Spiso				.lnk = NULL,
1355162674Spiso				.oaddr = NULL,
1356162674Spiso				.aaddr = NULL,
1357162674Spiso				.aport = NULL,
1358162674Spiso				.sport = NULL,
1359162674Spiso				.dport = NULL,
1360162674Spiso				.maxpktsize = 0
1361162674Spiso			};
1362162674Spiso
1363162674Spiso			/* Walk out chain. */
1364162674Spiso			error = find_handler(IN, IP, la, pip, &ad);
1365162674Spiso			if (error ==  0)
1366127094Sdes				iresult = PKT_ALIAS_OK;
1367127094Sdes			else
1368177098Spiso				iresult = ProtoAliasIn(la, pip->ip_src,
1369177098Spiso				    &pip->ip_dst, pip->ip_p, &pip->ip_sum);
1370162674Spiso		}
1371162674Spiso 			break;
1372127094Sdes		default:
1373177098Spiso			iresult = ProtoAliasIn(la, pip->ip_src, &pip->ip_dst,
1374177098Spiso			    pip->ip_p, &pip->ip_sum);
1375127094Sdes			break;
1376127094Sdes		}
137799207Sbrian
1378127094Sdes		if (ntohs(pip->ip_off) & IP_MF) {
1379131614Sdes			struct alias_link *lnk;
138026026Sbrian
1381131614Sdes			lnk = FindFragmentIn1(la, pip->ip_src, alias_addr, pip->ip_id);
1382131614Sdes			if (lnk != NULL) {
1383127094Sdes				iresult = PKT_ALIAS_FOUND_HEADER_FRAGMENT;
1384131614Sdes				SetFragmentAddr(lnk, pip->ip_dst);
1385127094Sdes			} else {
1386127094Sdes				iresult = PKT_ALIAS_ERROR;
1387127094Sdes			}
1388127094Sdes		}
1389127094Sdes	} else {
1390177098Spiso		iresult = FragmentIn(la, pip->ip_src, &pip->ip_dst, pip->ip_id,
1391177098Spiso		    &pip->ip_sum);
1392127094Sdes	}
139326026Sbrian
1394165243Spisogetout:
1395127094Sdes	return (iresult);
139626026Sbrian}
139726026Sbrian
139826026Sbrian
139926026Sbrian
140026026Sbrian/* Unregistered address ranges */
140126026Sbrian
140226026Sbrian/* 10.0.0.0   ->   10.255.255.255 */
140326026Sbrian#define UNREG_ADDR_A_LOWER 0x0a000000
140426026Sbrian#define UNREG_ADDR_A_UPPER 0x0affffff
140526026Sbrian
140626026Sbrian/* 172.16.0.0  ->  172.31.255.255 */
140726026Sbrian#define UNREG_ADDR_B_LOWER 0xac100000
140826026Sbrian#define UNREG_ADDR_B_UPPER 0xac1fffff
140926026Sbrian
141026026Sbrian/* 192.168.0.0 -> 192.168.255.255 */
141126026Sbrian#define UNREG_ADDR_C_LOWER 0xc0a80000
141226026Sbrian#define UNREG_ADDR_C_UPPER 0xc0a8ffff
141326026Sbrian
141426026Sbrianint
1415165243SpisoLibAliasOut(struct libalias *la, char *ptr, int maxpacketsize)
141626026Sbrian{
1417165243Spiso	int res;
1418165243Spiso
1419165243Spiso	LIBALIAS_LOCK(la);
1420165243Spiso	res = LibAliasOutLocked(la, ptr, maxpacketsize, 1);
1421165243Spiso	LIBALIAS_UNLOCK(la);
1422165243Spiso	return (res);
1423131566Sphk}
1424131566Sphk
1425131566Sphkint
1426165243SpisoLibAliasOutTry(struct libalias *la, char *ptr, int maxpacketsize, int create)
1427165243Spiso{
1428165243Spiso	int res;
1429165243Spiso
1430165243Spiso	LIBALIAS_LOCK(la);
1431165243Spiso	res = LibAliasOutLocked(la, ptr, maxpacketsize, create);
1432165243Spiso	LIBALIAS_UNLOCK(la);
1433165243Spiso	return (res);
1434165243Spiso}
1435165243Spiso
1436165243Spisostatic int
1437165243SpisoLibAliasOutLocked(struct libalias *la, char *ptr,	/* valid IP packet */
1438131566Sphk    int maxpacketsize,		/* How much the packet data may grow (FTP
1439131566Sphk				 * and IRC inline changes) */
1440165243Spiso    int create                  /* Create new entries ? */
1441131566Sphk)
1442131566Sphk{
1443127094Sdes	int iresult;
1444127094Sdes	struct in_addr addr_save;
1445127094Sdes	struct ip *pip;
144626026Sbrian
1447127094Sdes	if (la->packetAliasMode & PKT_ALIAS_REVERSE) {
1448127094Sdes		la->packetAliasMode &= ~PKT_ALIAS_REVERSE;
1449165243Spiso		iresult = LibAliasInLocked(la, ptr, maxpacketsize);
1450127094Sdes		la->packetAliasMode |= PKT_ALIAS_REVERSE;
1451165243Spiso		goto getout;
1452127094Sdes	}
1453127094Sdes	HouseKeeping(la);
1454127094Sdes	ClearCheckNewLink(la);
1455127094Sdes	pip = (struct ip *)ptr;
145644307Sbrian
1457127094Sdes	/* Defense against mangled packets */
1458127094Sdes	if (ntohs(pip->ip_len) > maxpacketsize
1459165243Spiso	    || (pip->ip_hl << 2) > maxpacketsize) {
1460165243Spiso		iresult = PKT_ALIAS_IGNORED;
1461165243Spiso		goto getout;
1462165243Spiso	}
146326026Sbrian
1464127094Sdes	addr_save = GetDefaultAliasAddress(la);
1465127094Sdes	if (la->packetAliasMode & PKT_ALIAS_UNREGISTERED_ONLY) {
1466127094Sdes		u_long addr;
1467127094Sdes		int iclass;
146832377Seivind
1469127094Sdes		iclass = 0;
1470127094Sdes		addr = ntohl(pip->ip_src.s_addr);
1471127094Sdes		if (addr >= UNREG_ADDR_C_LOWER && addr <= UNREG_ADDR_C_UPPER)
1472127094Sdes			iclass = 3;
1473127094Sdes		else if (addr >= UNREG_ADDR_B_LOWER && addr <= UNREG_ADDR_B_UPPER)
1474127094Sdes			iclass = 2;
1475127094Sdes		else if (addr >= UNREG_ADDR_A_LOWER && addr <= UNREG_ADDR_A_UPPER)
1476127094Sdes			iclass = 1;
147726026Sbrian
1478127094Sdes		if (iclass == 0) {
1479127094Sdes			SetDefaultAliasAddress(la, pip->ip_src);
1480127094Sdes		}
1481127094Sdes	} else if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY) {
1482127094Sdes		SetDefaultAliasAddress(la, pip->ip_src);
1483127094Sdes	}
1484127094Sdes	iresult = PKT_ALIAS_IGNORED;
1485127094Sdes	if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
1486127094Sdes		switch (pip->ip_p) {
1487127094Sdes		case IPPROTO_ICMP:
1488131566Sphk			iresult = IcmpAliasOut(la, pip, create);
1489127094Sdes			break;
1490127094Sdes		case IPPROTO_UDP:
1491179920Smav			iresult = UdpAliasOut(la, pip, maxpacketsize, create);
1492127094Sdes			break;
1493188294Spiso		case IPPROTO_TCP:
1494131566Sphk			iresult = TcpAliasOut(la, pip, maxpacketsize, create);
1495127094Sdes			break;
1496188294Spiso#ifdef _KERNEL
1497188294Spiso		case IPPROTO_SCTP:
1498188294Spiso		  iresult = SctpAlias(la, pip, SN_TO_GLOBAL);
1499188294Spiso			break;
1500188294Spiso#endif
1501188294Spiso		case IPPROTO_GRE: {
1502162674Spiso			int error;
1503162674Spiso			struct alias_data ad = {
1504162674Spiso				.lnk = NULL,
1505162674Spiso				.oaddr = NULL,
1506162674Spiso				.aaddr = NULL,
1507162674Spiso				.aport = NULL,
1508162674Spiso				.sport = NULL,
1509162674Spiso				.dport = NULL,
1510162674Spiso				.maxpktsize = 0
1511162674Spiso			};
1512162674Spiso			/* Walk out chain. */
1513162674Spiso			error = find_handler(OUT, IP, la, pip, &ad);
1514162674Spiso			if (error == 0)
1515162674Spiso 				iresult = PKT_ALIAS_OK;
1516162674Spiso 			else
1517177098Spiso 				iresult = ProtoAliasOut(la, &pip->ip_src,
1518177098Spiso				    pip->ip_dst, pip->ip_p, &pip->ip_sum, create);
1519162674Spiso		}
1520162674Spiso 			break;
1521127094Sdes		default:
1522177098Spiso			iresult = ProtoAliasOut(la, &pip->ip_src,
1523177098Spiso			    pip->ip_dst, pip->ip_p, &pip->ip_sum, create);
1524127094Sdes			break;
1525127094Sdes		}
1526127094Sdes	} else {
1527177098Spiso		iresult = FragmentOut(la, &pip->ip_src, &pip->ip_sum);
1528127094Sdes	}
152926026Sbrian
1530127094Sdes	SetDefaultAliasAddress(la, addr_save);
1531165243Spisogetout:
1532127094Sdes	return (iresult);
153326026Sbrian}
153463899Sarchie
153563899Sarchieint
1536127094SdesLibAliasUnaliasOut(struct libalias *la, char *ptr,	/* valid IP packet */
1537127094Sdes    int maxpacketsize		/* for error checking */
1538127094Sdes)
153963899Sarchie{
1540127094Sdes	struct ip *pip;
1541127094Sdes	struct icmp *ic;
1542127094Sdes	struct udphdr *ud;
1543127094Sdes	struct tcphdr *tc;
1544131614Sdes	struct alias_link *lnk;
1545127094Sdes	int iresult = PKT_ALIAS_IGNORED;
154663899Sarchie
1547165243Spiso	LIBALIAS_LOCK(la);
1548127094Sdes	pip = (struct ip *)ptr;
154963899Sarchie
1550127094Sdes	/* Defense against mangled packets */
1551127094Sdes	if (ntohs(pip->ip_len) > maxpacketsize
1552127094Sdes	    || (pip->ip_hl << 2) > maxpacketsize)
1553165243Spiso		goto getout;
155463899Sarchie
1555131699Sdes	ud = (struct udphdr *)ip_next(pip);
1556131699Sdes	tc = (struct tcphdr *)ip_next(pip);
1557131699Sdes	ic = (struct icmp *)ip_next(pip);
155863899Sarchie
1559127094Sdes	/* Find a link */
1560127094Sdes	if (pip->ip_p == IPPROTO_UDP)
1561131614Sdes		lnk = FindUdpTcpIn(la, pip->ip_dst, pip->ip_src,
1562127094Sdes		    ud->uh_dport, ud->uh_sport,
1563127094Sdes		    IPPROTO_UDP, 0);
1564127094Sdes	else if (pip->ip_p == IPPROTO_TCP)
1565131614Sdes		lnk = FindUdpTcpIn(la, pip->ip_dst, pip->ip_src,
1566127094Sdes		    tc->th_dport, tc->th_sport,
1567127094Sdes		    IPPROTO_TCP, 0);
1568127094Sdes	else if (pip->ip_p == IPPROTO_ICMP)
1569131614Sdes		lnk = FindIcmpIn(la, pip->ip_dst, pip->ip_src, ic->icmp_id, 0);
1570127094Sdes	else
1571131614Sdes		lnk = NULL;
157263899Sarchie
1573127094Sdes	/* Change it from an aliased packet to an unaliased packet */
1574131614Sdes	if (lnk != NULL) {
1575127094Sdes		if (pip->ip_p == IPPROTO_UDP || pip->ip_p == IPPROTO_TCP) {
1576127094Sdes			int accumulate;
1577127094Sdes			struct in_addr original_address;
1578127094Sdes			u_short original_port;
157963899Sarchie
1580131614Sdes			original_address = GetOriginalAddress(lnk);
1581131614Sdes			original_port = GetOriginalPort(lnk);
158299207Sbrian
1583127094Sdes			/* Adjust TCP/UDP checksum */
1584127689Sdes			accumulate = twowords(&pip->ip_src);
1585127689Sdes			accumulate -= twowords(&original_address);
158663899Sarchie
1587127094Sdes			if (pip->ip_p == IPPROTO_UDP) {
1588127094Sdes				accumulate += ud->uh_sport;
1589127094Sdes				accumulate -= original_port;
1590127094Sdes				ADJUST_CHECKSUM(accumulate, ud->uh_sum);
1591127094Sdes			} else {
1592127094Sdes				accumulate += tc->th_sport;
1593127094Sdes				accumulate -= original_port;
1594127094Sdes				ADJUST_CHECKSUM(accumulate, tc->th_sum);
1595127094Sdes			}
159663899Sarchie
1597127094Sdes			/* Adjust IP checksum */
1598127094Sdes			DifferentialChecksum(&pip->ip_sum,
1599127689Sdes			    &original_address, &pip->ip_src, 2);
160063899Sarchie
1601127094Sdes			/* Un-alias source address and port number */
1602127094Sdes			pip->ip_src = original_address;
1603127094Sdes			if (pip->ip_p == IPPROTO_UDP)
1604127094Sdes				ud->uh_sport = original_port;
1605127094Sdes			else
1606127094Sdes				tc->th_sport = original_port;
160799207Sbrian
1608127094Sdes			iresult = PKT_ALIAS_OK;
160963899Sarchie
1610127094Sdes		} else if (pip->ip_p == IPPROTO_ICMP) {
161163899Sarchie
1612127094Sdes			int accumulate;
1613127094Sdes			struct in_addr original_address;
1614127094Sdes			u_short original_id;
161563899Sarchie
1616131614Sdes			original_address = GetOriginalAddress(lnk);
1617131614Sdes			original_id = GetOriginalPort(lnk);
161863899Sarchie
1619127094Sdes			/* Adjust ICMP checksum */
1620127689Sdes			accumulate = twowords(&pip->ip_src);
1621127689Sdes			accumulate -= twowords(&original_address);
1622127094Sdes			accumulate += ic->icmp_id;
1623127094Sdes			accumulate -= original_id;
1624127094Sdes			ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
162563899Sarchie
1626127094Sdes			/* Adjust IP checksum */
1627127094Sdes			DifferentialChecksum(&pip->ip_sum,
1628127689Sdes			    &original_address, &pip->ip_src, 2);
162963899Sarchie
1630127094Sdes			/* Un-alias source address and port number */
1631127094Sdes			pip->ip_src = original_address;
1632127094Sdes			ic->icmp_id = original_id;
163363899Sarchie
1634127094Sdes			iresult = PKT_ALIAS_OK;
1635127094Sdes		}
1636127094Sdes	}
1637165243Spisogetout:
1638165243Spiso	LIBALIAS_UNLOCK(la);
1639127094Sdes	return (iresult);
164063899Sarchie
164163899Sarchie}
1642162674Spiso
1643162674Spiso#ifndef _KERNEL
1644162674Spiso
1645162674Spisoint
1646162674SpisoLibAliasRefreshModules(void)
1647162674Spiso{
1648162674Spiso	char buf[256], conf[] = "/etc/libalias.conf";
1649162674Spiso	FILE *fd;
1650164798Spiso	int i, len;
1651162674Spiso
1652162674Spiso	fd = fopen(conf, "r");
1653162674Spiso	if (fd == NULL)
1654162674Spiso		err(1, "fopen(%s)", conf);
1655162674Spiso
1656162674Spiso	LibAliasUnLoadAllModule();
1657162674Spiso
1658162674Spiso	for (;;) {
1659162674Spiso		fgets(buf, 256, fd);
1660178730Smarck		if (feof(fd))
1661162674Spiso		        break;
1662162674Spiso		len = strlen(buf);
1663162674Spiso		if (len > 1) {
1664164798Spiso			for (i = 0; i < len; i++)
1665164798Spiso				if (!isspace(buf[i]))
1666164798Spiso					break;
1667164798Spiso			if (buf[i] == '#')
1668164798Spiso				continue;
1669162674Spiso			buf[len - 1] = '\0';
1670162674Spiso			LibAliasLoadModule(buf);
1671162674Spiso		}
1672162674Spiso	}
1673198539Sbrueffer	fclose(fd);
1674162674Spiso	return (0);
1675162674Spiso}
1676162674Spiso
1677162674Spisoint
1678162674SpisoLibAliasLoadModule(char *path)
1679162674Spiso{
1680162674Spiso	struct dll *t;
1681162674Spiso	void *handle;
1682162674Spiso	struct proto_handler *m;
1683162674Spiso        const char *error;
1684162674Spiso	moduledata_t *p;
1685162674Spiso
1686162674Spiso        handle = dlopen (path, RTLD_LAZY);
1687162674Spiso        if (!handle) {
1688164798Spiso		fprintf(stderr, "%s\n", dlerror());
1689164798Spiso		return (EINVAL);
1690162674Spiso        }
1691162674Spiso
1692162674Spiso	p = dlsym(handle, "alias_mod");
1693162674Spiso        if ((error = dlerror()) != NULL)  {
1694164798Spiso		fprintf(stderr, "%s\n", dlerror());
1695164798Spiso		return (EINVAL);
1696162674Spiso        }
1697164798Spiso
1698162674Spiso	t = malloc(sizeof(struct dll));
1699162674Spiso	if (t == NULL)
1700162674Spiso		return (ENOMEM);
1701162674Spiso	strncpy(t->name, p->name, DLL_LEN);
1702162674Spiso	t->handle = handle;
1703162674Spiso	if (attach_dll(t) == EEXIST) {
1704162674Spiso		free(t);
1705164798Spiso		fprintf(stderr, "dll conflict\n");
1706162674Spiso		return (EEXIST);
1707162674Spiso	}
1708162674Spiso
1709162674Spiso        m = dlsym(t->handle, "handlers");
1710162674Spiso        if ((error = dlerror()) != NULL)  {
1711164798Spiso		fprintf(stderr, "%s\n", error);
1712164798Spiso		return (EINVAL);
1713164798Spiso	}
1714162674Spiso
1715162674Spiso	LibAliasAttachHandlers(m);
1716162674Spiso	return (0);
1717162674Spiso}
1718162674Spiso
1719162674Spisoint
1720162674SpisoLibAliasUnLoadAllModule(void)
1721162674Spiso{
1722162674Spiso	struct dll *t;
1723162674Spiso	struct proto_handler *p;
1724162674Spiso
1725162674Spiso	/* Unload all modules then reload everything. */
1726162674Spiso	while ((p = first_handler()) != NULL) {
1727162674Spiso		detach_handler(p);
1728162674Spiso	}
1729162674Spiso	while ((t = walk_dll_chain()) != NULL) {
1730162674Spiso		dlclose(t->handle);
1731162674Spiso		free(t);
1732162674Spiso	}
1733162674Spiso	return (1);
1734162674Spiso}
1735162674Spiso
1736162674Spiso#endif
1737164797Spiso
1738164797Spiso#ifdef _KERNEL
1739164797Spiso/*
1740165243Spiso * m_megapullup() - this function is a big hack.
1741165243Spiso * Thankfully, it's only used in ng_nat and ipfw+nat.
1742164797Spiso *
1743179478Smav * It allocates an mbuf with cluster and copies the specified part of the chain
1744179478Smav * into cluster, so that it is all contiguous and can be accessed via a plain
1745179478Smav * (char *) pointer. This is required, because libalias doesn't know how to
1746179478Smav * handle mbuf chains.
1747165243Spiso *
1748179478Smav * On success, m_megapullup returns an mbuf (possibly with cluster) containing
1749179478Smav * the input packet, on failure NULL. The input packet is always consumed.
1750164797Spiso */
1751164797Spisostruct mbuf *
1752335474Saem_megapullup(struct mbuf *m, int len)
1753335474Sae{
1754164797Spiso	struct mbuf *mcl;
1755248416Sglebius
1756179478Smav	if (len > m->m_pkthdr.len)
1757164797Spiso		goto bad;
1758248416Sglebius
1759248416Sglebius	if (m->m_next == NULL && M_WRITABLE(m))
1760179478Smav		return (m);
1761179478Smav
1762335474Sae	if (len <= MJUMPAGESIZE)
1763335474Sae		mcl = m_get2(len, M_NOWAIT, MT_DATA, M_PKTHDR);
1764335474Sae	else if (len <= MJUM9BYTES)
1765335474Sae		mcl = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUM9BYTES);
1766335474Sae	else if (len <= MJUM16BYTES)
1767335474Sae		mcl = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, MJUM16BYTES);
1768335474Sae	else
1769335474Sae		goto bad;
1770179478Smav	if (mcl == NULL)
1771179478Smav		goto bad;
1772248416Sglebius	m_align(mcl, len);
1773164797Spiso	m_move_pkthdr(mcl, m);
1774179478Smav	m_copydata(m, 0, len, mtod(mcl, caddr_t));
1775179478Smav	mcl->m_len = mcl->m_pkthdr.len = len;
1776164797Spiso	m_freem(m);
1777248416Sglebius
1778164797Spiso	return (mcl);
1779164797Spisobad:
1780164797Spiso	m_freem(m);
1781164797Spiso	return (NULL);
1782164797Spiso}
1783164797Spiso#endif
1784