mirror of
https://github.com/moparisthebest/curl
synced 2024-12-22 16:18:48 -05:00
ftpserver.pl: arbitrary application data splitting among TCP packets [I]
Initial step in order to allow our pingpong server to better support arbitrary application data splitting among TCP packets. This first commit only addresses reasembly of data that sockfilter processes reads from soockets and pingpong server later reads from sockfilters stdout.
This commit is contained in:
parent
33c2e1cafc
commit
e99128a5c9
@ -116,6 +116,8 @@ local *SFWRITE; # used to write to primary connection
|
|||||||
local *DREAD; # used to read from secondary connection
|
local *DREAD; # used to read from secondary connection
|
||||||
local *DWRITE; # used to write to secondary connection
|
local *DWRITE; # used to write to secondary connection
|
||||||
|
|
||||||
|
my $sockfilt_timeout = 5; # default timeout for sockfilter eXsysreads
|
||||||
|
|
||||||
#**********************************************************************
|
#**********************************************************************
|
||||||
# global vars which depend on server protocol selection
|
# global vars which depend on server protocol selection
|
||||||
#
|
#
|
||||||
@ -220,6 +222,141 @@ sub ftpmsg {
|
|||||||
# better on windows/cygwin
|
# better on windows/cygwin
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#**********************************************************************
|
||||||
|
# eXsysread is a wrapper around perl's sysread() function. This will
|
||||||
|
# repeat the call to sysread() until it has actually read the complete
|
||||||
|
# number of requested bytes or an unrecoverable condition occurs.
|
||||||
|
# On success returns a positive value, the number of bytes requested.
|
||||||
|
# On failure or timeout returns zero.
|
||||||
|
#
|
||||||
|
sub eXsysread {
|
||||||
|
my $FH = shift;
|
||||||
|
my $scalar = shift;
|
||||||
|
my $nbytes = shift;
|
||||||
|
my $timeout = shift; # A zero timeout disables eXsysread() time limit
|
||||||
|
#
|
||||||
|
my $time_limited = 0;
|
||||||
|
my $timeout_rest = 0;
|
||||||
|
my $start_time = 0;
|
||||||
|
my $nread = 0;
|
||||||
|
my $rc;
|
||||||
|
|
||||||
|
$$scalar = "";
|
||||||
|
|
||||||
|
if((not defined $nbytes) || ($nbytes < 1)) {
|
||||||
|
logmsg "Error: eXsysread() failure: " .
|
||||||
|
"length argument must be positive\n";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if((not defined $timeout) || ($timeout < 0)) {
|
||||||
|
logmsg "Error: eXsysread() failure: " .
|
||||||
|
"timeout argument must be zero or positive\n";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if($timeout > 0) {
|
||||||
|
# caller sets eXsysread() time limit
|
||||||
|
$time_limited = 1;
|
||||||
|
$timeout_rest = $timeout;
|
||||||
|
$start_time = int(time());
|
||||||
|
}
|
||||||
|
|
||||||
|
while($nread < $nbytes) {
|
||||||
|
if($time_limited) {
|
||||||
|
eval {
|
||||||
|
local $SIG{ALRM} = sub { die "alarm\n"; };
|
||||||
|
alarm $timeout_rest;
|
||||||
|
$rc = sysread($FH, $$scalar, $nbytes - $nread, $nread);
|
||||||
|
alarm 0;
|
||||||
|
};
|
||||||
|
$timeout_rest = $timeout - (int(time()) - $start_time);
|
||||||
|
if($timeout_rest < 1) {
|
||||||
|
logmsg "Error: eXsysread() failure: timed out\n";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$rc = sysread($FH, $$scalar, $nbytes - $nread, $nread);
|
||||||
|
}
|
||||||
|
if($got_exit_signal) {
|
||||||
|
logmsg "Error: eXsysread() failure: signalled to die\n";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if(not defined $rc) {
|
||||||
|
if($!{EINTR}) {
|
||||||
|
logmsg "Warning: retrying sysread() interrupted system call\n";
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
if($!{EAGAIN}) {
|
||||||
|
logmsg "Warning: retrying sysread() due to EAGAIN\n";
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
if($!{EWOULDBLOCK}) {
|
||||||
|
logmsg "Warning: retrying sysread() due to EWOULDBLOCK\n";
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
logmsg "Error: sysread() failure: $!\n";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if($rc < 0) {
|
||||||
|
logmsg "Error: sysread() failure: returned negative value $rc\n";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if($rc == 0) {
|
||||||
|
logmsg "Error: sysread() failure: read zero bytes\n";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
$nread += $rc;
|
||||||
|
}
|
||||||
|
return $nread;
|
||||||
|
}
|
||||||
|
|
||||||
|
#**********************************************************************
|
||||||
|
# read_mainsockf attempts to read the given amount of output from the
|
||||||
|
# sockfilter which is in use for the main or primary connection. This
|
||||||
|
# reads untranslated sockfilt lingo which may hold data read from the
|
||||||
|
# main or primary socket. On success returns 1, otherwise zero.
|
||||||
|
#
|
||||||
|
sub read_mainsockf {
|
||||||
|
my $scalar = shift;
|
||||||
|
my $nbytes = shift;
|
||||||
|
my $timeout = shift; # Optional argument, if zero blocks indefinitively
|
||||||
|
my $FH = \*SFREAD;
|
||||||
|
|
||||||
|
if(not defined $timeout) {
|
||||||
|
$timeout = $sockfilt_timeout + ($nbytes >> 12);
|
||||||
|
}
|
||||||
|
if(eXsysread($FH, $scalar, $nbytes, $timeout) != $nbytes) {
|
||||||
|
my ($fcaller, $lcaller) = (caller)[1,2];
|
||||||
|
logmsg "Error: read_mainsockf() failure at $fcaller " .
|
||||||
|
"line $lcaller. Due to eXsysread() failure\n";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#**********************************************************************
|
||||||
|
# read_datasockf attempts to read the given amount of output from the
|
||||||
|
# sockfilter which is in use for the data or secondary connection. This
|
||||||
|
# reads untranslated sockfilt lingo which may hold data read from the
|
||||||
|
# data or secondary socket. On success returns 1, otherwise zero.
|
||||||
|
#
|
||||||
|
sub read_datasockf {
|
||||||
|
my $scalar = shift;
|
||||||
|
my $nbytes = shift;
|
||||||
|
my $timeout = shift; # Optional argument, if zero blocks indefinitively
|
||||||
|
my $FH = \*DREAD;
|
||||||
|
|
||||||
|
if(not defined $timeout) {
|
||||||
|
$timeout = $sockfilt_timeout + ($nbytes >> 12);
|
||||||
|
}
|
||||||
|
if(eXsysread($FH, $scalar, $nbytes, $timeout) != $nbytes) {
|
||||||
|
my ($fcaller, $lcaller) = (caller)[1,2];
|
||||||
|
logmsg "Error: read_datasockf() failure at $fcaller " .
|
||||||
|
"line $lcaller. Due to eXsysread() failure\n";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
sub sysread_or_die {
|
sub sysread_or_die {
|
||||||
my $FH = shift;
|
my $FH = shift;
|
||||||
@ -566,7 +703,7 @@ sub DATA_smtp {
|
|||||||
$size = hex($1);
|
$size = hex($1);
|
||||||
}
|
}
|
||||||
|
|
||||||
sysread \*SFREAD, $line, $size;
|
read_mainsockf(\$line, $size);
|
||||||
|
|
||||||
$ulsize += $size;
|
$ulsize += $size;
|
||||||
print FILE $line if(!$nosave);
|
print FILE $line if(!$nosave);
|
||||||
@ -1141,7 +1278,7 @@ sub STOR_ftp {
|
|||||||
$size = hex($1);
|
$size = hex($1);
|
||||||
}
|
}
|
||||||
|
|
||||||
sysread DREAD, $line, $size;
|
read_datasockf(\$line, $size);
|
||||||
|
|
||||||
#print STDERR " GOT: $size bytes\n";
|
#print STDERR " GOT: $size bytes\n";
|
||||||
|
|
||||||
@ -1242,7 +1379,7 @@ sub PASV_ftp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# READ the response data
|
# READ the response data
|
||||||
sysread_or_die(\*DREAD, \$i, $size);
|
read_datasockf(\$i, $size);
|
||||||
|
|
||||||
# The data is in the format
|
# The data is in the format
|
||||||
# IPvX/NNN
|
# IPvX/NNN
|
||||||
@ -1816,38 +1953,38 @@ while(1) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# data
|
# data
|
||||||
sysread SFREAD, $_, $size;
|
read_mainsockf(\$input, $size);
|
||||||
|
|
||||||
ftpmsg $_;
|
ftpmsg $input;
|
||||||
|
|
||||||
# Remove trailing CRLF.
|
# Remove trailing CRLF.
|
||||||
s/[\n\r]+$//;
|
$input =~ s/[\n\r]+$//;
|
||||||
|
|
||||||
my $FTPCMD;
|
my $FTPCMD;
|
||||||
my $FTPARG;
|
my $FTPARG;
|
||||||
my $full=$_;
|
my $full = $input;
|
||||||
if($proto eq "imap") {
|
if($proto eq "imap") {
|
||||||
# IMAP is different with its identifier first on the command line
|
# IMAP is different with its identifier first on the command line
|
||||||
unless (m/^([^ ]+) ([^ ]+) (.*)/ ||
|
unless(($input =~ /^([^ ]+) ([^ ]+) (.*)/) ||
|
||||||
m/^([^ ]+) ([^ ]+)/) {
|
($input =~ /^([^ ]+) ([^ ]+)/)) {
|
||||||
sendcontrol "$1 '$_': command not understood.\r\n";
|
sendcontrol "$1 '$input': command not understood.\r\n";
|
||||||
last;
|
last;
|
||||||
}
|
}
|
||||||
$cmdid=$1; # set the global variable
|
$cmdid=$1; # set the global variable
|
||||||
$FTPCMD=$2;
|
$FTPCMD=$2;
|
||||||
$FTPARG=$3;
|
$FTPARG=$3;
|
||||||
}
|
}
|
||||||
elsif (m/^([A-Z]{3,4})(\s(.*))?$/i) {
|
elsif($input =~ /^([A-Z]{3,4})(\s(.*))?$/i) {
|
||||||
$FTPCMD=$1;
|
$FTPCMD=$1;
|
||||||
$FTPARG=$3;
|
$FTPARG=$3;
|
||||||
}
|
}
|
||||||
elsif($proto eq "smtp" && m/^[A-Z0-9+\/]{0,512}={0,2}$/i) {
|
elsif(($proto eq "smtp") && ($input =~ /^[A-Z0-9+\/]{0,512}={0,2}$/i)) {
|
||||||
# SMTP long "commands" are base64 authentication data.
|
# SMTP long "commands" are base64 authentication data.
|
||||||
$FTPCMD=$_;
|
$FTPCMD=$input;
|
||||||
$FTPARG="";
|
$FTPARG="";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
sendcontrol "500 '$_': command not understood.\r\n";
|
sendcontrol "500 '$input': command not understood.\r\n";
|
||||||
last;
|
last;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user