Script PHP para Verificar UDP em Proxy SOCKS5

Testes comuns via navegador ou conexões padrão via proxy SOCKS5 avaliam apenas conexões TCP. O fato de um provedor suportar SOCKS5 não garante que o tráfego UDP esteja funcional — um recurso essencial para chamadas de voz (Telegram, Discord), streaming e jogos online.

Este script PHP via linha de comando verifica não apenas o comando UDP ASSOCIATE, mas também a transmissão real de pacotes UDP: ele conecta ao proxy, realiza a autenticação, obtém o endereço do relay UDP e envia uma consulta DNS real para 1.1.1.1:53.

Execução do script no terminal:

  1. Baixe o script e abra-o para inserir suas credenciais:
wget https://dieg.net/scripts/socks5-udp-check.php
nano socks5-udp-check.php
  1. Defina o endereço do proxy, porta, usuário e senha nas variáveis $proxy, $port, $user e $pass.
  2. Execute a verificação: php socks5-udp-check.php. Se a transmissão de pacotes for bem-sucedida, o script retornará: [OK] UDP is working: DNS response received through SOCKS5.

Código-fonte:

socks5-udp-check.php [ Raw / Download ]
php <<'PHP'
<?php
$proxy = "accel.ipflygates.com";
$port = 5001;
$user = "USERNAME";
$pass = "PASSWORD";

function readExact($s, $n) {
    $data = "";
    while (strlen($data) < $n) {
        $part = fread($s, $n - strlen($data));
        if ($part === false || $part === "") {
            throw new Exception("Incomplete TCP response or timeout");
        }
        $data .= $part;
    }
    return $data;
}

function readAddress($s, $type) {
    switch ($type) {
        case 1: return inet_ntop(readExact($s, 4));
        case 3: return readExact($s, ord(readExact($s, 1)));
        case 4: return inet_ntop(readExact($s, 16));
        default: throw new Exception("Unknown address type");
    }
}

try {
    $tcp = @stream_socket_client("tcp://$proxy:$port", $errno, $errstr, 5);
    if (!$tcp) throw new Exception("TCP: $errstr");
    stream_set_timeout($tcp, 5);

    fwrite($tcp, "\x05\x01\x02");
    if (readExact($tcp, 2) !== "\x05\x02") {
        throw new Exception("Server did not select username/password authentication");
    }
    fwrite($tcp, "\x01".chr(strlen($user)).$user.chr(strlen($pass)).$pass);
    if (readExact($tcp, 2) !== "\x01\x00") {
        throw new Exception("Authentication failed");
    }

    fwrite($tcp, "\x05\x03\x00\x01".str_repeat("\x00", 6));
    $h = readExact($tcp, 4);
    if ($h[0] !== "\x05" || $h[2] !== "\x00") {
        throw new Exception("Invalid SOCKS5 response");
    }
    if (ord($h[1]) !== 0) {
        throw new Exception("UDP ASSOCIATE: reply code ".ord($h[1]));
    }

    $relay = readAddress($tcp, ord($h[3]));
    $relayPort = unpack("n", readExact($tcp, 2))[1];
    if ($relay === "0.0.0.0" || $relay === "::") {
        $peer = stream_socket_get_name($tcp, true);
        $relay = trim(substr($peer, 0, strrpos($peer, ":")), "[]");
    }
    if (!$relayPort) throw new Exception("Server returned UDP port zero");

    $host = strpos($relay, ":") !== false ? "[$relay]" : $relay;
    $udp = @stream_socket_client("udp://$host:$relayPort", $errno, $errstr, 5);
    if (!$udp) throw new Exception("UDP: $errstr");
    stream_set_timeout($udp, 5);

    // DNS A query for example.com sent through the UDP relay to 1.1.1.1:53.
    $id = random_bytes(2);
    $dns = $id.pack("nnnnn", 0x0100, 1, 0, 0, 0)
         . "\x07example\x03com\x00".pack("nn", 1, 1);
    $packet = "\x00\x00\x00\x01".inet_pton("1.1.1.1").pack("n", 53).$dns;

    fwrite($udp, $packet);
    $reply = fread($udp, 4096);
    if ($reply === false || strlen($reply) < 4) {
        throw new Exception("No UDP response: UDP data transfer not confirmed");
    }
    if (substr($reply, 0, 3) !== "\x00\x00\x00") {
        throw new Exception("Invalid SOCKS5 UDP header or fragmented datagram");
    }

    $type = ord($reply[3]);
    switch ($type) {
        case 1: $offset = 10; break;
        case 4: $offset = 22; break;
        case 3:
            if (strlen($reply) < 5) throw new Exception("Response too short");
            $offset = 7 + ord($reply[4]);
            break;
        default: throw new Exception("Unknown UDP address type");
    }
    $answer = substr($reply, $offset);
    if (strlen($answer) < 12 || substr($answer, 0, 2) !== $id
        || !(ord($answer[2]) & 0x80)) {
        throw new Exception("No matching DNS response received");
    }

    echo "[OK] UDP is working: DNS response received through SOCKS5.\n";
} catch (Throwable $e) {
    echo "[FAIL] ".$e->getMessage()."\n";
    exit(1);
}
PHP