VirtualBox

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

Last change on this file since 23154 was 23154, checked in by vboxsync, 15 years ago

NAT: BSD mbuf

  • 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", __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 int iresult;
1250
1251 if (la->packetAliasMode & PKT_ALIAS_REVERSE) {
1252 la->packetAliasMode &= ~PKT_ALIAS_REVERSE;
1253 iresult = LibAliasOutLocked(la, ptr, maxpacketsize, 1);
1254 la->packetAliasMode |= PKT_ALIAS_REVERSE;
1255 goto getout;
1256 }
1257 HouseKeeping(la);
1258 ClearCheckNewLink(la);
1259 pip = (struct ip *)ptr;
1260 alias_addr = pip->ip_dst;
1261
1262 /* Defense against mangled packets */
1263 if (ntohs(pip->ip_len) > maxpacketsize
1264 || (pip->ip_hl << 2) > maxpacketsize) {
1265 iresult = PKT_ALIAS_IGNORED;
1266 goto getout;
1267 }
1268
1269 iresult = PKT_ALIAS_IGNORED;
1270 if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
1271 switch (pip->ip_p) {
1272 case IPPROTO_ICMP:
1273 iresult = IcmpAliasIn(la, pip);
1274 break;
1275 case IPPROTO_UDP:
1276 iresult = UdpAliasIn(la, pip);
1277 break;
1278 case IPPROTO_TCP:
1279 iresult = TcpAliasIn(la, pip);
1280 break;
1281#ifndef VBOX
1282 case IPPROTO_GRE: {
1283 int error;
1284 struct alias_data ad;
1285 ad.lnk = NULL,
1286 ad.oaddr = NULL,
1287 ad.aaddr = NULL,
1288 ad.aport = NULL,
1289 ad.sport = NULL,
1290 ad.dport = NULL,
1291 ad.maxpktsize = 0
1292
1293 /* Walk out chain. */
1294 error = find_handler(IN, IP, la, pip, &ad);
1295 if (error == 0)
1296 iresult = PKT_ALIAS_OK;
1297 else
1298 iresult = ProtoAliasIn(la, pip);
1299 }
1300 break;
1301#endif
1302 default:
1303 iresult = ProtoAliasIn(la, pip);
1304 break;
1305 }
1306
1307 if (ntohs(pip->ip_off) & IP_MF) {
1308 struct alias_link *lnk;
1309
1310 lnk = FindFragmentIn1(la, pip->ip_src, alias_addr, pip->ip_id);
1311 if (lnk != NULL) {
1312 iresult = PKT_ALIAS_FOUND_HEADER_FRAGMENT;
1313 SetFragmentAddr(lnk, pip->ip_dst);
1314 } else {
1315 iresult = PKT_ALIAS_ERROR;
1316 }
1317 }
1318 } else {
1319 iresult = FragmentIn(la, pip);
1320 }
1321
1322getout:
1323 return (iresult);
1324}
1325
1326
1327
1328/* Unregistered address ranges */
1329
1330/* 10.0.0.0 -> 10.255.255.255 */
1331#define UNREG_ADDR_A_LOWER 0x0a000000
1332#define UNREG_ADDR_A_UPPER 0x0affffff
1333
1334/* 172.16.0.0 -> 172.31.255.255 */
1335#define UNREG_ADDR_B_LOWER 0xac100000
1336#define UNREG_ADDR_B_UPPER 0xac1fffff
1337
1338/* 192.168.0.0 -> 192.168.255.255 */
1339#define UNREG_ADDR_C_LOWER 0xc0a80000
1340#define UNREG_ADDR_C_UPPER 0xc0a8ffff
1341
1342int
1343LibAliasOut(struct libalias *la, char *ptr, int maxpacketsize)
1344{
1345 int res;
1346
1347 LIBALIAS_LOCK(la);
1348 res = LibAliasOutLocked(la, ptr, maxpacketsize, 1);
1349 LIBALIAS_UNLOCK(la);
1350 return (res);
1351}
1352
1353int
1354LibAliasOutTry(struct libalias *la, char *ptr, int maxpacketsize, int create)
1355{
1356 int res;
1357
1358 LIBALIAS_LOCK(la);
1359 res = LibAliasOutLocked(la, ptr, maxpacketsize, create);
1360 LIBALIAS_UNLOCK(la);
1361 return (res);
1362}
1363
1364static int
1365LibAliasOutLocked(struct libalias *la, char *ptr, /* valid IP packet */
1366 int maxpacketsize, /* How much the packet data may grow (FTP
1367 * and IRC inline changes) */
1368 int create /* Create new entries ? */
1369)
1370{
1371 int iresult;
1372 struct in_addr addr_save;
1373 struct ip *pip;
1374
1375 if (la->packetAliasMode & PKT_ALIAS_REVERSE) {
1376 la->packetAliasMode &= ~PKT_ALIAS_REVERSE;
1377 iresult = LibAliasInLocked(la, ptr, maxpacketsize);
1378 la->packetAliasMode |= PKT_ALIAS_REVERSE;
1379 goto getout;
1380 }
1381 HouseKeeping(la);
1382 ClearCheckNewLink(la);
1383 pip = (struct ip *)ptr;
1384
1385 /* Defense against mangled packets */
1386 if (ntohs(pip->ip_len) > maxpacketsize
1387 || (pip->ip_hl << 2) > maxpacketsize) {
1388 iresult = PKT_ALIAS_IGNORED;
1389 goto getout;
1390 }
1391
1392 addr_save = GetDefaultAliasAddress(la);
1393 if (la->packetAliasMode & PKT_ALIAS_UNREGISTERED_ONLY) {
1394 u_long addr;
1395 int iclass;
1396
1397 iclass = 0;
1398 addr = ntohl(pip->ip_src.s_addr);
1399 if (addr >= UNREG_ADDR_C_LOWER && addr <= UNREG_ADDR_C_UPPER)
1400 iclass = 3;
1401 else if (addr >= UNREG_ADDR_B_LOWER && addr <= UNREG_ADDR_B_UPPER)
1402 iclass = 2;
1403 else if (addr >= UNREG_ADDR_A_LOWER && addr <= UNREG_ADDR_A_UPPER)
1404 iclass = 1;
1405
1406 if (iclass == 0) {
1407 SetDefaultAliasAddress(la, pip->ip_src);
1408 }
1409 } else if (la->packetAliasMode & PKT_ALIAS_PROXY_ONLY) {
1410 SetDefaultAliasAddress(la, pip->ip_src);
1411 }
1412 iresult = PKT_ALIAS_IGNORED;
1413 if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
1414 switch (pip->ip_p) {
1415 case IPPROTO_ICMP:
1416 iresult = IcmpAliasOut(la, pip, create);
1417 break;
1418 case IPPROTO_UDP:
1419 iresult = UdpAliasOut(la, pip, create);
1420 break;
1421 case IPPROTO_TCP:
1422 iresult = TcpAliasOut(la, pip, maxpacketsize, create);
1423 break;
1424#ifndef VBOX
1425 case IPPROTO_GRE: {
1426 int error;
1427 struct alias_data ad = {
1428 .lnk = NULL,
1429 .oaddr = NULL,
1430 .aaddr = NULL,
1431 .aport = NULL,
1432 .sport = NULL,
1433 .dport = NULL,
1434 .maxpktsize = 0
1435 };
1436 /* Walk out chain. */
1437 error = find_handler(OUT, IP, la, pip, &ad);
1438 if (error == 0)
1439 iresult = PKT_ALIAS_OK;
1440 else
1441 iresult = ProtoAliasOut(la, pip, create);
1442 }
1443 break;
1444#endif
1445 default:
1446 iresult = ProtoAliasOut(la, pip, create);
1447 break;
1448 }
1449 } else {
1450 iresult = FragmentOut(la, pip);
1451 }
1452
1453 SetDefaultAliasAddress(la, addr_save);
1454getout:
1455 return (iresult);
1456}
1457
1458int
1459LibAliasUnaliasOut(struct libalias *la, char *ptr, /* valid IP packet */
1460 int maxpacketsize /* for error checking */
1461)
1462{
1463 struct ip *pip;
1464 struct icmp *ic;
1465 struct udphdr *ud;
1466 struct tcphdr *tc;
1467 struct alias_link *lnk;
1468 int iresult = PKT_ALIAS_IGNORED;
1469
1470 LIBALIAS_LOCK(la);
1471 pip = (struct ip *)ptr;
1472
1473 /* Defense against mangled packets */
1474 if (ntohs(pip->ip_len) > maxpacketsize
1475 || (pip->ip_hl << 2) > maxpacketsize)
1476 goto getout;
1477
1478 ud = (struct udphdr *)ip_next(pip);
1479 tc = (struct tcphdr *)ip_next(pip);
1480 ic = (struct icmp *)ip_next(pip);
1481
1482 /* Find a link */
1483 if (pip->ip_p == IPPROTO_UDP)
1484 lnk = FindUdpTcpIn(la, pip->ip_dst, pip->ip_src,
1485 ud->uh_dport, ud->uh_sport,
1486 IPPROTO_UDP, 0);
1487 else if (pip->ip_p == IPPROTO_TCP)
1488 lnk = FindUdpTcpIn(la, pip->ip_dst, pip->ip_src,
1489 tc->th_dport, tc->th_sport,
1490 IPPROTO_TCP, 0);
1491 else if (pip->ip_p == IPPROTO_ICMP)
1492 lnk = FindIcmpIn(la, pip->ip_dst, pip->ip_src, ic->icmp_id, 0);
1493 else
1494 lnk = NULL;
1495
1496 /* Change it from an aliased packet to an unaliased packet */
1497 if (lnk != NULL) {
1498 if (pip->ip_p == IPPROTO_UDP || pip->ip_p == IPPROTO_TCP) {
1499 int accumulate;
1500 struct in_addr original_address;
1501 u_short original_port;
1502
1503 original_address = GetOriginalAddress(lnk);
1504 original_port = GetOriginalPort(lnk);
1505
1506 /* Adjust TCP/UDP checksum */
1507 accumulate = twowords(&pip->ip_src);
1508 accumulate -= twowords(&original_address);
1509
1510 if (pip->ip_p == IPPROTO_UDP) {
1511 accumulate += ud->uh_sport;
1512 accumulate -= original_port;
1513 ADJUST_CHECKSUM(accumulate, ud->uh_sum);
1514 } else {
1515 accumulate += tc->th_sport;
1516 accumulate -= original_port;
1517 ADJUST_CHECKSUM(accumulate, tc->th_sum);
1518 }
1519
1520 /* Adjust IP checksum */
1521 DifferentialChecksum(&pip->ip_sum,
1522 &original_address, &pip->ip_src, 2);
1523
1524 /* Un-alias source address and port number */
1525 pip->ip_src = original_address;
1526 if (pip->ip_p == IPPROTO_UDP)
1527 ud->uh_sport = original_port;
1528 else
1529 tc->th_sport = original_port;
1530
1531 iresult = PKT_ALIAS_OK;
1532
1533 } else if (pip->ip_p == IPPROTO_ICMP) {
1534
1535 int accumulate;
1536 struct in_addr original_address;
1537 u_short original_id;
1538
1539 original_address = GetOriginalAddress(lnk);
1540 original_id = GetOriginalPort(lnk);
1541
1542 /* Adjust ICMP checksum */
1543 accumulate = twowords(&pip->ip_src);
1544 accumulate -= twowords(&original_address);
1545 accumulate += ic->icmp_id;
1546 accumulate -= original_id;
1547 ADJUST_CHECKSUM(accumulate, ic->icmp_cksum);
1548
1549 /* Adjust IP checksum */
1550 DifferentialChecksum(&pip->ip_sum,
1551 &original_address, &pip->ip_src, 2);
1552
1553 /* Un-alias source address and port number */
1554 pip->ip_src = original_address;
1555 ic->icmp_id = original_id;
1556
1557 iresult = PKT_ALIAS_OK;
1558 }
1559 }
1560getout:
1561 LIBALIAS_UNLOCK(la);
1562 return (iresult);
1563
1564}
1565
1566#ifndef _KERNEL
1567
1568int
1569LibAliasRefreshModules(void)
1570{
1571 /* @todo (r - vasily) here should be module loading */
1572#ifndef VBOX
1573 char buf[256], conf[] = "/etc/libalias.conf";
1574 FILE *fd;
1575 int i, len;
1576
1577 fd = fopen(conf, "r");
1578 if (fd == NULL)
1579 err(1, "fopen(%s)", conf);
1580
1581 LibAliasUnLoadAllModule();
1582
1583 for (;;) {
1584 fgets(buf, 256, fd);
1585 if feof(fd)
1586 break;
1587 len = strlen(buf);
1588 if (len > 1) {
1589 for (i = 0; i < len; i++)
1590 if (!isspace(buf[i]))
1591 break;
1592 if (buf[i] == '#')
1593 continue;
1594 buf[len - 1] = '\0';
1595 printf("Loading %s\n", buf);
1596 LibAliasLoadModule(buf);
1597 }
1598 }
1599#endif /* !VBOX */
1600 return (0);
1601}
1602
1603int
1604LibAliasLoadModule(char *path)
1605{
1606#ifndef VBOX
1607 struct dll *t;
1608 void *handle;
1609 struct proto_handler *m;
1610 const char *error;
1611 moduledata_t *p;
1612
1613 handle = dlopen (path, RTLD_LAZY);
1614 if (!handle) {
1615 fprintf(stderr, "%s\n", dlerror());
1616 return (EINVAL);
1617 }
1618
1619 p = dlsym(handle, "alias_mod");
1620 if ((error = dlerror()) != NULL) {
1621 fprintf(stderr, "%s\n", dlerror());
1622 return (EINVAL);
1623 }
1624
1625 t = malloc(sizeof(struct dll));
1626 if (t == NULL)
1627 return (ENOMEM);
1628 strncpy(t->name, p->name, DLL_LEN);
1629 t->handle = handle;
1630 if (attach_dll(t) == EEXIST) {
1631 free(t);
1632 fprintf(stderr, "dll conflict\n");
1633 return (EEXIST);
1634 }
1635
1636 m = dlsym(t->handle, "handlers");
1637 if ((error = dlerror()) != NULL) {
1638 fprintf(stderr, "%s\n", error);
1639 return (EINVAL);
1640 }
1641
1642 LibAliasAttachHandlers(m);
1643#endif /* !VBOX */
1644 return (0);
1645}
1646
1647int
1648LibAliasUnLoadAllModule(void)
1649{
1650#ifndef VBOX
1651 struct dll *t;
1652 struct proto_handler *p;
1653
1654 /* Unload all modules then reload everything. */
1655 while ((p = first_handler()) != NULL) {
1656 detach_handler(p);
1657 }
1658 while ((t = walk_dll_chain()) != NULL) {
1659 dlclose(t->handle);
1660 free(t);
1661 }
1662#endif /* !VBOX */
1663 return (1);
1664}
1665
1666#endif
1667
1668#if defined(_KERNEL) || (defined(VBOX) && defined(VBOX_WITH_SLIRP_BSD_MBUF))
1669/*
1670 * m_megapullup() - this function is a big hack.
1671 * Thankfully, it's only used in ng_nat and ipfw+nat.
1672 *
1673 * It allocates an mbuf with cluster and copies the specified part of the chain
1674 * into cluster, so that it is all contiguous and can be accessed via a plain
1675 * (char *) pointer. This is required, because libalias doesn't know how to
1676 * handle mbuf chains.
1677 *
1678 * On success, m_megapullup returns an mbuf (possibly with cluster) containing
1679 * the input packet, on failure NULL. The input packet is always consumed.
1680 */
1681struct mbuf *
1682#ifndef VBOX
1683m_megapullup(struct mbuf *m, int len)
1684#else
1685m_megapullup(PNATState pData, struct mbuf *m, int len)
1686#endif
1687{
1688 struct mbuf *mcl;
1689
1690 if (len > m->m_pkthdr.len)
1691 goto bad;
1692
1693 /* Do not reallocate packet if it is sequentional,
1694 * writable and has some extra space for expansion.
1695 * XXX: Constant 100bytes is completely empirical. */
1696#define RESERVE 100
1697 if (m->m_next == NULL && M_WRITABLE(m) && M_TRAILINGSPACE(m) >= RESERVE)
1698 return (m);
1699
1700 if (len <= MCLBYTES - RESERVE) {
1701#ifndef VBOX
1702 mcl = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
1703#else
1704 mcl = m_getcl(pData, M_DONTWAIT, MT_DATA, M_PKTHDR);
1705#endif
1706 } else if (len < MJUM16BYTES) {
1707 int size;
1708 if (len <= MJUMPAGESIZE - RESERVE) {
1709 size = MJUMPAGESIZE;
1710 } else if (len <= MJUM9BYTES - RESERVE) {
1711 size = MJUM9BYTES;
1712 } else {
1713 size = MJUM16BYTES;
1714 };
1715#ifndef VBOX
1716 mcl = m_getjcl(M_DONTWAIT, MT_DATA, M_PKTHDR, size);
1717#else
1718 mcl = m_getjcl(pData, M_DONTWAIT, MT_DATA, M_PKTHDR, size);
1719#endif
1720 } else {
1721 goto bad;
1722 }
1723 if (mcl == NULL)
1724 goto bad;
1725
1726 m_move_pkthdr(mcl, m);
1727 m_copydata(m, 0, len, mtod(mcl, caddr_t));
1728 mcl->m_len = mcl->m_pkthdr.len = len;
1729#ifndef VBOX
1730 m_freem(m);
1731#else
1732 m_freem(pData, m);
1733#endif
1734
1735 return (mcl);
1736bad:
1737#ifndef VBOX
1738 m_freem(m);
1739#else
1740 m_freem(pData, m);
1741#endif
1742 return (NULL);
1743}
1744#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