VirtualBox

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

Last change on this file since 52379 was 40117, checked in by vboxsync, 13 years ago

NAT/libalias: calm down clang-analyzer (replace assignment with initialization).

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

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