Antichat снова доступен.
Форум Antichat (Античат) возвращается и снова открыт для пользователей.
Здесь обсуждаются безопасность, программирование, технологии и многое другое.
Сообщество снова собирается вместе.
Новый адрес: forum.antichat.xyz

08.04.2009, 21:48
|
|
Участник форума
Регистрация: 20.12.2007
Сообщений: 295
Провел на форуме: 1777055
Репутация:
347
|
|
SOCKS прокси на PHP
это недописанные скрипты для 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;
}
?>
Код:
#!/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;
}
Последний раз редактировалось bons; 08.04.2009 в 22:43..
|
|
|

09.04.2009, 00:05
|
|
Познавший АНТИЧАТ
Регистрация: 29.04.2007
Сообщений: 1,189
Провел на форуме: 5749763
Репутация:
1680
|
|
+1 Подписываюсь, гуру ачата помогите разобратся с данной проблеммой, ибо вещь действительно была бы незаменимой!
|
|
|

09.04.2009, 07:39
|
|
Познающий
Регистрация: 06.03.2007
Сообщений: 59
Провел на форуме: 371875
Репутация:
137
|
|
Тоже довненько искал, что не буть подобное, также подписываюсь, автору темы плюс, за актуальность вопроса)
|
|
|

10.04.2009, 13:43
|
|
Новичок
Регистрация: 30.01.2009
Сообщений: 16
Провел на форуме: 30718
Репутация:
18
|
|
Не вглядываясь просмотрел твой скрипт.
Насколько я понял ты пытаешься досылать данные работающему скрипту.
Я тоже пытался реализовать подобное поведение, но отказался от этой затеи из-за того, что работа скрипта ограничена max_execution_time и постоянное соединение поддерживать не удастся.
А не влияет ли отключение сокетов на функции stream_socket_*?
Может дело в этом? На большинстве серверов они отключены.
|
|
|

14.04.2009, 02:54
|
|
Познавший АНТИЧАТ
Регистрация: 29.04.2007
Сообщений: 1,189
Провел на форуме: 5749763
Репутация:
1680
|
|
Сообщение от needDrivers
На большинстве серверов они отключены.
Ну а вообще с помощью хоть каких то библотэк php можно ли сокс таким образом организовать?
|
|
|

14.04.2009, 03:54
|
|
Динозавр
Регистрация: 10.01.2008
Сообщений: 2,841
Провел на форуме: 9220514
Репутация:
3338
|
|
http://www.phpclasses.org/browse/package/1822.html
http://www.phpclasses.org/browse/package/5049.html
во второй ссылке клянется, что рабочий, плюс есть поддержка авторизации. В обоих случаях есть пример использования. Сам не проверял.
Последний раз редактировалось Pashkela; 14.04.2009 в 04:09..
|
|
|

14.04.2009, 04:47
|
|
Познавший АНТИЧАТ
Регистрация: 29.04.2007
Сообщений: 1,189
Провел на форуме: 5749763
Репутация:
1680
|
|
Сообщение от Pashkela
http://www.phpclasses.org/browse/package/1822.html
http://www.phpclasses.org/browse/package/5049.html
во второй ссылке клянется, что рабочий, плюс есть поддержка авторизации. В обоих случаях есть пример использования. Сам не проверял.
Мляяя это РАЗНЫЕ вещи.
Мы говорим в этой теме о СКРИПТЕ socks 5 а не о поднятии службы на сервере с открытым портом.
Последних скриптов навалом, только толку от них 0.
Смысл сабжа в том, что мы просто кладём скрипт на сервер и коннектимся к нему клиентом, а не поднимаем процесс на хосте.
|
|
|

14.04.2009, 07:44
|
|
Постоянный
Регистрация: 11.11.2006
Сообщений: 834
Провел на форуме: 3941248
Репутация:
668
|
|
я гдето в теме полезных скриптов выкладывал рабочий класс для работы через сокс ...
|
|
|

14.04.2009, 09:42
|
|
Участник форума
Регистрация: 20.12.2007
Сообщений: 295
Провел на форуме: 1777055
Репутация:
347
|
|
Сообщение от Doom123
я гдето в теме полезных скриптов выкладывал рабочий класс для работы через сокс ...
тут немного не тот принцип действия и сокс-класс тут как-бы не поможет. Основная задача в том, как заметил needDrivers, чтобы дослать данные работающему php скрипту.
Когда нужно создать туннель, perl-скрипт вызывает по HTTP-протоколу php-скрипт, который в свою очередь соединяется с целью и создает на сервере UNIX-сокет для межпроцессной связи. Когда нужно дослать данные, perl-скрипт опять же шлет данные по HTTP, а php-скрипт просто пишет в этот UNIX-сокет. Таким образом время ограничено только После закрытия соединения сокет удаляется.
Понятно, что php-скрипт не кроссплатформенный, UNIX-сокет в windows создать пока нельзя
Сообщение от needDrivers
работа скрипта ограничена max_execution_time и постоянное соединение поддерживать не удастся
если на сервере не запрещена функция set_time_limit то это легко исправляется. Даже если запрещена то соединение можно удерживать целых 30 секунд или сколько там выставят в настройках.
Сообщение от needDrivers
А не влияет ли отключение сокетов на функции stream_socket_*?
Может дело в этом? На большинстве серверов они отключены.
если они отключены то конечно скрипт работать не будет. Но на тех серверах, на которых я это тестил, вроде как с этим было все в порядке
Последний раз редактировалось bons; 14.04.2009 в 09:44..
|
|
|

14.04.2009, 11:54
|
|
Новичок
Регистрация: 30.01.2009
Сообщений: 16
Провел на форуме: 30718
Репутация:
18
|
|
Раз у тебя 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 секунд соединения. Да и задача изначально у него другая - вроде как универсальный модификатор исходящих заголовков, хотя цель такая же - изменить заголовок таким образом, чтобы передать его в любом направлении любому клиенту (преимущественно скрипту).
|
|
|
|
 |
|
|
Здесь присутствуют: 1 (пользователей: 0 , гостей: 1)
|
|
|
|