это недописанные скрипты для SOCKS-версии pproxy. (HTTP - версия в этой теме http://forum.antichat.ru/thread93318.html). Запускается так же. Проблема простая - php-скрипт работает только на моем компе (debian AMD64, также работал когда на нем был x86). Версия PHP - та что в stable репозитариях дебиана. На других машинах(с той же версией линукса и PHP) работать отказывается(если точнее то некорректно работает php-функция stream_select). Из-за чего такая проблема выяснить не удалось. Так как эта софтина нужна множеству людей, большая просьба знающим найти и исправить ошибки. PHP: <?php //$secret = 'pproxypass'; $TIMEOUT = 500; $TMPDIR = '/tmp'; ob_implicit_flush(TRUE); $socketpath = $TMPDIR . '/pipe' . $_POST['key']; $pipename = 'unix://' . $socketpath; function downscript() { if(file_exists($socketpath))unlink($socketpath); } if(isset($secret) && ($_POST['secret'] != $secret))exit; if(isset($_POST['key']) && (isset($_POST['data']) || isset($_POST['kill']))) { $pipe = @stream_socket_client($pipename); if(!$pipe)exit; if(isset($_POST['kill']))fwrite($pipe, 'kill.'); elseif(isset($_POST['data'])) fwrite($pipe, 'data=' . base64_decode(str_replace(" ", "+", $_POST['data']))); fclose($pipe); exit; } if(isset($_POST['host']) && isset($_POST['key'])) { set_time_limit(0); header('Content-type: application/octet-stream'); $sock = @stream_socket_client('tcp://' . $_POST['host']); if(!$sock)exit; umask(0); $unixsocket = stream_socket_server($pipename); if(!$unixsocket)exit; register_shutdown_function('downscript'); echo 'connected'; $readers = array($unixsocket, $sock); $up = true; while($up) { $read = $readers; $num_changed_streams = stream_select($read, $write = NULL, $except = NULL, $TIMEOUT); if(!$num_changed_streams)break; if ($read[0] == $unixsocket) { $pipe = stream_socket_accept ($unixsocket); if(!$pipe)$up = false; else { $inbuf = ''; while (!feof($pipe)) $inbuf .= fread($pipe, 300); fclose($pipe); $cmd = substr($inbuf, 0, 5); if ($cmd == 'data=')fwrite($sock, substr($inbuf, 5)); elseif ($cmd == 'kill.')$up = false; } } if ($read[0] == $sock) { $resp = fread($sock, 8096); echo $resp; if(feof($sock)) { $up = false; $readers = array($unixsocket); } } } fclose($sock); fclose($unixsocket); if(file_exists($socketpath))unlink($socketpath); exit; } ?> Code: #!/usr/bin/perl use MIME::Base64 (); use Getopt::Long; use POSIX ":sys_wait_h"; use IO::Socket::INET; use strict; our %children; $|++; my ($pproxyhost, $pproxyport, $pproxyurl); my ($tunnelhost, $tunnelport); my ($pproxy, $bindport, $tunnel, $secret); my ($destaddr, $destport, $desturl); my $clientsock; my $user_agent = 'Mozilla/5.0 (X11; U; Linux i686; ru; rv:1.9.0.4) Gecko/2008102920 Firefox/3.0.4'; #Вывод справки Usage() if @ARGV==0; #Задание опций GetOptions( "px=s" => \$pproxy, "bp=s" => \$bindport, "tpx=s" => \$tunnel, "pwd=s" => \$secret ); die "need pproxysocks.php url" unless $pproxy; #Получение параметров $pproxy =~ /http:\/\/([\w\.\-]+)(:\d*)?\/(.+)/; $pproxyhost = $1; $pproxyport = substr($2, 1); $pproxyurl = '/' . $3; defined($pproxyport) || ($pproxyport = 80); defined($bindport) || ($bindport = 8008); if(defined($tunnel)) { $tunnel =~ /http:\/\/([\w\.\-]+):(\d*)?/; $tunnelhost = $1; $tunnelport = $2; $destaddr = $tunnelhost; $destport = $tunnelport; $desturl = $pproxy; print "# tunnelhost = $tunnelhost\n"; print "# tunnelport = $tunnelport\n"; }else{ $destaddr = $pproxyhost; $destport = $pproxyport; $desturl = $pproxyurl; } print "# pproxysocks host = $pproxyhost\n"; print "# pproxysocks port = $pproxyport\n"; print "# pproxysocks url = $pproxyurl\n"; print "# bindport = $bindport\n\n"; print "# start /p/ local socks script\n"; #Создать сокет и привязать его к порту на локалхосте my $listener = IO::Socket::INET->new( LocalAddr => 'localhost', LocalPort => $bindport, ReuseAddr => 1, Listen => 5 ) || die "cannot create listener: $!\n"; #цикл приема подключений клиента MainProc($clientsock) while $clientsock = $listener->accept; #-------------------------------------------------# # Главная подпрограмма обработки подключений клиента # Ответвляет себе процесс # Параметр - сокет соединения с клиентом # sub MainProc($) { my $client = shift; my ($vers, $size, $methods, $cmd, $reserv, $AType, $ip, $host, $port, $rport, $resp); #Ответвление процесса my $pid = fork(); unless(defined($pid)) { close $client; die "# Erorr couldn't fork\n"; } if($pid) { close $client; $children{$pid}++; #Зачистка зомби foreach(keys %children) { my $kid = waitpid($_, &WNOHANG); delete $children{$_} if($kid == -1 || $kid == $_); } return; } #ОБработка клиента SOCKS5 sysread($client, $vers, 1); exit unless $vers eq "\x05"; sysread($client, $size, 1); exit if $size eq "\x00"; my $nread = sysread($client,$methods,ord($size)); syswrite($client, "\x05\x00", 2); sysread($client, $vers, 1); exit unless $vers eq "\x05"; sysread($client, $cmd, 1); exit unless $cmd eq "\x01"; sysread($client, $reserv, 1); exit unless $reserv eq "\x00"; sysread($client, $AType, 1); #Целевой хост задан IP-адресом if($AType eq "\x01") { sysread($client, $ip, 4); my @host = $ip =~ /(.)/g; $host = ord($host[0]).".".ord($host[1]).".".ord($host[2]).".".ord($host[3]); } #Целевой хост задан DNS-именем elsif($AType eq "\x03") { sysread($client, $size, 1); sysread($client, $host, ord($size)); }else{exit;} #Чтение целевого порта sysread($client, $rport, 2); my @pps = $rport =~ /(.)/g; $port = 256 * ord($pps[0]) | ord($pps[1]); #Создание уникального идентификатора подключения my $key = random_int_in(100000,999999); CreateTunnel($client, $key, $host . ':' . $port); exit; } #--------------------------------------- # Возвращает случайное число в указанно диапазоне # Параметры: # 1. Минимальное значение # 2. Максимальное значение # sub random_int_in ($$) { my($min, $max) = @_; return $min if $min == $max; ($min, $max) = ($max, $min) if $min > $max; return $min + int rand(1 + $max - $min); } #-------------------------------------- # Содержит цикл обработки данных от клиента. # Ответвляет для себя отдельный процесс. # Параметры: # 1. Уникальный идентификатор соединения # 2. Сокет клиента sub ReceiveDataFromTunnel($$) { my $key = shift; my $client = shift; my $pid = fork(); unless(defined($pid)) { close $client; die "# Erorr couldn't fork\n"; } if($pid) { $children{$pid}++; return; } my ($buffer, $result, $proxysock); while(1) { $result = sysread($client, $buffer, 4096); close $proxysock if defined($proxysock); last if !defined($result) || !$result; $proxysock = DataToTunnel($key, $buffer); } KillTunnel($key); close $client; exit; } #-------------------------------------- # Отправляет данные по соединению # Параметры: # 1. Уникальный идентификатор соединения # 2. Данные # sub DataToTunnel($$) { my $key = shift; my $data = shift; my $post_query = 'key=' . $key . '&data=' . MIME::Base64::encode($data); my $proxysock = HttpConnection($post_query); unless($proxysock) { print "could not connect to proxy\n"; return; } return $proxysock; } #--------------------------------------- # Уничтожает существующее соединение # Параметр - уникальный идентификатор соединения # sub KillTunnel($) { my $key = shift; my $post_query = 'key=' . $key . '&kill=1'; my $proxysock = HttpConnection($post_query); unless($proxysock) { print "could not connect to proxy\n"; return; } close $proxysock; } #--------------------------------------- # Создает соединение к целевому серверу # Если удалось то # 1. передает клиенту последний SOCKS-ответ # 2. создает процесс для дальнейшего приема данных от клиента # 3. в цикле принимает данные из соединения и передает их клиенту # Принимает параметры: # 1. Сокет клиента # 2. Уникальный идентификатор соединения # 3. Имя целевого сервера # sub CreateTunnel($$$) { my $clientsock = shift; my $key = shift; my $host = shift; my $sig_conn = 'connected'; my $post_query = 'host=' . $host . '&key=' . $key; my $time_start = time; print TranslateTimeHour($time_start), " dest host: $host\n"; my $proxysock = HttpConnection($post_query); unless($proxysock) { print "could not connect to proxy\n"; return; } my ($result, $buffer, $contentstart, $response); $contentstart = -1; #Цикл приема данных от pproxysocks.php while(1) { $result = sysread($proxysock, $buffer, 256); last if !defined($result) || !$result; if($contentstart == -1) { $response .= $buffer; last if length($response)>65535; $contentstart = index($response,"\x0D\x0A\x0D\x0A" . $sig_conn); next if $contentstart == -1; #Если HTTP-заголовок с сигнатурой удачно принят то соединение установлено syswrite($clientsock, "\x05\x00\x00\x01\x10\x10\x10\x10\x00\x00", 10); ReceiveDataFromTunnel($key, $clientsock); $buffer = substr($response, $contentstart + 4 + length($sig_conn)); } syswrite($clientsock, $buffer, length($buffer)); } my $time_end = time; if($contentstart == -1) { #Сигнатура не обнаружена значит что-то пошло не так print TranslateTimeHour($time_end), " could not connect to $host\n"; syswrite($clientsock, "\x05\x04\x00", 3); }else{ #Лог print TranslateTimeHour($time_end), " connection closed - ", $host, " (", TranslateTime($time_end - $time_start), ")\n"; } close $proxysock; shutdown $clientsock, 0; close $clientsock; } #--------------------------------------- # Устанавливает соединение с web-сервером или HTTP-прокси # В качестве параметра принимает данные для POST-запроса # Использует глобальные переменные: # $destaddr, $destport, $desturl # $pproxyhost, $pproxyport, $secret # sub HttpConnection($) { my $post = shift; my $proxysock = IO::Socket::INET->new(Proto=>'tcp', PeerAddr=>$destaddr, PeerPort=>$destport); unless($proxysock) { return; } $post = 'secret=' . $secret . '&' . $post if defined($secret); my $postlen = length($post); my $request = "POST $desturl HTTP/1.0\x0D\x0A". "Host: $pproxyhost:$pproxyport\x0D\x0A". "Accept: */*\x0D\x0A". "Content-Type: application/x-www-form-urlencoded\x0D\x0A". "Content-Length: $postlen\x0D\x0A". "User-Agent: $user_agent\x0D\x0A". "Connection: close\x0D\x0A\x0D\x0A" . $post; syswrite($proxysock, $request, length($request)); return $proxysock; } #--------------------------------------- # Переводит время в формат - мин:сек # sub TranslateTime { my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(shift); return sprintf "%02u:%02u", $min, $sec; } #--------------------------------------- # Переводит время в формат - час:мин:сек # sub TranslateTimeHour { my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(shift); return sprintf "%02u:%02u:%02u", $hour, $min, $sec; } #--------------------------------------- # Выводит справку # sub Usage { print "Usage: $0 -px proxy_url [-bp bindport] [-tpx tunnel_proxy] [-pwd secret]\n"; print "Example: $0 -px http://site.com/proxy/proxy.php -bp 8080\n"; print " $0 -px http://site.com/proxy/proxy.php -pwd pproxypass\n"; print " $0 -px http://site.com/proxy/proxy.php -tpx http://localhost:8118\n"; print "\nDefault bind port - 8008\n"; exit; }
Тоже довненько искал, что не буть подобное, также подписываюсь, автору темы плюс, за актуальность вопроса)
Не вглядываясь просмотрел твой скрипт. Насколько я понял ты пытаешься досылать данные работающему скрипту. Я тоже пытался реализовать подобное поведение, но отказался от этой затеи из-за того, что работа скрипта ограничена max_execution_time и постоянное соединение поддерживать не удастся. А не влияет ли отключение сокетов на функции stream_socket_*? Может дело в этом? На большинстве серверов они отключены.
http://www.phpclasses.org/browse/package/1822.html http://www.phpclasses.org/browse/package/5049.html во второй ссылке клянется, что рабочий, плюс есть поддержка авторизации. В обоих случаях есть пример использования. Сам не проверял.
тут немного не тот принцип действия и сокс-класс тут как-бы не поможет. Основная задача в том, как заметил needDrivers, чтобы дослать данные работающему php скрипту. Когда нужно создать туннель, perl-скрипт вызывает по HTTP-протоколу php-скрипт, который в свою очередь соединяется с целью и создает на сервере UNIX-сокет для межпроцессной связи. Когда нужно дослать данные, perl-скрипт опять же шлет данные по HTTP, а php-скрипт просто пишет в этот UNIX-сокет. Таким образом время ограничено только После закрытия соединения сокет удаляется. Понятно, что php-скрипт не кроссплатформенный, UNIX-сокет в windows создать пока нельзя если на сервере не запрещена функция set_time_limit то это легко исправляется. Даже если запрещена то соединение можно удерживать целых 30 секунд или сколько там выставят в настройках. если они отключены то конечно скрипт работать не будет. Но на тех серверах, на которых я это тестил, вроде как с этим было все в порядке
Раз у тебя stream_* плохо работают, попробуй тоже самое через socket_* функции реализовать. Я вот такой тестовый скрипт прогонял: PHP: <?php header("Content-Type: text/plain; charset=windows-1251"); echo "Creating...\r\n"; flush(); $fp = socket_create(AF_UNIX, SOCK_STREAM, 0); if($fp) { if($m === "r") { socket_bind($fp, "my.sock"); socket_listen($fp); $sk = socket_accept($fp); echo "socket_read: ".socket_read($sk, 1024, PHP_BINARY_READ); socket_close($sk); } else if($m === "w") { socket_connect($fp, "my.sock"); echo "socket_write: ".socket_write($fp, "1024, PHP_BINARY_READ"); } socket_close($fp); if($m === "r") { unlink("my.sock"); } } else { echo "error"; } ?> А для чего тебе сокс, который больше 30 секунд соединение держать не будет? Была у меня мысля свой proxy_rd по такому же принципу реализовать, но столько геморроя с этим из-за каких-то 30 секунд соединения. Да и задача изначально у него другая - вроде как универсальный модификатор исходящих заголовков, хотя цель такая же - изменить заголовок таким образом, чтобы передать его в любом направлении любому клиенту (преимущественно скрипту).
А вы ничего не путаете? мне всегда казалось что max_execution_time - это процесорное время работы скрипта. Т.е. реального времени там вполне может быть несколько часов.
вобще вот уже готовое решение http://sourceforge.net/project/showfiles.php?group_id=178782 как собственно упоминалось не раз уже на этом форуме. я пользуюсь - только подправил немного - GET убрал, фигню всякую ненужную чтоб вес уменьшить и упростить, админку и тп, правда шифрование так и несмог заставить работать у себя.
http://slil.ru/27501988 но всеже советую качать оригинальный вариант http://sourceforge.net/project/showfiles.php?group_id=178782 шифрование- трафик проходящий между скриптами шифруется.
у меня пашет хз что у вас там - попробуйте напрямую прописать конфиг чтоб не искал его. и кстати в офф версии тоже самое ?
из 70 мною перепробаваных хостов(php 5, safe_mode off и сокеты соответсвенно на всех были) он завелся на двух, причем носок поднялся а вот https так и нет, я про офф версию. А насчет путей то он ясно говорит куда скинуть конфиг(C:/Perl/site/lib/).
у меня честно на всех работало где php 5 и папка для темпа, может конечно я мало еще юзал ее, виндовые сервера и фри хостинги в том числе. там у серверной части логи же есть тоже смотрите на всякий случай.