检查PHP中的SOCKS4还是5?

发布于 2024-12-20 20:53:41 字数 86 浏览 2 评论 0原文

基本上,我有一个代理列表。我想将它们分为 SOCKS4 和 SOCKS5。我想编写一个小型 PHP 脚本来为我完成此任务。我将如何在 PHP 中检测它的类型?

Basically, I have a list of proxies. I'm wanting to separate them into SOCKS4 and SOCKS5. I'd like to code up a small PHP script to do this for me. How would I go about detecting which type it is in PHP?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

只为守护你 2024-12-27 20:53:42

我认为您能做的最好的事情就是首先尝试通过尝试最高版本 - 5 来建立 CURL 连接。

  curl_setopt($curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);

无论哪种方式,这都会给您答案。执行后检查curl_error。如果没有错误,则您使用的是 SOCKS5,否则您使用的是 SOCKS4。

I think the best you can do is to first try to establish a CURL connection by trying the highest version - 5.

  curl_setopt($curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);

This will give you the answer either way. Check curl_error after you execute it. If there is no error, you are using SOCKS5, else you are using SOCKS4.

世俗缘 2024-12-27 20:53:42

根据 RFC1928,要建立 SOCKS 连接,首先将这些字节发送到服务器:

1 byte      SOCKS version
1 byte      Number of authentication methods (n)
n bytes     List of method identifiers

服务器响应:

1 byte      SOCKS version
1 byte      Accepted method

这在 SOCKS 的第 4 版和第 5 版之间很常见。因此,您可以从一个版本(例如 5)开始,如果服务器没有相应响应,则回退到另一个版本。

According to RFC1928, for establishing a SOCKS connection you start by sending these bytes to the server:

1 byte      SOCKS version
1 byte      Number of authentication methods (n)
n bytes     List of method identifiers

And server responds with

1 byte      SOCKS version
1 byte      Accepted method

This is common between both 4th and 5th versions of SOCKS. So you can start by one version (5, for example) and fall back to another version if server doesn't respond accordingly.

我恋#小黄人 2024-12-27 20:53:41

您需要自己编写一些小代码来尝试连接任何代理并检查袜子版本。不同版本的连接协议和错误代码记录在有关 SOCKS 的维基百科页面上。

考虑到这一点,剩下的或多或少是与 PHP 的标准套接字连接。

示例:

$proxies = array( '66.135.131.74:1681', '172.52.61.244:48943',
                  '75.101.237.217:1080', '76.68.128.165:39879',);

foreach ($proxies as $index => $proxy)
{
    $type = SOCKSVersion::getType($proxy);
    $typeName = SOCKSVersion::getTypeName($type);
    printf("Proxy #%d: %s\n", $index, $typeName);
}

输出:

Proxy #0: SOCKS4
Proxy #1: SOCKS4
Proxy #2: Unknown
Proxy #3: SOCKS4

此示例性实现仅检查 SOCKS4,但可以通过添加类似于 isSocks4() 的方法轻松扩展以测试 SOCK4a 和 SOCKS5:

/**
 * SOCKS server identifiation class.
 */
class SOCKSVersion
{
    const TYPE_UNKNOWN = 0;
    const TYPE_SOCKS4 = 1;
    const TYPE_SOCKS4a = 2;
    const TYPE_SOCKS5 = 3;

    /**
     * @var string[]
     */
    private static $typeNames = array(
        self::TYPE_UNKNOWN => 'Unknown',
        self::TYPE_SOCKS4 => 'SOCKS4',
        self::TYPE_SOCKS4a => 'SOCKS4a',
        self::TYPE_SOCKS5 => 'SOCKS5',
    );

    /**
     * @var int
     */
    private $timeout = 30;

    /**
     * @var int
     */
    private $host, $port;

    /**
     * @var string[]
     */
    private $errors;

    /**
     * @var string[]
     */
    private $socks4Errors = array(
        91 => "Request rejected or failed",
        92 => "Request failed because client is not running identd (or not reachable from the server)",
        93 => "Request failed because client's identd could not confirm the user ID string in the request",
    );

    public function __construct($endpoint)
    {
        $this->setEndpoint($endpoint);
    }

    /**
     * @static
     * @param string $proxy
     * @return int any of the TYPE_* constants
     */
    public static function getType($proxy)
    {
        $socks = new self($proxy);
        return $socks->getSocksVersion();
    }

    /**
     * @static
     * @param int $type
     * @return string
     */
    public static function getTypeName($type)
    {
        $typeNames = self::$typeNames;
        if (isset($typeNames[$type])) {
            return $typeNames[$type];
        }
        return $typeNames[self::TYPE_UNKNOWN];
    }

    public function setEndpoint($endpoint)
    {
        if (!$parts = parse_url('http://' . $endpoint)) {
            throw new InvalidArgumentException(sprintf('Unable to parse endpoint "%s".', $endpoint));
        }
        if (empty($parts['host'])) {
            throw new InvalidArgumentException('No host given.');
        }
        if (empty($parts['port'])) {
            throw new InvalidArgumentException('No port given.');
        }
        $this->host = $parts['host'];
        $this->port = $parts['port'];
    }

    /**
     * @return int any of the TYPE_* constants
     */
    public function getSocksVersion()
    {
        try {
            if ($this->isSocks4()) {
                return self::TYPE_SOCKS4;
            }
        } catch (BadFunctionCallException $e) {
            $this->errors[] = sprintf("SOCKS4 Test: ", $this->host, $e->getMessage());
        }
        return self::TYPE_UNKNOWN;
    }

    public function isSocks4()
    {
        $socket = stream_socket_client("tcp://" . $this->host . ":" . $this->port, $errno, $errstr, $this->timeout, STREAM_CLIENT_CONNECT);
        if (!$socket) {
            throw new BadFunctionCallException(sprintf('Socket-Error #%d: %s', $errno, $errstr));
        }

        // SOCKS4; @link <http://en.wikipedia.org/wiki/SOCKS#Protocol>
        $userId = "";
        $packet = "\x04\x01" . pack("n", $this->port) . pack("H*", dechex(ip2long($this->host))) . $userId . "\0";
        fwrite($socket, $packet, strlen($packet));
        $response = fread($socket, 9);
        if (strlen($response) == 8 && (ord($response[0]) == 0 || ord($response[0]) == 4)) {
            $status = ord($response[1]);
            if ($status != 90) {
                throw new BadFunctionCallException(sprintf("Error from SOCKS4 server: %s.", $this->socks4Errors[$status]));
            }
        } else {
            throw new BadFunctionCallException("The SOCKS server returned an invalid response");
        }
        fclose($socket);

        return TRUE;
    }
}

希望这会有所帮助。如果引入多个版本,则应该改进错误处理,并且如果在之前的测试中连接失败,则不要多次连接到同一主机。

You need to write yourself some little code that tries to connect with any of your proxies and inspect the socks version. Connection protocol for the different versions and error codes are documented on the wikipedia page about SOCKS.

Taking that into account, the rest is more or less standard socket connection with PHP.

Example:

$proxies = array( '66.135.131.74:1681', '172.52.61.244:48943',
                  '75.101.237.217:1080', '76.68.128.165:39879',);

foreach ($proxies as $index => $proxy)
{
    $type = SOCKSVersion::getType($proxy);
    $typeName = SOCKSVersion::getTypeName($type);
    printf("Proxy #%d: %s\n", $index, $typeName);
}

Output:

Proxy #0: SOCKS4
Proxy #1: SOCKS4
Proxy #2: Unknown
Proxy #3: SOCKS4

This exemplary implementation does only check for SOCKS4 so, but it could be easily extended to test as well for SOCK4a and SOCKS5 by adding methods similar to isSocks4():

/**
 * SOCKS server identifiation class.
 */
class SOCKSVersion
{
    const TYPE_UNKNOWN = 0;
    const TYPE_SOCKS4 = 1;
    const TYPE_SOCKS4a = 2;
    const TYPE_SOCKS5 = 3;

    /**
     * @var string[]
     */
    private static $typeNames = array(
        self::TYPE_UNKNOWN => 'Unknown',
        self::TYPE_SOCKS4 => 'SOCKS4',
        self::TYPE_SOCKS4a => 'SOCKS4a',
        self::TYPE_SOCKS5 => 'SOCKS5',
    );

    /**
     * @var int
     */
    private $timeout = 30;

    /**
     * @var int
     */
    private $host, $port;

    /**
     * @var string[]
     */
    private $errors;

    /**
     * @var string[]
     */
    private $socks4Errors = array(
        91 => "Request rejected or failed",
        92 => "Request failed because client is not running identd (or not reachable from the server)",
        93 => "Request failed because client's identd could not confirm the user ID string in the request",
    );

    public function __construct($endpoint)
    {
        $this->setEndpoint($endpoint);
    }

    /**
     * @static
     * @param string $proxy
     * @return int any of the TYPE_* constants
     */
    public static function getType($proxy)
    {
        $socks = new self($proxy);
        return $socks->getSocksVersion();
    }

    /**
     * @static
     * @param int $type
     * @return string
     */
    public static function getTypeName($type)
    {
        $typeNames = self::$typeNames;
        if (isset($typeNames[$type])) {
            return $typeNames[$type];
        }
        return $typeNames[self::TYPE_UNKNOWN];
    }

    public function setEndpoint($endpoint)
    {
        if (!$parts = parse_url('http://' . $endpoint)) {
            throw new InvalidArgumentException(sprintf('Unable to parse endpoint "%s".', $endpoint));
        }
        if (empty($parts['host'])) {
            throw new InvalidArgumentException('No host given.');
        }
        if (empty($parts['port'])) {
            throw new InvalidArgumentException('No port given.');
        }
        $this->host = $parts['host'];
        $this->port = $parts['port'];
    }

    /**
     * @return int any of the TYPE_* constants
     */
    public function getSocksVersion()
    {
        try {
            if ($this->isSocks4()) {
                return self::TYPE_SOCKS4;
            }
        } catch (BadFunctionCallException $e) {
            $this->errors[] = sprintf("SOCKS4 Test: ", $this->host, $e->getMessage());
        }
        return self::TYPE_UNKNOWN;
    }

    public function isSocks4()
    {
        $socket = stream_socket_client("tcp://" . $this->host . ":" . $this->port, $errno, $errstr, $this->timeout, STREAM_CLIENT_CONNECT);
        if (!$socket) {
            throw new BadFunctionCallException(sprintf('Socket-Error #%d: %s', $errno, $errstr));
        }

        // SOCKS4; @link <http://en.wikipedia.org/wiki/SOCKS#Protocol>
        $userId = "";
        $packet = "\x04\x01" . pack("n", $this->port) . pack("H*", dechex(ip2long($this->host))) . $userId . "\0";
        fwrite($socket, $packet, strlen($packet));
        $response = fread($socket, 9);
        if (strlen($response) == 8 && (ord($response[0]) == 0 || ord($response[0]) == 4)) {
            $status = ord($response[1]);
            if ($status != 90) {
                throw new BadFunctionCallException(sprintf("Error from SOCKS4 server: %s.", $this->socks4Errors[$status]));
            }
        } else {
            throw new BadFunctionCallException("The SOCKS server returned an invalid response");
        }
        fclose($socket);

        return TRUE;
    }
}

Hope this is helpful. If you introduce multiple versions, you should improve the error handling and don't connect more than once to the same host if the connection failed in a previous test.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文