PDA

Просмотр полной версии : PHP Proxy Server


Dr.Z3r0
22.02.2008, 17:10
PHP Proxy Server v1.0 pre-realase

Вообщем вот проксик написал.
Писал для себя скажем так для развития. Интересовала библиотека socket. Вот собственно из этого и получился прокси серв.

Возможности эт собственно сам прокси сервер, тунелирование, логирование и пр.

Для работы требуется библиотека socket!
<?php
/////////////////////////////////////////
// PHP Proxy Server v1.0 pre-realase //
// Created by I-I()/Ib //
// 22.02.08 //
/////////////////////////////////////////
$set['port']=3333;//порт для прокси серва
$set['mxconnect']=5;//максимальное количество одновременных подключений
$set['lenpack']=10240;//max кол-во байт на прием/отссылку за один раз от/к клиент(а/у)
$set['dishost']='microsoft.com';//Хост запросив который мы вырубим проксик
/////////////////////////////////////////
$set['usagent']='Mozilla/5.0 ( Windows; U; AOL 5.0; TWRAITH )';//Заменять User-Agent на это... (false оставить прежним)
$set['xforwadfor']=0;//X-Forwarded-For: 0-не указывать/удалить существующий, 1-указывать реальный, 2-генерить случайно
$set['referer']=0;//Referer: 0-удалять, 1-оставить
$set['chngprx']=0;//0-Менять заголовок указывающий на то что используется прокси сервер, 1-не менять
$set['addcapt']=0;//1-Добавлять заголовок указывающий версию этого прокси серва, 0-не добалять
/////////////////////////////////////////
$set['allip']=true;//true-прокси для всех ип, false только для $set['acssip']
$set['acssip']=array('127.0.');//маски разрешенных ип...
/////////////////////////////////////////
$set['logerror']='error.log';//Файл лога ошибок, false-не писать...
$set['logacess']='acess.log';//Лог запросов прокси, false-не писать...
$set['savacess']=1;//0-Указать только ип и время, 1-указать ип время и удаленный хост
/////////////////////////////////////////
$set['tnlnbld']=false;//Включить поддержку тунелирования проксиком
$set['fltnl']='proxy.txt';//Файл список всех прокси серверов
$set['rntnl']=true;//Рандомно изменять порядок серверов
$set['ndtnl']=false;//Последний сервер в списке всегда конечный
$set['nmtnl']='Data-Send';//Имя параметра в заголвке в котором будет передаваться весь список прокси
/////////////////////////////////////////

function parse_packet(&$packet, &$host, &$error, $ip){
global $set;

$error=false;
//Валидность ипа
if(!preg_match('/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/',$ip)){
$error='Proxy don\'t understend your ip. Sorry...';
}else{
//Разрешен ли проксик для всех ипов
if(!$set['allip']){
$error='This proxy can not used from anything ip. Acsess denieded.';
foreach($set['acssip'] as $key){
if(preg_match('/'.preg_quote($key).'/',$ip)){
$error=false;
break;
}
}
}
}

if(!$error){
//Проверка валидности пакета
if(!preg_match('/^(GET|POST|HEAD) \S+ HTTP\/1\.[1|0]\r\n([\w-]+: [\w|\W]+\r\n)+\r\n[\w|\W]*/i',$packet))$error='Proxy don\'t understand your packet. Sorry...';
else{
//Выдираем имя хоста
if(!preg_match('/Host: ([^\r\n]+)/i',$packet,$tmp))$error='In your packet don\'t writing remote host. Sorry...';
else{
if(!preg_match('/^[\w\.\-:]+$/',$tmp[1]))$error='Remote host not valid. Sorry...';
else{
$host=$tmp[1];
$tmp='';
//Лог обращений к проксику
if($set['logacess']){
$fp=fopen($set['logacess'], 'a');
fputs($fp,$ip.' ['.date('H:i d.m.Y',time()).'] '.$host."\r\n");
fclose($fp);
}
//Меняем User-Agent
if($set['usagent'])$packet=preg_replace('/User-Agent: [^\r\n]+/i','User-Agent: '.$set['usagent'],$packet);
//Меняем Referer
if($set['referer']===0)$packet=preg_replace('/Referer: [^\r\n]+\r\n/i','',$packet);
//Меняем лишние заголовки
if($set['chngprx']===0)$packet=preg_replace('/Proxy-Connection: /','Connection: ',$packet);
//Операции с X-Forwarded-For
if($set['xforwadfor']===0)$packet=preg_replace('/X-Forwarded-For: [^\r\n]+\r\n/i','',$packet);
else if($set['xforwadfor']===1)$packet=preg_replace('/Host: ([^\r\n]+)/i','Host: \\1'."\r\n".'X-Forwarded-For: '.$ip,$packet);
else if($set['xforwadfor']===2)$packet=preg_replace('/Host: ([^\r\n]+)/i','Host: \\1'."\r\n".'X-Forwarded-For: '.gen_ran_ip(),$packet);
//Указываем версию проксика
if($set['addcapt']===1)$packet=preg_replace('/Host: ([^\r\n]+)/i','Host: \\1'."\r\n".'Use-Proxy: PPS v1.0',$packet);
}
}
}
}

if(!$error)return true;
else return false;
}

function gen_ran_ip(){
$ip=rand(80,255);
$ip.='.'.rand(80,255);
$ip.='.'.rand(80,255);
$ip.='.'.rand(80,255);

return $ip;
}

function eror_rep($error,$ip){
global $set;

if($error){
//Лог ошибок
if($set['logerror']){
$fp=fopen($set['logerror'], 'a');
fputs($fp,$ip.' ['.date('H:i d.m.Y',time()).']'.$error."\r\n");
fclose($fp);
}
$packet_ret='HTTP/1.1 500 Error
Server: PPS v1.0
Connection: Close
Transfer-Encoding: chunked
Content-Type: text/html

';
$tmp='<html>
<head>
<title>Proxy Error...</title>
<head>
<body>
Proxy return error:<br>
'.$error.'
</body>
</html>';
$packet_ret.=dechex(strlen($tmp))."\r\n".$tmp."\r\n".'0'."\r\n\r\n";
return $packet_ret;
}else return false;

}

error_reporting(0);
set_time_limit(0);
ignore_user_abort(true);
//Подключенна ли данная библиотека
if(!function_exists('socket_create'))die("socket_create() failed, reason: socket library is not loaded");
//Создание сокета
if(!($sock=@socket_create(AF_INET, SOCK_STREAM, SOL_TCP)))die("socket_create() failed, reason: ".socket_last_error()."<br>\r\n".socket_strerror(socket_last_error()));
//Открываем порт
if(!(@socket_bind($sock, '127.0.0.1', $set['port'])))die("socket_bind() failed, reason: ".socket_last_error()."<br>\r\n".socket_strerror(socket_last_error()));
//Ждем подключений
if(!@socket_listen($sock, $set['mxconnect']))die("socket_listen() failed, reason: ".socket_last_error()."<br>\r\n".socket_strerror(socket_last_error()));

while(1){
//Создаем новый ресурс сокета на новое подключение
if(!($msgsock=@socket_accept($sock))){
socket_close($msgsock);
continue;
}
//Узнаем ип клиента
$ip='';
if(!@socket_getpeername($msgsock,$ip)){
socket_close($msgsock);
continue;
}

$zzz='';
$buf='';
$pak='';
//Читаем пакет от клиента
while(1){
$tmp=@socket_read($msgsock, $set['lenpack'],PHP_BINARY_READ);
if(!empty($tmp)){
if(!is_array($pak)){
$buf.=$tmp;
//Прием заголовка окончен
if(preg_match('/\r\n\r\n/i',$buf)){
//Определяемся с методом передачи данных
if(preg_match('/^(GET|POST|HEAD)/i',$buf,$zzz)){
$pak['type']=$zzz[1];
$zzz='';
//Для GET и HEAD одного заголовка достаточно
if(($pak['type']==='GET')||($pak['type']==='HEAD')){
$pak['header']=$buf;
$pak['receiv']='';
break;
}else{
//Выдираем Content-Length для метода POST
if(preg_match('/Content-Length: (\d+)\r\n/i',$buf,$zzz)){
$pak['length']=$zzz[1];
//Делим пакет на заголовок и данные
preg_match('/([\w|\W]+)\r\n\r\n([\w|\W]*)/i',$buf,$zzz);
$pak['header']=$zzz[1];
$pak['receiv']=$zzz[2];
$zzz='';
if(strlen($pak['receiv'])==$pak['length'])break;
}else break;
}
}else{
$pak['header']='';
$pak['receiv']='';
$pak['length']='0';
break;
}
}
}else{
//Собираем до конца все данные
$pak['receiv'].=$tmp;
if(!(strlen($pak['receiv'])<$pak['length']))break;
}
$tmp='';
}
}
$buf=$pak['header']."\r\n\r\n".$pak['receiv'];

$tmp='';
if(parse_packet($buf,$host,$error,$ip)){
//Вырубить проксик
if($host===$set['dishost']){
socket_close($msgsock);
socket_close($sock);
die();
}

//Поддержка тунелирования
$proxy='';
if($set['tnlnbld']){
//Передан ли параметр с прокси сервами
if(preg_match('/'.preg_quote($set['nmtnl']).': ([^\r\n]+)/',$buf,$tmp)){
$tmp=explode('|',base64_decode($tmp[1]));
if(!empty($tmp)){
//Убираем адрес следующего прокси сервера
$host=$tmp[0];
if(count($tmp)>1){
$proxy='';
for($i=1;$i<count($tmp);$i++)$proxy.=$tmp[$i].'|';
$proxy=substr($proxy,0,strlen($proxy)-1);
$proxy=base64_encode($proxy);
//Записываем это все в заголовок
$buf=preg_replace('/'.preg_quote($set['nmtnl']).': ([^\r\n]+)/i',$set['nmtnl'].': '.$proxy,$buf);
$tmp='';
}else{
$buf=preg_replace('/'.preg_quote($set['nmtnl']).': ([^\r\n]+)\r\n/i','',$buf);
}
}
$tmp='';
}else{
//Существует ли файл со списоком(предполагается что этот сервер - 1ый)
if(file_exists($set['fltnl'])){
$tmp=file($set['fltnl']);
$host=trim($tmp[0]);
if(count($tmp)>1){
$proxy='';
$xxxx='';
//Перемешивание
if($set['rntnl']){
//Конечный проксик один и тот же всегда
if($set['ndtnl']){
$yyyy=$tmp[count($tmp)-1];
for($i=1;$i<count($tmp)-1;$i++)$xxxx[$i-1]=trim($tmp[$i]);
shuffle($xxxx);
$xxxx[]=$yyyy;
$yyyy='';
}else{
for($i=1;$i<count($tmp);$i++)$xxxx[$i-1]=trim($tmp[$i]);
shuffle($xxxx);
}
}else{
for($i=1;$i<count($tmp);$i++)$xxxx[$i-1]=trim($tmp[$i]);
}
$tmp='';
foreach($xxxx as $tmp)$proxy.=$tmp.'|';
$proxy=substr($proxy,0,strlen($proxy)-1);
$proxy=base64_encode($proxy);
//Записываем это все в заголовок
$buf=preg_replace('/Host: ([^\r\n]+)/i','Host: \\1'."\r\n".$set['nmtnl'].': '.$proxy,$buf);
$xxxx='';
}
$tmp='';
}
}
}
$proxy='';
$tmp='';

$port=80;
//Если в хосте указан порт то его нужно выдрать
if(preg_match('/^([^:]+)(:\d+)*$/',$host,$tmp)){
$host=$tmp[1];
if(isset($tmp[2])){
$port=$tmp[2];
preg_match('/^:(\d+)$/',$port,$tmp);
$port=$tmp[1];
}
}

$tmp='';
//Если в кач-ве хоста передано имя домена, то его нуно преобразовать в айпишник...
if(!preg_match('/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/',$host)){
$tmp=gethostbyname($host);
if($tmp===$host){
//Имя домена не найденно
$tmp=eror_rep('Remote server not found. Sorry...',$ip);
socket_write($msgsock,$tmp,strlen($tmp));
$error=true;
}else $host=$tmp;
$tmp='';
}

if(!$error){
//Посылка запроса на удаленный сервер
$sock2=socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
//Подключение
if(!(@socket_connect($sock2, $host, $port))){
$tmp=eror_rep('Can\'t connect ro remote server. Reason:'."<br>\r\n".socket_strerror(socket_last_error()),$ip);
socket_write($msgsock,$tmp,strlen($tmp));
break;
}else{
//Отправка пакета
if(!(@socket_write($sock2, $buf, strlen($buf)))){
$tmp=eror_rep('Can\'t send packet ro remote server. Reason:'."<br>\r\n".socket_strerror(socket_last_error()),$ip);
socket_write($msgsock,$tmp,strlen($tmp));
break;
}else{
//Чтение
while($tmp=@socket_read($sock2, $set['lenpack'])){
//Отправка приянтых данных клиенту
if(!$tmp)break;
socket_write($msgsock,$tmp,strlen($tmp));
}
}
}
socket_close($sock2);
}
}else{
//Отправка текста ошибки клиенту
$tmp=eror_rep($error."<br>\r\n",$ip);
socket_write($msgsock,$tmp,strlen($tmp));
}
$ip='';
$buf='';
$pak='';
socket_close($msgsock);
}
socket_close($sock);
?>

bul.666
22.02.2008, 17:14
$ip='';
$buf='';
$pak='';
Не лучшебы использовать unset() ?

DIAgen
22.02.2008, 17:22
Я тебе уже говорил что скриптик прикольный, только жалко его не возможно поставить на сервак...

P.S>А да еще заметил одну фишку с socket, когда работаешь с протоколами например с SMTP or FTP то команды посылаются нормально через socket, если посылать запросы HTTP сначало один запрос с заголовков, а потом второй, то первый пройдет, а второй почему то не хочет проходить.. фиг знает почему, это было так маленькое отступление наболевшего:)

Isis
22.02.2008, 19:23
Не лучшебы использовать unset() ?
Вообще-то все правильно :)
Посмотри...он эти переменные просто определяет что они существуют для дальнейшего использования без ошибок !

xaker-boss
24.02.2008, 12:58
Отлично работает, спасибо

ElteRUS
24.02.2008, 13:32
если посылать запросы HTTP сначало один запрос с заголовков, а потом второй, то первый пройдет, а второй почему то не хочет проходить.. фиг знает почему, это было так маленькое отступление наболевшего:)

Для каждого HTTP запроса нужно создавать сокет заново. Клиент посылает 1 запрос - получает от сервера 1 ответ - связь окончена. Когда-то тут цитировали рфц по этому поводу, не помню уже где )

heks
24.02.2008, 13:49
у меня что то не работает как можно проверить присутствует ли библиотека сокет

Dr.Z3r0
24.02.2008, 14:14
По идее скрипт должен вырубаться с сообщением:
"socket_create() failed, reason: socket library is not loaded"

Pernat1y
24.02.2008, 14:15
посмотри лог ошибок апача, и проверь, подключен-ли php_sockets.dll расширениях (php.ini)

nc.STRIEM
24.02.2008, 23:44
все хорошо, но для каждого нового подключения необходимо создавать новый паток.
В твоем варианте все работает, но вот скорсть страдает, т.к. все запросы становяться в очередь и ждут окончания выполнения придыдущего. А есле это будет скачка тяжолого файла? вобщем думаю понял что я имел ввиду

Dr.Z3r0
25.02.2008, 00:08
Вообще этот прокси расчитан на 5 коннектов одновременно по дефолту(что можно поменять в настройках) раз, а во вторых многопоточность в пхп - это извращение как таковое...

nc.STRIEM
25.02.2008, 00:38
Вообще этот прокси расчитан на 5 коннектов одновременно по дефолту(что можно поменять в настройках)

Эт я видел, но каая разница скок конектов, начнеш через него файл скачивать и все.... один конект...

а во вторых многопоточность в пхп - это извращение как таковое...

Согласен, но а что делать..

sabe
18.07.2008, 20:47
socket_bind() failed, reason: 98
Address already in use
как исправить ?

Developer
18.07.2008, 22:50
Как юзать можно? Реально, чтобы прописать в браузере ИП сайта и порт 80 где он стоит и чтобы работал?

Dr.Z3r0
19.07.2008, 18:56
socket_bind() failed, reason: 98
Address already in use как исправить ?Измени на что нить другое:
$set['port']=3333;//порт для прокси серва
PS Кхм а перевести самому слабо было?)


Как юзать можно? Реально, чтобы прописать в браузере ИП сайта и порт 80 где он стоит и чтобы работал?Правда хер пойми че те надо. Но вообщем алгоритм юзания следующий. Берем скрипт этого проксика засовываем на какой нить хост. Запускаем этот скрипт (как запускать писать не буду). Если запустился без ошибок значит все ок. Далее в браузере пишем в качестве адреса прокси IP адрес хоста и порт который вы указали в настройках (для танкистов $set['port']). И можете спокойно работать через этот проксег.

PS Ляд ну пожалуйста научитесь писать нормально чего вам надо, в конце концов оно надо вам. Почему мы должны угадывать что вам нужно?

DVD_RW
22.08.2008, 16:43
эм...за нубский вопрос сорри... а на coolpage.biz пойдёт? ><

Romaxa55
25.08.2008, 02:14
Пишет
socket_create() failed, reason: 0
Success
Проблеммаа с самим хостингом?

Скорей всего сокет не подключин на хосте

sharky_fish
23.12.2008, 22:43
А на каком бесплатном хостинге работает? Может ктото подсказать?
Или можно ПМ. Спасибо.

ntldr
23.12.2008, 23:22
искал давно!

sharky_fish
23.12.2008, 23:43
Наверное уже не судьба получить ответ :)