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: releng/10.3/sys/netinet/libalias/alias.c 248416 2013-03-17 07:37:10Z glebius $");
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	int iresult;
443	struct icmp *ic;
444
445	LIBALIAS_LOCK_ASSERT(la);
446/* Return if proxy-only mode is enabled */
447	if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
448		return (PKT_ALIAS_OK);
449
450	ic = (struct icmp *)ip_next(pip);
451
452	iresult = PKT_ALIAS_IGNORED;
453	switch (ic->icmp_type) {
454	case ICMP_ECHOREPLY:
455	case ICMP_TSTAMPREPLY:
456		if (ic->icmp_code == 0) {
457			iresult = IcmpAliasIn1(la, pip);
458		}
459		break;
460	case ICMP_UNREACH:
461	case ICMP_SOURCEQUENCH:
462	case ICMP_TIMXCEED:
463	case ICMP_PARAMPROB:
464		iresult = IcmpAliasIn2(la, pip);
465		break;
466	case ICMP_ECHO:
467	case ICMP_TSTAMP:
468		iresult = IcmpAliasIn1(la, pip);
469		break;
470	}
471	return (iresult);
472}
473
474
475static int
476IcmpAliasOut1(struct libalias *la, struct ip *pip, int create)
477{
478/*
479    Alias outgoing echo and timestamp requests.
480    De-alias outgoing echo and timestamp replies.
481*/
482	struct alias_link *lnk;
483	struct icmp *ic;
484
485	LIBALIAS_LOCK_ASSERT(la);
486	ic = (struct icmp *)ip_next(pip);
487
488/* Save overwritten data for when echo packet returns */
489	lnk = FindIcmpOut(la, pip->ip_src, pip->ip_dst, ic->icmp_id, create);
490	if (lnk != NULL) {
491		u_short alias_id;
492		int accumulate;
493
494		alias_id = GetAliasPort(lnk);
495
496/* Since data field is being modified, adjust ICMP checksum */
497		accumulate = ic->icmp_id;
498		accumulate -= alias_id;
499		ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
500
501/* Alias sequence number */
502		ic->icmp_id = alias_id;
503
504/* Change source address */
505		{
506			struct in_addr alias_address;
507
508			alias_address = GetAliasAddress(lnk);
509			DifferentialChecksum(&pip->ip_sum,
510			    &alias_address, &pip->ip_src, 2);
511			pip->ip_src = alias_address;
512		}
513
514		return (PKT_ALIAS_OK);
515	}
516	return (PKT_ALIAS_IGNORED);
517}
518
519
520static int
521IcmpAliasOut2(struct libalias *la, struct ip *pip)
522{
523/*
524    Alias outgoing ICMP error messages containing
525    IP header and first 64 bits of datagram.
526*/
527	struct ip *ip;
528	struct icmp *ic, *ic2;
529	struct udphdr *ud;
530	struct tcphdr *tc;
531	struct alias_link *lnk;
532
533	LIBALIAS_LOCK_ASSERT(la);
534	ic = (struct icmp *)ip_next(pip);
535	ip = &ic->icmp_ip;
536
537	ud = (struct udphdr *)ip_next(ip);
538	tc = (struct tcphdr *)ip_next(ip);
539	ic2 = (struct icmp *)ip_next(ip);
540
541	if (ip->ip_p == IPPROTO_UDP)
542		lnk = FindUdpTcpOut(la, ip->ip_dst, ip->ip_src,
543		    ud->uh_dport, ud->uh_sport,
544		    IPPROTO_UDP, 0);
545	else if (ip->ip_p == IPPROTO_TCP)
546		lnk = FindUdpTcpOut(la, ip->ip_dst, ip->ip_src,
547		    tc->th_dport, tc->th_sport,
548		    IPPROTO_TCP, 0);
549	else if (ip->ip_p == IPPROTO_ICMP) {
550		if (ic2->icmp_type == ICMP_ECHO || ic2->icmp_type == ICMP_TSTAMP)
551			lnk = FindIcmpOut(la, ip->ip_dst, ip->ip_src, ic2->icmp_id, 0);
552		else
553			lnk = NULL;
554	} else
555		lnk = NULL;
556
557	if (lnk != NULL) {
558		if (ip->ip_p == IPPROTO_UDP || ip->ip_p == IPPROTO_TCP) {
559			int accumulate;
560			struct in_addr alias_address;
561			u_short alias_port;
562
563			alias_address = GetAliasAddress(lnk);
564			alias_port = GetAliasPort(lnk);
565
566/* Adjust ICMP checksum */
567			accumulate = twowords(&ip->ip_dst);
568			accumulate -= twowords(&alias_address);
569			accumulate += ud->uh_dport;
570			accumulate -= alias_port;
571			ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
572
573/*
574 * Alias address in IP header if it comes from the host
575 * the original TCP/UDP packet was destined for.
576 */
577			if (pip->ip_src.s_addr == ip->ip_dst.s_addr) {
578				DifferentialChecksum(&pip->ip_sum,
579				    &alias_address, &pip->ip_src, 2);
580				pip->ip_src = alias_address;
581			}
582/* Alias address and port number of original IP packet
583fragment contained in ICMP data section */
584			ip->ip_dst = alias_address;
585			ud->uh_dport = alias_port;
586		} else if (ip->ip_p == IPPROTO_ICMP) {
587			int accumulate;
588			struct in_addr alias_address;
589			u_short alias_id;
590
591			alias_address = GetAliasAddress(lnk);
592			alias_id = GetAliasPort(lnk);
593
594/* Adjust ICMP checksum */
595			accumulate = twowords(&ip->ip_dst);
596			accumulate -= twowords(&alias_address);
597			accumulate += ic2->icmp_id;
598			accumulate -= alias_id;
599			ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
600
601/*
602 * Alias address in IP header if it comes from the host
603 * the original ICMP message was destined for.
604 */
605			if (pip->ip_src.s_addr == ip->ip_dst.s_addr) {
606				DifferentialChecksum(&pip->ip_sum,
607				    &alias_address, &pip->ip_src, 2);
608				pip->ip_src = alias_address;
609			}
610/* Alias address of original IP packet and sequence number of
611   embedded ICMP datagram */
612			ip->ip_dst = alias_address;
613			ic2->icmp_id = alias_id;
614		}
615		return (PKT_ALIAS_OK);
616	}
617	return (PKT_ALIAS_IGNORED);
618}
619
620
621static int
622IcmpAliasOut(struct libalias *la, struct ip *pip, int create)
623{
624	int iresult;
625	struct icmp *ic;
626
627	LIBALIAS_LOCK_ASSERT(la);
628	(void)create;
629
630/* Return if proxy-only mode is enabled */
631	if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
632		return (PKT_ALIAS_OK);
633
634	ic = (struct icmp *)ip_next(pip);
635
636	iresult = PKT_ALIAS_IGNORED;
637	switch (ic->icmp_type) {
638	case ICMP_ECHO:
639	case ICMP_TSTAMP:
640		if (ic->icmp_code == 0) {
641			iresult = IcmpAliasOut1(la, pip, create);
642		}
643		break;
644	case ICMP_UNREACH:
645	case ICMP_SOURCEQUENCH:
646	case ICMP_TIMXCEED:
647	case ICMP_PARAMPROB:
648		iresult = IcmpAliasOut2(la, pip);
649		break;
650	case ICMP_ECHOREPLY:
651	case ICMP_TSTAMPREPLY:
652		iresult = IcmpAliasOut1(la, pip, create);
653	}
654	return (iresult);
655}
656
657static int
658ProtoAliasIn(struct libalias *la, struct in_addr ip_src,
659    struct in_addr *ip_dst, u_char ip_p, u_short *ip_sum)
660{
661/*
662  Handle incoming IP packets. The
663  only thing which is done in this case is to alias
664  the dest IP address of the packet to our inside
665  machine.
666*/
667	struct alias_link *lnk;
668
669	LIBALIAS_LOCK_ASSERT(la);
670/* Return if proxy-only mode is enabled */
671	if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
672		return (PKT_ALIAS_OK);
673
674	lnk = FindProtoIn(la, ip_src, *ip_dst, ip_p);
675	if (lnk != NULL) {
676		struct in_addr original_address;
677
678		original_address = GetOriginalAddress(lnk);
679
680/* Restore original IP address */
681		DifferentialChecksum(ip_sum,
682		    &original_address, ip_dst, 2);
683		*ip_dst = original_address;
684
685		return (PKT_ALIAS_OK);
686	}
687	return (PKT_ALIAS_IGNORED);
688}
689
690static int
691ProtoAliasOut(struct libalias *la, struct in_addr *ip_src,
692    struct in_addr ip_dst, u_char ip_p, u_short *ip_sum, int create)
693{
694/*
695  Handle outgoing IP packets. The
696  only thing which is done in this case is to alias
697  the source IP address of the packet.
698*/
699	struct alias_link *lnk;
700
701	LIBALIAS_LOCK_ASSERT(la);
702	(void)create;
703
704/* Return if proxy-only mode is enabled */
705	if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
706		return (PKT_ALIAS_OK);
707
708	lnk = FindProtoOut(la, *ip_src, ip_dst, ip_p);
709	if (lnk != NULL) {
710		struct in_addr alias_address;
711
712		alias_address = GetAliasAddress(lnk);
713
714/* Change source address */
715		DifferentialChecksum(ip_sum,
716		    &alias_address, ip_src, 2);
717		*ip_src = alias_address;
718
719		return (PKT_ALIAS_OK);
720	}
721	return (PKT_ALIAS_IGNORED);
722}
723
724
725static int
726UdpAliasIn(struct libalias *la, struct ip *pip)
727{
728	struct udphdr *ud;
729	struct alias_link *lnk;
730
731	LIBALIAS_LOCK_ASSERT(la);
732
733	ud = (struct udphdr *)ip_next(pip);
734
735	lnk = FindUdpTcpIn(la, pip->ip_src, pip->ip_dst,
736	    ud->uh_sport, ud->uh_dport,
737	    IPPROTO_UDP, !(la->packetAliasMode & PKT_ALIAS_PROXY_ONLY));
738	if (lnk != NULL) {
739		struct in_addr alias_address;
740		struct in_addr original_address;
741		struct in_addr proxy_address;
742		u_short alias_port;
743		u_short proxy_port;
744		int accumulate;
745		int error;
746		struct alias_data ad = {
747			.lnk = lnk,
748			.oaddr = &original_address,
749			.aaddr = &alias_address,
750			.aport = &alias_port,
751			.sport = &ud->uh_sport,
752			.dport = &ud->uh_dport,
753			.maxpktsize = 0
754		};
755
756		alias_address = GetAliasAddress(lnk);
757		original_address = GetOriginalAddress(lnk);
758		proxy_address = GetProxyAddress(lnk);
759		alias_port = ud->uh_dport;
760		ud->uh_dport = GetOriginalPort(lnk);
761		proxy_port = GetProxyPort(lnk);
762
763		/* Walk out chain. */
764		error = find_handler(IN, UDP, la, pip, &ad);
765		/* If we cannot figure out the packet, ignore it. */
766		if (error < 0)
767			return (PKT_ALIAS_IGNORED);
768
769/* If UDP checksum is not zero, then adjust since destination port */
770/* is being unaliased and destination address is being altered.    */
771		if (ud->uh_sum != 0) {
772			accumulate = alias_port;
773			accumulate -= ud->uh_dport;
774			accumulate += twowords(&alias_address);
775			accumulate -= twowords(&original_address);
776
777/* If this is a proxy packet, modify checksum because of source change.*/
778        		if (proxy_port != 0) {
779		                accumulate += ud->uh_sport;
780		                accumulate -= proxy_port;
781	                }
782
783	                if (proxy_address.s_addr != 0) {
784				accumulate += twowords(&pip->ip_src);
785				accumulate -= twowords(&proxy_address);
786	                }
787
788			ADJUST_CHECKSUM(accumulate, ud->uh_sum);
789		}
790/* XXX: Could the two if's below be concatenated to one ? */
791/* Restore source port and/or address in case of proxying*/
792
793    		if (proxy_port != 0)
794        		ud->uh_sport = proxy_port;
795
796    		if (proxy_address.s_addr != 0) {
797        		DifferentialChecksum(&pip->ip_sum,
798                	    &proxy_address, &pip->ip_src, 2);
799	        	pip->ip_src = proxy_address;
800    		}
801
802/* Restore original IP address */
803		DifferentialChecksum(&pip->ip_sum,
804		    &original_address, &pip->ip_dst, 2);
805		pip->ip_dst = original_address;
806
807		return (PKT_ALIAS_OK);
808	}
809	return (PKT_ALIAS_IGNORED);
810}
811
812static int
813UdpAliasOut(struct libalias *la, struct ip *pip, int maxpacketsize, int create)
814{
815	struct udphdr *ud;
816	struct alias_link *lnk;
817	struct in_addr dest_address;
818	struct in_addr proxy_server_address;
819	u_short dest_port;
820	u_short proxy_server_port;
821	int proxy_type;
822	int error;
823
824	LIBALIAS_LOCK_ASSERT(la);
825
826/* Return if proxy-only mode is enabled and not proxyrule found.*/
827	ud = (struct udphdr *)ip_next(pip);
828	proxy_type = ProxyCheck(la, &proxy_server_address,
829		&proxy_server_port, pip->ip_src, pip->ip_dst,
830		ud->uh_dport, pip->ip_p);
831	if (proxy_type == 0 && (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY))
832		return (PKT_ALIAS_OK);
833
834/* If this is a transparent proxy, save original destination,
835 * then alter the destination and adjust checksums */
836	dest_port = ud->uh_dport;
837	dest_address = pip->ip_dst;
838
839	if (proxy_type != 0) {
840	        int accumulate;
841
842		accumulate = twowords(&pip->ip_dst);
843		accumulate -= twowords(&proxy_server_address);
844
845	        ADJUST_CHECKSUM(accumulate, pip->ip_sum);
846
847		if (ud->uh_sum != 0) {
848			accumulate = twowords(&pip->ip_dst);
849			accumulate -= twowords(&proxy_server_address);
850    			accumulate += ud->uh_dport;
851	        	accumulate -= proxy_server_port;
852	    		ADJUST_CHECKSUM(accumulate, ud->uh_sum);
853		}
854	        pip->ip_dst = proxy_server_address;
855	        ud->uh_dport = proxy_server_port;
856	}
857	lnk = FindUdpTcpOut(la, pip->ip_src, pip->ip_dst,
858	    ud->uh_sport, ud->uh_dport,
859	    IPPROTO_UDP, create);
860	if (lnk != NULL) {
861		u_short alias_port;
862		struct in_addr alias_address;
863		struct alias_data ad = {
864			.lnk = lnk,
865			.oaddr = NULL,
866			.aaddr = &alias_address,
867			.aport = &alias_port,
868			.sport = &ud->uh_sport,
869			.dport = &ud->uh_dport,
870			.maxpktsize = 0
871		};
872
873/* Save original destination address, if this is a proxy packet.
874 * Also modify packet to include destination encoding.  This may
875 * change the size of IP header. */
876		if (proxy_type != 0) {
877	                SetProxyPort(lnk, dest_port);
878	                SetProxyAddress(lnk, dest_address);
879	                ProxyModify(la, lnk, pip, maxpacketsize, proxy_type);
880	                ud = (struct udphdr *)ip_next(pip);
881	        }
882
883		alias_address = GetAliasAddress(lnk);
884		alias_port = GetAliasPort(lnk);
885
886		/* Walk out chain. */
887		error = find_handler(OUT, UDP, la, pip, &ad);
888
889/* If UDP checksum is not zero, adjust since source port is */
890/* being aliased and source address is being altered        */
891		if (ud->uh_sum != 0) {
892			int accumulate;
893
894			accumulate = ud->uh_sport;
895			accumulate -= alias_port;
896			accumulate += twowords(&pip->ip_src);
897			accumulate -= twowords(&alias_address);
898			ADJUST_CHECKSUM(accumulate, ud->uh_sum);
899		}
900/* Put alias port in UDP header */
901		ud->uh_sport = alias_port;
902
903/* Change source address */
904		DifferentialChecksum(&pip->ip_sum,
905		    &alias_address, &pip->ip_src, 2);
906		pip->ip_src = alias_address;
907
908		return (PKT_ALIAS_OK);
909	}
910	return (PKT_ALIAS_IGNORED);
911}
912
913
914
915static int
916TcpAliasIn(struct libalias *la, struct ip *pip)
917{
918	struct tcphdr *tc;
919	struct alias_link *lnk;
920
921	LIBALIAS_LOCK_ASSERT(la);
922	tc = (struct tcphdr *)ip_next(pip);
923
924	lnk = FindUdpTcpIn(la, pip->ip_src, pip->ip_dst,
925	    tc->th_sport, tc->th_dport,
926	    IPPROTO_TCP,
927	    !(la->packetAliasMode & PKT_ALIAS_PROXY_ONLY));
928	if (lnk != NULL) {
929		struct in_addr alias_address;
930		struct in_addr original_address;
931		struct in_addr proxy_address;
932		u_short alias_port;
933		u_short proxy_port;
934		int accumulate, error;
935
936		/*
937		 * The init of MANY vars is a bit below, but aliashandlepptpin
938		 * seems to need the destination port that came within the
939		 * packet and not the original one looks below [*].
940		 */
941
942		struct alias_data ad = {
943			.lnk = lnk,
944			.oaddr = NULL,
945			.aaddr = NULL,
946			.aport = NULL,
947			.sport = &tc->th_sport,
948			.dport = &tc->th_dport,
949			.maxpktsize = 0
950		};
951
952		/* Walk out chain. */
953		error = find_handler(IN, TCP, la, pip, &ad);
954
955		alias_address = GetAliasAddress(lnk);
956		original_address = GetOriginalAddress(lnk);
957		proxy_address = GetProxyAddress(lnk);
958		alias_port = tc->th_dport;
959		tc->th_dport = GetOriginalPort(lnk);
960		proxy_port = GetProxyPort(lnk);
961
962		/*
963		 * Look above, if anyone is going to add find_handler AFTER
964		 * this aliashandlepptpin/point, please redo alias_data too.
965		 * Uncommenting the piece here below should be enough.
966		 */
967#if 0
968				 struct alias_data ad = {
969					.lnk = lnk,
970					.oaddr = &original_address,
971					.aaddr = &alias_address,
972					.aport = &alias_port,
973					.sport = &ud->uh_sport,
974					.dport = &ud->uh_dport,
975					.maxpktsize = 0
976				};
977
978				/* Walk out chain. */
979				error = find_handler(la, pip, &ad);
980				if (error == EHDNOF)
981					printf("Protocol handler not found\n");
982#endif
983
984/* Adjust TCP checksum since destination port is being unaliased */
985/* and destination port is being altered.                        */
986		accumulate = alias_port;
987		accumulate -= tc->th_dport;
988		accumulate += twowords(&alias_address);
989		accumulate -= twowords(&original_address);
990
991/* If this is a proxy, then modify the TCP source port and
992   checksum accumulation */
993		if (proxy_port != 0) {
994			accumulate += tc->th_sport;
995			tc->th_sport = proxy_port;
996			accumulate -= tc->th_sport;
997			accumulate += twowords(&pip->ip_src);
998			accumulate -= twowords(&proxy_address);
999		}
1000/* See if ACK number needs to be modified */
1001		if (GetAckModified(lnk) == 1) {
1002			int delta;
1003
1004			tc = (struct tcphdr *)ip_next(pip);
1005			delta = GetDeltaAckIn(tc->th_ack, lnk);
1006			if (delta != 0) {
1007				accumulate += twowords(&tc->th_ack);
1008				tc->th_ack = htonl(ntohl(tc->th_ack) - delta);
1009				accumulate -= twowords(&tc->th_ack);
1010			}
1011		}
1012		ADJUST_CHECKSUM(accumulate, tc->th_sum);
1013
1014/* Restore original IP address */
1015		accumulate = twowords(&pip->ip_dst);
1016		pip->ip_dst = original_address;
1017		accumulate -= twowords(&pip->ip_dst);
1018
1019/* If this is a transparent proxy packet, then modify the source
1020   address */
1021		if (proxy_address.s_addr != 0) {
1022			accumulate += twowords(&pip->ip_src);
1023			pip->ip_src = proxy_address;
1024			accumulate -= twowords(&pip->ip_src);
1025		}
1026		ADJUST_CHECKSUM(accumulate, pip->ip_sum);
1027
1028/* Monitor TCP connection state */
1029		tc = (struct tcphdr *)ip_next(pip);
1030		TcpMonitorIn(tc->th_flags, lnk);
1031
1032		return (PKT_ALIAS_OK);
1033	}
1034	return (PKT_ALIAS_IGNORED);
1035}
1036
1037static int
1038TcpAliasOut(struct libalias *la, struct ip *pip, int maxpacketsize, int create)
1039{
1040	int proxy_type, error;
1041	u_short dest_port;
1042	u_short proxy_server_port;
1043	struct in_addr dest_address;
1044	struct in_addr proxy_server_address;
1045	struct tcphdr *tc;
1046	struct alias_link *lnk;
1047
1048	LIBALIAS_LOCK_ASSERT(la);
1049	tc = (struct tcphdr *)ip_next(pip);
1050
1051	if (create)
1052		proxy_type = ProxyCheck(la, &proxy_server_address,
1053		    &proxy_server_port, pip->ip_src, pip->ip_dst,
1054		    tc->th_dport, pip->ip_p);
1055	else
1056		proxy_type = 0;
1057
1058	if (proxy_type == 0 && (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY))
1059		return (PKT_ALIAS_OK);
1060
1061/* If this is a transparent proxy, save original destination,
1062   then alter the destination and adjust checksums */
1063	dest_port = tc->th_dport;
1064	dest_address = pip->ip_dst;
1065	if (proxy_type != 0) {
1066		int accumulate;
1067
1068		accumulate = tc->th_dport;
1069		tc->th_dport = proxy_server_port;
1070		accumulate -= tc->th_dport;
1071		accumulate += twowords(&pip->ip_dst);
1072		accumulate -= twowords(&proxy_server_address);
1073		ADJUST_CHECKSUM(accumulate, tc->th_sum);
1074
1075		accumulate = twowords(&pip->ip_dst);
1076		pip->ip_dst = proxy_server_address;
1077		accumulate -= twowords(&pip->ip_dst);
1078		ADJUST_CHECKSUM(accumulate, pip->ip_sum);
1079	}
1080	lnk = FindUdpTcpOut(la, pip->ip_src, pip->ip_dst,
1081	    tc->th_sport, tc->th_dport,
1082	    IPPROTO_TCP, create);
1083	if (lnk == NULL)
1084		return (PKT_ALIAS_IGNORED);
1085	if (lnk != NULL) {
1086		u_short alias_port;
1087		struct in_addr alias_address;
1088		int accumulate;
1089		struct alias_data ad = {
1090			.lnk = lnk,
1091			.oaddr = NULL,
1092			.aaddr = &alias_address,
1093			.aport = &alias_port,
1094			.sport = &tc->th_sport,
1095			.dport = &tc->th_dport,
1096			.maxpktsize = maxpacketsize
1097		};
1098
1099/* Save original destination address, if this is a proxy packet.
1100   Also modify packet to include destination encoding.  This may
1101   change the size of IP header. */
1102		if (proxy_type != 0) {
1103			SetProxyPort(lnk, dest_port);
1104			SetProxyAddress(lnk, dest_address);
1105			ProxyModify(la, lnk, pip, maxpacketsize, proxy_type);
1106			tc = (struct tcphdr *)ip_next(pip);
1107		}
1108/* Get alias address and port */
1109		alias_port = GetAliasPort(lnk);
1110		alias_address = GetAliasAddress(lnk);
1111
1112/* Monitor TCP connection state */
1113		tc = (struct tcphdr *)ip_next(pip);
1114		TcpMonitorOut(tc->th_flags, lnk);
1115
1116		/* Walk out chain. */
1117		error = find_handler(OUT, TCP, la, pip, &ad);
1118
1119/* Adjust TCP checksum since source port is being aliased */
1120/* and source address is being altered                    */
1121		accumulate = tc->th_sport;
1122		tc->th_sport = alias_port;
1123		accumulate -= tc->th_sport;
1124		accumulate += twowords(&pip->ip_src);
1125		accumulate -= twowords(&alias_address);
1126
1127/* Modify sequence number if necessary */
1128		if (GetAckModified(lnk) == 1) {
1129			int delta;
1130
1131			tc = (struct tcphdr *)ip_next(pip);
1132			delta = GetDeltaSeqOut(tc->th_seq, lnk);
1133			if (delta != 0) {
1134				accumulate += twowords(&tc->th_seq);
1135				tc->th_seq = htonl(ntohl(tc->th_seq) + delta);
1136				accumulate -= twowords(&tc->th_seq);
1137			}
1138		}
1139		ADJUST_CHECKSUM(accumulate, tc->th_sum);
1140
1141/* Change source address */
1142		accumulate = twowords(&pip->ip_src);
1143		pip->ip_src = alias_address;
1144		accumulate -= twowords(&pip->ip_src);
1145		ADJUST_CHECKSUM(accumulate, pip->ip_sum);
1146
1147		return (PKT_ALIAS_OK);
1148	}
1149	return (PKT_ALIAS_IGNORED);
1150}
1151
1152
1153
1154
1155/* Fragment Handling
1156
1157    FragmentIn()
1158    FragmentOut()
1159
1160The packet aliasing module has a limited ability for handling IP
1161fragments.  If the ICMP, TCP or UDP header is in the first fragment
1162received, then the ID number of the IP packet is saved, and other
1163fragments are identified according to their ID number and IP address
1164they were sent from.  Pointers to unresolved fragments can also be
1165saved and recalled when a header fragment is seen.
1166*/
1167
1168/* Local prototypes */
1169static int	FragmentIn(struct libalias *la, struct in_addr ip_src,
1170		    struct in_addr *ip_dst, u_short ip_id, u_short *ip_sum);
1171static int	FragmentOut(struct libalias *, struct in_addr *ip_src,
1172		    u_short *ip_sum);
1173
1174static int
1175FragmentIn(struct libalias *la, struct in_addr ip_src, struct in_addr *ip_dst,
1176    u_short ip_id, u_short *ip_sum)
1177{
1178	struct alias_link *lnk;
1179
1180	LIBALIAS_LOCK_ASSERT(la);
1181	lnk = FindFragmentIn2(la, ip_src, *ip_dst, ip_id);
1182	if (lnk != NULL) {
1183		struct in_addr original_address;
1184
1185		GetFragmentAddr(lnk, &original_address);
1186		DifferentialChecksum(ip_sum,
1187		    &original_address, ip_dst, 2);
1188		*ip_dst = original_address;
1189
1190		return (PKT_ALIAS_OK);
1191	}
1192	return (PKT_ALIAS_UNRESOLVED_FRAGMENT);
1193}
1194
1195static int
1196FragmentOut(struct libalias *la, struct in_addr *ip_src, u_short *ip_sum)
1197{
1198	struct in_addr alias_address;
1199
1200	LIBALIAS_LOCK_ASSERT(la);
1201	alias_address = FindAliasAddress(la, *ip_src);
1202	DifferentialChecksum(ip_sum,
1203	    &alias_address, ip_src, 2);
1204	*ip_src = alias_address;
1205
1206	return (PKT_ALIAS_OK);
1207}
1208
1209
1210
1211
1212
1213
1214/* Outside World Access
1215
1216	PacketAliasSaveFragment()
1217	PacketAliasGetFragment()
1218	PacketAliasFragmentIn()
1219	PacketAliasIn()
1220	PacketAliasOut()
1221	PacketUnaliasOut()
1222
1223(prototypes in alias.h)
1224*/
1225
1226int
1227LibAliasSaveFragment(struct libalias *la, char *ptr)
1228{
1229	int iresult;
1230	struct alias_link *lnk;
1231	struct ip *pip;
1232
1233	LIBALIAS_LOCK(la);
1234	pip = (struct ip *)ptr;
1235	lnk = AddFragmentPtrLink(la, pip->ip_src, pip->ip_id);
1236	iresult = PKT_ALIAS_ERROR;
1237	if (lnk != NULL) {
1238		SetFragmentPtr(lnk, ptr);
1239		iresult = PKT_ALIAS_OK;
1240	}
1241	LIBALIAS_UNLOCK(la);
1242	return (iresult);
1243}
1244
1245char           *
1246LibAliasGetFragment(struct libalias *la, char *ptr)
1247{
1248	struct alias_link *lnk;
1249	char *fptr;
1250	struct ip *pip;
1251
1252	LIBALIAS_LOCK(la);
1253	pip = (struct ip *)ptr;
1254	lnk = FindFragmentPtr(la, pip->ip_src, pip->ip_id);
1255	if (lnk != NULL) {
1256		GetFragmentPtr(lnk, &fptr);
1257		SetFragmentPtr(lnk, NULL);
1258		SetExpire(lnk, 0);	/* Deletes link */
1259	} else
1260		fptr = NULL;
1261
1262	LIBALIAS_UNLOCK(la);
1263	return (fptr);
1264}
1265
1266void
1267LibAliasFragmentIn(struct libalias *la, char *ptr,	/* Points to correctly
1268							 * de-aliased header
1269							 * fragment */
1270    char *ptr_fragment		/* Points to fragment which must be
1271				 * de-aliased   */
1272)
1273{
1274	struct ip *pip;
1275	struct ip *fpip;
1276
1277	LIBALIAS_LOCK(la);
1278	(void)la;
1279	pip = (struct ip *)ptr;
1280	fpip = (struct ip *)ptr_fragment;
1281
1282	DifferentialChecksum(&fpip->ip_sum,
1283	    &pip->ip_dst, &fpip->ip_dst, 2);
1284	fpip->ip_dst = pip->ip_dst;
1285	LIBALIAS_UNLOCK(la);
1286}
1287
1288/* Local prototypes */
1289static int
1290LibAliasOutLocked(struct libalias *la, char *ptr,
1291		  int maxpacketsize, int create);
1292static int
1293LibAliasInLocked(struct libalias *la, char *ptr,
1294		  int maxpacketsize);
1295
1296int
1297LibAliasIn(struct libalias *la, char *ptr, int maxpacketsize)
1298{
1299	int res;
1300
1301	LIBALIAS_LOCK(la);
1302	res = LibAliasInLocked(la, ptr, maxpacketsize);
1303	LIBALIAS_UNLOCK(la);
1304	return (res);
1305}
1306
1307static int
1308LibAliasInLocked(struct libalias *la, char *ptr, int maxpacketsize)
1309{
1310	struct in_addr alias_addr;
1311	struct ip *pip;
1312	int iresult;
1313
1314	if (la->packetAliasMode & PKT_ALIAS_REVERSE) {
1315		la->packetAliasMode &= ~PKT_ALIAS_REVERSE;
1316		iresult = LibAliasOutLocked(la, ptr, maxpacketsize, 1);
1317		la->packetAliasMode |= PKT_ALIAS_REVERSE;
1318		goto getout;
1319	}
1320	HouseKeeping(la);
1321	ClearCheckNewLink(la);
1322	pip = (struct ip *)ptr;
1323	alias_addr = pip->ip_dst;
1324
1325	/* Defense against mangled packets */
1326	if (ntohs(pip->ip_len) > maxpacketsize
1327	    || (pip->ip_hl << 2) > maxpacketsize) {
1328		iresult = PKT_ALIAS_IGNORED;
1329		goto getout;
1330	}
1331
1332	iresult = PKT_ALIAS_IGNORED;
1333	if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
1334		switch (pip->ip_p) {
1335		case IPPROTO_ICMP:
1336			iresult = IcmpAliasIn(la, pip);
1337			break;
1338		case IPPROTO_UDP:
1339			iresult = UdpAliasIn(la, pip);
1340			break;
1341		case IPPROTO_TCP:
1342			iresult = TcpAliasIn(la, pip);
1343			break;
1344#ifdef _KERNEL
1345		case IPPROTO_SCTP:
1346		  iresult = SctpAlias(la, pip, SN_TO_LOCAL);
1347			break;
1348#endif
1349 		case IPPROTO_GRE: {
1350			int error;
1351			struct alias_data ad = {
1352				.lnk = NULL,
1353				.oaddr = NULL,
1354				.aaddr = NULL,
1355				.aport = NULL,
1356				.sport = NULL,
1357				.dport = NULL,
1358				.maxpktsize = 0
1359			};
1360
1361			/* Walk out chain. */
1362			error = find_handler(IN, IP, la, pip, &ad);
1363			if (error ==  0)
1364				iresult = PKT_ALIAS_OK;
1365			else
1366				iresult = ProtoAliasIn(la, pip->ip_src,
1367				    &pip->ip_dst, pip->ip_p, &pip->ip_sum);
1368		}
1369 			break;
1370		default:
1371			iresult = ProtoAliasIn(la, pip->ip_src, &pip->ip_dst,
1372			    pip->ip_p, &pip->ip_sum);
1373			break;
1374		}
1375
1376		if (ntohs(pip->ip_off) & IP_MF) {
1377			struct alias_link *lnk;
1378
1379			lnk = FindFragmentIn1(la, pip->ip_src, alias_addr, pip->ip_id);
1380			if (lnk != NULL) {
1381				iresult = PKT_ALIAS_FOUND_HEADER_FRAGMENT;
1382				SetFragmentAddr(lnk, pip->ip_dst);
1383			} else {
1384				iresult = PKT_ALIAS_ERROR;
1385			}
1386		}
1387	} else {
1388		iresult = FragmentIn(la, pip->ip_src, &pip->ip_dst, pip->ip_id,
1389		    &pip->ip_sum);
1390	}
1391
1392getout:
1393	return (iresult);
1394}
1395
1396
1397
1398/* Unregistered address ranges */
1399
1400/* 10.0.0.0   ->   10.255.255.255 */
1401#define UNREG_ADDR_A_LOWER 0x0a000000
1402#define UNREG_ADDR_A_UPPER 0x0affffff
1403
1404/* 172.16.0.0  ->  172.31.255.255 */
1405#define UNREG_ADDR_B_LOWER 0xac100000
1406#define UNREG_ADDR_B_UPPER 0xac1fffff
1407
1408/* 192.168.0.0 -> 192.168.255.255 */
1409#define UNREG_ADDR_C_LOWER 0xc0a80000
1410#define UNREG_ADDR_C_UPPER 0xc0a8ffff
1411
1412int
1413LibAliasOut(struct libalias *la, char *ptr, int maxpacketsize)
1414{
1415	int res;
1416
1417	LIBALIAS_LOCK(la);
1418	res = LibAliasOutLocked(la, ptr, maxpacketsize, 1);
1419	LIBALIAS_UNLOCK(la);
1420	return (res);
1421}
1422
1423int
1424LibAliasOutTry(struct libalias *la, char *ptr, int maxpacketsize, int create)
1425{
1426	int res;
1427
1428	LIBALIAS_LOCK(la);
1429	res = LibAliasOutLocked(la, ptr, maxpacketsize, create);
1430	LIBALIAS_UNLOCK(la);
1431	return (res);
1432}
1433
1434static int
1435LibAliasOutLocked(struct libalias *la, char *ptr,	/* valid IP packet */
1436    int maxpacketsize,		/* How much the packet data may grow (FTP
1437				 * and IRC inline changes) */
1438    int create                  /* Create new entries ? */
1439)
1440{
1441	int iresult;
1442	struct in_addr addr_save;
1443	struct ip *pip;
1444
1445	if (la->packetAliasMode & PKT_ALIAS_REVERSE) {
1446		la->packetAliasMode &= ~PKT_ALIAS_REVERSE;
1447		iresult = LibAliasInLocked(la, ptr, maxpacketsize);
1448		la->packetAliasMode |= PKT_ALIAS_REVERSE;
1449		goto getout;
1450	}
1451	HouseKeeping(la);
1452	ClearCheckNewLink(la);
1453	pip = (struct ip *)ptr;
1454
1455	/* Defense against mangled packets */
1456	if (ntohs(pip->ip_len) > maxpacketsize
1457	    || (pip->ip_hl << 2) > maxpacketsize) {
1458		iresult = PKT_ALIAS_IGNORED;
1459		goto getout;
1460	}
1461
1462	addr_save = GetDefaultAliasAddress(la);
1463	if (la->packetAliasMode & PKT_ALIAS_UNREGISTERED_ONLY) {
1464		u_long addr;
1465		int iclass;
1466
1467		iclass = 0;
1468		addr = ntohl(pip->ip_src.s_addr);
1469		if (addr >= UNREG_ADDR_C_LOWER && addr <= UNREG_ADDR_C_UPPER)
1470			iclass = 3;
1471		else if (addr >= UNREG_ADDR_B_LOWER && addr <= UNREG_ADDR_B_UPPER)
1472			iclass = 2;
1473		else if (addr >= UNREG_ADDR_A_LOWER && addr <= UNREG_ADDR_A_UPPER)
1474			iclass = 1;
1475
1476		if (iclass == 0) {
1477			SetDefaultAliasAddress(la, pip->ip_src);
1478		}
1479	} else if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY) {
1480		SetDefaultAliasAddress(la, pip->ip_src);
1481	}
1482	iresult = PKT_ALIAS_IGNORED;
1483	if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
1484		switch (pip->ip_p) {
1485		case IPPROTO_ICMP:
1486			iresult = IcmpAliasOut(la, pip, create);
1487			break;
1488		case IPPROTO_UDP:
1489			iresult = UdpAliasOut(la, pip, maxpacketsize, create);
1490			break;
1491		case IPPROTO_TCP:
1492			iresult = TcpAliasOut(la, pip, maxpacketsize, create);
1493			break;
1494#ifdef _KERNEL
1495		case IPPROTO_SCTP:
1496		  iresult = SctpAlias(la, pip, SN_TO_GLOBAL);
1497			break;
1498#endif
1499		case IPPROTO_GRE: {
1500			int error;
1501			struct alias_data ad = {
1502				.lnk = NULL,
1503				.oaddr = NULL,
1504				.aaddr = NULL,
1505				.aport = NULL,
1506				.sport = NULL,
1507				.dport = NULL,
1508				.maxpktsize = 0
1509			};
1510			/* Walk out chain. */
1511			error = find_handler(OUT, IP, la, pip, &ad);
1512			if (error == 0)
1513 				iresult = PKT_ALIAS_OK;
1514 			else
1515 				iresult = ProtoAliasOut(la, &pip->ip_src,
1516				    pip->ip_dst, pip->ip_p, &pip->ip_sum, create);
1517		}
1518 			break;
1519		default:
1520			iresult = ProtoAliasOut(la, &pip->ip_src,
1521			    pip->ip_dst, pip->ip_p, &pip->ip_sum, create);
1522			break;
1523		}
1524	} else {
1525		iresult = FragmentOut(la, &pip->ip_src, &pip->ip_sum);
1526	}
1527
1528	SetDefaultAliasAddress(la, addr_save);
1529getout:
1530	return (iresult);
1531}
1532
1533int
1534LibAliasUnaliasOut(struct libalias *la, char *ptr,	/* valid IP packet */
1535    int maxpacketsize		/* for error checking */
1536)
1537{
1538	struct ip *pip;
1539	struct icmp *ic;
1540	struct udphdr *ud;
1541	struct tcphdr *tc;
1542	struct alias_link *lnk;
1543	int iresult = PKT_ALIAS_IGNORED;
1544
1545	LIBALIAS_LOCK(la);
1546	pip = (struct ip *)ptr;
1547
1548	/* Defense against mangled packets */
1549	if (ntohs(pip->ip_len) > maxpacketsize
1550	    || (pip->ip_hl << 2) > maxpacketsize)
1551		goto getout;
1552
1553	ud = (struct udphdr *)ip_next(pip);
1554	tc = (struct tcphdr *)ip_next(pip);
1555	ic = (struct icmp *)ip_next(pip);
1556
1557	/* Find a link */
1558	if (pip->ip_p == IPPROTO_UDP)
1559		lnk = FindUdpTcpIn(la, pip->ip_dst, pip->ip_src,
1560		    ud->uh_dport, ud->uh_sport,
1561		    IPPROTO_UDP, 0);
1562	else if (pip->ip_p == IPPROTO_TCP)
1563		lnk = FindUdpTcpIn(la, pip->ip_dst, pip->ip_src,
1564		    tc->th_dport, tc->th_sport,
1565		    IPPROTO_TCP, 0);
1566	else if (pip->ip_p == IPPROTO_ICMP)
1567		lnk = FindIcmpIn(la, pip->ip_dst, pip->ip_src, ic->icmp_id, 0);
1568	else
1569		lnk = NULL;
1570
1571	/* Change it from an aliased packet to an unaliased packet */
1572	if (lnk != NULL) {
1573		if (pip->ip_p == IPPROTO_UDP || pip->ip_p == IPPROTO_TCP) {
1574			int accumulate;
1575			struct in_addr original_address;
1576			u_short original_port;
1577
1578			original_address = GetOriginalAddress(lnk);
1579			original_port = GetOriginalPort(lnk);
1580
1581			/* Adjust TCP/UDP checksum */
1582			accumulate = twowords(&pip->ip_src);
1583			accumulate -= twowords(&original_address);
1584
1585			if (pip->ip_p == IPPROTO_UDP) {
1586				accumulate += ud->uh_sport;
1587				accumulate -= original_port;
1588				ADJUST_CHECKSUM(accumulate, ud->uh_sum);
1589			} else {
1590				accumulate += tc->th_sport;
1591				accumulate -= original_port;
1592				ADJUST_CHECKSUM(accumulate, tc->th_sum);
1593			}
1594
1595			/* Adjust IP checksum */
1596			DifferentialChecksum(&pip->ip_sum,
1597			    &original_address, &pip->ip_src, 2);
1598
1599			/* Un-alias source address and port number */
1600			pip->ip_src = original_address;
1601			if (pip->ip_p == IPPROTO_UDP)
1602				ud->uh_sport = original_port;
1603			else
1604				tc->th_sport = original_port;
1605
1606			iresult = PKT_ALIAS_OK;
1607
1608		} else if (pip->ip_p == IPPROTO_ICMP) {
1609
1610			int accumulate;
1611			struct in_addr original_address;
1612			u_short original_id;
1613
1614			original_address = GetOriginalAddress(lnk);
1615			original_id = GetOriginalPort(lnk);
1616
1617			/* Adjust ICMP checksum */
1618			accumulate = twowords(&pip->ip_src);
1619			accumulate -= twowords(&original_address);
1620			accumulate += ic->icmp_id;
1621			accumulate -= original_id;
1622			ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
1623
1624			/* Adjust IP checksum */
1625			DifferentialChecksum(&pip->ip_sum,
1626			    &original_address, &pip->ip_src, 2);
1627
1628			/* Un-alias source address and port number */
1629			pip->ip_src = original_address;
1630			ic->icmp_id = original_id;
1631
1632			iresult = PKT_ALIAS_OK;
1633		}
1634	}
1635getout:
1636	LIBALIAS_UNLOCK(la);
1637	return (iresult);
1638
1639}
1640
1641#ifndef _KERNEL
1642
1643int
1644LibAliasRefreshModules(void)
1645{
1646	char buf[256], conf[] = "/etc/libalias.conf";
1647	FILE *fd;
1648	int i, len;
1649
1650	fd = fopen(conf, "r");
1651	if (fd == NULL)
1652		err(1, "fopen(%s)", conf);
1653
1654	LibAliasUnLoadAllModule();
1655
1656	for (;;) {
1657		fgets(buf, 256, fd);
1658		if (feof(fd))
1659		        break;
1660		len = strlen(buf);
1661		if (len > 1) {
1662			for (i = 0; i < len; i++)
1663				if (!isspace(buf[i]))
1664					break;
1665			if (buf[i] == '#')
1666				continue;
1667			buf[len - 1] = '\0';
1668			LibAliasLoadModule(buf);
1669		}
1670	}
1671	fclose(fd);
1672	return (0);
1673}
1674
1675int
1676LibAliasLoadModule(char *path)
1677{
1678	struct dll *t;
1679	void *handle;
1680	struct proto_handler *m;
1681        const char *error;
1682	moduledata_t *p;
1683
1684        handle = dlopen (path, RTLD_LAZY);
1685        if (!handle) {
1686		fprintf(stderr, "%s\n", dlerror());
1687		return (EINVAL);
1688        }
1689
1690	p = dlsym(handle, "alias_mod");
1691        if ((error = dlerror()) != NULL)  {
1692		fprintf(stderr, "%s\n", dlerror());
1693		return (EINVAL);
1694        }
1695
1696	t = malloc(sizeof(struct dll));
1697	if (t == NULL)
1698		return (ENOMEM);
1699	strncpy(t->name, p->name, DLL_LEN);
1700	t->handle = handle;
1701	if (attach_dll(t) == EEXIST) {
1702		free(t);
1703		fprintf(stderr, "dll conflict\n");
1704		return (EEXIST);
1705	}
1706
1707        m = dlsym(t->handle, "handlers");
1708        if ((error = dlerror()) != NULL)  {
1709		fprintf(stderr, "%s\n", error);
1710		return (EINVAL);
1711	}
1712
1713	LibAliasAttachHandlers(m);
1714	return (0);
1715}
1716
1717int
1718LibAliasUnLoadAllModule(void)
1719{
1720	struct dll *t;
1721	struct proto_handler *p;
1722
1723	/* Unload all modules then reload everything. */
1724	while ((p = first_handler()) != NULL) {
1725		detach_handler(p);
1726	}
1727	while ((t = walk_dll_chain()) != NULL) {
1728		dlclose(t->handle);
1729		free(t);
1730	}
1731	return (1);
1732}
1733
1734#endif
1735
1736#ifdef _KERNEL
1737/*
1738 * m_megapullup() - this function is a big hack.
1739 * Thankfully, it's only used in ng_nat and ipfw+nat.
1740 *
1741 * It allocates an mbuf with cluster and copies the specified part of the chain
1742 * into cluster, so that it is all contiguous and can be accessed via a plain
1743 * (char *) pointer. This is required, because libalias doesn't know how to
1744 * handle mbuf chains.
1745 *
1746 * On success, m_megapullup returns an mbuf (possibly with cluster) containing
1747 * the input packet, on failure NULL. The input packet is always consumed.
1748 */
1749struct mbuf *
1750m_megapullup(struct mbuf *m, int len) {
1751	struct mbuf *mcl;
1752
1753	if (len > m->m_pkthdr.len)
1754		goto bad;
1755
1756	if (m->m_next == NULL && M_WRITABLE(m))
1757		return (m);
1758
1759	mcl = m_get2(len, M_NOWAIT, MT_DATA, M_PKTHDR);
1760	if (mcl == NULL)
1761		goto bad;
1762	m_align(mcl, len);
1763	m_move_pkthdr(mcl, m);
1764	m_copydata(m, 0, len, mtod(mcl, caddr_t));
1765	mcl->m_len = mcl->m_pkthdr.len = len;
1766	m_freem(m);
1767
1768	return (mcl);
1769bad:
1770	m_freem(m);
1771	return (NULL);
1772}
1773#endif
1774