VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/slirp/libalias/alias_ftp.c@ 64572

最後變更 在這個檔案從64572是 63015,由 vboxsync 提交於 8 年 前

slirp: warnings

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 20.0 KB
 
1/*-
2 * Copyright (c) 2001 Charles Mott <[email protected]>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#ifndef VBOX
28#include <sys/cdefs.h>
29__FBSDID("$FreeBSD: src/sys/netinet/libalias/alias_ftp.c,v 1.29.2.1.4.1 2009/04/15 03:14:26 kensmith Exp $");
30
31/*
32 Alias_ftp.c performs special processing for FTP sessions under
33 TCP. Specifically, when a PORT/EPRT command from the client
34 side or 227/229 reply from the server is sent, it is intercepted
35 and modified. The address is changed to the gateway machine
36 and an aliasing port is used.
37
38 For this routine to work, the message must fit entirely into a
39 single TCP packet. This is typically the case, but exceptions
40 can easily be envisioned under the actual specifications.
41
42 Probably the most troubling aspect of the approach taken here is
43 that the new message will typically be a different length, and
44 this causes a certain amount of bookkeeping to keep track of the
45 changes of sequence and acknowledgment numbers, since the client
46 machine is totally unaware of the modification to the TCP stream.
47
48
49 References: RFC 959, RFC 2428.
50
51 Initial version: August, 1996 (cjm)
52
53 Version 1.6
54 Brian Somers and Martin Renters identified an IP checksum
55 error for modified IP packets.
56
57 Version 1.7: January 9, 1996 (cjm)
58 Differential checksum computation for change
59 in IP packet length.
60
61 Version 2.1: May, 1997 (cjm)
62 Very minor changes to conform with
63 local/global/function naming conventions
64 within the packet aliasing module.
65
66 Version 3.1: May, 2000 (eds)
67 Add support for passive mode, alias the 227 replies.
68
69 See HISTORY file for record of revisions.
70*/
71
72/* Includes */
73#ifdef _KERNEL
74#include <sys/param.h>
75#include <sys/ctype.h>
76#include <sys/systm.h>
77#include <sys/kernel.h>
78#include <sys/module.h>
79#else
80#include <errno.h>
81#include <sys/types.h>
82#include <stdio.h>
83#include <string.h>
84#endif
85
86#include <netinet/in_systm.h>
87#include <netinet/in.h>
88#include <netinet/ip.h>
89#include <netinet/tcp.h>
90
91#ifdef _KERNEL
92#include <netinet/libalias/alias.h>
93#include <netinet/libalias/alias_local.h>
94#include <netinet/libalias/alias_mod.h>
95#else
96#include "alias_local.h"
97#include "alias_mod.h"
98#endif
99#else /* VBOX */
100# include <iprt/ctype.h>
101# include <slirp.h>
102# include "alias_local.h"
103# include "alias_mod.h"
104# define isspace(ch) RT_C_IS_SPACE(ch)
105# define isdigit(ch) RT_C_IS_DIGIT(ch)
106#endif /* VBOX */
107
108#define FTP_CONTROL_PORT_NUMBER 21
109
110static void
111AliasHandleFtpOut(struct libalias *, struct ip *, struct alias_link *,
112 int maxpacketsize);
113
114static int
115fingerprint(struct libalias *la, struct ip *pip, struct alias_data *ah)
116{
117
118#ifdef VBOX
119 NOREF(la);
120 NOREF(pip);
121#endif
122 if (ah->dport == NULL || ah->sport == NULL || ah->lnk == NULL ||
123 ah->maxpktsize == 0)
124 return (-1);
125 if (ntohs(*ah->dport) == FTP_CONTROL_PORT_NUMBER
126 || ntohs(*ah->sport) == FTP_CONTROL_PORT_NUMBER)
127 return (0);
128 return (-1);
129}
130
131static int
132protohandler(struct libalias *la, struct ip *pip, struct alias_data *ah)
133{
134
135 AliasHandleFtpOut(la, pip, ah->lnk, ah->maxpktsize);
136 return (0);
137}
138
139#ifndef VBOX
140struct proto_handler handlers[] = {
141 {
142 .pri = 80,
143 .dir = OUT,
144 .proto = TCP,
145 .fingerprint = &fingerprint,
146 .protohandler = &protohandler
147 },
148 { EOH }
149};
150#else /* VBOX */
151#define handlers pData->ftp_module
152#endif /* VBOX */
153
154#ifndef VBOX
155static int
156mod_handler(module_t mod, int type, void *data)
157#else
158static int ftp_alias_handler(PNATState pData, int type);
159
160int
161ftp_alias_load(PNATState pData)
162{
163 return ftp_alias_handler(pData, MOD_LOAD);
164}
165
166int
167ftp_alias_unload(PNATState pData)
168{
169 return ftp_alias_handler(pData, MOD_UNLOAD);
170}
171static int
172ftp_alias_handler(PNATState pData, int type)
173#endif
174{
175 int error;
176#ifdef VBOX
177 if (handlers == NULL)
178 handlers = RTMemAllocZ(2 * sizeof(struct proto_handler));
179 handlers[0].pri = 80;
180 handlers[0].dir = OUT;
181 handlers[0].proto = TCP;
182 handlers[0].fingerprint = &fingerprint;
183 handlers[0].protohandler = &protohandler;
184 handlers[1].pri = (u_int)EOH;
185#endif /* VBOX */
186
187 switch (type) {
188 case MOD_LOAD:
189 error = 0;
190#ifdef VBOX
191 LibAliasAttachHandlers(pData, handlers);
192#else
193 LibAliasAttachHandlers(handlers);
194#endif
195 break;
196 case MOD_UNLOAD:
197 error = 0;
198#ifdef VBOX
199 LibAliasDetachHandlers(pData, handlers);
200 RTMemFree(handlers);
201 handlers = NULL;
202#else
203 LibAliasDetachHandlers(handlers);
204#endif
205 break;
206 default:
207 error = EINVAL;
208 }
209 return (error);
210}
211
212#ifndef VBOX
213#ifdef _KERNEL
214static
215#endif
216moduledata_t alias_mod = {
217 "alias_ftp", mod_handler, NULL
218};
219#endif /* !VBOX */
220
221#ifdef _KERNEL
222DECLARE_MODULE(alias_ftp, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
223MODULE_VERSION(alias_ftp, 1);
224MODULE_DEPEND(alias_ftp, libalias, 1, 1, 1);
225#endif
226
227#define FTP_CONTROL_PORT_NUMBER 21
228#define MAX_MESSAGE_SIZE 128
229
230/* FTP protocol flags. */
231#define WAIT_CRLF 0x01
232
233enum ftp_message_type {
234 FTP_PORT_COMMAND,
235 FTP_EPRT_COMMAND,
236 FTP_227_REPLY,
237 FTP_229_REPLY,
238 FTP_UNKNOWN_MESSAGE
239};
240
241static int ParseFtpPortCommand(struct libalias *la, char *, int);
242static int ParseFtpEprtCommand(struct libalias *la, char *, int);
243static int ParseFtp227Reply(struct libalias *la, char *, int);
244static int ParseFtp229Reply(struct libalias *la, char *, int);
245static void NewFtpMessage(struct libalias *la, struct ip *, struct alias_link *, int, int);
246
247static void
248AliasHandleFtpOut(
249 struct libalias *la,
250 struct ip *pip, /* IP packet to examine/patch */
251 struct alias_link *lnk, /* The link to go through (aliased port) */
252 int maxpacketsize /* The maximum size this packet can grow to
253 (including headers) */ )
254{
255 int hlen, tlen, dlen, pflags;
256 char *sptr;
257 struct tcphdr *tc;
258 int ftp_message_type;
259
260/* Calculate data length of TCP packet */
261 tc = (struct tcphdr *)ip_next(pip);
262 hlen = (pip->ip_hl + tc->th_off) << 2;
263 tlen = ntohs(pip->ip_len);
264 dlen = tlen - hlen;
265
266/* Place string pointer and beginning of data */
267 sptr = (char *)pip;
268 sptr += hlen;
269
270/*
271 * Check that data length is not too long and previous message was
272 * properly terminated with CRLF.
273 */
274 pflags = GetProtocolFlags(lnk);
275 if (dlen <= MAX_MESSAGE_SIZE && !(pflags & WAIT_CRLF)) {
276 ftp_message_type = FTP_UNKNOWN_MESSAGE;
277
278 if (ntohs(tc->th_dport) == FTP_CONTROL_PORT_NUMBER) {
279/*
280 * When aliasing a client, check for the PORT/EPRT command.
281 */
282 if (ParseFtpPortCommand(la, sptr, dlen))
283 ftp_message_type = FTP_PORT_COMMAND;
284 else if (ParseFtpEprtCommand(la, sptr, dlen))
285 ftp_message_type = FTP_EPRT_COMMAND;
286 } else {
287/*
288 * When aliasing a server, check for the 227/229 reply.
289 */
290 if (ParseFtp227Reply(la, sptr, dlen))
291 ftp_message_type = FTP_227_REPLY;
292 else if (ParseFtp229Reply(la, sptr, dlen)) {
293 ftp_message_type = FTP_229_REPLY;
294 la->true_addr.s_addr = pip->ip_src.s_addr;
295 }
296 }
297
298 if (ftp_message_type != FTP_UNKNOWN_MESSAGE)
299 NewFtpMessage(la, pip, lnk, maxpacketsize, ftp_message_type);
300 }
301/* Track the msgs which are CRLF term'd for PORT/PASV FW breach */
302
303 if (dlen) { /* only if there's data */
304 sptr = (char *)pip; /* start over at beginning */
305 tlen = ntohs(pip->ip_len); /* recalc tlen, pkt may
306 * have grown */
307 if (sptr[tlen - 2] == '\r' && sptr[tlen - 1] == '\n')
308 pflags &= ~WAIT_CRLF;
309 else
310 pflags |= WAIT_CRLF;
311 SetProtocolFlags(lnk, pflags);
312 }
313}
314
315static int
316ParseFtpPortCommand(struct libalias *la, char *sptr, int dlen)
317{
318 char ch;
319 int i, state;
320 u_int32_t addr;
321 u_short port;
322 u_int8_t octet;
323
324 /* Format: "PORT A,D,D,R,PO,RT". */
325
326 /* Return if data length is too short. */
327 if (dlen < 18)
328 return (0);
329
330 if (strncasecmp("PORT ", sptr, 5))
331 return (0);
332
333 addr = port = octet = 0;
334 state = 0;
335 for (i = 5; i < dlen; i++) {
336 ch = sptr[i];
337 switch (state) {
338 case 0:
339 if (isspace(ch))
340 break;
341 else
342 state++;
343 case 1:
344 case 3:
345 case 5:
346 case 7:
347 case 9:
348 case 11:
349 if (isdigit(ch)) {
350 octet = ch - '0';
351 state++;
352 } else
353 return (0);
354 break;
355 case 2:
356 case 4:
357 case 6:
358 case 8:
359 if (isdigit(ch))
360 octet = 10 * octet + ch - '0';
361 else if (ch == ',') {
362 addr = (addr << 8) + octet;
363 state++;
364 } else
365 return (0);
366 break;
367 case 10:
368 case 12:
369 if (isdigit(ch))
370 octet = 10 * octet + ch - '0';
371 else if (ch == ',' || state == 12) {
372 port = (port << 8) + octet;
373 state++;
374 } else
375 return (0);
376 break;
377 }
378 }
379
380 if (state == 13) {
381 la->true_addr.s_addr = htonl(addr);
382 la->true_port = port;
383 return (1);
384 } else
385 return (0);
386}
387
388static int
389ParseFtpEprtCommand(struct libalias *la, char *sptr, int dlen)
390{
391 char ch, delim;
392 int i, state;
393 u_int32_t addr;
394 u_short port;
395 u_int8_t octet;
396
397 /* Format: "EPRT |1|A.D.D.R|PORT|". */
398
399 /* Return if data length is too short. */
400 if (dlen < 18)
401 return (0);
402
403 if (strncasecmp("EPRT ", sptr, 5))
404 return (0);
405
406 addr = port = octet = 0;
407 delim = '|'; /* XXX gcc -Wuninitialized */
408 state = 0;
409 for (i = 5; i < dlen; i++) {
410 ch = sptr[i];
411 switch (state) {
412 case 0:
413 if (!isspace(ch)) {
414 delim = ch;
415 state++;
416 }
417 break;
418 case 1:
419 if (ch == '1') /* IPv4 address */
420 state++;
421 else
422 return (0);
423 break;
424 case 2:
425 if (ch == delim)
426 state++;
427 else
428 return (0);
429 break;
430 case 3:
431 case 5:
432 case 7:
433 case 9:
434 if (isdigit(ch)) {
435 octet = ch - '0';
436 state++;
437 } else
438 return (0);
439 break;
440 case 4:
441 case 6:
442 case 8:
443 case 10:
444 if (isdigit(ch))
445 octet = 10 * octet + ch - '0';
446 else if (ch == '.' || state == 10) {
447 addr = (addr << 8) + octet;
448 state++;
449 } else
450 return (0);
451 break;
452 case 11:
453 if (isdigit(ch)) {
454 port = ch - '0';
455 state++;
456 } else
457 return (0);
458 break;
459 case 12:
460 if (isdigit(ch))
461 port = 10 * port + ch - '0';
462 else if (ch == delim)
463 state++;
464 else
465 return (0);
466 break;
467 }
468 }
469
470 if (state == 13) {
471 la->true_addr.s_addr = htonl(addr);
472 la->true_port = port;
473 return (1);
474 } else
475 return (0);
476}
477
478static int
479ParseFtp227Reply(struct libalias *la, char *sptr, int dlen)
480{
481 char ch;
482 int i, state;
483 u_int32_t addr;
484 u_short port;
485 u_int8_t octet;
486
487 /* Format: "227 Entering Passive Mode (A,D,D,R,PO,RT)" */
488
489 /* Return if data length is too short. */
490 if (dlen < 17)
491 return (0);
492
493 if (strncmp("227 ", sptr, 4))
494 return (0);
495
496 addr = port = octet = 0;
497
498 state = 0;
499 for (i = 4; i < dlen; i++) {
500 ch = sptr[i];
501 switch (state) {
502 case 0:
503 if (ch == '(')
504 state++;
505 break;
506 case 1:
507 case 3:
508 case 5:
509 case 7:
510 case 9:
511 case 11:
512 if (isdigit(ch)) {
513 octet = ch - '0';
514 state++;
515 } else
516 return (0);
517 break;
518 case 2:
519 case 4:
520 case 6:
521 case 8:
522 if (isdigit(ch))
523 octet = 10 * octet + ch - '0';
524 else if (ch == ',') {
525 addr = (addr << 8) + octet;
526 state++;
527 } else
528 return (0);
529 break;
530 case 10:
531 case 12:
532 if (isdigit(ch))
533 octet = 10 * octet + ch - '0';
534 else if (ch == ',' || (state == 12 && ch == ')')) {
535 port = (port << 8) + octet;
536 state++;
537 } else
538 return (0);
539 break;
540 }
541 }
542
543 if (state == 13) {
544 if (addr != INADDR_LOOPBACK)
545 la->true_addr.s_addr = htonl(addr);
546 else
547 la->true_addr.s_addr = la->pData->alias_addr.s_addr;
548 la->true_port = port;
549 return (1);
550 } else
551 return (0);
552}
553
554static int
555ParseFtp229Reply(struct libalias *la, char *sptr, int dlen)
556{
557 char ch, delim;
558 int i, state;
559 u_short port;
560
561 /* Format: "229 Entering Extended Passive Mode (|||PORT|)" */
562
563 /* Return if data length is too short. */
564 if (dlen < 11)
565 return (0);
566
567 if (strncmp("229 ", sptr, 4))
568 return (0);
569
570 port = 0;
571 delim = '|'; /* XXX gcc -Wuninitialized */
572
573 state = 0;
574 for (i = 4; i < dlen; i++) {
575 ch = sptr[i];
576 switch (state) {
577 case 0:
578 if (ch == '(')
579 state++;
580 break;
581 case 1:
582 delim = ch;
583 state++;
584 break;
585 case 2:
586 case 3:
587 if (ch == delim)
588 state++;
589 else
590 return (0);
591 break;
592 case 4:
593 if (isdigit(ch)) {
594 port = ch - '0';
595 state++;
596 } else
597 return (0);
598 break;
599 case 5:
600 if (isdigit(ch))
601 port = 10 * port + ch - '0';
602 else if (ch == delim)
603 state++;
604 else
605 return (0);
606 break;
607 case 6:
608 if (ch == ')')
609 state++;
610 else
611 return (0);
612 break;
613 }
614 }
615
616 if (state == 7) {
617 la->true_port = port;
618 return (1);
619 } else
620 return (0);
621}
622
623static void
624NewFtpMessage(struct libalias *la, struct ip *pip,
625 struct alias_link *lnk,
626 int maxpacketsize,
627 int ftp_message_type)
628{
629 struct alias_link *ftp_lnk;
630
631/* Security checks. */
632 if (pip->ip_src.s_addr != la->true_addr.s_addr)
633 return;
634
635 if (la->true_port < IPPORT_RESERVED)
636 return;
637
638/* Establish link to address and port found in FTP control message. */
639 ftp_lnk = FindUdpTcpOut(la, la->true_addr, GetDestAddress(lnk),
640 htons(la->true_port), 0, IPPROTO_TCP, 1);
641
642 if (ftp_lnk != NULL) {
643 int slen, hlen, tlen, dlen;
644 struct tcphdr *tc;
645
646#ifndef NO_FW_PUNCH
647 /* Punch hole in firewall */
648 PunchFWHole(ftp_lnk);
649#endif
650
651/* Calculate data length of TCP packet */
652 tc = (struct tcphdr *)ip_next(pip);
653 hlen = (pip->ip_hl + tc->th_off) << 2;
654 tlen = ntohs(pip->ip_len);
655 dlen = tlen - hlen;
656
657/* Create new FTP message. */
658 {
659 char stemp[MAX_MESSAGE_SIZE + 1];
660 char *sptr;
661 u_short alias_port;
662 u_char *ptr;
663 int a1, a2, a3, a4, p1, p2;
664 struct in_addr alias_address;
665
666/* Decompose alias address into quad format */
667 alias_address = GetAliasAddress(lnk);
668 ptr = (u_char *) & alias_address.s_addr;
669 a1 = *ptr++;
670 a2 = *ptr++;
671 a3 = *ptr++;
672 a4 = *ptr;
673
674 alias_port = GetAliasPort(ftp_lnk);
675
676/* Prepare new command */
677 switch (ftp_message_type) {
678 case FTP_PORT_COMMAND:
679 case FTP_227_REPLY:
680 /* Decompose alias port into pair format. */
681 ptr = (u_char *)&alias_port;
682 p1 = *ptr++;
683 p2 = *ptr;
684
685 if (ftp_message_type == FTP_PORT_COMMAND) {
686 /* Generate PORT command string. */
687#ifndef VBOX
688 sprintf(stemp, "PORT %d,%d,%d,%d,%d,%d\r\n",
689 a1, a2, a3, a4, p1, p2);
690#else
691 RTStrPrintf(stemp, sizeof(stemp), "PORT %d,%d,%d,%d,%d,%d\r\n",
692 a1, a2, a3, a4, p1, p2);
693#endif
694 } else {
695 /* Generate 227 reply string. */
696#ifndef VBOX
697 sprintf(stemp,
698 "227 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n",
699 a1, a2, a3, a4, p1, p2);
700#else
701 RTStrPrintf(stemp, sizeof(stemp),
702 "227 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n",
703 a1, a2, a3, a4, p1, p2);
704#endif
705 }
706 break;
707 case FTP_EPRT_COMMAND:
708 /* Generate EPRT command string. */
709#ifndef VBOX
710 sprintf(stemp, "EPRT |1|%d.%d.%d.%d|%d|\r\n",
711 a1, a2, a3, a4, ntohs(alias_port));
712#else
713 RTStrPrintf(stemp, sizeof(stemp), "EPRT |1|%d.%d.%d.%d|%d|\r\n",
714 a1, a2, a3, a4, ntohs(alias_port));
715#endif
716 break;
717 case FTP_229_REPLY:
718 /* Generate 229 reply string. */
719#ifndef VBOX
720 sprintf(stemp, "229 Entering Extended Passive Mode (|||%d|)\r\n",
721 ntohs(alias_port));
722#else
723 RTStrPrintf(stemp, sizeof(stemp), "229 Entering Extended Passive Mode (|||%d|)\r\n",
724 ntohs(alias_port));
725#endif
726 break;
727 }
728
729/* Save string length for IP header modification */
730 slen = (int)strlen(stemp);
731
732/* Copy modified buffer into IP packet. */
733 sptr = (char *)pip;
734 sptr += hlen;
735 strncpy(sptr, stemp, maxpacketsize - hlen);
736 }
737
738/* Save information regarding modified seq and ack numbers */
739 {
740 int delta;
741
742 SetAckModified(lnk);
743 delta = GetDeltaSeqOut(pip, lnk);
744 AddSeq(pip, lnk, delta + slen - dlen);
745 }
746
747/* Revise IP header */
748 {
749 u_short new_len;
750
751 new_len = htons(hlen + slen);
752 DifferentialChecksum(&pip->ip_sum,
753 &new_len,
754 &pip->ip_len,
755 1);
756 pip->ip_len = new_len;
757 }
758
759/* Compute TCP checksum for revised packet */
760 tc->th_sum = 0;
761#ifdef _KERNEL
762 tc->th_x2 = 1;
763#else
764 tc->th_sum = TcpChecksum(pip);
765#endif
766 } else {
767#ifdef LIBALIAS_DEBUG
768 fprintf(stderr,
769 "PacketAlias/HandleFtpOut: Cannot allocate FTP data port\n");
770#endif
771 }
772}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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