I'm trying to establish a SOCKS 5 connection (to a tor proxy) in my code but my connection request (after greeting and auth method choose) is completely malformed for some reason.
I tried using gdb to look at values in-memory but that looks fine. also tried printing info to console which gave me nothing too.
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;
}
boost::asio::write(socket, socks_request.conn(socks5::request::connect, socks5::addr_type::Domain, hostname, port));
we can split this code into:
[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);
in conn
we have a lot local variables, which are passed into boost::asio::buffer
. What does buffer
do ? It returns wrapper for data details here, which consists of pointer to data
and length of data. No data are copied. So when conn
ends, you have vector of buffers which refer to data which was destroyed - undefined behaviour.
You need to find new approach to send data, or provide that data are valid when boost::asio::write
uses buffer to them.