Форум: Форум PHPФорум ApacheФорум Регулярные ВыраженияФорум MySQLHTML+CSS+JavaScriptФорум FlashРазное
Новые темы: 0000000
Социальная инженерия и социальные хакеры. Авторы: Кузнецов М.В., Симдянов И.В. MySQL 5. В подлиннике. Авторы: Кузнецов М.В., Симдянов И.В. PHP. Практика создания Web-сайтов (второе издание). Авторы: Кузнецов М.В., Симдянов И.В. Программирование. Ступени успешной карьеры. Авторы: Кузнецов М.В., Симдянов И.В. PHP Puzzles. Авторы: Кузнецов М.В., Симдянов И.В.
ВСЕ НАШИ КНИГИ
Консультационный центр SoftTime

Форум PHP

Выбрать другой форум

 

Здравствуйте, Посетитель!

вид форума:
Линейный форум Структурный форум

тема: Класс сокета с поддержкой socks4/5-прокси
 
 автор: куч1963   (21.01.2008 в 08:27)   письмо автору
 
 

для тех, кому интересна эта тема.
socket.class.php

<?
/**
 * Socket Class

 * @author  hodik <icq://664679>
 * @package Classes
 * @subpackage network
 * @version 1.0
 * @filesource
 */

/**
 * CSocket

 * @package Classes
 * @subpackage network
 */ 

class CSocket{
    
/**
      * @desc
      * @access private
      */
    
var $_persistent false;
    
    
/**
      * @desc
      * @access private
      */
    
var $_connected false;
    
    
/**
      * @desc
      * @access private
      */
    
var $_conn null;
    
    
/**
      * Конструктор класса
      * @param boolean постоянное соединение или нет
      * @return void
      */
    
function CSocket($persistent false)
    {
        
$this->_persistent $persistent;
    }
    
    
/**
      * Проверяет, установлено ли соединение
      * @return boolean
      */
    
function _valid()
    {
        return 
is_resource($this->_conn) && ($this->_connected == true);
    }
    
    
/**
      * Устанавливает соединение
      * @param string
      * @param int
      * @return bool
      */
    
function connect($url$timeout 10)
    {
        
$host     parse_url($urlPHP_URL_HOST);
        if(!
$port parse_url($urlPHP_URL_PORT)) $port 80;
        
        
$sockFunc    = ($this->_persistent) ? "pfsockopen" "fsockopen";
        
$this->_conn $sockFunc($host$port$errno$errstr$timeout);
        
        if(!
$this->_conn)
        {
            
trigger_error("Couldn't connect to $host:$port"E_USER_WARNING);
            return 
false;
        }
        
        
$this->_connected true;
        return 
true;
    }
    
    
/**
      * Посылает данные (binary-safe)
      * @param какие-то данные
      * @return boolean
      */
    
function send($data)
    {
        if(!
$this->_valid())
        {
            
trigger_error("Error on sending data. Reason: Not connected"E_USER_WARNING);
            return 
false;
        }
        
        if(
fputs($this->_conn$data) === FALSE)
        {
            
trigger_error("Error on sending data to the server"E_USER_WARNING);
            return 
false;
        }
        return 
true;
    }
    
    
/**
      * Читает из входного потока определенное количество символов
      * @param int
      * @return string
      */
    
function read($len)
    {
        if(!
$this->_valid())
        {
            
trigger_error("Error on reading data. Reason: Not connected"E_USER_WARNING);
            return 
false;
        }

        if((
$buf fgets($this->_conn$len)) === FALSE)
        {
            
trigger_error("Error on reading data. Reason: Connection error"E_USER_WARNING);
            return 
false;
        }
        return 
$buf;
    }
    
    
/**
      * Читает строку из входного потока
      * @return string
      */
    
function readString()
    {
        if(!
$this->_valid())
        {
            
trigger_error("Error on reading string. Reason: Not connected"E_USER_WARNING);
            return 
false;
        }
        
        
$str null
        while(!
feof($this->_conn))
        {
            if((
$buf fgets($this->_conn128)) === FALSE)
            {
                
trigger_error("Error on reading string. Reason: Connection error"E_USER_WARNING);
                return 
false;
            }
            
            
$str .= $buf;
            if(
strlen($str) >= && (substr($str, -2) == "\r\n" || substr($str, -1) == "\n"))
            {
                return 
rtrim($str);
            }
        }
        
        if(
$str) return $str; else return false;
    }
    
    
/**
      * Читает все данные из входного потока
      * @return string
      */
    
function readAll()
    {
        if(!
$this->_valid())
        {
            
trigger_error("Error on reading data. Reason: Not connected"E_USER_WARNING);
            return 
false;
        }

        
$str "";
        while(!
feof($this->_conn))
        {
            if((
$buf fgets($this->_conn128)) === FALSE)
            {
                
trigger_error("Error on reading data. Reason: Connection error"E_USER_WARNING);
                return 
false;            
            }
            
$str .= $buf;
        }
        return 
$str;
    }
    
    
/**
      * Проверяет, активно ли соединение
      * @return boolean
      */
    
function isActive()
    {
        return 
$this->_valid();
    }
    
    
/**
      * Разрывает соединение
      * @return boolean
      */
    
function disconnect()
    {
        if(!
$this->_valid())
        {
            
trigger_error("Error on disconnecting. Reason: Not connected"E_USER_WARNING);
            return 
false;
        }
        
        
$this->_connected false;
        
fclose($this->_conn);
        return 
true;
    }
}
?> 




socks.class.php

<?
/**
 * Socket Class Through SOCKS4/5 proxy

 * @author hodik <icq://664679>
 * @package Classes
 * @subpackage network
 * @version 1.0
 * @filesource
 */

/**
 * CSocksSocket

 * @package Classes
 * @subpackage network
 */ 

require_once("socket.class.php");
define("SOCKS4_TYPE"1);
define("SOCKS5_TYPE"2);
define("AUTOMATIC_TYPE"3);

class 
CSocksSocket extends CSocket{
    
/**
      * @desc
      * @access private
      */
    
var $_proxyHost;
    
    
/**
      * @desc
      * @access private
      */    
    
var $_proxyPort;
    
    
/**
      * @desc
      * @access private
      */
    
var $_proxyType;

    
/**
      * @desc
      * @access private
      */
    
var $_proxyUser;

    
/**
      * @desc
      * @access private
      */
    
var $_proxyPwd;
    
    
/**
      * @desc
      * @access private
      */
    
var $_host;
    
    
/**
      * @desc
      * @access private
      */
    
var $_port;

    
/**
      * @desc
      * @access private
      */
    
var $_timeout;
    
    
/**
      * Устанавливает прокси и его тип
      * @param string
      * @return void
      */
    
function setProxy($proxyURL)
    {
        
$this->_proxyHost parse_url($proxyURLPHP_URL_HOST);
        
$this->_proxyPort parse_url($proxyURLPHP_URL_PORT);
        
$this->_proxyUser parse_url($proxyURLPHP_URL_USER);
        
$this->_proxyPwd  parse_url($proxyURLPHP_URL_PASS);
        
$this->_proxyType strtolower(parse_url($proxyURLPHP_URL_SCHEME));
    }
    
    
/**
      * Преобразует имя хоста или его адрес в число (4 байта)
      * @param string
      * @return int
      * @access private
      */
    
function _host2int($host)
    {
        
$ip gethostbyname($host);
        if(
preg_match("/(\d+)\.(\d+)\.(\d+)\.(\d+)/"$ip$matches))
        {
            
$retVal pack("C4"$matches[1], $matches[2], $matches[3], $matches[4]);
        }
        return 
$retVal;
    }
    
    
/** 
      * Соединяется через socks4
      * @access private
      * @return boolean
      */
    
function _connectThroughSocks4()
    {
        
$query  pack("C2"0x040x01); //VN, CD
        
$query .= pack("n"$this->_port); //DSTPORT
        
$query .= $this->_host2int($this->_host); //DSTIP
        
$query .= ($this->_proxyUser != "")? $this->_proxyUser "0"//IDENTD
        
$query .= pack("C"0); //NULL
        
        
if(!$this->send($query)) return false;
        if((
$response $this->read(9)) === false) return false;
        
        
$answer   unpack("Cvn/Ccd"substr($response02));
        
        
//по протоколу vn всегда должен быть 0
        
if($answer["vn"] != 0)
        {
            
trigger_error("The VN field of proxy server response is not zero. It should be 0"E_USER_WARNING);
            return 
false;
        }
        
        switch(
$answer["cd"])
        {
            case 
90:
                return 
true;
                break;
            case 
91:
            case 
92:
            case 
93:
                
trigger_error("Request to proxy have been rejected or failed"E_USER_WARNING);
                return 
false;
                break;
            default:
                
trigger_error("Unknow response from proxy"E_USER_WARNING);
                return 
false;
                break;
        }
        return 
false;
    }
    
    
/**
      * Выполняет аутентификацию логин/пароль по протоколу SOCKS5
      * @access private
      * @return boolean
      */
    
function _doSOCKS5Auth()
    {
        
$request  pack("C"1); //VN
        
$request .= pack("C"strlen($this->_proxyUser));
        
$request .= $this->_proxyUser;
        
$request .= pack("C"strlen($this->_proxyPwd));
        
$request .= $this->_proxyPwd;
        
        if(!
$this->send($request)) return false;
        if((
$response $this->read(3)) === false) return false;
        
        
$answer unpack("Cvn/Cresult"$response);
        if(
$answer["vn"] != && $answer["result"] != 0)
        {
            
trigger_error("Proxy have rejected the connection. Reason: Invalid username or/and password"E_USER_WARNING);
            return 
false;
        }
        return 
true;
    }
    
    
/**
      * Соединяется через socks5
      * @access private
      * @return boolean
      */
    
function _connectThroughSocks5()
    {
        
//выбор тип аутентификации
        
if($this->_proxyUser)
        {
            
$request pack("C4"5//версия сокс-протокола
                                  
2//длина
                                  
0//без аутентификации
                                  
2);//логин и пароль
        
}
        else
        {
            
$request pack("C3"510); //без аутентификации
        
}
        
        if(!
$this->send($request)) return false;
        if((
$response $this->read(3)) === false) return false;

        
$answer   unpack("Cver/Cmethod"$response);

        
//аутентификация: логин и пароль
        
if($answer["method"] == && !$this->_doSOCKS5Auth()) return false;
        
//без аутентификации
        
elseif($answer["method"] == 0) { /* ничего не делаем*/ }
        else 
        {
            
trigger_error("Proxy have rejected the connection. Reason: All the auth methods not supported"E_USER_WARNING);
            return 
false;
        }
        
        
//запрос CONNECT
        
$request  pack("C4"0x050x010x000x01); //VN=5,Method=1,Reserved=0,ATYP=ipv4
        
$request .= $this->_host2int($this->_host); //DSTIP
        
$request .= pack("n"$this->_port); //DSTPORT
        
        
if(!$this->send($request)) return false;
        if((
$response $this->read(11)) === false) return false//читаем ответ сервера

        
$answer   unpack("Cver/CREP"substr($response02));
        switch(
$answer["REP"])
        {
            case 
0:
                return 
true;
            default:
                
trigger_error("Proxy have rejected the connection. Reason: code error={$answer['REP']}"E_USER_WARNING);
                return 
false;
        }
    }
    
    
/**
      * Определяет тип прокси и соединяется
      * @return boolean
      */
    
function _connectAutoType()
    {
        
//попробуем как через сокс4, а вдруг получится
        
if($this->_connectThroughSocks4())
        {
            
$this->_proxyType "socks4";
            return 
true;
        }
        
//остался последний вариант: сокс5 (!!!)
        
else
        {
            
//на всякий случай разорвать соединение, а то сервер подумает, что над ним издеваются =)
            
$this->disconnect();
            if(!
parent::connect("{$this->_proxyHost}:{$this->_proxyPort}"$this->_timeout)) return false;
            if(
$this->_connectThroughSocks5())
            {
                
$this->_proxyType "socks5";
                return 
true;
            }
        }
        
        
//наверно это оказался SOCKS6, поддержку потом добавлю =)
        
return false;
    }
    
    
/**
      * Устанавливает соединение
      * @param string
      * @param int
      * @return boolean
      */
    
function connect($url$timeout 10)
    {
        
$this->_host     parse_url($urlPHP_URL_HOST);
        if(!
$this->_port parse_url($urlPHP_URL_PORT)) $this->_port 80;
        
$this->_timeout  $timeout;

        if(!
parent::connect("{$this->_proxyHost}:{$this->_proxyPort}"$this->_timeout)) return false;
        
        switch(
$this->_proxyType)
        {
            case 
"socks4";
                return 
$this->_connectThroughSocks4();
                break;
            case 
"socks5":
                return 
$this->_connectThroughSocks5();
                break;
            case 
"socks":
                return 
$this->_connectAutoType();
                break;
            default:
                return 
$this->_connectAutoType();
                break;
        }
    }
}
?> 


Пример использования:

include("socks.class.php");

$sock = new CSocksSocket();
$sock->setProxy("socks://127.0.0.1:1080");//автоопределение
$sock->setProxy("socks4://127.0.0.1:1080"); //явно задан вид - сокс4
$sock->setProxy("socks5://127.0.0.1:1080"); //явно задан вид - сокс5
$sock->connect("yandex.ru:80", 10); //10-это таймаут
$sock->send("GET / HTTP/1.0\r\nConnection: close\r\n\r\n");
print $sock->readAll();  

класс взят с адреса
http://www.xaker.name/forvb/showthread.php?t=6366

   
Rambler's Top100
вверх

Rambler's Top100 Яндекс.Метрика Яндекс цитирования