VirtualBox

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

Last change on this file since 103068 was 85195, checked in by vboxsync, 4 years ago

slirp: Clang 11 / OSX SDK 10.13 adjustments. bugref:9790

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

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