From 8733116cbfad2069bb19559571dd361846380f35 Mon Sep 17 00:00:00 2001 From: b Date: Thu, 12 Nov 2015 20:31:49 +0000 Subject: [PATCH] Proxying preparing. git-svn-id: svn://botcastle1b/yplom/proxy@5 05ce6ebb-7522-4a6e-a768-0026ae12be9f --- access.1.pl | 4 +- configure.pl | 4 ++ proxy.1.pl | 178 ++++++++++++++++++++++++++++++++++++++++++++++++--- settings | 6 ++ 4 files changed, 181 insertions(+), 11 deletions(-) diff --git a/access.1.pl b/access.1.pl index 2d0cf82..dbbd195 100644 --- a/access.1.pl +++ b/access.1.pl @@ -24,8 +24,8 @@ while () { $unlocktime=<$accessfile>; $lasttime=<$accessfile>; close($accessfile); - $unlocktime =~ s/\n//g; - $lasttime =~ s/\n//g; + $unlocktime =~ s/[\r\n]//g; + $lasttime =~ s/[\r\n]//g; if ((abs($accesstime-$unlocktime)>$timeout_unlock) or (abs($accesstime-$unlocktime)>$timeout_inact)){ print "ERR too long\n"; diff --git a/configure.pl b/configure.pl index 0daff92..b4a7b39 100755 --- a/configure.pl +++ b/configure.pl @@ -23,13 +23,17 @@ while ($line = <$configfile>) { close ($configfile); $def{'UNLOCK_LOG'} = "use constant UNLOCK_LOG => '".$set{'log_path'}."unlock.log';"; +$def{'CURL_PATH'} = "use constant CURL_PATH => '".$set{'curl'}."';"; $def{'DATA_PATH'} = "use constant DATA_PATH => '".$set{'data_path'}."';"; +$def{'TEMP_PATH'} = "use constant TEMP_PATH => '".$set{'tmp_path'}."';"; $def{'PASS_PATH'} = "use constant PASS_PATH => '".$set{'data_path'}."pass/';"; $def{'ACCESS_PATH'} = "use constant ACCESS_PATH => '".$set{'data_path'}."access/';"; $def{'UNLOCK_PROXY_URL'} = "use constant UNLOCK_PROXY_URL => 'http://".$set{'unlock_domain'}.$set{'unlock_path'}."';"; $def{'UNLOCK_PROXY_URL_S'}= "use constant UNLOCK_PROXY_URL_S => 'https://".$set{'unlock_domain'}.$set{'unlock_path'}."';"; $def{'UNLOCK_PROXY_HOST'} = "use constant UNLOCK_PROXY_HOST => qr/".$set{'unlock_domain_regex'}."/;"; $def{'UNLOCK_PROXY_PATH'} = "use constant UNLOCK_PROXY_PATH => qr/".$set{'unlock_path_regex'}."/;"; +$def{'BLOCK_HOST'} = "use constant BLOCK_HOST => qr/".$set{'block_host_regex'}."/;"; +$def{'BLOCK_PORT'} = 'use constant BLOCK_PORT => qr/^((0*'.$set{'http_proxy_port'}.')|('.$set{'https_proxy_port'}.')|('.$set{'ssl_proxy_port'}.'))$/;'; $def{'TIMEOUT_UNLOCK'} = "use constant TIMEOUT_UNLOCK => ".$set{'timeout_unlock'}.";"; $def{'TIMEOUT_INACT'} = "use constant TIMEOUT_INACT => ".$set{'timeout_inact'}.";"; $def{'REWRITE_URL'} = "use constant REWRITE_URL => '".$set{'https_proxy_domain'}.":".$set{'https_proxy_port'}."';"; diff --git a/proxy.1.pl b/proxy.1.pl index 5655ebd..bf614ac 100755 --- a/proxy.1.pl +++ b/proxy.1.pl @@ -3,7 +3,8 @@ use POSIX qw(strftime); ###UNLOCK_LOG; -###DATA_PATH; +###UNLOCK_LOG; +###CURL_PATH; ###PASS_PATH; ###ACCESS_PATH; ###UNLOCK_PROXY_URL; @@ -12,6 +13,12 @@ use POSIX qw(strftime); ###UNLOCK_PROXY_PATH; ###TIMEOUT_UNLOCK; ###TIMEOUT_INACT; +###BLOCK_HOST; +###BLOCK_PORT; +###TEMP_PATH; + +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; @@ -24,12 +31,133 @@ if (($ENV{'HTTP_HOST'} =~ UNLOCK_PROXY_HOST) and ($ENV{'PATH_INFO'} =~ UNLOCK_PR unlock(); } else { - if(access()) { - debag(); +# if(access()) { + proxy(); +# } +# else { +# noaccess(); +# } +} + +sub proxy { + srand(time()+$$); + + if ($ENV{'REQUEST_METHOD'} !~ /^(HEAD|GET|POST)$/) { + 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; + } + else{ + $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'); + } } else { - noaccess(); + return fail("Status: 400 Bad Request\n","400 Bad Request","The proxy couldn't understand this URL: $URL."); + } + + 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."); + } + } + + if ($host =~ BLOCK_HOST) { + return fail("Status: 403 Forbidden\n","403 Forbidden","The proxy does not accept $host as hostname."); + } + + if ($port =~ BLOCK_PORT) { + return fail("Status: 403 Forbidden\n","403 Forbidden","The proxy does not accept port number $port because of infinite loop prevention."); + } + + do { + $temppath=TEMP_PATH.int(rand(100000000)).'_'; + $headpath=$temppath.'h'; + $downpath=$temppath.'d'; + $uppath=$temppath.'u'; + } while (( -e $headpath) or ( -e $downpath) or ( -e $uppath)); + + @curl_arg=(CURL_PATH,'-s','-o',$downpath,'-D',$headpath); #-s + if ($ENV{'REQUEST_METHOD'} eq 'HEAD'){ + push @curl_arg, '-I'; + } + + if ($ENV{'REQUEST_METHOD'} eq 'POST'){ + binmode(STDIN) or return fail("Status: 500 Internal Server Error\n","500 Internal Server Error","Failed to switch STDIN to binary mode."); + open($upfile,">",$uppath) or return fail("Status: 500 Internal Server Error\n","500 Internal Server Error","Failed to create temporary file."); + binmode ($upfile) or return fail("Status: 500 Internal Server Error\n","500 Internal Server Error","Failed to switch temporary file to binary mode."); + + $buffer; + while (read (STDIN,$buffer,65536)) { + unless (print ($upfile $buffer)) { + return fail("Status: 500 Internal Server Error\n","500 Internal Server Error","Failed to write to temporary file."); + } + } + close ($upfile); + + 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; + # } + # } + + push @curl_arg, $URL; + + + ##DO REAL WORK HERE! + + + print "Content-type: text/plain\n\n"; + 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(); + } sub access { #kind of doubles the functionality of access.pl but for http @@ -46,8 +174,8 @@ sub access { #kind of doubles the functionality of access.pl but for http $unlocktime=<$accessfile>; $lasttime=<$accessfile>; close($accessfile); - $unlocktime =~ s/\n//g; - $lasttime =~ s/\n//g; + $unlocktime =~ s/[\r\n]//g; + $lasttime =~ s/[\r\n]//g; if ((abs($accesstime-$unlocktime)>$timeout_unlock) or (abs($accesstime-$unlocktime)>$timeout_inact)){ unlink $accesspath; @@ -69,6 +197,7 @@ sub access { #kind of doubles the functionality of access.pl but for http return 0; } } + sub unlock { if ($ENV{'REMOTE_ADDR'} =~ /^([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)$/) { $IP=$1; @@ -114,7 +243,7 @@ sub unlock { open($passfile, "<", $passpath) or return unlockpage('Wrong username or password.',"Status: 403 Forbidden\n"); $pass = <$passfile>; close($passfile); - $pass =~ s/\n//g; + $pass =~ s/[\r\n]//g; $pass = urldecode($pass); if ($pass ne $CGI{'password'}){ @@ -139,7 +268,7 @@ sub getcgi { my $varl; my %cgi; my $i = $_[0]; - $i =~ s/\n//g; + $i =~ s/[\r\n]//g; my @s = split('&',$i); foreach my $l ( @s) { ($arg,$val)=split('=',$l); @@ -155,6 +284,15 @@ sub urldecode { return $t; } +sub formatheader { + my $t = $_[0]; + $t =~ s/^HTTP_//; + $t = lc($t); + $t =~ s/^([a-z])/uc($1)/e; + $t =~ s/_([a-z])/'-'.uc($1)/eg; + return $t; +} + sub unlockpage { (my $message, my $header)=@_; if($header ne ''){ @@ -187,6 +325,28 @@ sub unlockpage { print "\n"; } +sub fail { + (my $header, my $title, my $message)=@_; + if($header ne ''){ + print $header; + } + print "Content-type: text/html\n\n"; + print ''; + print ''; + if($title ne ''){ + print "$title"; + } + print ''; + print ''; + if($title ne ''){ + print "

$title

"; + } + if($message ne ''){ + print $message; + } + print "\n"; +} + sub unlockedpage { print "Content-type: text/html\n\n"; print ''; @@ -234,7 +394,7 @@ sub debag { $URL=$ENV{'REQUEST_URI'} } else{ - $URL='http://'.$ENV{'HTTP_HOST'}.$ENV{'REQUEST_URI'}; + $URL=($ENV{'HTTPS'} eq 'on' ? 'https://' : 'http://').$ENV{'HTTP_HOST'}.$ENV{'REQUEST_URI'}; } print 'URL: ',$URL,"\n"; } diff --git a/settings b/settings index 39b4a7a..09502af 100644 --- a/settings +++ b/settings @@ -9,6 +9,7 @@ www_path = /yplom/www/proxy/ #for the www server (unused) #the server must recognise these domains as itself (127.0.0.1) #http and ssl proxy ports must be accessible from outside +#Don't set the ports to default values of non-proxy http(s): 80, 443! http_proxy_domain = bicyclesonthemoon.info https_proxy_domain = bicyclesonthemoon.info ssl_proxy_domain = bicyclesonthemoon.info @@ -28,12 +29,17 @@ unlock_path = /proxy/unlock unlock_domain_regex = ^yplom\.bicyclesonthemoon\.info(:[0-9]*)?$ unlock_path_regex = ^\/proxy\/unlock\/?$ +# A regex to catch hostnames that are, for example, defined in /etc/hosts and +# link to your local network and you don't want them to be proxied. +block_host_regex = ^(localhost|(botcastle[0-9]*))$ + #Time in minutes timeout_unlock = 90 timeout_inact = 15 path = /usr/local/bin:/usr/bin:/bin perl = /usr/bin/perl +curl = /usr/bin/curl chmod = /bin/chmod cp = /bin/cp mv = /bin/mv -- 2.30.2