| 118 | } |
| 119 | |
| 120 | td::Status wait_request() { |
| 121 | auto buf = pipe_.input_buffer().clone(); |
| 122 | TRY_RESULT(header, read(buf, 4)); |
| 123 | td::uint8 version = header[0]; |
| 124 | td::uint8 cmd = header[1]; |
| 125 | td::uint8 address_type = header[3]; |
| 126 | if (version != 0x5) { |
| 127 | return td::Status::Error(PSLICE() << "Invalid socks5 request version " << version << ", expected 0x5"); |
| 128 | } |
| 129 | if (cmd != 0x1) { |
| 130 | return td::Status::Error(PSLICE() << "Unsupported socks5 command " << cmd); |
| 131 | } |
| 132 | std::string host; |
| 133 | if (address_type == 1) { // ipv4 |
| 134 | TRY_RESULT(ipv4, read(buf, 4)); |
| 135 | host = PSTRING() << int(td::uint8(ipv4[0])) << "." << int(td::uint8(ipv4[1])) << "." << int(td::uint8(ipv4[2])) |
| 136 | << "." << int(td::uint8(ipv4[3])); |
| 137 | } else if (address_type == 3) { // host |
| 138 | return td::Status::Error("TODO: support host destination in socks5"); |
| 139 | } else if (address_type == 4) { // ipv6 |
| 140 | return td::Status::Error("TODO: support ipv6 destination in socks5"); |
| 141 | } else { |
| 142 | return td::Status::Error(PSLICE() << "Unsupported address type=" << address_type); |
| 143 | } |
| 144 | TRY_RESULT(port_raw, read(buf, 2)); |
| 145 | pipe_.input_buffer() = std::move(buf); |
| 146 | |
| 147 | td::int32 port = td::uint8(port_raw[0]) * 256 + td::uint8(port_raw[1]); |
| 148 | TRY_STATUS(destination_.init_host_port(host, port)); |
| 149 | LOG(INFO) << "Connect " << destination_; |
| 150 | TRY_RESULT(socket, td::SocketFd::open(destination_)); |
| 151 | td::IPAddress bound_address; |
| 152 | TRY_STATUS(bound_address.init_socket_address(socket)); |
| 153 | auto bound_port = bound_address.get_port(); |
| 154 | |
| 155 | td::string response; |
| 156 | response += '\x05'; |
| 157 | response += '\x00'; |
| 158 | response += '\x00'; |
| 159 | if (bound_address.is_ipv4()) { |
| 160 | response += '\x01'; |
| 161 | auto ipv4 = ntohl(bound_address.get_ipv4()); |
| 162 | response += static_cast<char>(ipv4 & 255); |
| 163 | response += static_cast<char>((ipv4 >> 8) & 255); |
| 164 | response += static_cast<char>((ipv4 >> 16) & 255); |
| 165 | response += static_cast<char>((ipv4 >> 24) & 255); |
| 166 | } else { |
| 167 | response += '\x04'; |
| 168 | response += bound_address.get_ipv6(); |
| 169 | } |
| 170 | response += static_cast<char>((bound_port >> 8) & 255); |
| 171 | response += static_cast<char>(bound_port & 255); |
| 172 | |
| 173 | pipe_.output_buffer().append(response); |
| 174 | dest_pipe_ = make_socket_pipe(std::move(socket)); |
| 175 | state_ = State::Done; |
| 176 | return td::Status::OK(); |
| 177 | } |
nothing calls this directly
no outgoing calls
no test coverage detected