diff options
-rwxr-xr-x | tests/ftpserver.pl | 173 | ||||
-rw-r--r-- | tests/server/sockfilt.c | 12 |
2 files changed, 151 insertions, 34 deletions
diff --git a/tests/ftpserver.pl b/tests/ftpserver.pl index 50ebf0a0f..474b4f293 100755 --- a/tests/ftpserver.pl +++ b/tests/ftpserver.pl @@ -143,10 +143,20 @@ my %delayreply; # # global variables for to test ftp wildcardmatching or other test that # need flexible LIST responses.. and corresponding files. # $ftptargetdir is keeping the fake "name" of LIST directory. +# my $ftplistparserstate; my $ftptargetdir; #********************************************************************** +# when running a ftp server, global var datasockf_mode var is used to +# keep info relative to the actual running state of the secondary or +# data sockfilt process. 'none' represents that the data sockfilt is +# not running. 'active' and 'passive' indicates that the data sockfilt +# is running and specifies operational mode. +# +my $datasockf_mode = 'none'; + +#********************************************************************** # global vars used for signal handling # my $got_exit_signal = 0; # set if program should finish execution ASAP @@ -455,25 +465,40 @@ sub close_dataconn { my $datapid = processexists($datasockf_pidfile); + logmsg "=====> Closing $datasockf_mode DATA connection...\n"; + if(!$closed) { - logmsg "* disconnect data connection\n"; if($datapid > 0) { + logmsg "Server disconnects $datasockf_mode DATA connection\n"; print DWRITE "DISC\n"; my $i; sysread DREAD, $i, 5; } + else { + logmsg "Server finds $datasockf_mode DATA connection already ". + "disconnected\n"; + } } else { - logmsg "data connection already disconnected\n"; + logmsg "Server knows $datasockf_mode DATA connection is already ". + "disconnected\n"; } - logmsg "=====> Closed data connection\n"; - logmsg "* quit sockfilt for data (pid $datapid)\n"; if($datapid > 0) { print DWRITE "QUIT\n"; waitpid($datapid, 0); unlink($datasockf_pidfile) if(-f $datasockf_pidfile); + logmsg "DATA sockfilt for $datasockf_mode data channel quits ". + "(pid $datapid)\n"; + } + else { + logmsg "DATA sockfilt for $datasockf_mode data channel already ". + "dead\n"; } + + logmsg "=====> Closed $datasockf_mode DATA connection\n"; + + $datasockf_mode = 'none'; } ################ @@ -1057,7 +1082,15 @@ sub PASV_ftp { my $pasvport; # kill previous data connection sockfilt when alive - killsockfilters($proto, $ipvnum, $idnum, $verbose, 'data'); + if($datasockf_mode ne 'none') { + killsockfilters($proto, $ipvnum, $idnum, $verbose, 'data'); + logmsg "DATA sockfilt for $datasockf_mode data channel killed\n"; + $datasockf_mode = 'none'; + } + + logmsg "====> Passive DATA channel requested by client\n"; + + logmsg "DATA sockfilt for passive data channel starting...\n"; # We fire up a new sockfilt to do the data transfer for us. my $datasockfcmd = "./server/sockfilt " . @@ -1066,18 +1099,34 @@ sub PASV_ftp { "--logfile \"$datasockf_logfile\""; $slavepid = open2(\*DREAD, \*DWRITE, $datasockfcmd); + $datasockf_mode = 'passive'; + + print STDERR "$datasockfcmd\n" if($verbose); + print DWRITE "PING\n"; my $pong; sysread_or_die(\*DREAD, \$pong, 5); - if($pong !~ /^PONG/) { - logmsg "failed to run sockfilt for data connection\n"; + if($pong =~ /^FAIL/) { + logmsg "DATA sockfilt said: FAIL\n"; + logmsg "DATA sockfilt for passive data channel failed\n"; + logmsg "DATA sockfilt not running\n"; + $datasockf_mode = 'none'; + sendcontrol "500 no free ports!\r\n"; + return; + } + elsif($pong !~ /^PONG/) { + logmsg "DATA sockfilt unexpected response: $pong\n"; + logmsg "DATA sockfilt for passive data channel failed\n"; + logmsg "DATA sockfilt killed now\n"; killsockfilters($proto, $ipvnum, $idnum, $verbose, 'data'); + logmsg "DATA sockfilt not running\n"; + $datasockf_mode = 'none'; sendcontrol "500 no free ports!\r\n"; return; } - logmsg "Run sockfilt for data on pid $slavepid\n"; + logmsg "DATA sockfilt for passive data channel started (pid $slavepid)\n"; # Find out what port we listen on my $i; @@ -1105,10 +1154,26 @@ sub PASV_ftp { $pasvport = $2; } + if(!$pasvport) { + logmsg "DATA sockfilt unknown listener port\n"; + logmsg "DATA sockfilt for passive data channel failed\n"; + logmsg "DATA sockfilt killed now\n"; + killsockfilters($proto, $ipvnum, $idnum, $verbose, 'data'); + logmsg "DATA sockfilt not running\n"; + $datasockf_mode = 'none'; + sendcontrol "500 no free ports!\r\n"; + return; + } + + logmsg "DATA sockfilt for passive data channel listens on port ". + "$pasvport\n"; + if($nodataconn) { - # kill data sockfilter and make believe the client - # that it is possible to establish a data connection. + logmsg "DATA sockfilt for passive data channel killed ". + "(NODATACONN)\n"; killsockfilters($proto, $ipvnum, $idnum, $verbose, 'data'); + logmsg "DATA sockfilt not running\n"; + $datasockf_mode = 'none'; } if($cmd ne "EPSV") { @@ -1126,8 +1191,11 @@ sub PASV_ftp { sendcontrol sprintf("229 Entering Passive Mode (|||%d|)\n", $pasvport); } + logmsg "Client has been notified that DATA conn ". + "will be accepted on port $pasvport\n"; + if($nodataconn) { - logmsg "client fooled, running without data connection\n"; + logmsg "====> Client fooled (NODATACONN)\n"; return; } @@ -1140,6 +1208,8 @@ sub PASV_ftp { # Wait for 'CNCT' my $input; + # FIX: Monitor ctrl conn for disconnect + while(sysread(DREAD, $input, 5)) { if($input !~ /^CNCT/) { @@ -1147,7 +1217,7 @@ sub PASV_ftp { logmsg "Odd, we got $input from client\n"; next; } - logmsg "====> Client DATA connect\n"; + logmsg "Client connects to port $pasvport\n"; last; } alarm 0; @@ -1157,11 +1227,15 @@ sub PASV_ftp { logmsg "$srvrname server timed out awaiting data connection ". "on port $pasvport\n"; logmsg "accept failed or connection not even attempted\n"; + logmsg "DATA sockfilt killed now\n"; killsockfilters($proto, $ipvnum, $idnum, $verbose, 'data'); + logmsg "DATA sockfilt not running\n"; + $datasockf_mode = 'none'; return; } else { - logmsg "data connection setup on port $pasvport\n"; + logmsg "====> Client established passive DATA connection ". + "on port $pasvport\n"; } return; @@ -1177,13 +1251,20 @@ sub PORT_ftp { my $addr; # kill previous data connection sockfilt when alive - killsockfilters($proto, $ipvnum, $idnum, $verbose, 'data'); + if($datasockf_mode ne 'none') { + killsockfilters($proto, $ipvnum, $idnum, $verbose, 'data'); + logmsg "DATA sockfilt for $datasockf_mode data channel killed\n"; + $datasockf_mode = 'none'; + } + + logmsg "====> Active DATA channel requested by client\n"; # We always ignore the given IP and use localhost. if($cmd eq "PORT") { if($arg !~ /(\d+),(\d+),(\d+),(\d+),(\d+),(\d+)/) { - logmsg "bad PORT-line: $arg\n"; + logmsg "DATA sockfilt for active data channel not started ". + "(bad PORT-line: $arg)\n"; sendcontrol "500 silly you, go away\r\n"; return; } @@ -1193,7 +1274,8 @@ sub PORT_ftp { # EPRT |2|::1|49706| elsif($cmd eq "EPRT") { if($arg !~ /(\d+)\|([^\|]+)\|(\d+)/) { - logmsg "bad EPRT-line: $arg\n"; + logmsg "DATA sockfilt for active data channel not started ". + "(bad EPRT-line: $arg)\n"; sendcontrol "500 silly you, go away\r\n"; return; } @@ -1202,34 +1284,39 @@ sub PORT_ftp { $addr = $2; } else { + logmsg "DATA sockfilt for active data channel not started ". + "(invalid command: $cmd)\n"; sendcontrol "500 we don't like $cmd now\r\n"; return; } if(!$port || $port > 65535) { - print STDERR "very illegal PORT number: $port\n"; + logmsg "DATA sockfilt for active data channel not started ". + "(illegal PORT number: $port)\n"; return; } if($nodataconn) { - # don't establish data connection back to client, - # and don't send anything over control connection. - logmsg "client fooled, will not connect back to him\n"; + logmsg "DATA sockfilt for active data channel not started ". + "(NODATACONN)\n"; + # client shall timeout awaiting connection from server return; } elsif($nodataconn425) { - # don't establish data connection back to client, - # reply with 425 over control connection. + logmsg "DATA sockfilt for active data channel not started ". + "(NODATACONN425)\n"; sendcontrol "425 Can't open data connection\r\n"; return; } elsif($nodataconn421) { - # don't establish data connection back to client - # reply with 421 over control connection. + logmsg "DATA sockfilt for active data channel not started ". + "(NODATACONN421)\n"; sendcontrol "421 Connection timed out\r\n"; return; } + logmsg "DATA sockfilt for active data channel starting...\n"; + # We fire up a new sockfilt to do the data transfer for us. my $datasockfcmd = "./server/sockfilt " . "--ipv$ipvnum --connect $port --addr \"$addr\" " . @@ -1237,18 +1324,36 @@ sub PORT_ftp { "--logfile \"$datasockf_logfile\""; $slavepid = open2(\*DREAD, \*DWRITE, $datasockfcmd); + $datasockf_mode = 'active'; + print STDERR "$datasockfcmd\n" if($verbose); print DWRITE "PING\n"; my $pong; sysread_or_die(\*DREAD, \$pong, 5); - if($pong !~ /^PONG/) { - logmsg "Failed sockfilt for data connection\n"; + if($pong =~ /^FAIL/) { + logmsg "DATA sockfilt said: FAIL\n"; + logmsg "DATA sockfilt for active data channel failed\n"; + logmsg "DATA sockfilt not running\n"; + $datasockf_mode = 'none'; + # client shall timeout awaiting connection from server + return; + } + elsif($pong !~ /^PONG/) { + logmsg "DATA sockfilt unexpected response: $pong\n"; + logmsg "DATA sockfilt for active data channel failed\n"; + logmsg "DATA sockfilt killed now\n"; killsockfilters($proto, $ipvnum, $idnum, $verbose, 'data'); + logmsg "DATA sockfilt not running\n"; + $datasockf_mode = 'none'; + # client shall timeout awaiting connection from server + return; } - logmsg "====> Client DATA connect to port $port\n"; + logmsg "DATA sockfilt for active data channel started (pid $slavepid)\n"; + + logmsg "====> Active DATA channel connected to client port $port\n"; return; } @@ -1474,6 +1579,14 @@ logmsg("logged pid $$ in $pidfile\n"); while(1) { + + # kill previous data connection sockfilt when alive + if($datasockf_mode ne 'none') { + killsockfilters($proto, $ipvnum, $idnum, $verbose, 'data'); + logmsg "DATA sockfilt for $datasockf_mode data channel killed now\n"; + $datasockf_mode = 'none'; + } + # # We read 'sockfilt' commands. # @@ -1484,7 +1597,7 @@ while(1) { if($input !~ /^CNCT/) { # we wait for a connected client - logmsg "sockfilt said: $input"; + logmsg "MAIN sockfilt said: $input"; next; } logmsg "====> Client connect\n"; @@ -1495,8 +1608,6 @@ while(1) { # flush data: $| = 1; - killsockfilters($proto, $ipvnum, $idnum, $verbose, 'data'); - &customize(); # read test control instructions sendcontrol @welcome; @@ -1525,7 +1636,7 @@ while(1) { sysread_or_die(\*SFREAD, \$i, 5); if($i !~ /^DATA/) { - logmsg "sockfilt said $i"; + logmsg "MAIN sockfilt said $i"; if($i =~ /^DISC/) { # disconnect last; diff --git a/tests/server/sockfilt.c b/tests/server/sockfilt.c index 90ce9d919..2731348ea 100644 --- a/tests/server/sockfilt.c +++ b/tests/server/sockfilt.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -950,6 +950,7 @@ int main(int argc, char *argv[]) error = SOCKERRNO; logmsg("Error creating socket: (%d) %s", error, strerror(error)); + write_stdout("FAIL\n", 5); goto sockfilt_cleanup; } @@ -985,6 +986,7 @@ int main(int argc, char *argv[]) error = SOCKERRNO; logmsg("Error connecting to port %hu: (%d) %s", connectport, error, strerror(error)); + write_stdout("FAIL\n", 5); goto sockfilt_cleanup; } logmsg("====> Client connect"); @@ -993,8 +995,10 @@ int main(int argc, char *argv[]) else { /* passive daemon style */ sock = sockdaemon(sock, &port); - if(CURL_SOCKET_BAD == sock) + if(CURL_SOCKET_BAD == sock) { + write_stdout("FAIL\n", 5); goto sockfilt_cleanup; + } msgsock = CURL_SOCKET_BAD; /* no stream socket yet */ } @@ -1006,8 +1010,10 @@ int main(int argc, char *argv[]) logmsg("Listening on port %hu", port); wrotepidfile = write_pidfile(pidname); - if(!wrotepidfile) + if(!wrotepidfile) { + write_stdout("FAIL\n", 5); goto sockfilt_cleanup; + } do { juggle_again = juggle(&msgsock, sock, &mode); |