diff options
-rw-r--r-- | tests/ftpserver.pl | 453 |
1 files changed, 268 insertions, 185 deletions
diff --git a/tests/ftpserver.pl b/tests/ftpserver.pl index 2e36a3fbf..ccdc4cbb4 100644 --- a/tests/ftpserver.pl +++ b/tests/ftpserver.pl @@ -58,33 +58,66 @@ BEGIN { #********************************************************************** # global vars... # -my $verbose = 0; # set to 1 for debugging -my $ftpdnum=""; +my $verbose = 0; # set to 1 for debugging +my $ftpdnum = ""; # server instance number +my $ipvnum = 4; # server IPv number (4 or 6) +my $proto = 'ftp'; # server protocol +my $srcdir = '.'; # directory where ftpserver.pl is located +my $ipv6 = ""; +my $ext = ""; +my $grok_eprt; + +#********************************************************************** +# global vars used for server address and primary listener port +# +my $port = 8921; # server primary listener port +my $listenaddr = '127.0.0.1'; # server address for listener port + +#********************************************************************** +# global vars used for file names +# my $logfilename = 'log/logfile.log'; # Override this for each test server +my $pidfile = '.ftpd.pid'; # a default, use --pidfile -my $pasvbadip=0; -my $retrweirdo=0; -my $retrnosize=0; -my $srcdir="."; -my $nosave=0; -my $controldelay=0; # set to 1 to delay the control connect data sending to - # test that curl deals with that nicely -my $slavepid; # for the DATA connection sockfilt slave process -my $ipv6=""; -my $ext=""; # append to log/pid file names -my $grok_eprt; -my $port = 8921; # just a default -my $listenaddr = "127.0.0.1"; # just a default -my $pidfile = ".ftpd.pid"; # a default, use --pidfile +#********************************************************************** +# global vars used for server logs advisor read lock handling +# +my $SERVERLOGS_LOCK = 'log/serverlogs.lock'; +my $serverlogslocked = 0; -my $SERVERLOGS_LOCK="log/serverlogs.lock"; # server logs advisor read lock -my $serverlogslocked=0; +#********************************************************************** +# global vars used for child processes PID tracking +# +my $sfpid; # PID for primary connection sockfilt process +my $slavepid; # PID for secondary connection sockfilt process -my $proto="ftp"; +#********************************************************************** +# global typeglob filehandle vars to read/write from/to sockfilters +# +local *SFREAD; # used to read from primary connection +local *SFWRITE; # used to write to primary connection +local *DREAD; # used to read from secondary connection +local *DWRITE; # used to write to secondary connection -my $sfpid; +#********************************************************************** +# global vars which depend on server protocol selection +# +my %commandfunc; # protocol command specific function callbacks +my %displaytext; # text returned to client before callback runs +my @welcome; # text returned to client upon connection -local(*SFREAD, *SFWRITE); +#********************************************************************** +# global vars customized for each test from the server commands file +# +my $ctrldelay; # set if server should throttle ctrl stream +my $datadelay; # set if server should throttle data stream +my $retrweirdo; # set if ftp server should use RETRWEIRDO +my $retrnosize; # set if ftp server should use RETRNOSIZE +my $pasvbadip; # set if ftp server should use PASVBADIP +my $nosave; # set if ftp server should not save uploaded data +my %customreply; # +my %customcount; # +my %delayreply; # #********************************************************************** # global vars used for signal handling @@ -160,51 +193,6 @@ sub ftpmsg { # better on windows/cygwin } -while(@ARGV) { - if($ARGV[0] eq "-v") { - $verbose=1; - } - elsif($ARGV[0] eq "-s") { - $srcdir=$ARGV[1]; - shift @ARGV; - } - elsif($ARGV[0] eq "--id") { - $ftpdnum=$ARGV[1]; - shift @ARGV; - } - elsif($ARGV[0] eq "--proto") { - # ftp pop3 imap smtp - $proto=$ARGV[1]; - shift @ARGV; - } - elsif($ARGV[0] eq "--pidfile") { - $pidfile=$ARGV[1]; - shift @ARGV; - } - elsif($ARGV[0] eq "--ipv6") { - $ipv6="--ipv6"; - $ext="ipv6"; - $grok_eprt = 1; - } - elsif($ARGV[0] eq "--port") { - $port = $ARGV[1]; - shift @ARGV; - } - elsif($ARGV[0] eq "--addr") { - $listenaddr = $ARGV[1]; - $listenaddr =~ s/^\[(.*)\]$/$1/; - shift @ARGV; - } - shift @ARGV; -}; - -# a dedicated protocol has been selected, check that it's a fine one -if($proto !~ /^(ftp|imap|pop3|smtp)\z/) { - die "unsupported protocol selected"; -} - -$SIG{INT} = \&exit_signal_handler; -$SIG{TERM} = \&exit_signal_handler; sub sysread_or_die { my $FH = shift; @@ -273,17 +261,6 @@ sub startsf { } } -$logfilename = getlogfilename(); - -startsf(); - -logmsg sprintf("%s server listens on port IPv%d/$port\n", uc($proto), - $ipv6?6:4); -open(PID, ">$pidfile"); -print PID $$."\n"; -close(PID); - -logmsg("logged pid $$ in $pidfile\n"); sub sockfilt { my $l; @@ -307,7 +284,7 @@ sub sockfiltsecondary { # stdout. sub sendcontrol { - if(!$controldelay) { + if(!$ctrldelay) { # spit it all out at once sockfilt @_; } @@ -333,7 +310,7 @@ sub sendcontrol { sub senddata { my $l; foreach $l (@_) { - if(!$controldelay) { + if(!$datadelay) { # spit it all out at once sockfiltsecondary $l; } @@ -347,80 +324,116 @@ sub senddata { } } -my %displaytext; -my %commandfunc; - -# callback functions for certain commands -# and text shown before the function specified below is run - -if($proto eq "ftp") { - %displaytext = ('USER' => '331 We are happy you popped in!', - 'PASS' => '230 Welcome you silly person', - 'PORT' => '200 You said PORT - I say FINE', - 'TYPE' => '200 I modify TYPE as you wanted', - 'LIST' => '150 here comes a directory', - 'NLST' => '150 here comes a directory', - 'CWD' => '250 CWD command successful.', - 'SYST' => '215 UNIX Type: L8', # just fake something - 'QUIT' => '221 bye bye baby', # just reply something - 'PWD' => '257 "/nowhere/anywhere" is current directory', - 'MKD' => '257 Created your requested directory', - 'REST' => '350 Yeah yeah we set it there for you', - 'DELE' => '200 OK OK OK whatever you say', - 'RNFR' => '350 Received your order. Please provide more', - 'RNTO' => '250 Ok, thanks. File renaming completed.', - 'NOOP' => '200 Yes, I\'m very good at doing nothing.', - 'PBSZ' => '500 PBSZ not implemented', - 'PROT' => '500 PROT not implemented', +#********************************************************************** +# protocolsetup initializes the 'displaytext' and 'commandfunc' hashes +# for the given protocol. References to protocol command callbacks are +# stored in 'commandfunc' hash, and text which will be returned to the +# client before the command callback runs is stored in 'displaytext'. +# +sub protocolsetup { + my $proto = $_[0]; + + if($proto eq 'ftp') { + %commandfunc = ( + 'PORT' => \&PORT_ftp, + 'EPRT' => \&PORT_ftp, + 'LIST' => \&LIST_ftp, + 'NLST' => \&NLST_ftp, + 'PASV' => \&PASV_ftp, + 'EPSV' => \&PASV_ftp, + 'RETR' => \&RETR_ftp, + 'SIZE' => \&SIZE_ftp, + 'REST' => \&REST_ftp, + 'STOR' => \&STOR_ftp, + 'APPE' => \&STOR_ftp, # append looks like upload + 'MDTM' => \&MDTM_ftp, ); - - %commandfunc = ( 'PORT' => \&PORT_ftp, - 'EPRT' => \&PORT_ftp, - 'LIST' => \&LIST_ftp, - 'NLST' => \&NLST_ftp, - 'PASV' => \&PASV_ftp, - 'EPSV' => \&PASV_ftp, - 'RETR' => \&RETR_ftp, - 'SIZE' => \&SIZE_ftp, - 'REST' => \&REST_ftp, - 'STOR' => \&STOR_ftp, - 'APPE' => \&STOR_ftp, # append looks like upload - 'MDTM' => \&MDTM_ftp, + %displaytext = ( + 'USER' => '331 We are happy you popped in!', + 'PASS' => '230 Welcome you silly person', + 'PORT' => '200 You said PORT - I say FINE', + 'TYPE' => '200 I modify TYPE as you wanted', + 'LIST' => '150 here comes a directory', + 'NLST' => '150 here comes a directory', + 'CWD' => '250 CWD command successful.', + 'SYST' => '215 UNIX Type: L8', # just fake something + 'QUIT' => '221 bye bye baby', # just reply something + 'PWD' => '257 "/nowhere/anywhere" is current directory', + 'MKD' => '257 Created your requested directory', + 'REST' => '350 Yeah yeah we set it there for you', + 'DELE' => '200 OK OK OK whatever you say', + 'RNFR' => '350 Received your order. Please provide more', + 'RNTO' => '250 Ok, thanks. File renaming completed.', + 'NOOP' => '200 Yes, I\'m very good at doing nothing.', + 'PBSZ' => '500 PBSZ not implemented', + 'PROT' => '500 PROT not implemented', ); -} -elsif($proto eq "pop3") { - %commandfunc = ('RETR' => \&RETR_pop3, + @welcome = ( + '220- _ _ ____ _ '."\r\n", + '220- ___| | | | _ \| | '."\r\n", + '220- / __| | | | |_) | | '."\r\n", + '220- | (__| |_| | _ <| |___ '."\r\n", + '220 \___|\___/|_| \_\_____|'."\r\n" ); - - %displaytext = ('USER' => '+OK We are happy you popped in!', - 'PASS' => '+OK Access granted', - 'QUIT' => '+OK byebye', + } + elsif($proto eq 'pop3') { + %commandfunc = ( + 'RETR' => \&RETR_pop3, ); - -} -elsif($proto eq "imap") { - %commandfunc = ('FETCH' => \&FETCH_imap, - 'SELECT' => \&SELECT_imap, + %displaytext = ( + 'USER' => '+OK We are happy you popped in!', + 'PASS' => '+OK Access granted', + 'QUIT' => '+OK byebye', ); - - %displaytext = ('LOGIN' => ' OK We are happy you popped in!', - 'SELECT' => ' OK selection done', - 'LOGOUT' => ' OK thanks for the fish', + @welcome = ( + ' _ _ ____ _ '."\r\n", + ' ___| | | | _ \| | '."\r\n", + ' / __| | | | |_) | | '."\r\n", + ' | (__| |_| | _ <| |___ '."\r\n", + ' \___|\___/|_| \_\_____|'."\r\n", + '+OK cURL POP3 server ready to serve'."\r\n" ); - -} -elsif($proto eq "smtp") { - %commandfunc = ('DATA' => \&DATA_smtp, - 'RCPT' => \&RCPT_smtp, + } + elsif($proto eq 'imap') { + %commandfunc = ( + 'FETCH' => \&FETCH_imap, + 'SELECT' => \&SELECT_imap, + ); + %displaytext = ( + 'LOGIN' => ' OK We are happy you popped in!', + 'SELECT' => ' OK selection done', + 'LOGOUT' => ' OK thanks for the fish', + ); + @welcome = ( + ' _ _ ____ _ '."\r\n", + ' ___| | | | _ \| | '."\r\n", + ' / __| | | | |_) | | '."\r\n", + ' | (__| |_| | _ <| |___ '."\r\n", + ' \___|\___/|_| \_\_____|'."\r\n", + '* OK cURL IMAP server ready to serve'."\r\n" ); - %displaytext = ('EHLO' => '230 We are happy you popped in!', - 'MAIL' => '200 Note taken', - 'RCPT' => '200 Receivers accepted', - 'QUIT' => '200 byebye', + } + elsif($proto eq 'smtp') { + %commandfunc = ( + 'DATA' => \&DATA_smtp, + 'RCPT' => \&RCPT_smtp, + ); + %displaytext = ( + 'EHLO' => '230 We are happy you popped in!', + 'MAIL' => '200 Note taken', + 'RCPT' => '200 Receivers accepted', + 'QUIT' => '200 byebye', ); + @welcome = ( + '220- _ _ ____ _ '."\r\n", + '220- ___| | | | _ \| | '."\r\n", + '220- / __| | | | |_) | | '."\r\n", + '220- | (__| |_| | _ <| |___ '."\r\n", + '220 \___|\___/|_| \_\_____|'."\r\n" + ); + } } - sub close_dataconn { my ($closed)=@_; # non-zero if already disconnected @@ -925,7 +938,7 @@ sub PASV_ftp { local $SIG{ALRM} = sub { die "alarm\n" }; # assume swift operations unless explicitly slow - alarm ($controldelay?20:10); + alarm ($datadelay?20:10); # Wait for 'CNCT' my $input; @@ -1018,19 +1031,22 @@ sub PORT_ftp { return; } -my %customreply; -my %customcount; -my %delayreply; +#********************************************************************** +# customize configures test server operation for each curl test, reading +# configuration commands/parameters from server commands file each time +# a new client control connection is established with the test server. +# On success returns 1, otherwise zero. +# sub customize { - $nosave = 0; # default is to save as normal - $controldelay = 0; # default is no delaying the responses - $retrweirdo = 0; - $retrnosize = 0; - $pasvbadip = 0; - $nosave = 0; - %customreply = (); - %customcount = (); - %delayreply = (); + $ctrldelay = 0; # default is no throttling of the ctrl stream + $datadelay = 0; # default is no throttling of the data stream + $retrweirdo = 0; # default is no use of RETRWEIRDO + $retrnosize = 0; # default is no use of RETRNOSIZE + $pasvbadip = 0; # default is no use of PASVBADIP + $nosave = 0; # default is to actually save uploaded data to file + %customreply = (); # + %customcount = (); # + %delayreply = (); # open(CUSTOM, "<log/ftpserver.cmd") || return 1; @@ -1053,8 +1069,9 @@ sub customize { logmsg "FTPD: delay reply for $1 with $2 seconds\n"; } elsif($_ =~ /SLOWDOWN/) { - $controldelay=1; - logmsg "FTPD: send response with 0.1 sec delay between each byte\n"; + $ctrldelay=1; + $datadelay=1; + logmsg "FTPD: send response with 0.01 sec delay between each byte\n"; } elsif($_ =~ /RETRWEIRDO/) { logmsg "FTPD: instructed to use RETRWEIRDO\n"; @@ -1078,34 +1095,100 @@ sub customize { close(CUSTOM); } -my @welcome; +#---------------------------------------------------------------------- +#---------------------------------------------------------------------- +#--------------------------- END OF SUBS ---------------------------- +#---------------------------------------------------------------------- +#---------------------------------------------------------------------- -if(($proto eq "ftp") || ($proto eq "smtp")) { - @welcome=( - '220- _ _ ____ _ '."\r\n", - '220- ___| | | | _ \| | '."\r\n", - '220- / __| | | | |_) | | '."\r\n", - '220- | (__| |_| | _ <| |___ '."\r\n", - '220 \___|\___/|_| \_\_____|'."\r\n"); -} -elsif($proto eq "pop3") { - @welcome=( - ' _ _ ____ _ '."\r\n", - ' ___| | | | _ \| | '."\r\n", - ' / __| | | | |_) | | '."\r\n", - ' | (__| |_| | _ <| |___ '."\r\n", - ' \___|\___/|_| \_\_____|'."\r\n", - '+OK cURL POP3 server ready to serve'."\r\n"); -} -elsif($proto eq "imap") { - @welcome=( - ' _ _ ____ _ '."\r\n", - ' ___| | | | _ \| | '."\r\n", - ' / __| | | | |_) | | '."\r\n", - ' | (__| |_| | _ <| |___ '."\r\n", - ' \___|\___/|_| \_\_____|'."\r\n", - '* OK cURL IMAP server ready to serve'."\r\n"); -} +#********************************************************************** +# Parse command line options +# +# Options: +# +# -v # verbose +# -s # source directory +# --id # server instance number +# --proto # server protocol +# --pidfile # server pid file +# --ipv6 # server IP version 6 +# --port # server listener port +# --addr # server address for listener port binding +# +while(@ARGV) { + if($ARGV[0] eq '-v') { + $verbose = 1; + } + elsif($ARGV[0] eq '-s') { + $srcdir = $ARGV[1]; + shift @ARGV; + } + elsif($ARGV[0] eq '--id') { + if($ARGV[1] =~ /^(\d+)$/) { + $ftpdnum = $1 if($1 > 0); + } + shift @ARGV; + } + elsif($ARGV[0] eq '--proto') { + if($ARGV[1] =~ /^(ftp|imap|pop3|smtp)$/) { + $proto = $1; + } + else { + die "unsupported protocol $ARGV[1]"; + } + shift @ARGV; + } + elsif($ARGV[0] eq '--pidfile') { + $pidfile = $ARGV[1]; + shift @ARGV; + } + elsif($ARGV[0] eq '--ipv6') { + $ipvnum = 6; + $listenaddr = '::1' if($listenaddr eq '127.0.0.1'); + $ipv6 = '--ipv6'; + $ext = 'ipv6'; + $grok_eprt = 1; + } + elsif($ARGV[0] eq '--port') { + if($ARGV[1] =~ /^(\d+)$/) { + $port = $1 if($1 > 1024); + } + shift @ARGV; + } + elsif($ARGV[0] eq '--addr') { + my $tmpstr = $ARGV[1]; + if($tmpstr =~ /^(\d\d?\d?)\.(\d\d?\d?)\.(\d\d?\d?)\.(\d\d?\d?)$/) { + $listenaddr = "$1.$2.$3.$4" if($ipvnum == 4); + } + elsif($ipvnum == 6) { + $listenaddr = $tmpstr; + $listenaddr =~ s/^\[(.*)\]$/$1/; + } + shift @ARGV; + } + shift @ARGV; +}; + +#*************************************************************************** +# Initialize command line option dependant variables +# + +$logfilename = getlogfilename(); + +protocolsetup($proto); + +$SIG{INT} = \&exit_signal_handler; +$SIG{TERM} = \&exit_signal_handler; + +startsf(); + +logmsg sprintf("%s server listens on port IPv%d/$port\n", uc($proto), + $ipv6?6:4); +open(PID, ">$pidfile"); +print PID $$."\n"; +close(PID); + +logmsg("logged pid $$ in $pidfile\n"); while(1) { |