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: releng/10.3/sys/netinet/libalias/alias.c 248416 2013-03-17 07:37:10Z glebius $");
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	(void)create;
703131614Sdes
70459356Sru/* Return if proxy-only mode is enabled */
705127094Sdes	if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
706131613Sdes		return (PKT_ALIAS_OK);
70744307Sbrian
708177098Spiso	lnk = FindProtoOut(la, *ip_src, ip_dst, ip_p);
709131614Sdes	if (lnk != NULL) {
710127094Sdes		struct in_addr alias_address;
71159356Sru
712131614Sdes		alias_address = GetAliasAddress(lnk);
71359356Sru
71459356Sru/* Change source address */
715177098Spiso		DifferentialChecksum(ip_sum,
716177098Spiso		    &alias_address, ip_src, 2);
717177098Spiso		*ip_src = alias_address;
71859356Sru
719127094Sdes		return (PKT_ALIAS_OK);
720127094Sdes	}
721127094Sdes	return (PKT_ALIAS_IGNORED);
72244307Sbrian}
72344307Sbrian
72444307Sbrian
72561861Srustatic int
726124621SphkUdpAliasIn(struct libalias *la, struct ip *pip)
72726026Sbrian{
728127094Sdes	struct udphdr *ud;
729131614Sdes	struct alias_link *lnk;
73026026Sbrian
731165243Spiso	LIBALIAS_LOCK_ASSERT(la);
73244307Sbrian
733131699Sdes	ud = (struct udphdr *)ip_next(pip);
73426026Sbrian
735131614Sdes	lnk = FindUdpTcpIn(la, pip->ip_src, pip->ip_dst,
736127094Sdes	    ud->uh_sport, ud->uh_dport,
737179920Smav	    IPPROTO_UDP, !(la->packetAliasMode & PKT_ALIAS_PROXY_ONLY));
738131614Sdes	if (lnk != NULL) {
739127094Sdes		struct in_addr alias_address;
740127094Sdes		struct in_addr original_address;
741179920Smav		struct in_addr proxy_address;
742127094Sdes		u_short alias_port;
743179920Smav		u_short proxy_port;
744127094Sdes		int accumulate;
745190938Spiso		int error;
746162674Spiso		struct alias_data ad = {
747162674Spiso			.lnk = lnk,
748162674Spiso			.oaddr = &original_address,
749162674Spiso			.aaddr = &alias_address,
750162674Spiso			.aport = &alias_port,
751162674Spiso			.sport = &ud->uh_sport,
752162674Spiso			.dport = &ud->uh_dport,
753162674Spiso			.maxpktsize = 0
754162674Spiso		};
75526026Sbrian
756131614Sdes		alias_address = GetAliasAddress(lnk);
757131614Sdes		original_address = GetOriginalAddress(lnk);
758179920Smav		proxy_address = GetProxyAddress(lnk);
759127094Sdes		alias_port = ud->uh_dport;
760131614Sdes		ud->uh_dport = GetOriginalPort(lnk);
761179920Smav		proxy_port = GetProxyPort(lnk);
76226026Sbrian
763162674Spiso		/* Walk out chain. */
764162674Spiso		error = find_handler(IN, UDP, la, pip, &ad);
765190941Spiso		/* If we cannot figure out the packet, ignore it. */
766190941Spiso		if (error < 0)
767190941Spiso			return (PKT_ALIAS_IGNORED);
76836321Samurai
76926026Sbrian/* If UDP checksum is not zero, then adjust since destination port */
77066545Sru/* is being unaliased and destination address is being altered.    */
771127094Sdes		if (ud->uh_sum != 0) {
772127094Sdes			accumulate = alias_port;
773127094Sdes			accumulate -= ud->uh_dport;
774127689Sdes			accumulate += twowords(&alias_address);
775127689Sdes			accumulate -= twowords(&original_address);
776179920Smav
777179920Smav/* If this is a proxy packet, modify checksum because of source change.*/
778179920Smav        		if (proxy_port != 0) {
779179920Smav		                accumulate += ud->uh_sport;
780179920Smav		                accumulate -= proxy_port;
781179920Smav	                }
782179920Smav
783179920Smav	                if (proxy_address.s_addr != 0) {
784179920Smav				accumulate += twowords(&pip->ip_src);
785179920Smav				accumulate -= twowords(&proxy_address);
786179920Smav	                }
787179920Smav
788127094Sdes			ADJUST_CHECKSUM(accumulate, ud->uh_sum);
789127094Sdes		}
790179920Smav/* XXX: Could the two if's below be concatenated to one ? */
791179920Smav/* Restore source port and/or address in case of proxying*/
792179920Smav
793179920Smav    		if (proxy_port != 0)
794179920Smav        		ud->uh_sport = proxy_port;
795179920Smav
796179920Smav    		if (proxy_address.s_addr != 0) {
797179920Smav        		DifferentialChecksum(&pip->ip_sum,
798179920Smav                	    &proxy_address, &pip->ip_src, 2);
799179920Smav	        	pip->ip_src = proxy_address;
800179920Smav    		}
801179920Smav
80226026Sbrian/* Restore original IP address */
803127094Sdes		DifferentialChecksum(&pip->ip_sum,
804127689Sdes		    &original_address, &pip->ip_dst, 2);
805127094Sdes		pip->ip_dst = original_address;
80641759Sdillon
807190941Spiso		return (PKT_ALIAS_OK);
808127094Sdes	}
809127094Sdes	return (PKT_ALIAS_IGNORED);
81026026Sbrian}
81126026Sbrian
81226026Sbrianstatic int
813179920SmavUdpAliasOut(struct libalias *la, struct ip *pip, int maxpacketsize, int create)
81426026Sbrian{
815127094Sdes	struct udphdr *ud;
816131614Sdes	struct alias_link *lnk;
817179920Smav	struct in_addr dest_address;
818179920Smav	struct in_addr proxy_server_address;
819179920Smav	u_short dest_port;
820179920Smav	u_short proxy_server_port;
821179920Smav	int proxy_type;
822162674Spiso	int error;
82326026Sbrian
824165243Spiso	LIBALIAS_LOCK_ASSERT(la);
82544307Sbrian
826179920Smav/* Return if proxy-only mode is enabled and not proxyrule found.*/
827131699Sdes	ud = (struct udphdr *)ip_next(pip);
828179920Smav	proxy_type = ProxyCheck(la, &proxy_server_address,
829179920Smav		&proxy_server_port, pip->ip_src, pip->ip_dst,
830179920Smav		ud->uh_dport, pip->ip_p);
831179920Smav	if (proxy_type == 0 && (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY))
832179920Smav		return (PKT_ALIAS_OK);
83326026Sbrian
834179920Smav/* If this is a transparent proxy, save original destination,
835179920Smav * then alter the destination and adjust checksums */
836179920Smav	dest_port = ud->uh_dport;
837179920Smav	dest_address = pip->ip_dst;
838179920Smav
839179920Smav	if (proxy_type != 0) {
840179920Smav	        int accumulate;
841179920Smav
842179920Smav		accumulate = twowords(&pip->ip_dst);
843179920Smav		accumulate -= twowords(&proxy_server_address);
844179920Smav
845179920Smav	        ADJUST_CHECKSUM(accumulate, pip->ip_sum);
846179920Smav
847179920Smav		if (ud->uh_sum != 0) {
848179920Smav			accumulate = twowords(&pip->ip_dst);
849179920Smav			accumulate -= twowords(&proxy_server_address);
850179920Smav    			accumulate += ud->uh_dport;
851179920Smav	        	accumulate -= proxy_server_port;
852179920Smav	    		ADJUST_CHECKSUM(accumulate, ud->uh_sum);
853179920Smav		}
854179920Smav	        pip->ip_dst = proxy_server_address;
855179920Smav	        ud->uh_dport = proxy_server_port;
856179920Smav	}
857131614Sdes	lnk = FindUdpTcpOut(la, pip->ip_src, pip->ip_dst,
858127094Sdes	    ud->uh_sport, ud->uh_dport,
859131566Sphk	    IPPROTO_UDP, create);
860131614Sdes	if (lnk != NULL) {
861127094Sdes		u_short alias_port;
862127094Sdes		struct in_addr alias_address;
863162674Spiso		struct alias_data ad = {
864162674Spiso			.lnk = lnk,
865162674Spiso			.oaddr = NULL,
866162674Spiso			.aaddr = &alias_address,
867162674Spiso			.aport = &alias_port,
868162674Spiso			.sport = &ud->uh_sport,
869162674Spiso			.dport = &ud->uh_dport,
870162674Spiso			.maxpktsize = 0
871162674Spiso		};
87226026Sbrian
873179920Smav/* Save original destination address, if this is a proxy packet.
874179920Smav * Also modify packet to include destination encoding.  This may
875179920Smav * change the size of IP header. */
876179920Smav		if (proxy_type != 0) {
877179920Smav	                SetProxyPort(lnk, dest_port);
878179920Smav	                SetProxyAddress(lnk, dest_address);
879179920Smav	                ProxyModify(la, lnk, pip, maxpacketsize, proxy_type);
880179920Smav	                ud = (struct udphdr *)ip_next(pip);
881179920Smav	        }
882179920Smav
883131614Sdes		alias_address = GetAliasAddress(lnk);
884131614Sdes		alias_port = GetAliasPort(lnk);
88526026Sbrian
886162674Spiso		/* Walk out chain. */
887162674Spiso		error = find_handler(OUT, UDP, la, pip, &ad);
88836321Samurai
88926026Sbrian/* If UDP checksum is not zero, adjust since source port is */
89026026Sbrian/* being aliased and source address is being altered        */
891127094Sdes		if (ud->uh_sum != 0) {
892127094Sdes			int accumulate;
89326026Sbrian
894127094Sdes			accumulate = ud->uh_sport;
895127094Sdes			accumulate -= alias_port;
896127689Sdes			accumulate += twowords(&pip->ip_src);
897127689Sdes			accumulate -= twowords(&alias_address);
898127094Sdes			ADJUST_CHECKSUM(accumulate, ud->uh_sum);
899127094Sdes		}
90036321Samurai/* Put alias port in UDP header */
901127094Sdes		ud->uh_sport = alias_port;
90226026Sbrian
90326026Sbrian/* Change source address */
904127094Sdes		DifferentialChecksum(&pip->ip_sum,
905127689Sdes		    &alias_address, &pip->ip_src, 2);
906127094Sdes		pip->ip_src = alias_address;
90726026Sbrian
908127094Sdes		return (PKT_ALIAS_OK);
909127094Sdes	}
910127094Sdes	return (PKT_ALIAS_IGNORED);
91126026Sbrian}
91226026Sbrian
91326026Sbrian
91426026Sbrian
91526026Sbrianstatic int
916124621SphkTcpAliasIn(struct libalias *la, struct ip *pip)
91726026Sbrian{
918127094Sdes	struct tcphdr *tc;
919131614Sdes	struct alias_link *lnk;
92026026Sbrian
921165243Spiso	LIBALIAS_LOCK_ASSERT(la);
922131699Sdes	tc = (struct tcphdr *)ip_next(pip);
92326026Sbrian
924131614Sdes	lnk = FindUdpTcpIn(la, pip->ip_src, pip->ip_dst,
925127094Sdes	    tc->th_sport, tc->th_dport,
926127094Sdes	    IPPROTO_TCP,
927127094Sdes	    !(la->packetAliasMode & PKT_ALIAS_PROXY_ONLY));
928131614Sdes	if (lnk != NULL) {
929127094Sdes		struct in_addr alias_address;
930127094Sdes		struct in_addr original_address;
931127094Sdes		struct in_addr proxy_address;
932127094Sdes		u_short alias_port;
933127094Sdes		u_short proxy_port;
934162674Spiso		int accumulate, error;
93526026Sbrian
936162674Spiso		/*
937162674Spiso		 * The init of MANY vars is a bit below, but aliashandlepptpin
938162674Spiso		 * seems to need the destination port that came within the
939162674Spiso		 * packet and not the original one looks below [*].
940162674Spiso		 */
94161861Sru
942162674Spiso		struct alias_data ad = {
943162674Spiso			.lnk = lnk,
944162674Spiso			.oaddr = NULL,
945162674Spiso			.aaddr = NULL,
946162674Spiso			.aport = NULL,
947162674Spiso			.sport = &tc->th_sport,
948162674Spiso			.dport = &tc->th_dport,
949162674Spiso			.maxpktsize = 0
950162674Spiso		};
951162674Spiso
952162674Spiso		/* Walk out chain. */
953162674Spiso		error = find_handler(IN, TCP, la, pip, &ad);
954162674Spiso
955131614Sdes		alias_address = GetAliasAddress(lnk);
956131614Sdes		original_address = GetOriginalAddress(lnk);
957131614Sdes		proxy_address = GetProxyAddress(lnk);
958127094Sdes		alias_port = tc->th_dport;
959131614Sdes		tc->th_dport = GetOriginalPort(lnk);
960131614Sdes		proxy_port = GetProxyPort(lnk);
96126026Sbrian
962162674Spiso		/*
963162674Spiso		 * Look above, if anyone is going to add find_handler AFTER
964162674Spiso		 * this aliashandlepptpin/point, please redo alias_data too.
965162674Spiso		 * Uncommenting the piece here below should be enough.
966162674Spiso		 */
967162674Spiso#if 0
968162674Spiso				 struct alias_data ad = {
969162674Spiso					.lnk = lnk,
970162674Spiso					.oaddr = &original_address,
971162674Spiso					.aaddr = &alias_address,
972162674Spiso					.aport = &alias_port,
973162674Spiso					.sport = &ud->uh_sport,
974162674Spiso					.dport = &ud->uh_dport,
975162674Spiso					.maxpktsize = 0
976162674Spiso				};
977162674Spiso
978162674Spiso				/* Walk out chain. */
979162674Spiso				error = find_handler(la, pip, &ad);
980162674Spiso				if (error == EHDNOF)
981162674Spiso					printf("Protocol handler not found\n");
982162674Spiso#endif
983162674Spiso
98426026Sbrian/* Adjust TCP checksum since destination port is being unaliased */
98526026Sbrian/* and destination port is being altered.                        */
986127094Sdes		accumulate = alias_port;
987127094Sdes		accumulate -= tc->th_dport;
988127689Sdes		accumulate += twowords(&alias_address);
989127689Sdes		accumulate -= twowords(&original_address);
99026026Sbrian
99159356Sru/* If this is a proxy, then modify the TCP source port and
99244307Sbrian   checksum accumulation */
993127094Sdes		if (proxy_port != 0) {
994127094Sdes			accumulate += tc->th_sport;
995127094Sdes			tc->th_sport = proxy_port;
996127094Sdes			accumulate -= tc->th_sport;
997127689Sdes			accumulate += twowords(&pip->ip_src);
998127689Sdes			accumulate -= twowords(&proxy_address);
999127094Sdes		}
100059356Sru/* See if ACK number needs to be modified */
1001131614Sdes		if (GetAckModified(lnk) == 1) {
1002127094Sdes			int delta;
100326026Sbrian
1004176884Spiso			tc = (struct tcphdr *)ip_next(pip);
1005176884Spiso			delta = GetDeltaAckIn(tc->th_ack, lnk);
1006127094Sdes			if (delta != 0) {
1007127689Sdes				accumulate += twowords(&tc->th_ack);
1008127094Sdes				tc->th_ack = htonl(ntohl(tc->th_ack) - delta);
1009127689Sdes				accumulate -= twowords(&tc->th_ack);
1010127094Sdes			}
1011127094Sdes		}
1012127094Sdes		ADJUST_CHECKSUM(accumulate, tc->th_sum);
101326026Sbrian
101426026Sbrian/* Restore original IP address */
1015127689Sdes		accumulate = twowords(&pip->ip_dst);
1016127757Sdeischen		pip->ip_dst = original_address;
1017127689Sdes		accumulate -= twowords(&pip->ip_dst);
101826026Sbrian
101944307Sbrian/* If this is a transparent proxy packet, then modify the source
102044307Sbrian   address */
1021127094Sdes		if (proxy_address.s_addr != 0) {
1022127689Sdes			accumulate += twowords(&pip->ip_src);
1023127094Sdes			pip->ip_src = proxy_address;
1024127689Sdes			accumulate -= twowords(&pip->ip_src);
1025127094Sdes		}
1026127094Sdes		ADJUST_CHECKSUM(accumulate, pip->ip_sum);
102744307Sbrian
102826026Sbrian/* Monitor TCP connection state */
1029176884Spiso		tc = (struct tcphdr *)ip_next(pip);
1030176884Spiso		TcpMonitorIn(tc->th_flags, lnk);
103126026Sbrian
1032127094Sdes		return (PKT_ALIAS_OK);
1033127094Sdes	}
1034127094Sdes	return (PKT_ALIAS_IGNORED);
103526026Sbrian}
103626026Sbrian
103726026Sbrianstatic int
1038131566SphkTcpAliasOut(struct libalias *la, struct ip *pip, int maxpacketsize, int create)
103926026Sbrian{
1040162674Spiso	int proxy_type, error;
1041127094Sdes	u_short dest_port;
1042127094Sdes	u_short proxy_server_port;
1043127094Sdes	struct in_addr dest_address;
1044127094Sdes	struct in_addr proxy_server_address;
1045127094Sdes	struct tcphdr *tc;
1046131614Sdes	struct alias_link *lnk;
104726026Sbrian
1048165243Spiso	LIBALIAS_LOCK_ASSERT(la);
1049131699Sdes	tc = (struct tcphdr *)ip_next(pip);
105026026Sbrian
1051147636Sphk	if (create)
1052176884Spiso		proxy_type = ProxyCheck(la, &proxy_server_address,
1053176884Spiso		    &proxy_server_port, pip->ip_src, pip->ip_dst,
1054176884Spiso		    tc->th_dport, pip->ip_p);
1055147636Sphk	else
1056147636Sphk		proxy_type = 0;
105744307Sbrian
1058127094Sdes	if (proxy_type == 0 && (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY))
1059131613Sdes		return (PKT_ALIAS_OK);
106044307Sbrian
106144307Sbrian/* If this is a transparent proxy, save original destination,
106259356Sru   then alter the destination and adjust checksums */
1063127094Sdes	dest_port = tc->th_dport;
1064127094Sdes	dest_address = pip->ip_dst;
1065127094Sdes	if (proxy_type != 0) {
1066127094Sdes		int accumulate;
106744307Sbrian
1068127094Sdes		accumulate = tc->th_dport;
1069127094Sdes		tc->th_dport = proxy_server_port;
1070127094Sdes		accumulate -= tc->th_dport;
1071127689Sdes		accumulate += twowords(&pip->ip_dst);
1072127689Sdes		accumulate -= twowords(&proxy_server_address);
1073127094Sdes		ADJUST_CHECKSUM(accumulate, tc->th_sum);
107444307Sbrian
1075127689Sdes		accumulate = twowords(&pip->ip_dst);
1076127094Sdes		pip->ip_dst = proxy_server_address;
1077127689Sdes		accumulate -= twowords(&pip->ip_dst);
1078127094Sdes		ADJUST_CHECKSUM(accumulate, pip->ip_sum);
1079127094Sdes	}
1080131614Sdes	lnk = FindUdpTcpOut(la, pip->ip_src, pip->ip_dst,
1081127094Sdes	    tc->th_sport, tc->th_dport,
1082131566Sphk	    IPPROTO_TCP, create);
1083131614Sdes	if (lnk == NULL)
1084131566Sphk		return (PKT_ALIAS_IGNORED);
1085131614Sdes	if (lnk != NULL) {
1086127094Sdes		u_short alias_port;
1087127094Sdes		struct in_addr alias_address;
1088127094Sdes		int accumulate;
1089162674Spiso		struct alias_data ad = {
1090162674Spiso			.lnk = lnk,
1091162674Spiso			.oaddr = NULL,
1092162674Spiso			.aaddr = &alias_address,
1093162674Spiso			.aport = &alias_port,
1094162674Spiso			.sport = &tc->th_sport,
1095162674Spiso			.dport = &tc->th_dport,
1096162674Spiso			.maxpktsize = maxpacketsize
1097162674Spiso		};
109844307Sbrian
109944307Sbrian/* Save original destination address, if this is a proxy packet.
110088132Sru   Also modify packet to include destination encoding.  This may
110188132Sru   change the size of IP header. */
1102127094Sdes		if (proxy_type != 0) {
1103131614Sdes			SetProxyPort(lnk, dest_port);
1104131614Sdes			SetProxyAddress(lnk, dest_address);
1105131614Sdes			ProxyModify(la, lnk, pip, maxpacketsize, proxy_type);
1106131699Sdes			tc = (struct tcphdr *)ip_next(pip);
1107127094Sdes		}
110844307Sbrian/* Get alias address and port */
1109131614Sdes		alias_port = GetAliasPort(lnk);
1110131614Sdes		alias_address = GetAliasAddress(lnk);
111126026Sbrian
111259356Sru/* Monitor TCP connection state */
1113176884Spiso		tc = (struct tcphdr *)ip_next(pip);
1114176884Spiso		TcpMonitorOut(tc->th_flags, lnk);
1115162674Spiso
1116162674Spiso		/* Walk out chain. */
1117162674Spiso		error = find_handler(OUT, TCP, la, pip, &ad);
111826026Sbrian
111926026Sbrian/* Adjust TCP checksum since source port is being aliased */
112026026Sbrian/* and source address is being altered                    */
1121127094Sdes		accumulate = tc->th_sport;
1122127094Sdes		tc->th_sport = alias_port;
1123127094Sdes		accumulate -= tc->th_sport;
1124127689Sdes		accumulate += twowords(&pip->ip_src);
1125127689Sdes		accumulate -= twowords(&alias_address);
112644307Sbrian
112726026Sbrian/* Modify sequence number if necessary */
1128131614Sdes		if (GetAckModified(lnk) == 1) {
1129127094Sdes			int delta;
1130176884Spiso
1131176884Spiso			tc = (struct tcphdr *)ip_next(pip);
1132176884Spiso			delta = GetDeltaSeqOut(tc->th_seq, lnk);
1133127094Sdes			if (delta != 0) {
1134127689Sdes				accumulate += twowords(&tc->th_seq);
1135127094Sdes				tc->th_seq = htonl(ntohl(tc->th_seq) + delta);
1136127689Sdes				accumulate -= twowords(&tc->th_seq);
1137127094Sdes			}
1138127094Sdes		}
1139127094Sdes		ADJUST_CHECKSUM(accumulate, tc->th_sum);
114026026Sbrian
114126026Sbrian/* Change source address */
1142127689Sdes		accumulate = twowords(&pip->ip_src);
1143127094Sdes		pip->ip_src = alias_address;
1144127689Sdes		accumulate -= twowords(&pip->ip_src);
1145127094Sdes		ADJUST_CHECKSUM(accumulate, pip->ip_sum);
114644307Sbrian
1147127094Sdes		return (PKT_ALIAS_OK);
1148127094Sdes	}
1149127094Sdes	return (PKT_ALIAS_IGNORED);
115026026Sbrian}
115126026Sbrian
115226026Sbrian
115326026Sbrian
115426026Sbrian
115526026Sbrian/* Fragment Handling
115626026Sbrian
115726026Sbrian    FragmentIn()
115826026Sbrian    FragmentOut()
115926026Sbrian
116026026SbrianThe packet aliasing module has a limited ability for handling IP
116126026Sbrianfragments.  If the ICMP, TCP or UDP header is in the first fragment
116259356Srureceived, then the ID number of the IP packet is saved, and other
116326026Sbrianfragments are identified according to their ID number and IP address
116426026Sbrianthey were sent from.  Pointers to unresolved fragments can also be
116526026Sbriansaved and recalled when a header fragment is seen.
116626026Sbrian*/
116726026Sbrian
116826026Sbrian/* Local prototypes */
1169177098Spisostatic int	FragmentIn(struct libalias *la, struct in_addr ip_src,
1170179472Smav		    struct in_addr *ip_dst, u_short ip_id, u_short *ip_sum);
1171177098Spisostatic int	FragmentOut(struct libalias *, struct in_addr *ip_src,
1172177098Spiso		    u_short *ip_sum);
117326026Sbrian
117426026Sbrianstatic int
1175177098SpisoFragmentIn(struct libalias *la, struct in_addr ip_src, struct in_addr *ip_dst,
1176179472Smav    u_short ip_id, u_short *ip_sum)
117726026Sbrian{
1178131614Sdes	struct alias_link *lnk;
117926026Sbrian
1180165243Spiso	LIBALIAS_LOCK_ASSERT(la);
1181177098Spiso	lnk = FindFragmentIn2(la, ip_src, *ip_dst, ip_id);
1182131614Sdes	if (lnk != NULL) {
1183127094Sdes		struct in_addr original_address;
118426026Sbrian
1185131614Sdes		GetFragmentAddr(lnk, &original_address);
1186177098Spiso		DifferentialChecksum(ip_sum,
1187177098Spiso		    &original_address, ip_dst, 2);
1188177098Spiso		*ip_dst = original_address;
118999207Sbrian
1190127094Sdes		return (PKT_ALIAS_OK);
1191127094Sdes	}
1192127094Sdes	return (PKT_ALIAS_UNRESOLVED_FRAGMENT);
119326026Sbrian}
119426026Sbrian
119526026Sbrianstatic int
1196177098SpisoFragmentOut(struct libalias *la, struct in_addr *ip_src, u_short *ip_sum)
119726026Sbrian{
1198127094Sdes	struct in_addr alias_address;
119926026Sbrian
1200165243Spiso	LIBALIAS_LOCK_ASSERT(la);
1201177098Spiso	alias_address = FindAliasAddress(la, *ip_src);
1202177098Spiso	DifferentialChecksum(ip_sum,
1203177098Spiso	    &alias_address, ip_src, 2);
1204177098Spiso	*ip_src = alias_address;
120526026Sbrian
1206127094Sdes	return (PKT_ALIAS_OK);
120726026Sbrian}
120826026Sbrian
120926026Sbrian
121026026Sbrian
121126026Sbrian
121226026Sbrian
121326026Sbrian
121426026Sbrian/* Outside World Access
121526026Sbrian
1216131612Sdes	PacketAliasSaveFragment()
1217131612Sdes	PacketAliasGetFragment()
1218131612Sdes	PacketAliasFragmentIn()
1219131612Sdes	PacketAliasIn()
1220131612Sdes	PacketAliasOut()
1221131612Sdes	PacketUnaliasOut()
122226026Sbrian
122326026Sbrian(prototypes in alias.h)
122426026Sbrian*/
122526026Sbrian
122626026Sbrianint
1227124621SphkLibAliasSaveFragment(struct libalias *la, char *ptr)
122826026Sbrian{
1229127094Sdes	int iresult;
1230131614Sdes	struct alias_link *lnk;
1231127094Sdes	struct ip *pip;
123226026Sbrian
1233165243Spiso	LIBALIAS_LOCK(la);
1234127094Sdes	pip = (struct ip *)ptr;
1235131614Sdes	lnk = AddFragmentPtrLink(la, pip->ip_src, pip->ip_id);
1236127094Sdes	iresult = PKT_ALIAS_ERROR;
1237131614Sdes	if (lnk != NULL) {
1238131614Sdes		SetFragmentPtr(lnk, ptr);
1239127094Sdes		iresult = PKT_ALIAS_OK;
1240127094Sdes	}
1241165243Spiso	LIBALIAS_UNLOCK(la);
1242127094Sdes	return (iresult);
124326026Sbrian}
124426026Sbrian
1245127094Sdeschar           *
1246124621SphkLibAliasGetFragment(struct libalias *la, char *ptr)
124726026Sbrian{
1248131614Sdes	struct alias_link *lnk;
1249127094Sdes	char *fptr;
1250127094Sdes	struct ip *pip;
125126026Sbrian
1252165243Spiso	LIBALIAS_LOCK(la);
1253127094Sdes	pip = (struct ip *)ptr;
1254131614Sdes	lnk = FindFragmentPtr(la, pip->ip_src, pip->ip_id);
1255131614Sdes	if (lnk != NULL) {
1256131614Sdes		GetFragmentPtr(lnk, &fptr);
1257131614Sdes		SetFragmentPtr(lnk, NULL);
1258131614Sdes		SetExpire(lnk, 0);	/* Deletes link */
1259165243Spiso	} else
1260165243Spiso		fptr = NULL;
126126026Sbrian
1262165243Spiso	LIBALIAS_UNLOCK(la);
1263165243Spiso	return (fptr);
126426026Sbrian}
126526026Sbrian
126626026Sbrianvoid
1267127094SdesLibAliasFragmentIn(struct libalias *la, char *ptr,	/* Points to correctly
1268127094Sdes							 * de-aliased header
1269127094Sdes							 * fragment */
1270127094Sdes    char *ptr_fragment		/* Points to fragment which must be
1271127094Sdes				 * de-aliased   */
1272127094Sdes)
127326026Sbrian{
1274127094Sdes	struct ip *pip;
1275127094Sdes	struct ip *fpip;
127626026Sbrian
1277165243Spiso	LIBALIAS_LOCK(la);
1278131614Sdes	(void)la;
1279127094Sdes	pip = (struct ip *)ptr;
1280127094Sdes	fpip = (struct ip *)ptr_fragment;
128126026Sbrian
1282127094Sdes	DifferentialChecksum(&fpip->ip_sum,
1283127689Sdes	    &pip->ip_dst, &fpip->ip_dst, 2);
1284127094Sdes	fpip->ip_dst = pip->ip_dst;
1285165243Spiso	LIBALIAS_UNLOCK(la);
128626026Sbrian}
128726026Sbrian
1288165243Spiso/* Local prototypes */
1289165243Spisostatic int
1290165243SpisoLibAliasOutLocked(struct libalias *la, char *ptr,
1291165243Spiso		  int maxpacketsize, int create);
1292165243Spisostatic int
1293165243SpisoLibAliasInLocked(struct libalias *la, char *ptr,
1294165243Spiso		  int maxpacketsize);
129526026Sbrian
129626026Sbrianint
1297124621SphkLibAliasIn(struct libalias *la, char *ptr, int maxpacketsize)
129826026Sbrian{
1299165243Spiso	int res;
1300165243Spiso
1301165243Spiso	LIBALIAS_LOCK(la);
1302165243Spiso	res = LibAliasInLocked(la, ptr, maxpacketsize);
1303165243Spiso	LIBALIAS_UNLOCK(la);
1304165243Spiso	return (res);
1305165243Spiso}
1306165243Spiso
1307165243Spisostatic int
1308165243SpisoLibAliasInLocked(struct libalias *la, char *ptr, int maxpacketsize)
1309165243Spiso{
1310127094Sdes	struct in_addr alias_addr;
1311127094Sdes	struct ip *pip;
1312127094Sdes	int iresult;
131326026Sbrian
1314127094Sdes	if (la->packetAliasMode & PKT_ALIAS_REVERSE) {
1315127094Sdes		la->packetAliasMode &= ~PKT_ALIAS_REVERSE;
1316165243Spiso		iresult = LibAliasOutLocked(la, ptr, maxpacketsize, 1);
1317127094Sdes		la->packetAliasMode |= PKT_ALIAS_REVERSE;
1318165243Spiso		goto getout;
1319127094Sdes	}
1320127094Sdes	HouseKeeping(la);
1321127094Sdes	ClearCheckNewLink(la);
1322127094Sdes	pip = (struct ip *)ptr;
1323127094Sdes	alias_addr = pip->ip_dst;
132444307Sbrian
1325127094Sdes	/* Defense against mangled packets */
1326127094Sdes	if (ntohs(pip->ip_len) > maxpacketsize
1327165243Spiso	    || (pip->ip_hl << 2) > maxpacketsize) {
1328165243Spiso		iresult = PKT_ALIAS_IGNORED;
1329165243Spiso		goto getout;
1330165243Spiso	}
133199207Sbrian
1332127094Sdes	iresult = PKT_ALIAS_IGNORED;
1333127094Sdes	if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
1334127094Sdes		switch (pip->ip_p) {
1335127094Sdes		case IPPROTO_ICMP:
1336127094Sdes			iresult = IcmpAliasIn(la, pip);
1337127094Sdes			break;
1338127094Sdes		case IPPROTO_UDP:
1339127094Sdes			iresult = UdpAliasIn(la, pip);
1340127094Sdes			break;
1341127094Sdes		case IPPROTO_TCP:
1342127094Sdes			iresult = TcpAliasIn(la, pip);
1343127094Sdes			break;
1344188294Spiso#ifdef _KERNEL
1345188294Spiso		case IPPROTO_SCTP:
1346188294Spiso		  iresult = SctpAlias(la, pip, SN_TO_LOCAL);
1347188294Spiso			break;
1348188294Spiso#endif
1349162674Spiso 		case IPPROTO_GRE: {
1350162674Spiso			int error;
1351162674Spiso			struct alias_data ad = {
1352162674Spiso				.lnk = NULL,
1353162674Spiso				.oaddr = NULL,
1354162674Spiso				.aaddr = NULL,
1355162674Spiso				.aport = NULL,
1356162674Spiso				.sport = NULL,
1357162674Spiso				.dport = NULL,
1358162674Spiso				.maxpktsize = 0
1359162674Spiso			};
1360162674Spiso
1361162674Spiso			/* Walk out chain. */
1362162674Spiso			error = find_handler(IN, IP, la, pip, &ad);
1363162674Spiso			if (error ==  0)
1364127094Sdes				iresult = PKT_ALIAS_OK;
1365127094Sdes			else
1366177098Spiso				iresult = ProtoAliasIn(la, pip->ip_src,
1367177098Spiso				    &pip->ip_dst, pip->ip_p, &pip->ip_sum);
1368162674Spiso		}
1369162674Spiso 			break;
1370127094Sdes		default:
1371177098Spiso			iresult = ProtoAliasIn(la, pip->ip_src, &pip->ip_dst,
1372177098Spiso			    pip->ip_p, &pip->ip_sum);
1373127094Sdes			break;
1374127094Sdes		}
137599207Sbrian
1376127094Sdes		if (ntohs(pip->ip_off) & IP_MF) {
1377131614Sdes			struct alias_link *lnk;
137826026Sbrian
1379131614Sdes			lnk = FindFragmentIn1(la, pip->ip_src, alias_addr, pip->ip_id);
1380131614Sdes			if (lnk != NULL) {
1381127094Sdes				iresult = PKT_ALIAS_FOUND_HEADER_FRAGMENT;
1382131614Sdes				SetFragmentAddr(lnk, pip->ip_dst);
1383127094Sdes			} else {
1384127094Sdes				iresult = PKT_ALIAS_ERROR;
1385127094Sdes			}
1386127094Sdes		}
1387127094Sdes	} else {
1388177098Spiso		iresult = FragmentIn(la, pip->ip_src, &pip->ip_dst, pip->ip_id,
1389177098Spiso		    &pip->ip_sum);
1390127094Sdes	}
139126026Sbrian
1392165243Spisogetout:
1393127094Sdes	return (iresult);
139426026Sbrian}
139526026Sbrian
139626026Sbrian
139726026Sbrian
139826026Sbrian/* Unregistered address ranges */
139926026Sbrian
140026026Sbrian/* 10.0.0.0   ->   10.255.255.255 */
140126026Sbrian#define UNREG_ADDR_A_LOWER 0x0a000000
140226026Sbrian#define UNREG_ADDR_A_UPPER 0x0affffff
140326026Sbrian
140426026Sbrian/* 172.16.0.0  ->  172.31.255.255 */
140526026Sbrian#define UNREG_ADDR_B_LOWER 0xac100000
140626026Sbrian#define UNREG_ADDR_B_UPPER 0xac1fffff
140726026Sbrian
140826026Sbrian/* 192.168.0.0 -> 192.168.255.255 */
140926026Sbrian#define UNREG_ADDR_C_LOWER 0xc0a80000
141026026Sbrian#define UNREG_ADDR_C_UPPER 0xc0a8ffff
141126026Sbrian
141226026Sbrianint
1413165243SpisoLibAliasOut(struct libalias *la, char *ptr, int maxpacketsize)
141426026Sbrian{
1415165243Spiso	int res;
1416165243Spiso
1417165243Spiso	LIBALIAS_LOCK(la);
1418165243Spiso	res = LibAliasOutLocked(la, ptr, maxpacketsize, 1);
1419165243Spiso	LIBALIAS_UNLOCK(la);
1420165243Spiso	return (res);
1421131566Sphk}
1422131566Sphk
1423131566Sphkint
1424165243SpisoLibAliasOutTry(struct libalias *la, char *ptr, int maxpacketsize, int create)
1425165243Spiso{
1426165243Spiso	int res;
1427165243Spiso
1428165243Spiso	LIBALIAS_LOCK(la);
1429165243Spiso	res = LibAliasOutLocked(la, ptr, maxpacketsize, create);
1430165243Spiso	LIBALIAS_UNLOCK(la);
1431165243Spiso	return (res);
1432165243Spiso}
1433165243Spiso
1434165243Spisostatic int
1435165243SpisoLibAliasOutLocked(struct libalias *la, char *ptr,	/* valid IP packet */
1436131566Sphk    int maxpacketsize,		/* How much the packet data may grow (FTP
1437131566Sphk				 * and IRC inline changes) */
1438165243Spiso    int create                  /* Create new entries ? */
1439131566Sphk)
1440131566Sphk{
1441127094Sdes	int iresult;
1442127094Sdes	struct in_addr addr_save;
1443127094Sdes	struct ip *pip;
144426026Sbrian
1445127094Sdes	if (la->packetAliasMode & PKT_ALIAS_REVERSE) {
1446127094Sdes		la->packetAliasMode &= ~PKT_ALIAS_REVERSE;
1447165243Spiso		iresult = LibAliasInLocked(la, ptr, maxpacketsize);
1448127094Sdes		la->packetAliasMode |= PKT_ALIAS_REVERSE;
1449165243Spiso		goto getout;
1450127094Sdes	}
1451127094Sdes	HouseKeeping(la);
1452127094Sdes	ClearCheckNewLink(la);
1453127094Sdes	pip = (struct ip *)ptr;
145444307Sbrian
1455127094Sdes	/* Defense against mangled packets */
1456127094Sdes	if (ntohs(pip->ip_len) > maxpacketsize
1457165243Spiso	    || (pip->ip_hl << 2) > maxpacketsize) {
1458165243Spiso		iresult = PKT_ALIAS_IGNORED;
1459165243Spiso		goto getout;
1460165243Spiso	}
146126026Sbrian
1462127094Sdes	addr_save = GetDefaultAliasAddress(la);
1463127094Sdes	if (la->packetAliasMode & PKT_ALIAS_UNREGISTERED_ONLY) {
1464127094Sdes		u_long addr;
1465127094Sdes		int iclass;
146632377Seivind
1467127094Sdes		iclass = 0;
1468127094Sdes		addr = ntohl(pip->ip_src.s_addr);
1469127094Sdes		if (addr >= UNREG_ADDR_C_LOWER && addr <= UNREG_ADDR_C_UPPER)
1470127094Sdes			iclass = 3;
1471127094Sdes		else if (addr >= UNREG_ADDR_B_LOWER && addr <= UNREG_ADDR_B_UPPER)
1472127094Sdes			iclass = 2;
1473127094Sdes		else if (addr >= UNREG_ADDR_A_LOWER && addr <= UNREG_ADDR_A_UPPER)
1474127094Sdes			iclass = 1;
147526026Sbrian
1476127094Sdes		if (iclass == 0) {
1477127094Sdes			SetDefaultAliasAddress(la, pip->ip_src);
1478127094Sdes		}
1479127094Sdes	} else if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY) {
1480127094Sdes		SetDefaultAliasAddress(la, pip->ip_src);
1481127094Sdes	}
1482127094Sdes	iresult = PKT_ALIAS_IGNORED;
1483127094Sdes	if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
1484127094Sdes		switch (pip->ip_p) {
1485127094Sdes		case IPPROTO_ICMP:
1486131566Sphk			iresult = IcmpAliasOut(la, pip, create);
1487127094Sdes			break;
1488127094Sdes		case IPPROTO_UDP:
1489179920Smav			iresult = UdpAliasOut(la, pip, maxpacketsize, create);
1490127094Sdes			break;
1491188294Spiso		case IPPROTO_TCP:
1492131566Sphk			iresult = TcpAliasOut(la, pip, maxpacketsize, create);
1493127094Sdes			break;
1494188294Spiso#ifdef _KERNEL
1495188294Spiso		case IPPROTO_SCTP:
1496188294Spiso		  iresult = SctpAlias(la, pip, SN_TO_GLOBAL);
1497188294Spiso			break;
1498188294Spiso#endif
1499188294Spiso		case IPPROTO_GRE: {
1500162674Spiso			int error;
1501162674Spiso			struct alias_data ad = {
1502162674Spiso				.lnk = NULL,
1503162674Spiso				.oaddr = NULL,
1504162674Spiso				.aaddr = NULL,
1505162674Spiso				.aport = NULL,
1506162674Spiso				.sport = NULL,
1507162674Spiso				.dport = NULL,
1508162674Spiso				.maxpktsize = 0
1509162674Spiso			};
1510162674Spiso			/* Walk out chain. */
1511162674Spiso			error = find_handler(OUT, IP, la, pip, &ad);
1512162674Spiso			if (error == 0)
1513162674Spiso 				iresult = PKT_ALIAS_OK;
1514162674Spiso 			else
1515177098Spiso 				iresult = ProtoAliasOut(la, &pip->ip_src,
1516177098Spiso				    pip->ip_dst, pip->ip_p, &pip->ip_sum, create);
1517162674Spiso		}
1518162674Spiso 			break;
1519127094Sdes		default:
1520177098Spiso			iresult = ProtoAliasOut(la, &pip->ip_src,
1521177098Spiso			    pip->ip_dst, pip->ip_p, &pip->ip_sum, create);
1522127094Sdes			break;
1523127094Sdes		}
1524127094Sdes	} else {
1525177098Spiso		iresult = FragmentOut(la, &pip->ip_src, &pip->ip_sum);
1526127094Sdes	}
152726026Sbrian
1528127094Sdes	SetDefaultAliasAddress(la, addr_save);
1529165243Spisogetout:
1530127094Sdes	return (iresult);
153126026Sbrian}
153263899Sarchie
153363899Sarchieint
1534127094SdesLibAliasUnaliasOut(struct libalias *la, char *ptr,	/* valid IP packet */
1535127094Sdes    int maxpacketsize		/* for error checking */
1536127094Sdes)
153763899Sarchie{
1538127094Sdes	struct ip *pip;
1539127094Sdes	struct icmp *ic;
1540127094Sdes	struct udphdr *ud;
1541127094Sdes	struct tcphdr *tc;
1542131614Sdes	struct alias_link *lnk;
1543127094Sdes	int iresult = PKT_ALIAS_IGNORED;
154463899Sarchie
1545165243Spiso	LIBALIAS_LOCK(la);
1546127094Sdes	pip = (struct ip *)ptr;
154763899Sarchie
1548127094Sdes	/* Defense against mangled packets */
1549127094Sdes	if (ntohs(pip->ip_len) > maxpacketsize
1550127094Sdes	    || (pip->ip_hl << 2) > maxpacketsize)
1551165243Spiso		goto getout;
155263899Sarchie
1553131699Sdes	ud = (struct udphdr *)ip_next(pip);
1554131699Sdes	tc = (struct tcphdr *)ip_next(pip);
1555131699Sdes	ic = (struct icmp *)ip_next(pip);
155663899Sarchie
1557127094Sdes	/* Find a link */
1558127094Sdes	if (pip->ip_p == IPPROTO_UDP)
1559131614Sdes		lnk = FindUdpTcpIn(la, pip->ip_dst, pip->ip_src,
1560127094Sdes		    ud->uh_dport, ud->uh_sport,
1561127094Sdes		    IPPROTO_UDP, 0);
1562127094Sdes	else if (pip->ip_p == IPPROTO_TCP)
1563131614Sdes		lnk = FindUdpTcpIn(la, pip->ip_dst, pip->ip_src,
1564127094Sdes		    tc->th_dport, tc->th_sport,
1565127094Sdes		    IPPROTO_TCP, 0);
1566127094Sdes	else if (pip->ip_p == IPPROTO_ICMP)
1567131614Sdes		lnk = FindIcmpIn(la, pip->ip_dst, pip->ip_src, ic->icmp_id, 0);
1568127094Sdes	else
1569131614Sdes		lnk = NULL;
157063899Sarchie
1571127094Sdes	/* Change it from an aliased packet to an unaliased packet */
1572131614Sdes	if (lnk != NULL) {
1573127094Sdes		if (pip->ip_p == IPPROTO_UDP || pip->ip_p == IPPROTO_TCP) {
1574127094Sdes			int accumulate;
1575127094Sdes			struct in_addr original_address;
1576127094Sdes			u_short original_port;
157763899Sarchie
1578131614Sdes			original_address = GetOriginalAddress(lnk);
1579131614Sdes			original_port = GetOriginalPort(lnk);
158099207Sbrian
1581127094Sdes			/* Adjust TCP/UDP checksum */
1582127689Sdes			accumulate = twowords(&pip->ip_src);
1583127689Sdes			accumulate -= twowords(&original_address);
158463899Sarchie
1585127094Sdes			if (pip->ip_p == IPPROTO_UDP) {
1586127094Sdes				accumulate += ud->uh_sport;
1587127094Sdes				accumulate -= original_port;
1588127094Sdes				ADJUST_CHECKSUM(accumulate, ud->uh_sum);
1589127094Sdes			} else {
1590127094Sdes				accumulate += tc->th_sport;
1591127094Sdes				accumulate -= original_port;
1592127094Sdes				ADJUST_CHECKSUM(accumulate, tc->th_sum);
1593127094Sdes			}
159463899Sarchie
1595127094Sdes			/* Adjust IP checksum */
1596127094Sdes			DifferentialChecksum(&pip->ip_sum,
1597127689Sdes			    &original_address, &pip->ip_src, 2);
159863899Sarchie
1599127094Sdes			/* Un-alias source address and port number */
1600127094Sdes			pip->ip_src = original_address;
1601127094Sdes			if (pip->ip_p == IPPROTO_UDP)
1602127094Sdes				ud->uh_sport = original_port;
1603127094Sdes			else
1604127094Sdes				tc->th_sport = original_port;
160599207Sbrian
1606127094Sdes			iresult = PKT_ALIAS_OK;
160763899Sarchie
1608127094Sdes		} else if (pip->ip_p == IPPROTO_ICMP) {
160963899Sarchie
1610127094Sdes			int accumulate;
1611127094Sdes			struct in_addr original_address;
1612127094Sdes			u_short original_id;
161363899Sarchie
1614131614Sdes			original_address = GetOriginalAddress(lnk);
1615131614Sdes			original_id = GetOriginalPort(lnk);
161663899Sarchie
1617127094Sdes			/* Adjust ICMP checksum */
1618127689Sdes			accumulate = twowords(&pip->ip_src);
1619127689Sdes			accumulate -= twowords(&original_address);
1620127094Sdes			accumulate += ic->icmp_id;
1621127094Sdes			accumulate -= original_id;
1622127094Sdes			ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
162363899Sarchie
1624127094Sdes			/* Adjust IP checksum */
1625127094Sdes			DifferentialChecksum(&pip->ip_sum,
1626127689Sdes			    &original_address, &pip->ip_src, 2);
162763899Sarchie
1628127094Sdes			/* Un-alias source address and port number */
1629127094Sdes			pip->ip_src = original_address;
1630127094Sdes			ic->icmp_id = original_id;
163163899Sarchie
1632127094Sdes			iresult = PKT_ALIAS_OK;
1633127094Sdes		}
1634127094Sdes	}
1635165243Spisogetout:
1636165243Spiso	LIBALIAS_UNLOCK(la);
1637127094Sdes	return (iresult);
163863899Sarchie
163963899Sarchie}
1640162674Spiso
1641162674Spiso#ifndef _KERNEL
1642162674Spiso
1643162674Spisoint
1644162674SpisoLibAliasRefreshModules(void)
1645162674Spiso{
1646162674Spiso	char buf[256], conf[] = "/etc/libalias.conf";
1647162674Spiso	FILE *fd;
1648164798Spiso	int i, len;
1649162674Spiso
1650162674Spiso	fd = fopen(conf, "r");
1651162674Spiso	if (fd == NULL)
1652162674Spiso		err(1, "fopen(%s)", conf);
1653162674Spiso
1654162674Spiso	LibAliasUnLoadAllModule();
1655162674Spiso
1656162674Spiso	for (;;) {
1657162674Spiso		fgets(buf, 256, fd);
1658178730Smarck		if (feof(fd))
1659162674Spiso		        break;
1660162674Spiso		len = strlen(buf);
1661162674Spiso		if (len > 1) {
1662164798Spiso			for (i = 0; i < len; i++)
1663164798Spiso				if (!isspace(buf[i]))
1664164798Spiso					break;
1665164798Spiso			if (buf[i] == '#')
1666164798Spiso				continue;
1667162674Spiso			buf[len - 1] = '\0';
1668162674Spiso			LibAliasLoadModule(buf);
1669162674Spiso		}
1670162674Spiso	}
1671198539Sbrueffer	fclose(fd);
1672162674Spiso	return (0);
1673162674Spiso}
1674162674Spiso
1675162674Spisoint
1676162674SpisoLibAliasLoadModule(char *path)
1677162674Spiso{
1678162674Spiso	struct dll *t;
1679162674Spiso	void *handle;
1680162674Spiso	struct proto_handler *m;
1681162674Spiso        const char *error;
1682162674Spiso	moduledata_t *p;
1683162674Spiso
1684162674Spiso        handle = dlopen (path, RTLD_LAZY);
1685162674Spiso        if (!handle) {
1686164798Spiso		fprintf(stderr, "%s\n", dlerror());
1687164798Spiso		return (EINVAL);
1688162674Spiso        }
1689162674Spiso
1690162674Spiso	p = dlsym(handle, "alias_mod");
1691162674Spiso        if ((error = dlerror()) != NULL)  {
1692164798Spiso		fprintf(stderr, "%s\n", dlerror());
1693164798Spiso		return (EINVAL);
1694162674Spiso        }
1695164798Spiso
1696162674Spiso	t = malloc(sizeof(struct dll));
1697162674Spiso	if (t == NULL)
1698162674Spiso		return (ENOMEM);
1699162674Spiso	strncpy(t->name, p->name, DLL_LEN);
1700162674Spiso	t->handle = handle;
1701162674Spiso	if (attach_dll(t) == EEXIST) {
1702162674Spiso		free(t);
1703164798Spiso		fprintf(stderr, "dll conflict\n");
1704162674Spiso		return (EEXIST);
1705162674Spiso	}
1706162674Spiso
1707162674Spiso        m = dlsym(t->handle, "handlers");
1708162674Spiso        if ((error = dlerror()) != NULL)  {
1709164798Spiso		fprintf(stderr, "%s\n", error);
1710164798Spiso		return (EINVAL);
1711164798Spiso	}
1712162674Spiso
1713162674Spiso	LibAliasAttachHandlers(m);
1714162674Spiso	return (0);
1715162674Spiso}
1716162674Spiso
1717162674Spisoint
1718162674SpisoLibAliasUnLoadAllModule(void)
1719162674Spiso{
1720162674Spiso	struct dll *t;
1721162674Spiso	struct proto_handler *p;
1722162674Spiso
1723162674Spiso	/* Unload all modules then reload everything. */
1724162674Spiso	while ((p = first_handler()) != NULL) {
1725162674Spiso		detach_handler(p);
1726162674Spiso	}
1727162674Spiso	while ((t = walk_dll_chain()) != NULL) {
1728162674Spiso		dlclose(t->handle);
1729162674Spiso		free(t);
1730162674Spiso	}
1731162674Spiso	return (1);
1732162674Spiso}
1733162674Spiso
1734162674Spiso#endif
1735164797Spiso
1736164797Spiso#ifdef _KERNEL
1737164797Spiso/*
1738165243Spiso * m_megapullup() - this function is a big hack.
1739165243Spiso * Thankfully, it's only used in ng_nat and ipfw+nat.
1740164797Spiso *
1741179478Smav * It allocates an mbuf with cluster and copies the specified part of the chain
1742179478Smav * into cluster, so that it is all contiguous and can be accessed via a plain
1743179478Smav * (char *) pointer. This is required, because libalias doesn't know how to
1744179478Smav * handle mbuf chains.
1745165243Spiso *
1746179478Smav * On success, m_megapullup returns an mbuf (possibly with cluster) containing
1747179478Smav * the input packet, on failure NULL. The input packet is always consumed.
1748164797Spiso */
1749164797Spisostruct mbuf *
1750164797Spisom_megapullup(struct mbuf *m, int len) {
1751164797Spiso	struct mbuf *mcl;
1752248416Sglebius
1753179478Smav	if (len > m->m_pkthdr.len)
1754164797Spiso		goto bad;
1755248416Sglebius
1756248416Sglebius	if (m->m_next == NULL && M_WRITABLE(m))
1757179478Smav		return (m);
1758179478Smav
1759248416Sglebius	mcl = m_get2(len, M_NOWAIT, MT_DATA, M_PKTHDR);
1760179478Smav	if (mcl == NULL)
1761179478Smav		goto bad;
1762248416Sglebius	m_align(mcl, len);
1763164797Spiso	m_move_pkthdr(mcl, m);
1764179478Smav	m_copydata(m, 0, len, mtod(mcl, caddr_t));
1765179478Smav	mcl->m_len = mcl->m_pkthdr.len = len;
1766164797Spiso	m_freem(m);
1767248416Sglebius
1768164797Spiso	return (mcl);
1769164797Spisobad:
1770164797Spiso	m_freem(m);
1771164797Spiso	return (NULL);
1772164797Spiso}
1773164797Spiso#endif
1774