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