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