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