From 8465a21006875d06eaa16f7354967d34c9b85e0e Mon Sep 17 00:00:00 2001 From: b Date: Fri, 13 Nov 2015 15:22:20 +0000 Subject: [PATCH] Proxying works now! git-svn-id: svn://botcastle1b/yplom/proxy@6 05ce6ebb-7522-4a6e-a768-0026ae12be9f --- proxy.1.pl | 325 +++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 267 insertions(+), 58 deletions(-) diff --git a/proxy.1.pl b/proxy.1.pl index bf614ac..ad41fa3 100755 --- a/proxy.1.pl +++ b/proxy.1.pl @@ -19,7 +19,6 @@ use POSIX qw(strftime); use constant REQUEST_HEADER_BLOCK => qr/^(accept-encoding|connection|te|transfer-encoding|via)$/; use constant RESPONSE_HEADER_BLOCK => qr/^(connection|content-encoding|content-length|trailer|transfer-encoding)$/; - $accesstime = time(); $timeout_unlock = TIMEOUT_UNLOCK*60; $timeout_inact = TIMEOUT_INACT*60; @@ -27,16 +26,16 @@ $timeout_inact = TIMEOUT_INACT*60; delete @ENV{qw(IFS CDPATH ENV BASH_ENV)}; ###PATH; -if (($ENV{'HTTP_HOST'} =~ UNLOCK_PROXY_HOST) and ($ENV{'PATH_INFO'} =~ UNLOCK_PROXY_PATH)){ +if (($ENV{'HTTP_HOST'} =~ UNLOCK_PROXY_HOST) and (urldecode($ENV{'PATH_INFO'}) =~ UNLOCK_PROXY_PATH)){ unlock(); } else { -# if(access()) { + if(access()) { proxy(); -# } -# else { -# noaccess(); -# } + } + else { + noaccess(); + } } sub proxy { @@ -46,29 +45,25 @@ sub proxy { return fail("Status: 405 Method Not Allowed\nAllow: GET, POST, HEAD\n","405 Method Not Allowed","The proxy does not support the $ENV{'REQUEST_METHOD'} method."); } - if ($ENV{'REQUEST_URI'} =~ /^([a-z]*(:[0-9]*)?:\/\/.*)$/){ - $URL=$1; + if ($ENV{'REQUEST_URI'} =~ /^[a-z]*(:[0-9]*)?:\/\/.*$/){ + $URL=$ENV{'REQUEST_URI'}; } else{ - $URL=($ENV{'HTTPS'} eq 'on' ? 'https://' : 'http://');.$ENV{'HTTP_HOST'}.$ENV{'REQUEST_URI'}; + $URL=($ENV{'HTTPS'} eq 'on' ? 'https://' : 'http://').$ENV{'HTTP_HOST'}.$ENV{'REQUEST_URI'}; } - #HTTP_HOST might theoretically not agree with REQUESR_URI. - if ($URL =~ /^https*:\/\/(.*)$/) { - $host= $1; - $host =~ s/\/.*$//; - if($host =~ /^(.*):([0-9]+)$/) { - $host=$1; - $port=$2; - } - else { - $port=($ENV{'HTTPS'} eq 'on' ? '443' : '80'); - } + if (validateurl($URL)) { #validate URL against illegal characters + $URL =~ /^(.*)$/; + $URL = $1; } else { - return fail("Status: 400 Bad Request\n","400 Bad Request","The proxy couldn't understand this URL: $URL."); + return fail("Status: 400 Bad Request\n","400 Bad Request","Invalid URL: $URL."); } + if ($port eq ''){ + $port=($ENV{'HTTPS'} eq 'on' ? '443' : '80'); + } + if ($host =~ /^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$/) {#IP instead of hostname if ($host =~ /^((0*10\..*)|(0*127\..*)|(0*172\.0*((1[6-9])|(2[0-9])|(3[0-1]))\..*)|(0*192\.0*168\..*))$/) { return fail("Status: 403 Forbidden\n","403 Forbidden","The proxy does not accept a private IP address $host as hostname."); @@ -90,7 +85,9 @@ sub proxy { $uppath=$temppath.'u'; } while (( -e $headpath) or ( -e $downpath) or ( -e $uppath)); - @curl_arg=(CURL_PATH,'-s','-o',$downpath,'-D',$headpath); #-s + # @curl_arg=(CURL_PATH,'-o',$downpath,'-D',$headpath); #-s + @curl_arg=(CURL_PATH,'-i','-#'); #-s + if ($ENV{'REQUEST_METHOD'} eq 'HEAD'){ push @curl_arg, '-I'; } @@ -111,52 +108,193 @@ sub proxy { push @curl_arg, '--data-binary'; push @curl_arg, '@'.$uppath; } - # foreach $envk (keys %ENV) { - # if ($envk =~ /^HTTP_/) { - # $headname=formatheader($envk); - # $headval=$ENV{$envk}; - # if ($headname !~ /^[A-Za-z\-]+$/) { - # next; - # } - # if(lc($headname) =~ REQUEST_HEADER_BLOCK) { - # next; - # } - # unless (exists $ENV{'HTTP_USER_AGENT'}) { - # push @curl_arg, '-H'; - # push @curl_arg, 'User-Agent:'; - # } - # unless (exists $ENV{'HTTP_ACCEPT'}) { - # push @curl_arg, '-H'; - # push @curl_arg, 'ACCEPT:'; - # } - # $headval=~ s/[\r\n]//g; - # $headarg=$headname.(($headval eq '')?';':': '.$headval); - # push @curl_arg, '-H'; - # push @curl_arg, $headarg; - # } - # } + foreach $envk (keys %ENV) { + if ($envk =~ /^(HTTP_[A-Z_]+)$/) { + $headname=formatheader($1); + if ($ENV{$envk} =~ /^([\x20-\x7e]*)$/) { + $headval=$1; + } + if(lc($headname) =~ REQUEST_HEADER_BLOCK) { + next; + } + unless (exists $ENV{'HTTP_USER_AGENT'}) { + push @curl_arg, '-H'; + push @curl_arg, 'User-Agent:'; + } + unless (exists $ENV{'HTTP_ACCEPT'}) { + push @curl_arg, '-H'; + push @curl_arg, 'ACCEPT:'; + } + $headval=~ s/[\r\n]//g; + $headarg=$headname.(($headval eq '')?';':': '.$headval); + push @curl_arg, '-H'; + push @curl_arg, $headarg; + } + } push @curl_arg, $URL; + pipe ($STDREAD, $STDWRITE) or return fail("Status: 500 Internal Server Error\n","500 Internal Server Error","Failed to create stdout pipe."); + pipe ($ERRREAD, $ERRWRITE) or return fail("Status: 500 Internal Server Error\n","500 Internal Server Error","Failed to create stderr pipe."); + + $curlpid = fork(); + unless (defined $curlpid) { + return fail("Status: 500 Internal Server Error\n","500 Internal Server Error","fork() failed."); + } + unless ($curlpid) { + close ($STDREAD); + close ($ERRREAD); + + open(STDERR, ">&=" . fileno($ERRWRITE)) or die "Failed to open stderr pipe.\n"; + open(STDOUT, ">&=" . fileno($STDWRITE)) or die "Failed to open stdout pipe.\n"; + + exec @curl_arg; + exit 1; + } + + close ($STDWRITE); + close ($ERRWRITE); - ##DO REAL WORK HERE! + $safelength=1; + $definedlength=0; + $safeerror=1; + $lastskipped=1; + $forceexit=0; - print "Content-type: text/plain\n\n"; - print "host: $host\nport: $port\n\n"; - foreach $yyyb (@curl_arg) { - print "$yyyb\n"; + if ($line = <$STDREAD>) { + $line =~ s/\r?\n$//; + if ($line =~ /^HTTP\/[0-9]+\.[0-9]+ ([0-9]+ .*)$/) { + @resphead=('Status: '.$1); + while ($line = <$STDREAD>) { + $line =~ s/[\r\n]$//g; + + if($line eq ''){ + last; + } + + if($line =~ /^[ \t](.*)$/){ + if ($lastskipped) { + next; + } + else { + #$lastline = pop @resphead; + #push @resphead, $lastline.$1; + push @resphead, $line; + } + } + + if ($line =~ /^([^:]*):(.*)$/) { + $headname=lc($1); + $headvalue=$2; + } + else { + $lastskipped=1; + next; + } + + if($headname eq 'transfer-encoding') { + $safelength = 0; + } + if($headname eq 'content-encoding') { + if($headvalue !~ /^[\r\n \t]*identity[\r\n \t]*$/) { + $safelength = 0; + } + } + if($headname eq 'content-length') { + $definedlength=1; + $headvalue =~ s/^[\r\n \t]*//; + $headvalue =~ s/[\r\n \t]*$//; + $contentlength = int($headvalue); + } + if($headname =~ RESPONSE_HEADER_BLOCK) { + $lastskipped =1; + next; + } + $line; + $lastskipped=0; + push @resphead, $line; + } + + if ($lengthdefined and ($lengthsafe or ($contentlength==0))) { + push @resphead, 'Content-length: '.$contentlength; + } + + #! write this to file (h) too ! { + $safeerror=0; + foreach $line (@resphead) { + print $line."\n"; + } + print "\n"; + #! } + + if ( ! binmode ($STDREAD)) { + print "FAIL 1\n"; + $forceexit=1; + } + elsif ( ! binmode (STDOUT) ) { + print "FAIL 2\n"; + $forceexit=1; + } + else { + + #! write this to file (c) too ! { + while (read ($STDREAD,$buffer,65536)) { + unless (print (STDOUT $buffer)) { + $forceexit=1; + next; + } + } + #! } + } + } + else { + $errormsg="Server respose is not HTTP: $line"; + } } - #print "\n".(system @curl_arg)."\n"; - unlink $headpath; - unlink $downpath; - unlink $uppath; + # print "Content-type: text/plain\n\n"; - print "\nDEBUGINFO:\n"; + # print"\n"; - return debag(); + waitpid($curlpid,0); + if ($? != 0) { + if ($safeerror) { + $errormsg=''; + while ($line = <$ERRREAD>) { + $line =~ s/\r?\n/
/g; + $errormsg=$errormsg.$line; + } + } + else { + $forceexit=1; + } + } + close(STDREAD); + close(ERRREAD); + + if($safeerror){ + return fail("Status: 500 Internal Server Error\n","500 Internal Server Error",$errormsg); + } + elsif ($forceexit) { + exit 1; + } + + # print "host: $host\nport: $port\n\n"; + # foreach $yyyb (@curl_arg) { + # print "$yyyb\n"; + # } + # #print "\n".(system @curl_arg)."\n"; + + # unlink $headpath; + # unlink $downpath; + # unlink $uppath; + + + # print "\nDEBUGINFO:\n"; + + # return debag(); } @@ -398,3 +536,74 @@ sub debag { } print 'URL: ',$URL,"\n"; } + +sub validateurl { + my $url = $_[0]; + my $prot; + my $hostportpathquery; + my $hostportpath; + $query; + my $hostport; + $path; + my $part; + $host; + $port; + + if ($url =~ /^([A-Za-z]+):\/\/(.*)/) { + $prot = $1; + $hostportpathquery = $2; + } + else { + return 0; + } + + if ($prot !~ /^https?$/) { + return 0; + } + + if ($hostportpathquery eq ''){ + return 0; + } + + if ($hostportpathquery =~ /^([^?]+)\?(.*)$/) { + $hostportpath = $1; + $query = $2; + + if ($query !~ /^((%[0-9A-Fa-f][0-9A-Fa-f])|([A-Za-z0-9;\/\?:@&=\+\$\,\-_\.~\*'\(\)]))*$/) { + return 0; + } + } + else { + $hostportpath = $hostportpathquery; + $query = ''; + } + + if($hostportpath =~ /^([^\/]+)(\/.*)$/){ + $hostport = $1; + $path = $2; + + if ($path !~ /^((%[0-9A-Fa-f][0-9A-Fa-f])|([A-Za-z0-9:;@&=\+\$\,-_\.~\*'\(\)]))*$/) { + return 0; + } + + } + else { + $hostport = $hostportpath; + $path = ''; + } + + if ($hostport =~ /^(.*):([0-9]+)$/) { + $host = $1; + $port = $2; + } + else { + $host=$hostport; + $port=''; + } + + if ($host !~ /^[A-Za-z0-9\-\.]+$/) { + return 0; + } + + return 1; +} -- 2.30.2