尝试使用 boost::asio 连接到 SOCKS 5 服务器,但我的连接请求格式错误

Trying to connect to a SOCKS 5 server using boost::asio but my connection request turns out malformed

我正在尝试在我的代码中建立一个 SOCKS 5 连接(到 Tor 代理),但我的连接请求(在选择问候语和身份验证方法之后)由于某种原因完全不正确。

我尝试使用 gdb 查看内存中的值,但看起来不错。还尝试将信息打印到控制台,但也没有给我任何帮助。

(洋葱站地址只是一个例子)

main.cpp https://pastebin.com/zjHb7vg3

socks5.hpp https://pastebin.com/pksnqmfa 或者只是创建数据包的函数

std::vector<boost::asio::const_buffer> conn(unsigned char cmd, unsigned char type, std::string hostname, int port) {
            int cmd_ = 0x04;
            int type_ = 0x03;
            std::vector<boost::asio::const_buffer> buffers = {
                //{
                    boost::asio::buffer(&version, 1),
                    boost::asio::buffer(&cmd_, 1),
                    boost::asio::buffer(&null_byte, 1),
                    boost::asio::buffer(&type_, 1)
                //}
            };

            std::cout << "Conn:" << cmd << std::endl << "type:" << type << std::endl;

            if (type_ == IPv4) {
                int byte1=0x5d, byte2=0xb8, byte3=0xd8, byte4=0x22;
                char dot;
                std::istringstream s(hostname);  // input stream that now contains the ip address string

                //s >> byte1 >> dot >> byte2 >> dot >> byte3 >> dot >> byte4 >> dot;
                // buffers.push_back(boost::asio::buffer({
                //     (unsigned char)byte1,
                //     (unsigned char)byte2,
                //     (unsigned char)byte3,
                //     (unsigned char)byte4
                // }));
                buffers.push_back(boost::asio::buffer(&byte1, 1));    
                buffers.push_back(boost::asio::buffer(&byte2, 1));            
                buffers.push_back(boost::asio::buffer(&byte3, 1));            
                buffers.push_back(boost::asio::buffer(&byte4, 1));            

            } else if (type_ == IPv6) {
                int byte1,
                    byte2,
                    byte3,
                    byte4,
                    byte5,
                    byte6,
                    byte7,
                    byte8,
                    byte9,
                    byte10,
                    byte11,
                    byte12,
                    byte13,
                    byte14,
                    byte15,
                    byte16;
                char sep;
                std::istringstream s(hostname);  // input stream that now contains the ip address string

                s >> 
                    byte1 >> sep >>
                    byte2 >> sep >>
                    byte3 >> sep >>
                    byte4 >> sep >>
                    byte5 >> sep >>
                    byte6 >> sep >>
                    byte7 >> sep >>
                    byte8 >> sep >>
                    byte9 >> sep >>
                    byte10 >> sep >>
                    byte11 >> sep >>
                    byte12 >> sep >>
                    byte13 >> sep >>
                    byte14 >> sep >>
                    byte15 >> sep >>
                    byte16;

                buffers.push_back(boost::asio::buffer({
                    (unsigned char)byte1,
                    (unsigned char)byte2,
                    (unsigned char)byte3,
                    (unsigned char)byte4,
                    (unsigned char)byte5,
                    (unsigned char)byte6,
                    (unsigned char)byte7,
                    (unsigned char)byte8,
                    (unsigned char)byte9,
                    (unsigned char)byte10,
                    (unsigned char)byte11,
                    (unsigned char)byte12,
                    (unsigned char)byte13,
                    (unsigned char)byte14,
                    (unsigned char)byte15,
                    (unsigned char)byte16
                }));
            } else if (type_ == Domain) {
                int hostnameLen = hostname.length();
                buffers.push_back(boost::asio::buffer(&hostnameLen, 1));
                buffers.push_back(boost::asio::buffer(hostname, 255));

                std::cout << hostnameLen << std::endl << hostname << std::endl;
            }

            unsigned char port_high_byte_ = (port >> 8) & 0xff;
            unsigned char port_low_byte_ = port & 0xff;

            buffers.push_back(boost::asio::buffer(&port_high_byte_, 1));
            buffers.push_back(boost::asio::buffer(&port_low_byte_, 1));

            std::cout << buffers[0].data();
            return buffers;
        }            

};

class reply {

    private:
        int hostnameLen;
        int hostname;
        int port_nbo;

        enum state {
            AUTH_CHOICE = 0,
            PASSWORD = 1,
            CONNECT = 2
        };

        state state;

    public:

        unsigned char ver;
        unsigned char auth;
        unsigned char auth_ver;
        unsigned char status_;
        addr_type type;

        bool success() {
            return ver == version &&
                (state == AUTH_CHOICE ? state == NO_AUTH || state == PASSWORD : true) &&
                (state == PASSWORD ? status_ == 0x00 : true) &&
                (state == CONNECT ? status_ == 0x00 : true);
        }

        std::string status() const {
            if (state == AUTH_CHOICE) {
                if (auth == 0xFF) {
                    return "No acceptable auth methods";
                }
            } else if (state == PASSWORD) {
                return status_ == 0x00 ? "Auth success" : "Auth error: "+std::to_string(status_);
            } else if (state == CONNECT) {
                return status_ == 0x00 ? "Connect success" : "Connect error: "+std::to_string(status_);
            }
            return "";
        }

        std::array<boost::asio::mutable_buffer, 5> auth_choice() {
            state = AUTH_CHOICE;
            return {
                {
                    boost::asio::buffer(&ver, 1),
                    boost::asio::buffer(&auth, 1)
                }
            };
        }

        std::array<boost::asio::mutable_buffer, 5> password_verif() {
            state = PASSWORD;
            return {
                {
                    boost::asio::buffer(&auth_ver, 1),
                    boost::asio::buffer(&status_, 1)
                }
            };
        }

        std::vector<boost::asio::mutable_buffer> connect_reply() {
            state = CONNECT;
            std::vector<boost::asio::mutable_buffer> buffers = {
                {
                    boost::asio::buffer(&ver, 1),
                    boost::asio::buffer(&status_, 1),
                    boost::asio::buffer(&null_byte, 1),
                    boost::asio::buffer(&type, 1)
                }
            };

            if (type == IPv4) {
                buffers.push_back(boost::asio::buffer(&hostname, 4));
            } else if (type == IPv6) {
                buffers.push_back(boost::asio::buffer(&hostname, 16));
            } else if (type == Domain) {
                buffers.push_back(boost::asio::buffer(&hostnameLen, 1));
                buffers.push_back(boost::asio::buffer(&hostname, 255));
            }

            buffers.push_back(boost::asio::buffer(&port_nbo, 2));

            return buffers;
        }         

wireshark 捕获:(使用视图过滤器"socks") https://quickfileshare.org/1Kjr/socks-capture.pcapng

boost::asio::write(socket, socks_request.conn(socks5::request::connect, socks5::addr_type::Domain, hostname, port));

我们可以将这段代码拆分成:

[1] get buffers
std::vector<boost::asio::const_buffer> buffs = 
socks_request.conn(socks5::request::connect, socks5::addr_type::Domain, hostname, port);
[2] send data
boost::asio::write(socket, buffs);

conn中我们有很多局部变量,它们被传递到boost::asio::buffer中。 buffer 是做什么的?它 returns 数据 details here 的包装器,由 pointer to data 和数据长度组成。 没有数据被复制。因此,当 conn 结束时,您将获得缓冲区向量,这些缓冲区指向被破坏的数据 - 未定义的行为。

您需要找到发送数据的新方法,或者在 boost::asio::write 使用缓冲区时提供数据有效。