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