Ходим в php через socks4/5

Обсуждение в разделе «PHP, PERL, MySQL, JavaScript», начал(-а) h0d, 31.12.2007.

  1. h0d

    h0d New Member

    Регистрация:
    31.12.2007
    Сообщения:
    3
    Одобрения:
    1
    Репутация:
    0
    Класс сокета с поддержкой socks4/5-прокси
    фичи:
    - полная поддержка сокс4/5-прокси
    - автоопределение типа прокси


    вспомогательный класс (socket.class.php)
    от этого класса идет наследование класса с поддержкой соксов

    socket.class.php
    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)


    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;
            }
        }
    }
    ?> 
    пример использования:

    PHP:
    <?
    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();  
    ?>
     
Loading...
Похожие темы
  1. Ответы:
    1
    Просмотры:
    866
  2. Ответы:
    1
    Просмотры:
    715
  3. Ответы:
    0
    Просмотры:
    614
  4. Ответы:
    1
    Просмотры:
    719
  5. Ответы:
    4
    Просмотры:
    4 021