VirtualBox

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

最後變更 在這個檔案從28023是 26495,由 vboxsync 提交於 15 年 前

Devices: whitespace cleanup

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 19.8 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 if (ah->dport == NULL || ah->sport == NULL || ah->lnk == NULL ||
119 ah->maxpktsize == 0)
120 return (-1);
121 if (ntohs(*ah->dport) == FTP_CONTROL_PORT_NUMBER
122 || ntohs(*ah->sport) == FTP_CONTROL_PORT_NUMBER)
123 return (0);
124 return (-1);
125}
126
127static int
128protohandler(struct libalias *la, struct ip *pip, struct alias_data *ah)
129{
130
131 AliasHandleFtpOut(la, pip, ah->lnk, ah->maxpktsize);
132 return (0);
133}
134
135#ifndef VBOX
136struct proto_handler handlers[] = {
137 {
138 .pri = 80,
139 .dir = OUT,
140 .proto = TCP,
141 .fingerprint = &fingerprint,
142 .protohandler = &protohandler
143 },
144 { EOH }
145};
146#else /* !VBOX */
147#define handlers pData->ftp_module
148#endif /* VBOX */
149
150#ifndef VBOX
151static int
152mod_handler(module_t mod, int type, void *data)
153#else
154static int ftp_alias_handler(PNATState pData, int type);
155
156int
157ftp_alias_load(PNATState pData)
158{
159 return ftp_alias_handler(pData, MOD_LOAD);
160}
161
162int
163ftp_alias_unload(PNATState pData)
164{
165 return ftp_alias_handler(pData, MOD_UNLOAD);
166}
167static int
168ftp_alias_handler(PNATState pData, int type)
169#endif
170{
171 int error;
172#ifdef VBOX
173 if (handlers == NULL)
174 handlers = RTMemAllocZ(2 * sizeof(struct proto_handler));
175 handlers[0].pri = 80;
176 handlers[0].dir = OUT;
177 handlers[0].proto = TCP;
178 handlers[0].fingerprint = &fingerprint;
179 handlers[0].protohandler = &protohandler;
180 handlers[1].pri = EOH;
181#endif /* VBOX */
182
183 switch (type) {
184 case MOD_LOAD:
185 error = 0;
186#ifdef VBOX
187 LibAliasAttachHandlers(pData, handlers);
188#else
189 LibAliasAttachHandlers(handlers);
190#endif
191 break;
192 case MOD_UNLOAD:
193 error = 0;
194#ifdef VBOX
195 LibAliasDetachHandlers(pData, handlers);
196 RTMemFree(handlers);
197 handlers = NULL;
198#else
199 LibAliasDetachHandlers(handlers);
200#endif
201 break;
202 default:
203 error = EINVAL;
204 }
205 return (error);
206}
207
208#ifndef VBOX
209#ifdef _KERNEL
210static
211#endif
212moduledata_t alias_mod = {
213 "alias_ftp", mod_handler, NULL
214};
215#endif /*!VBOX*/
216
217#ifdef _KERNEL
218DECLARE_MODULE(alias_ftp, alias_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND);
219MODULE_VERSION(alias_ftp, 1);
220MODULE_DEPEND(alias_ftp, libalias, 1, 1, 1);
221#endif
222
223#define FTP_CONTROL_PORT_NUMBER 21
224#define MAX_MESSAGE_SIZE 128
225
226/* FTP protocol flags. */
227#define WAIT_CRLF 0x01
228
229enum ftp_message_type {
230 FTP_PORT_COMMAND,
231 FTP_EPRT_COMMAND,
232 FTP_227_REPLY,
233 FTP_229_REPLY,
234 FTP_UNKNOWN_MESSAGE
235};
236
237static int ParseFtpPortCommand(struct libalias *la, char *, int);
238static int ParseFtpEprtCommand(struct libalias *la, char *, int);
239static int ParseFtp227Reply(struct libalias *la, char *, int);
240static int ParseFtp229Reply(struct libalias *la, char *, int);
241static void NewFtpMessage(struct libalias *la, struct ip *, struct alias_link *, int, int);
242
243static void
244AliasHandleFtpOut(
245 struct libalias *la,
246 struct ip *pip, /* IP packet to examine/patch */
247 struct alias_link *lnk, /* The link to go through (aliased port) */
248 int maxpacketsize /* The maximum size this packet can grow to
249 (including headers) */ )
250{
251 int hlen, tlen, dlen, pflags;
252 char *sptr;
253 struct tcphdr *tc;
254 int ftp_message_type;
255
256/* Calculate data length of TCP packet */
257 tc = (struct tcphdr *)ip_next(pip);
258 hlen = (pip->ip_hl + tc->th_off) << 2;
259 tlen = ntohs(pip->ip_len);
260 dlen = tlen - hlen;
261
262/* Place string pointer and beginning of data */
263 sptr = (char *)pip;
264 sptr += hlen;
265
266/*
267 * Check that data length is not too long and previous message was
268 * properly terminated with CRLF.
269 */
270 pflags = GetProtocolFlags(lnk);
271 if (dlen <= MAX_MESSAGE_SIZE && !(pflags & WAIT_CRLF)) {
272 ftp_message_type = FTP_UNKNOWN_MESSAGE;
273
274 if (ntohs(tc->th_dport) == FTP_CONTROL_PORT_NUMBER) {
275/*
276 * When aliasing a client, check for the PORT/EPRT command.
277 */
278 if (ParseFtpPortCommand(la, sptr, dlen))
279 ftp_message_type = FTP_PORT_COMMAND;
280 else if (ParseFtpEprtCommand(la, sptr, dlen))
281 ftp_message_type = FTP_EPRT_COMMAND;
282 } else {
283/*
284 * When aliasing a server, check for the 227/229 reply.
285 */
286 if (ParseFtp227Reply(la, sptr, dlen))
287 ftp_message_type = FTP_227_REPLY;
288 else if (ParseFtp229Reply(la, sptr, dlen)) {
289 ftp_message_type = FTP_229_REPLY;
290 la->true_addr.s_addr = pip->ip_src.s_addr;
291 }
292 }
293
294 if (ftp_message_type != FTP_UNKNOWN_MESSAGE)
295 NewFtpMessage(la, pip, lnk, maxpacketsize, ftp_message_type);
296 }
297/* Track the msgs which are CRLF term'd for PORT/PASV FW breach */
298
299 if (dlen) { /* only if there's data */
300 sptr = (char *)pip; /* start over at beginning */
301 tlen = ntohs(pip->ip_len); /* recalc tlen, pkt may
302 * have grown */
303 if (sptr[tlen - 2] == '\r' && sptr[tlen - 1] == '\n')
304 pflags &= ~WAIT_CRLF;
305 else
306 pflags |= WAIT_CRLF;
307 SetProtocolFlags(lnk, pflags);
308 }
309}
310
311static int
312ParseFtpPortCommand(struct libalias *la, char *sptr, int dlen)
313{
314 char ch;
315 int i, state;
316 u_int32_t addr;
317 u_short port;
318 u_int8_t octet;
319
320 /* Format: "PORT A,D,D,R,PO,RT". */
321
322 /* Return if data length is too short. */
323 if (dlen < 18)
324 return (0);
325
326 if (strncasecmp("PORT ", sptr, 5))
327 return (0);
328
329 addr = port = octet = 0;
330 state = 0;
331 for (i = 5; i < dlen; i++) {
332 ch = sptr[i];
333 switch (state) {
334 case 0:
335 if (isspace(ch))
336 break;
337 else
338 state++;
339 case 1:
340 case 3:
341 case 5:
342 case 7:
343 case 9:
344 case 11:
345 if (isdigit(ch)) {
346 octet = ch - '0';
347 state++;
348 } else
349 return (0);
350 break;
351 case 2:
352 case 4:
353 case 6:
354 case 8:
355 if (isdigit(ch))
356 octet = 10 * octet + ch - '0';
357 else if (ch == ',') {
358 addr = (addr << 8) + octet;
359 state++;
360 } else
361 return (0);
362 break;
363 case 10:
364 case 12:
365 if (isdigit(ch))
366 octet = 10 * octet + ch - '0';
367 else if (ch == ',' || state == 12) {
368 port = (port << 8) + octet;
369 state++;
370 } else
371 return (0);
372 break;
373 }
374 }
375
376 if (state == 13) {
377 la->true_addr.s_addr = htonl(addr);
378 la->true_port = port;
379 return (1);
380 } else
381 return (0);
382}
383
384static int
385ParseFtpEprtCommand(struct libalias *la, char *sptr, int dlen)
386{
387 char ch, delim;
388 int i, state;
389 u_int32_t addr;
390 u_short port;
391 u_int8_t octet;
392
393 /* Format: "EPRT |1|A.D.D.R|PORT|". */
394
395 /* Return if data length is too short. */
396 if (dlen < 18)
397 return (0);
398
399 if (strncasecmp("EPRT ", sptr, 5))
400 return (0);
401
402 addr = port = octet = 0;
403 delim = '|'; /* XXX gcc -Wuninitialized */
404 state = 0;
405 for (i = 5; i < dlen; i++) {
406 ch = sptr[i];
407 switch (state) {
408 case 0:
409 if (!isspace(ch)) {
410 delim = ch;
411 state++;
412 }
413 break;
414 case 1:
415 if (ch == '1') /* IPv4 address */
416 state++;
417 else
418 return (0);
419 break;
420 case 2:
421 if (ch == delim)
422 state++;
423 else
424 return (0);
425 break;
426 case 3:
427 case 5:
428 case 7:
429 case 9:
430 if (isdigit(ch)) {
431 octet = ch - '0';
432 state++;
433 } else
434 return (0);
435 break;
436 case 4:
437 case 6:
438 case 8:
439 case 10:
440 if (isdigit(ch))
441 octet = 10 * octet + ch - '0';
442 else if (ch == '.' || state == 10) {
443 addr = (addr << 8) + octet;
444 state++;
445 } else
446 return (0);
447 break;
448 case 11:
449 if (isdigit(ch)) {
450 port = ch - '0';
451 state++;
452 } else
453 return (0);
454 break;
455 case 12:
456 if (isdigit(ch))
457 port = 10 * port + ch - '0';
458 else if (ch == delim)
459 state++;
460 else
461 return (0);
462 break;
463 }
464 }
465
466 if (state == 13) {
467 la->true_addr.s_addr = htonl(addr);
468 la->true_port = port;
469 return (1);
470 } else
471 return (0);
472}
473
474static int
475ParseFtp227Reply(struct libalias *la, char *sptr, int dlen)
476{
477 char ch;
478 int i, state;
479 u_int32_t addr;
480 u_short port;
481 u_int8_t octet;
482
483 /* Format: "227 Entering Passive Mode (A,D,D,R,PO,RT)" */
484
485 /* Return if data length is too short. */
486 if (dlen < 17)
487 return (0);
488
489 if (strncmp("227 ", sptr, 4))
490 return (0);
491
492 addr = port = octet = 0;
493
494 state = 0;
495 for (i = 4; i < dlen; i++) {
496 ch = sptr[i];
497 switch (state) {
498 case 0:
499 if (ch == '(')
500 state++;
501 break;
502 case 1:
503 case 3:
504 case 5:
505 case 7:
506 case 9:
507 case 11:
508 if (isdigit(ch)) {
509 octet = ch - '0';
510 state++;
511 } else
512 return (0);
513 break;
514 case 2:
515 case 4:
516 case 6:
517 case 8:
518 if (isdigit(ch))
519 octet = 10 * octet + ch - '0';
520 else if (ch == ',') {
521 addr = (addr << 8) + octet;
522 state++;
523 } else
524 return (0);
525 break;
526 case 10:
527 case 12:
528 if (isdigit(ch))
529 octet = 10 * octet + ch - '0';
530 else if (ch == ',' || (state == 12 && ch == ')')) {
531 port = (port << 8) + octet;
532 state++;
533 } else
534 return (0);
535 break;
536 }
537 }
538
539 if (state == 13) {
540 la->true_port = port;
541 la->true_addr.s_addr = htonl(addr);
542 return (1);
543 } else
544 return (0);
545}
546
547static int
548ParseFtp229Reply(struct libalias *la, char *sptr, int dlen)
549{
550 char ch, delim;
551 int i, state;
552 u_short port;
553
554 /* Format: "229 Entering Extended Passive Mode (|||PORT|)" */
555
556 /* Return if data length is too short. */
557 if (dlen < 11)
558 return (0);
559
560 if (strncmp("229 ", sptr, 4))
561 return (0);
562
563 port = 0;
564 delim = '|'; /* XXX gcc -Wuninitialized */
565
566 state = 0;
567 for (i = 4; i < dlen; i++) {
568 ch = sptr[i];
569 switch (state) {
570 case 0:
571 if (ch == '(')
572 state++;
573 break;
574 case 1:
575 delim = ch;
576 state++;
577 break;
578 case 2:
579 case 3:
580 if (ch == delim)
581 state++;
582 else
583 return (0);
584 break;
585 case 4:
586 if (isdigit(ch)) {
587 port = ch - '0';
588 state++;
589 } else
590 return (0);
591 break;
592 case 5:
593 if (isdigit(ch))
594 port = 10 * port + ch - '0';
595 else if (ch == delim)
596 state++;
597 else
598 return (0);
599 break;
600 case 6:
601 if (ch == ')')
602 state++;
603 else
604 return (0);
605 break;
606 }
607 }
608
609 if (state == 7) {
610 la->true_port = port;
611 return (1);
612 } else
613 return (0);
614}
615
616static void
617NewFtpMessage(struct libalias *la, struct ip *pip,
618 struct alias_link *lnk,
619 int maxpacketsize,
620 int ftp_message_type)
621{
622 struct alias_link *ftp_lnk;
623
624/* Security checks. */
625 if (pip->ip_src.s_addr != la->true_addr.s_addr)
626 return;
627
628 if (la->true_port < IPPORT_RESERVED)
629 return;
630
631/* Establish link to address and port found in FTP control message. */
632 ftp_lnk = FindUdpTcpOut(la, la->true_addr, GetDestAddress(lnk),
633 htons(la->true_port), 0, IPPROTO_TCP, 1);
634
635 if (ftp_lnk != NULL) {
636 int slen, hlen, tlen, dlen;
637 struct tcphdr *tc;
638
639#ifndef NO_FW_PUNCH
640 /* Punch hole in firewall */
641 PunchFWHole(ftp_lnk);
642#endif
643
644/* Calculate data length of TCP packet */
645 tc = (struct tcphdr *)ip_next(pip);
646 hlen = (pip->ip_hl + tc->th_off) << 2;
647 tlen = ntohs(pip->ip_len);
648 dlen = tlen - hlen;
649
650/* Create new FTP message. */
651 {
652 char stemp[MAX_MESSAGE_SIZE + 1];
653 char *sptr;
654 u_short alias_port;
655 u_char *ptr;
656 int a1, a2, a3, a4, p1, p2;
657 struct in_addr alias_address;
658
659/* Decompose alias address into quad format */
660 alias_address = GetAliasAddress(lnk);
661 ptr = (u_char *) & alias_address.s_addr;
662 a1 = *ptr++;
663 a2 = *ptr++;
664 a3 = *ptr++;
665 a4 = *ptr;
666
667 alias_port = GetAliasPort(ftp_lnk);
668
669/* Prepare new command */
670 switch (ftp_message_type) {
671 case FTP_PORT_COMMAND:
672 case FTP_227_REPLY:
673 /* Decompose alias port into pair format. */
674 ptr = (u_char *)&alias_port;
675 p1 = *ptr++;
676 p2 = *ptr;
677
678 if (ftp_message_type == FTP_PORT_COMMAND) {
679 /* Generate PORT command string. */
680#ifndef VBOX
681 sprintf(stemp, "PORT %d,%d,%d,%d,%d,%d\r\n",
682 a1, a2, a3, a4, p1, p2);
683#else
684 RTStrPrintf(stemp, sizeof(stemp), "PORT %d,%d,%d,%d,%d,%d\r\n",
685 a1, a2, a3, a4, p1, p2);
686#endif
687 } else {
688 /* Generate 227 reply string. */
689#ifndef VBOX
690 sprintf(stemp,
691 "227 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n",
692 a1, a2, a3, a4, p1, p2);
693#else
694 RTStrPrintf(stemp, sizeof(stemp),
695 "227 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n",
696 a1, a2, a3, a4, p1, p2);
697#endif
698 }
699 break;
700 case FTP_EPRT_COMMAND:
701 /* Generate EPRT command string. */
702#ifndef VBOX
703 sprintf(stemp, "EPRT |1|%d.%d.%d.%d|%d|\r\n",
704 a1, a2, a3, a4, ntohs(alias_port));
705#else
706 RTStrPrintf(stemp, sizeof(stemp), "EPRT |1|%d.%d.%d.%d|%d|\r\n",
707 a1, a2, a3, a4, ntohs(alias_port));
708#endif
709 break;
710 case FTP_229_REPLY:
711 /* Generate 229 reply string. */
712#ifndef VBOX
713 sprintf(stemp, "229 Entering Extended Passive Mode (|||%d|)\r\n",
714 ntohs(alias_port));
715#else
716 RTStrPrintf(stemp, sizeof(stemp), "229 Entering Extended Passive Mode (|||%d|)\r\n",
717 ntohs(alias_port));
718#endif
719 break;
720 }
721
722/* Save string length for IP header modification */
723 slen = strlen(stemp);
724
725/* Copy modified buffer into IP packet. */
726 sptr = (char *)pip;
727 sptr += hlen;
728 strncpy(sptr, stemp, maxpacketsize - hlen);
729 }
730
731/* Save information regarding modified seq and ack numbers */
732 {
733 int delta;
734
735 SetAckModified(lnk);
736 delta = GetDeltaSeqOut(pip, lnk);
737 AddSeq(pip, lnk, delta + slen - dlen);
738 }
739
740/* Revise IP header */
741 {
742 u_short new_len;
743
744 new_len = htons(hlen + slen);
745 DifferentialChecksum(&pip->ip_sum,
746 &new_len,
747 &pip->ip_len,
748 1);
749 pip->ip_len = new_len;
750 }
751
752/* Compute TCP checksum for revised packet */
753 tc->th_sum = 0;
754#ifdef _KERNEL
755 tc->th_x2 = 1;
756#else
757 tc->th_sum = TcpChecksum(pip);
758#endif
759 } else {
760#ifdef LIBALIAS_DEBUG
761 fprintf(stderr,
762 "PacketAlias/HandleFtpOut: Cannot allocate FTP data port\n");
763#endif
764 }
765}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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