VirtualBox

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

Last change on this file since 63015 was 63014, checked in by vboxsync, 8 years ago

slirp: warnings

  • 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#ifdef RT_LITTLE_ENDIAN //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 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 /* If we cannot figure out the packet, ignore it. */
772 if (error < 0)
773 return (PKT_ALIAS_IGNORED);
774
775/* If UDP checksum is not zero, then adjust since destination port */
776/* is being unaliased and destination address is being altered. */
777 if (ud->uh_sum != 0) {
778 accumulate = alias_port;
779 accumulate -= ud->uh_dport;
780 accumulate += twowords(&alias_address);
781 accumulate -= twowords(&original_address);
782 ADJUST_CHECKSUM(accumulate, ud->uh_sum);
783 }
784/* Restore original IP address */
785 DifferentialChecksum(&pip->ip_sum,
786 &original_address, &pip->ip_dst, 2);
787 pip->ip_dst = original_address;
788
789 return (PKT_ALIAS_OK);
790 }
791 return (PKT_ALIAS_IGNORED);
792}
793
794static int
795UdpAliasOut(struct libalias *la, struct ip *pip, int create)
796{
797 struct udphdr *ud;
798 struct alias_link *lnk;
799 int error;
800
801 LIBALIAS_LOCK_ASSERT(la);
802/* Return if proxy-only mode is enabled */
803 if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY)
804 return (PKT_ALIAS_OK);
805
806 ud = (struct udphdr *)ip_next(pip);
807
808 lnk = FindUdpTcpOut(la, pip->ip_src, pip->ip_dst,
809 ud->uh_sport, ud->uh_dport,
810 IPPROTO_UDP, create);
811 if (lnk != NULL) {
812 u_short alias_port;
813 struct in_addr alias_address;
814 struct alias_data ad;
815 ad.lnk = lnk;
816 ad.oaddr = NULL;
817 ad.aaddr = &alias_address;
818 ad.aport = &alias_port;
819 ad.sport = &ud->uh_sport;
820 ad.dport = &ud->uh_dport;
821 ad.maxpktsize = 0;
822
823 alias_address = GetAliasAddress(lnk);
824 alias_port = GetAliasPort(lnk);
825
826 /* Walk out chain. */
827 error = find_handler(OUT, UDP, la, pip, &ad);
828
829/* If UDP checksum is not zero, adjust since source port is */
830/* being aliased and source address is being altered */
831 if (ud->uh_sum != 0) {
832 int accumulate;
833
834 accumulate = ud->uh_sport;
835 accumulate -= alias_port;
836 accumulate += twowords(&pip->ip_src);
837 accumulate -= twowords(&alias_address);
838 ADJUST_CHECKSUM(accumulate, ud->uh_sum);
839 }
840/* Put alias port in UDP header */
841 ud->uh_sport = alias_port;
842
843/* Change source address */
844 DifferentialChecksum(&pip->ip_sum,
845 &alias_address, &pip->ip_src, 2);
846 pip->ip_src = alias_address;
847
848 return (PKT_ALIAS_OK);
849 }
850 return (PKT_ALIAS_IGNORED);
851}
852
853
854
855static int
856TcpAliasIn(struct libalias *la, struct ip *pip)
857{
858 struct tcphdr *tc;
859 struct alias_link *lnk;
860
861 LIBALIAS_LOCK_ASSERT(la);
862 tc = (struct tcphdr *)ip_next(pip);
863
864 lnk = FindUdpTcpIn(la, pip->ip_src, pip->ip_dst,
865 tc->th_sport, tc->th_dport,
866 IPPROTO_TCP,
867 !(la->packetAliasMode & PKT_ALIAS_PROXY_ONLY));
868 if (lnk != NULL) {
869 struct in_addr alias_address;
870 struct in_addr original_address;
871 struct in_addr proxy_address;
872 u_short alias_port;
873 u_short proxy_port;
874 int accumulate, error;
875
876 /*
877 * The init of MANY vars is a bit below, but aliashandlepptpin
878 * seems to need the destination port that came within the
879 * packet and not the original one looks below [*].
880 */
881
882 struct alias_data ad;
883 ad.lnk = lnk;
884 ad.oaddr = NULL;
885 ad.aaddr = NULL;
886 ad.aport = NULL;
887 ad.sport = &tc->th_sport;
888 ad.dport = &tc->th_dport;
889 ad.maxpktsize = 0;
890
891 /* Walk out chain. */
892 error = find_handler(IN, TCP, la, pip, &ad);
893
894 alias_address = GetAliasAddress(lnk);
895 original_address = GetOriginalAddress(lnk);
896 proxy_address = GetProxyAddress(lnk);
897 alias_port = tc->th_dport;
898 tc->th_dport = GetOriginalPort(lnk);
899 proxy_port = GetProxyPort(lnk);
900
901 /*
902 * Look above, if anyone is going to add find_handler AFTER
903 * this aliashandlepptpin/point, please redo alias_data too.
904 * Uncommenting the piece here below should be enough.
905 */
906#if 0
907 struct alias_data ad = {
908 .lnk = lnk,
909 .oaddr = &original_address,
910 .aaddr = &alias_address,
911 .aport = &alias_port,
912 .sport = &ud->uh_sport,
913 .dport = &ud->uh_dport,
914 .maxpktsize = 0
915 };
916
917 /* Walk out chain. */
918 error = find_handler(la, pip, &ad);
919 if (error == EHDNOF)
920 printf("Protocol handler not found\n");
921#endif
922
923/* Adjust TCP checksum since destination port is being unaliased */
924/* and destination port is being altered. */
925 accumulate = alias_port;
926 accumulate -= tc->th_dport;
927 accumulate += twowords(&alias_address);
928 accumulate -= twowords(&original_address);
929
930/* If this is a proxy, then modify the TCP source port and
931 checksum accumulation */
932 if (proxy_port != 0) {
933 accumulate += tc->th_sport;
934 tc->th_sport = proxy_port;
935 accumulate -= tc->th_sport;
936 accumulate += twowords(&pip->ip_src);
937 accumulate -= twowords(&proxy_address);
938 }
939/* See if ACK number needs to be modified */
940 if (GetAckModified(lnk) == 1) {
941 int delta;
942
943 delta = GetDeltaAckIn(pip, lnk);
944 if (delta != 0) {
945 accumulate += twowords(&tc->th_ack);
946 tc->th_ack = htonl(ntohl(tc->th_ack) - delta);
947 accumulate -= twowords(&tc->th_ack);
948 }
949 }
950 ADJUST_CHECKSUM(accumulate, tc->th_sum);
951
952/* Restore original IP address */
953 accumulate = twowords(&pip->ip_dst);
954 pip->ip_dst = original_address;
955 accumulate -= twowords(&pip->ip_dst);
956
957/* If this is a transparent proxy packet, then modify the source
958 address */
959 if (proxy_address.s_addr != 0) {
960 accumulate += twowords(&pip->ip_src);
961 pip->ip_src = proxy_address;
962 accumulate -= twowords(&pip->ip_src);
963 }
964 ADJUST_CHECKSUM(accumulate, pip->ip_sum);
965
966/* Monitor TCP connection state */
967 TcpMonitorIn(pip, lnk);
968
969 return (PKT_ALIAS_OK);
970 }
971 return (PKT_ALIAS_IGNORED);
972}
973
974static int
975TcpAliasOut(struct libalias *la, struct ip *pip, int maxpacketsize, int create)
976{
977 int proxy_type, error;
978 u_short dest_port;
979 u_short proxy_server_port = 0; /* Shut up MSC. */
980 struct in_addr dest_address;
981 struct in_addr proxy_server_address;
982 struct tcphdr *tc;
983 struct alias_link *lnk;
984
985 LIBALIAS_LOCK_ASSERT(la);
986 tc = (struct tcphdr *)ip_next(pip);
987
988 if (create)
989 proxy_type =
990 ProxyCheck(la, pip, &proxy_server_address, &proxy_server_port);
991 else
992 proxy_type = 0;
993
994 if (proxy_type == 0 && (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY))
995 return (PKT_ALIAS_OK);
996
997/* If this is a transparent proxy, save original destination,
998 then alter the destination and adjust checksums */
999 dest_port = tc->th_dport;
1000 dest_address = pip->ip_dst;
1001 if (proxy_type != 0) {
1002 int accumulate;
1003
1004 accumulate = tc->th_dport;
1005 tc->th_dport = proxy_server_port;
1006 accumulate -= tc->th_dport;
1007 accumulate += twowords(&pip->ip_dst);
1008 accumulate -= twowords(&proxy_server_address);
1009 ADJUST_CHECKSUM(accumulate, tc->th_sum);
1010
1011 accumulate = twowords(&pip->ip_dst);
1012 pip->ip_dst = proxy_server_address;
1013 accumulate -= twowords(&pip->ip_dst);
1014 ADJUST_CHECKSUM(accumulate, pip->ip_sum);
1015 }
1016 lnk = FindUdpTcpOut(la, pip->ip_src, pip->ip_dst,
1017 tc->th_sport, tc->th_dport,
1018 IPPROTO_TCP, create);
1019 if (lnk == NULL)
1020 return (PKT_ALIAS_IGNORED);
1021 if (lnk != NULL) {
1022 u_short alias_port;
1023 struct in_addr alias_address;
1024 int accumulate;
1025 struct alias_data ad;
1026 ad.lnk = lnk;
1027 ad.oaddr = NULL;
1028 ad.aaddr = &alias_address;
1029 ad.aport = &alias_port;
1030 ad.sport = &tc->th_sport;
1031 ad.dport = &tc->th_dport;
1032 ad.maxpktsize = maxpacketsize;
1033
1034/* Save original destination address, if this is a proxy packet.
1035 Also modify packet to include destination encoding. This may
1036 change the size of IP header. */
1037 if (proxy_type != 0) {
1038 SetProxyPort(lnk, dest_port);
1039 SetProxyAddress(lnk, dest_address);
1040 ProxyModify(la, lnk, pip, maxpacketsize, proxy_type);
1041 tc = (struct tcphdr *)ip_next(pip);
1042 }
1043/* Get alias address and port */
1044 alias_port = GetAliasPort(lnk);
1045 alias_address = GetAliasAddress(lnk);
1046
1047/* Monitor TCP connection state */
1048 TcpMonitorOut(pip, lnk);
1049
1050 /* Walk out chain. */
1051 error = find_handler(OUT, TCP, la, pip, &ad);
1052
1053/* Adjust TCP checksum since source port is being aliased */
1054/* and source address is being altered */
1055 accumulate = tc->th_sport;
1056 tc->th_sport = alias_port;
1057 accumulate -= tc->th_sport;
1058 accumulate += twowords(&pip->ip_src);
1059 accumulate -= twowords(&alias_address);
1060
1061/* Modify sequence number if necessary */
1062 if (GetAckModified(lnk) == 1) {
1063 int delta;
1064
1065 delta = GetDeltaSeqOut(pip, lnk);
1066 if (delta != 0) {
1067 accumulate += twowords(&tc->th_seq);
1068 tc->th_seq = htonl(ntohl(tc->th_seq) + delta);
1069 accumulate -= twowords(&tc->th_seq);
1070 }
1071 }
1072 ADJUST_CHECKSUM(accumulate, tc->th_sum);
1073
1074/* Change source address */
1075 accumulate = twowords(&pip->ip_src);
1076 pip->ip_src = alias_address;
1077 accumulate -= twowords(&pip->ip_src);
1078 ADJUST_CHECKSUM(accumulate, pip->ip_sum);
1079
1080 return (PKT_ALIAS_OK);
1081 }
1082 return (PKT_ALIAS_IGNORED);
1083}
1084
1085
1086
1087
1088/* Fragment Handling
1089
1090 FragmentIn()
1091 FragmentOut()
1092
1093The packet aliasing module has a limited ability for handling IP
1094fragments. If the ICMP, TCP or UDP header is in the first fragment
1095received, then the ID number of the IP packet is saved, and other
1096fragments are identified according to their ID number and IP address
1097they were sent from. Pointers to unresolved fragments can also be
1098saved and recalled when a header fragment is seen.
1099*/
1100
1101/* Local prototypes */
1102static int FragmentIn(struct libalias *, struct ip *);
1103static int FragmentOut(struct libalias *, struct ip *);
1104
1105
1106static int
1107FragmentIn(struct libalias *la, struct ip *pip)
1108{
1109 struct alias_link *lnk;
1110
1111 LIBALIAS_LOCK_ASSERT(la);
1112 lnk = FindFragmentIn2(la, pip->ip_src, pip->ip_dst, pip->ip_id);
1113 if (lnk != NULL) {
1114 struct in_addr original_address;
1115
1116 GetFragmentAddr(lnk, &original_address);
1117 DifferentialChecksum(&pip->ip_sum,
1118 &original_address, &pip->ip_dst, 2);
1119 pip->ip_dst = original_address;
1120
1121 return (PKT_ALIAS_OK);
1122 }
1123 return (PKT_ALIAS_UNRESOLVED_FRAGMENT);
1124}
1125
1126
1127static int
1128FragmentOut(struct libalias *la, struct ip *pip)
1129{
1130 struct in_addr alias_address;
1131
1132 LIBALIAS_LOCK_ASSERT(la);
1133 alias_address = FindAliasAddress(la, pip->ip_src);
1134 DifferentialChecksum(&pip->ip_sum,
1135 &alias_address, &pip->ip_src, 2);
1136 pip->ip_src = alias_address;
1137
1138 return (PKT_ALIAS_OK);
1139}
1140
1141
1142
1143
1144
1145
1146/* Outside World Access
1147
1148 PacketAliasSaveFragment()
1149 PacketAliasGetFragment()
1150 PacketAliasFragmentIn()
1151 PacketAliasIn()
1152 PacketAliasOut()
1153 PacketUnaliasOut()
1154
1155(prototypes in alias.h)
1156*/
1157
1158
1159int
1160LibAliasSaveFragment(struct libalias *la, char *ptr)
1161{
1162 int iresult;
1163 struct alias_link *lnk;
1164 struct ip *pip;
1165
1166 LIBALIAS_LOCK(la);
1167 pip = (struct ip *)ptr;
1168 lnk = AddFragmentPtrLink(la, pip->ip_src, pip->ip_id);
1169 iresult = PKT_ALIAS_ERROR;
1170 if (lnk != NULL) {
1171 SetFragmentPtr(lnk, ptr);
1172 iresult = PKT_ALIAS_OK;
1173 }
1174 LIBALIAS_UNLOCK(la);
1175 return (iresult);
1176}
1177
1178
1179char *
1180LibAliasGetFragment(struct libalias *la, char *ptr)
1181{
1182 struct alias_link *lnk;
1183 char *fptr;
1184 struct ip *pip;
1185
1186 LIBALIAS_LOCK(la);
1187 pip = (struct ip *)ptr;
1188 lnk = FindFragmentPtr(la, pip->ip_src, pip->ip_id);
1189 if (lnk != NULL) {
1190 GetFragmentPtr(lnk, &fptr);
1191 SetFragmentPtr(lnk, NULL);
1192 SetExpire(lnk, 0); /* Deletes link */
1193 } else
1194 fptr = NULL;
1195
1196 LIBALIAS_UNLOCK(la);
1197 return (fptr);
1198}
1199
1200
1201void
1202LibAliasFragmentIn(struct libalias *la, char *ptr, /* Points to correctly
1203 * de-aliased header
1204 * fragment */
1205 char *ptr_fragment /* Points to fragment which must be
1206 * de-aliased */
1207)
1208{
1209 struct ip *pip;
1210 struct ip *fpip;
1211
1212 LIBALIAS_LOCK(la);
1213 (void)la;
1214 pip = (struct ip *)ptr;
1215 fpip = (struct ip *)ptr_fragment;
1216
1217 DifferentialChecksum(&fpip->ip_sum,
1218 &pip->ip_dst, &fpip->ip_dst, 2);
1219 fpip->ip_dst = pip->ip_dst;
1220 LIBALIAS_UNLOCK(la);
1221}
1222
1223/* Local prototypes */
1224static int
1225LibAliasOutLocked(struct libalias *la, char *ptr,
1226 int maxpacketsize, int create);
1227static int
1228LibAliasInLocked(struct libalias *la, char *ptr,
1229 int maxpacketsize);
1230
1231int
1232LibAliasIn(struct libalias *la, char *ptr, int maxpacketsize)
1233{
1234 int res;
1235
1236 LIBALIAS_LOCK(la);
1237 res = LibAliasInLocked(la, ptr, maxpacketsize);
1238 LIBALIAS_UNLOCK(la);
1239 return (res);
1240}
1241
1242static int
1243LibAliasInLocked(struct libalias *la, char *ptr, int maxpacketsize)
1244{
1245 struct in_addr alias_addr;
1246 struct ip *pip;
1247#ifndef VBOX
1248 int iresult;
1249#else
1250 int iresult = PKT_ALIAS_IGNORED;
1251#endif
1252
1253 if (la->packetAliasMode & PKT_ALIAS_REVERSE) {
1254 la->packetAliasMode &= ~PKT_ALIAS_REVERSE;
1255 iresult = LibAliasOutLocked(la, ptr, maxpacketsize, 1);
1256 la->packetAliasMode |= PKT_ALIAS_REVERSE;
1257 goto getout;
1258 }
1259 HouseKeeping(la);
1260 ClearCheckNewLink(la);
1261 pip = (struct ip *)ptr;
1262 alias_addr = pip->ip_dst;
1263
1264 /* Defense against mangled packets */
1265 if (ntohs(pip->ip_len) > maxpacketsize
1266 || (pip->ip_hl << 2) > maxpacketsize) {
1267 iresult = PKT_ALIAS_IGNORED;
1268 goto getout;
1269 }
1270
1271#ifndef VBOX
1272 iresult = PKT_ALIAS_IGNORED;
1273#endif
1274 if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
1275 switch (pip->ip_p) {
1276 case IPPROTO_ICMP:
1277 iresult = IcmpAliasIn(la, pip);
1278 break;
1279 case IPPROTO_UDP:
1280 iresult = UdpAliasIn(la, pip);
1281 break;
1282 case IPPROTO_TCP:
1283 iresult = TcpAliasIn(la, pip);
1284 break;
1285#ifndef VBOX
1286 case IPPROTO_GRE: {
1287 int error;
1288 struct alias_data ad;
1289 ad.lnk = NULL,
1290 ad.oaddr = NULL,
1291 ad.aaddr = NULL,
1292 ad.aport = NULL,
1293 ad.sport = NULL,
1294 ad.dport = NULL,
1295 ad.maxpktsize = 0
1296
1297 /* Walk out chain. */
1298 error = find_handler(IN, IP, la, pip, &ad);
1299 if (error == 0)
1300 iresult = PKT_ALIAS_OK;
1301 else
1302 iresult = ProtoAliasIn(la, pip);
1303 }
1304 break;
1305#endif
1306 default:
1307 iresult = ProtoAliasIn(la, pip);
1308 break;
1309 }
1310
1311 if (ntohs(pip->ip_off) & IP_MF) {
1312 struct alias_link *lnk;
1313
1314 lnk = FindFragmentIn1(la, pip->ip_src, alias_addr, pip->ip_id);
1315 if (lnk != NULL) {
1316 iresult = PKT_ALIAS_FOUND_HEADER_FRAGMENT;
1317 SetFragmentAddr(lnk, pip->ip_dst);
1318 } else {
1319 iresult = PKT_ALIAS_ERROR;
1320 }
1321 }
1322 } else {
1323 iresult = FragmentIn(la, pip);
1324 }
1325
1326getout:
1327 return (iresult);
1328}
1329
1330
1331
1332/* Unregistered address ranges */
1333
1334/* 10.0.0.0 -> 10.255.255.255 */
1335#define UNREG_ADDR_A_LOWER 0x0a000000
1336#define UNREG_ADDR_A_UPPER 0x0affffff
1337
1338/* 172.16.0.0 -> 172.31.255.255 */
1339#define UNREG_ADDR_B_LOWER 0xac100000
1340#define UNREG_ADDR_B_UPPER 0xac1fffff
1341
1342/* 192.168.0.0 -> 192.168.255.255 */
1343#define UNREG_ADDR_C_LOWER 0xc0a80000
1344#define UNREG_ADDR_C_UPPER 0xc0a8ffff
1345
1346int
1347LibAliasOut(struct libalias *la, char *ptr, int maxpacketsize)
1348{
1349 int res;
1350
1351 LIBALIAS_LOCK(la);
1352 res = LibAliasOutLocked(la, ptr, maxpacketsize, 1);
1353 LIBALIAS_UNLOCK(la);
1354 return (res);
1355}
1356
1357int
1358LibAliasOutTry(struct libalias *la, char *ptr, int maxpacketsize, int create)
1359{
1360 int res;
1361
1362 LIBALIAS_LOCK(la);
1363 res = LibAliasOutLocked(la, ptr, maxpacketsize, create);
1364 LIBALIAS_UNLOCK(la);
1365 return (res);
1366}
1367
1368static int
1369LibAliasOutLocked(struct libalias *la, char *ptr, /* valid IP packet */
1370 int maxpacketsize, /* How much the packet data may grow (FTP
1371 * and IRC inline changes) */
1372 int create /* Create new entries ? */
1373)
1374{
1375#ifndef VBOX
1376 int iresult;
1377#else
1378 int iresult = PKT_ALIAS_IGNORED;
1379#endif
1380 struct in_addr addr_save;
1381 struct ip *pip;
1382
1383 if (la->packetAliasMode & PKT_ALIAS_REVERSE) {
1384 la->packetAliasMode &= ~PKT_ALIAS_REVERSE;
1385 iresult = LibAliasInLocked(la, ptr, maxpacketsize);
1386 la->packetAliasMode |= PKT_ALIAS_REVERSE;
1387 goto getout;
1388 }
1389 HouseKeeping(la);
1390 ClearCheckNewLink(la);
1391 pip = (struct ip *)ptr;
1392
1393 /* Defense against mangled packets */
1394 if (ntohs(pip->ip_len) > maxpacketsize
1395 || (pip->ip_hl << 2) > maxpacketsize) {
1396 iresult = PKT_ALIAS_IGNORED;
1397 goto getout;
1398 }
1399
1400 addr_save = GetDefaultAliasAddress(la);
1401 if (la->packetAliasMode & PKT_ALIAS_UNREGISTERED_ONLY) {
1402 u_long addr;
1403 int iclass;
1404
1405 iclass = 0;
1406 addr = ntohl(pip->ip_src.s_addr);
1407 if (addr >= UNREG_ADDR_C_LOWER && addr <= UNREG_ADDR_C_UPPER)
1408 iclass = 3;
1409 else if (addr >= UNREG_ADDR_B_LOWER && addr <= UNREG_ADDR_B_UPPER)
1410 iclass = 2;
1411 else if (addr >= UNREG_ADDR_A_LOWER && addr <= UNREG_ADDR_A_UPPER)
1412 iclass = 1;
1413
1414 if (iclass == 0) {
1415 SetDefaultAliasAddress(la, pip->ip_src);
1416 }
1417 } else if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY) {
1418 SetDefaultAliasAddress(la, pip->ip_src);
1419 }
1420#ifndef VBOX
1421 iresult = PKT_ALIAS_IGNORED;
1422#endif
1423 if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
1424 switch (pip->ip_p) {
1425 case IPPROTO_ICMP:
1426 iresult = IcmpAliasOut(la, pip, create);
1427 break;
1428 case IPPROTO_UDP:
1429 iresult = UdpAliasOut(la, pip, create);
1430 break;
1431 case IPPROTO_TCP:
1432 iresult = TcpAliasOut(la, pip, maxpacketsize, create);
1433 break;
1434#ifndef VBOX
1435 case IPPROTO_GRE: {
1436 int error;
1437 struct alias_data ad = {
1438 .lnk = NULL,
1439 .oaddr = NULL,
1440 .aaddr = NULL,
1441 .aport = NULL,
1442 .sport = NULL,
1443 .dport = NULL,
1444 .maxpktsize = 0
1445 };
1446 /* Walk out chain. */
1447 error = find_handler(OUT, IP, la, pip, &ad);
1448 if (error == 0)
1449 iresult = PKT_ALIAS_OK;
1450 else
1451 iresult = ProtoAliasOut(la, pip, create);
1452 }
1453 break;
1454#endif
1455 default:
1456 iresult = ProtoAliasOut(la, pip, create);
1457 break;
1458 }
1459 } else {
1460 iresult = FragmentOut(la, pip);
1461 }
1462
1463 SetDefaultAliasAddress(la, addr_save);
1464getout:
1465 return (iresult);
1466}
1467
1468int
1469LibAliasUnaliasOut(struct libalias *la, char *ptr, /* valid IP packet */
1470 int maxpacketsize /* for error checking */
1471)
1472{
1473 struct ip *pip;
1474 struct icmp *ic;
1475 struct udphdr *ud;
1476 struct tcphdr *tc;
1477 struct alias_link *lnk;
1478 int iresult = PKT_ALIAS_IGNORED;
1479
1480 LIBALIAS_LOCK(la);
1481 pip = (struct ip *)ptr;
1482
1483 /* Defense against mangled packets */
1484 if (ntohs(pip->ip_len) > maxpacketsize
1485 || (pip->ip_hl << 2) > maxpacketsize)
1486 goto getout;
1487
1488 ud = (struct udphdr *)ip_next(pip);
1489 tc = (struct tcphdr *)ip_next(pip);
1490 ic = (struct icmp *)ip_next(pip);
1491
1492 /* Find a link */
1493 if (pip->ip_p == IPPROTO_UDP)
1494 lnk = FindUdpTcpIn(la, pip->ip_dst, pip->ip_src,
1495 ud->uh_dport, ud->uh_sport,
1496 IPPROTO_UDP, 0);
1497 else if (pip->ip_p == IPPROTO_TCP)
1498 lnk = FindUdpTcpIn(la, pip->ip_dst, pip->ip_src,
1499 tc->th_dport, tc->th_sport,
1500 IPPROTO_TCP, 0);
1501 else if (pip->ip_p == IPPROTO_ICMP)
1502 lnk = FindIcmpIn(la, pip->ip_dst, pip->ip_src, ic->icmp_id, 0);
1503 else
1504 lnk = NULL;
1505
1506 /* Change it from an aliased packet to an unaliased packet */
1507 if (lnk != NULL) {
1508 if (pip->ip_p == IPPROTO_UDP || pip->ip_p == IPPROTO_TCP) {
1509 int accumulate;
1510 struct in_addr original_address;
1511 u_short original_port;
1512
1513 original_address = GetOriginalAddress(lnk);
1514 original_port = GetOriginalPort(lnk);
1515
1516 /* Adjust TCP/UDP checksum */
1517 accumulate = twowords(&pip->ip_src);
1518 accumulate -= twowords(&original_address);
1519
1520 if (pip->ip_p == IPPROTO_UDP) {
1521 accumulate += ud->uh_sport;
1522 accumulate -= original_port;
1523 ADJUST_CHECKSUM(accumulate, ud->uh_sum);
1524 } else {
1525 accumulate += tc->th_sport;
1526 accumulate -= original_port;
1527 ADJUST_CHECKSUM(accumulate, tc->th_sum);
1528 }
1529
1530 /* Adjust IP checksum */
1531 DifferentialChecksum(&pip->ip_sum,
1532 &original_address, &pip->ip_src, 2);
1533
1534 /* Un-alias source address and port number */
1535 pip->ip_src = original_address;
1536 if (pip->ip_p == IPPROTO_UDP)
1537 ud->uh_sport = original_port;
1538 else
1539 tc->th_sport = original_port;
1540
1541 iresult = PKT_ALIAS_OK;
1542
1543 } else if (pip->ip_p == IPPROTO_ICMP) {
1544
1545 int accumulate;
1546 struct in_addr original_address;
1547 u_short original_id;
1548
1549 original_address = GetOriginalAddress(lnk);
1550 original_id = GetOriginalPort(lnk);
1551
1552 /* Adjust ICMP checksum */
1553 accumulate = twowords(&pip->ip_src);
1554 accumulate -= twowords(&original_address);
1555 accumulate += ic->icmp_id;
1556 accumulate -= original_id;
1557 ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
1558
1559 /* Adjust IP checksum */
1560 DifferentialChecksum(&pip->ip_sum,
1561 &original_address, &pip->ip_src, 2);
1562
1563 /* Un-alias source address and port number */
1564 pip->ip_src = original_address;
1565 ic->icmp_id = original_id;
1566
1567 iresult = PKT_ALIAS_OK;
1568 }
1569 }
1570getout:
1571 LIBALIAS_UNLOCK(la);
1572 return (iresult);
1573
1574}
1575
1576#ifndef _KERNEL
1577
1578int
1579LibAliasRefreshModules(void)
1580{
1581 /* @todo (r - vasily) here should be module loading */
1582#ifndef VBOX
1583 char buf[256], conf[] = "/etc/libalias.conf";
1584 FILE *fd;
1585 int i, len;
1586
1587 fd = fopen(conf, "r");
1588 if (fd == NULL)
1589 err(1, "fopen(%s)", conf);
1590
1591 LibAliasUnLoadAllModule();
1592
1593 for (;;) {
1594 fgets(buf, 256, fd);
1595 if feof(fd)
1596 break;
1597 len = strlen(buf);
1598 if (len > 1) {
1599 for (i = 0; i < len; i++)
1600 if (!isspace(buf[i]))
1601 break;
1602 if (buf[i] == '#')
1603 continue;
1604 buf[len - 1] = '\0';
1605 printf("Loading %s\n", buf);
1606 LibAliasLoadModule(buf);
1607 }
1608 }
1609#endif /* !VBOX */
1610 return (0);
1611}
1612
1613int
1614LibAliasLoadModule(char *path)
1615{
1616#ifndef VBOX
1617 struct dll *t;
1618 void *handle;
1619 struct proto_handler *m;
1620 const char *error;
1621 moduledata_t *p;
1622
1623 handle = dlopen (path, RTLD_LAZY);
1624 if (!handle) {
1625 fprintf(stderr, "%s\n", dlerror());
1626 return (EINVAL);
1627 }
1628
1629 p = dlsym(handle, "alias_mod");
1630 if ((error = dlerror()) != NULL) {
1631 fprintf(stderr, "%s\n", dlerror());
1632 return (EINVAL);
1633 }
1634
1635 t = malloc(sizeof(struct dll));
1636 if (t == NULL)
1637 return (ENOMEM);
1638 strncpy(t->name, p->name, DLL_LEN);
1639 t->handle = handle;
1640 if (attach_dll(t) == EEXIST) {
1641 free(t);
1642 fprintf(stderr, "dll conflict\n");
1643 return (EEXIST);
1644 }
1645
1646 m = dlsym(t->handle, "handlers");
1647 if ((error = dlerror()) != NULL) {
1648 fprintf(stderr, "%s\n", error);
1649 return (EINVAL);
1650 }
1651
1652 LibAliasAttachHandlers(m);
1653#else /* VBOX */
1654 NOREF(path);
1655#endif /* VBOX */
1656 return (0);
1657}
1658
1659int
1660LibAliasUnLoadAllModule(void)
1661{
1662#ifndef VBOX
1663 struct dll *t;
1664 struct proto_handler *p;
1665
1666 /* Unload all modules then reload everything. */
1667 while ((p = first_handler()) != NULL) {
1668 detach_handler(p);
1669 }
1670 while ((t = walk_dll_chain()) != NULL) {
1671 dlclose(t->handle);
1672 free(t);
1673 }
1674#endif /* !VBOX */
1675 return (1);
1676}
1677
1678#endif
1679
1680#if defined(_KERNEL) || defined(VBOX)
1681/*
1682 * m_megapullup() - this function is a big hack.
1683 * Thankfully, it's only used in ng_nat and ipfw+nat.
1684 *
1685 * It allocates an mbuf with cluster and copies the specified part of the chain
1686 * into cluster, so that it is all contiguous and can be accessed via a plain
1687 * (char *) pointer. This is required, because libalias doesn't know how to
1688 * handle mbuf chains.
1689 *
1690 * On success, m_megapullup returns an mbuf (possibly with cluster) containing
1691 * the input packet, on failure NULL. The input packet is always consumed.
1692 */
1693struct mbuf *
1694#ifndef VBOX
1695m_megapullup(struct mbuf *m, int len)
1696#else
1697m_megapullup(PNATState pData, struct mbuf *m, int len)
1698#endif
1699{
1700 struct mbuf *mcl;
1701
1702 if (len > m->m_pkthdr.len)
1703 goto bad;
1704
1705 /* Do not reallocate packet if it is sequentional,
1706 * writable and has some extra space for expansion.
1707 * XXX: Constant 100bytes is completely empirical. */
1708#define RESERVE 100
1709 if (m->m_next == NULL && M_WRITABLE(m) && M_TRAILINGSPACE(m) >= RESERVE)
1710 return (m);
1711
1712 if (len <= MCLBYTES - RESERVE) {
1713#ifndef VBOX
1714 mcl = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
1715#else
1716 mcl = m_getcl(pData, M_DONTWAIT, MT_DATA, M_PKTHDR);
1717#endif
1718 } else if (len < MJUM16BYTES) {
1719 int size;
1720 if (len <= MJUMPAGESIZE - RESERVE) {
1721 size = MJUMPAGESIZE;
1722 } else if (len <= MJUM9BYTES - RESERVE) {
1723 size = MJUM9BYTES;
1724 } else {
1725 size = MJUM16BYTES;
1726 };
1727#ifndef VBOX
1728 mcl = m_getjcl(M_DONTWAIT, MT_DATA, M_PKTHDR, size);
1729#else
1730 mcl = m_getjcl(pData, M_DONTWAIT, MT_DATA, M_PKTHDR, size);
1731#endif
1732 } else {
1733 goto bad;
1734 }
1735 if (mcl == NULL)
1736 goto bad;
1737
1738 m_move_pkthdr(mcl, m);
1739 m_copydata(m, 0, len, mtod(mcl, caddr_t));
1740 mcl->m_len = mcl->m_pkthdr.len = len;
1741#ifndef VBOX
1742 m_freem(m);
1743#else
1744 m_freem(pData, m);
1745#endif
1746
1747 return (mcl);
1748bad:
1749#ifndef VBOX
1750 m_freem(m);
1751#else
1752 m_freem(pData, m);
1753#endif
1754 return (NULL);
1755}
1756#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