VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/slirp/libalias/alias.c@ 56377

Last change on this file since 56377 was 56377, checked in by vboxsync, 10 years ago

more RT_GCC_EXTENSION required for gcc-5

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette