mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-12 21:30:45 +01:00
Remove SOCKS5 support
Bug: webrtc:15726 Change-Id: Icd3aca433966f76e1b200b0f4790013cce12095a Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/331820 Reviewed-by: Tomas Gunnarsson <tommi@webrtc.org> Commit-Queue: Harald Alvestrand <hta@webrtc.org> Cr-Commit-Position: refs/heads/main@{#41655}
This commit is contained in:
parent
c1cc6a36b2
commit
b5f2b17fd8
10 changed files with 14 additions and 537 deletions
|
@ -119,11 +119,7 @@ AsyncPacketSocket* BasicPacketSocketFactory::CreateClientTcpSocket(
|
|||
<< socket->GetError();
|
||||
}
|
||||
|
||||
// If using a proxy, wrap the socket in a proxy socket.
|
||||
if (proxy_info.type == PROXY_SOCKS5) {
|
||||
socket = new AsyncSocksProxySocket(
|
||||
socket, proxy_info.address, proxy_info.username, proxy_info.password);
|
||||
} else if (proxy_info.type == PROXY_HTTPS) {
|
||||
if (proxy_info.type == PROXY_HTTPS) {
|
||||
socket =
|
||||
new AsyncHttpsProxySocket(socket, user_agent, proxy_info.address,
|
||||
proxy_info.username, proxy_info.password);
|
||||
|
|
|
@ -286,14 +286,6 @@ class P2PTransportChannelTestBase : public ::testing::Test,
|
|||
main_(ss_.get()),
|
||||
stun_server_(TestStunServer::Create(ss_.get(), kStunAddr, main_)),
|
||||
turn_server_(&main_, ss_.get(), kTurnUdpIntAddr, kTurnUdpExtAddr),
|
||||
socks_server1_(ss_.get(),
|
||||
kSocksProxyAddrs[0],
|
||||
ss_.get(),
|
||||
kSocksProxyAddrs[0]),
|
||||
socks_server2_(ss_.get(),
|
||||
kSocksProxyAddrs[1],
|
||||
ss_.get(),
|
||||
kSocksProxyAddrs[1]),
|
||||
force_relay_(false) {
|
||||
ep1_.role_ = ICEROLE_CONTROLLING;
|
||||
ep2_.role_ = ICEROLE_CONTROLLED;
|
||||
|
@ -330,7 +322,6 @@ class P2PTransportChannelTestBase : public ::testing::Test,
|
|||
BLOCK_UDP_AND_INCOMING_TCP, // Firewall, UDP in/out and TCP in blocked
|
||||
BLOCK_ALL_BUT_OUTGOING_HTTP, // Firewall, only TCP out on 80/443
|
||||
PROXY_HTTPS, // All traffic through HTTPS proxy
|
||||
PROXY_SOCKS, // All traffic through SOCKS proxy
|
||||
NUM_CONFIGS
|
||||
};
|
||||
|
||||
|
@ -1028,8 +1019,6 @@ class P2PTransportChannelTestBase : public ::testing::Test,
|
|||
PendingTaskSafetyFlag::Create();
|
||||
TestStunServer::StunServerPtr stun_server_;
|
||||
TestTurnServer turn_server_;
|
||||
rtc::SocksProxyServer socks_server1_;
|
||||
rtc::SocksProxyServer socks_server2_;
|
||||
Endpoint ep1_;
|
||||
Endpoint ep2_;
|
||||
RemoteIceParameterSource remote_ice_parameter_source_ = FROM_CANDIDATE;
|
||||
|
@ -1179,7 +1168,6 @@ class P2PTransportChannelTest : public P2PTransportChannelTestBase {
|
|||
case BLOCK_UDP_AND_INCOMING_TCP:
|
||||
case BLOCK_ALL_BUT_OUTGOING_HTTP:
|
||||
case PROXY_HTTPS:
|
||||
case PROXY_SOCKS:
|
||||
AddAddress(endpoint, kPublicAddrs[endpoint]);
|
||||
// Block all UDP
|
||||
fw()->AddRule(false, rtc::FP_UDP, rtc::FD_ANY, kPublicAddrs[endpoint]);
|
||||
|
@ -1202,13 +1190,6 @@ class P2PTransportChannelTest : public P2PTransportChannelTestBase {
|
|||
fw()->AddRule(false, rtc::FP_TCP, rtc::FD_ANY,
|
||||
kPublicAddrs[endpoint]);
|
||||
SetProxy(endpoint, rtc::PROXY_HTTPS);
|
||||
} else if (config == PROXY_SOCKS) {
|
||||
// Block all TCP to/from the endpoint except to the proxy server
|
||||
fw()->AddRule(true, rtc::FP_TCP, kPublicAddrs[endpoint],
|
||||
kSocksProxyAddrs[endpoint]);
|
||||
fw()->AddRule(false, rtc::FP_TCP, rtc::FD_ANY,
|
||||
kPublicAddrs[endpoint]);
|
||||
SetProxy(endpoint, rtc::PROXY_SOCKS5);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -1253,42 +1234,28 @@ class P2PTransportChannelMatrixTest : public P2PTransportChannelTest,
|
|||
const P2PTransportChannelMatrixTest::Result*
|
||||
P2PTransportChannelMatrixTest::kMatrix[NUM_CONFIGS][NUM_CONFIGS] = {
|
||||
// OPEN CONE ADDR PORT SYMM 2CON SCON !UDP !TCP HTTP PRXH
|
||||
// PRXS
|
||||
/*OP*/ {LULU, LUSU, LUSU, LUSU, LUPU, LUSU, LUPU, LTPT, LTPT, LSRS,
|
||||
NULL, LTPT},
|
||||
/*OP*/
|
||||
{LULU, LUSU, LUSU, LUSU, LUPU, LUSU, LUPU, LTPT, LTPT, LSRS, NULL},
|
||||
/*CO*/
|
||||
{SULU, SUSU, SUSU, SUSU, SUPU, SUSU, SUPU, NULL, NULL, LSRS, NULL,
|
||||
LTRT},
|
||||
{SULU, SUSU, SUSU, SUSU, SUPU, SUSU, SUPU, NULL, NULL, LSRS, NULL},
|
||||
/*AD*/
|
||||
{SULU, SUSU, SUSU, SUSU, SUPU, SUSU, SUPU, NULL, NULL, LSRS, NULL,
|
||||
LTRT},
|
||||
{SULU, SUSU, SUSU, SUSU, SUPU, SUSU, SUPU, NULL, NULL, LSRS, NULL},
|
||||
/*PO*/
|
||||
{SULU, SUSU, SUSU, SUSU, RUPU, SUSU, RUPU, NULL, NULL, LSRS, NULL,
|
||||
LTRT},
|
||||
{SULU, SUSU, SUSU, SUSU, RUPU, SUSU, RUPU, NULL, NULL, LSRS, NULL},
|
||||
/*SY*/
|
||||
{PULU, PUSU, PUSU, PURU, PURU, PUSU, PURU, NULL, NULL, LSRS, NULL,
|
||||
LTRT},
|
||||
{PULU, PUSU, PUSU, PURU, PURU, PUSU, PURU, NULL, NULL, LSRS, NULL},
|
||||
/*2C*/
|
||||
{SULU, SUSU, SUSU, SUSU, SUPU, SUSU, SUPU, NULL, NULL, LSRS, NULL,
|
||||
LTRT},
|
||||
{SULU, SUSU, SUSU, SUSU, SUPU, SUSU, SUPU, NULL, NULL, LSRS, NULL},
|
||||
/*SC*/
|
||||
{PULU, PUSU, PUSU, PURU, PURU, PUSU, PURU, NULL, NULL, LSRS, NULL,
|
||||
LTRT},
|
||||
{PULU, PUSU, PUSU, PURU, PURU, PUSU, PURU, NULL, NULL, LSRS, NULL},
|
||||
/*!U*/
|
||||
{LTPT, NULL, NULL, NULL, NULL, NULL, NULL, LTPT, LTPT, LSRS, NULL,
|
||||
LTRT},
|
||||
{LTPT, NULL, NULL, NULL, NULL, NULL, NULL, LTPT, LTPT, LSRS, NULL},
|
||||
/*!T*/
|
||||
{PTLT, NULL, NULL, NULL, NULL, NULL, NULL, PTLT, LTRT, LSRS, NULL,
|
||||
LTRT},
|
||||
{PTLT, NULL, NULL, NULL, NULL, NULL, NULL, PTLT, LTRT, LSRS, NULL},
|
||||
/*HT*/
|
||||
{LSRS, LSRS, LSRS, LSRS, LSRS, LSRS, LSRS, LSRS, LSRS, LSRS, NULL,
|
||||
LSRS},
|
||||
{LSRS, LSRS, LSRS, LSRS, LSRS, LSRS, LSRS, LSRS, LSRS, LSRS, NULL},
|
||||
/*PR*/
|
||||
{NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
||||
NULL},
|
||||
/*PR*/
|
||||
{LTRT, LTRT, LTRT, LTRT, LTRT, LTRT, LTRT, LTRT, LTRT, LSRS, NULL,
|
||||
LTRT},
|
||||
{NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
|
||||
};
|
||||
|
||||
// The actual tests that exercise all the various configurations.
|
||||
|
@ -1316,8 +1283,7 @@ const P2PTransportChannelMatrixTest::Result*
|
|||
P2P_TEST(x, BLOCK_UDP) \
|
||||
P2P_TEST(x, BLOCK_UDP_AND_INCOMING_TCP) \
|
||||
P2P_TEST(x, BLOCK_ALL_BUT_OUTGOING_HTTP) \
|
||||
P2P_TEST(x, PROXY_HTTPS) \
|
||||
P2P_TEST(x, PROXY_SOCKS)
|
||||
P2P_TEST(x, PROXY_HTTPS)
|
||||
|
||||
P2P_TEST_SET(OPEN)
|
||||
P2P_TEST_SET(NAT_FULL_CONE)
|
||||
|
@ -1330,7 +1296,6 @@ P2P_TEST_SET(BLOCK_UDP)
|
|||
P2P_TEST_SET(BLOCK_UDP_AND_INCOMING_TCP)
|
||||
P2P_TEST_SET(BLOCK_ALL_BUT_OUTGOING_HTTP)
|
||||
P2P_TEST_SET(PROXY_HTTPS)
|
||||
P2P_TEST_SET(PROXY_SOCKS)
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
All,
|
||||
|
|
|
@ -2088,7 +2088,6 @@ if (rtc_include_tests) {
|
|||
"nat_unittest.cc",
|
||||
"network_route_unittest.cc",
|
||||
"network_unittest.cc",
|
||||
"proxy_unittest.cc",
|
||||
"rolling_accumulator_unittest.cc",
|
||||
"rtc_certificate_generator_unittest.cc",
|
||||
"rtc_certificate_unittest.cc",
|
||||
|
|
|
@ -149,8 +149,4 @@ void ProxyBinding::Destroy() {
|
|||
SignalDestroyed(this);
|
||||
}
|
||||
|
||||
AsyncProxyServerSocket* SocksProxyServer::WrapSocket(Socket* socket) {
|
||||
return new AsyncSocksProxyServerSocket(socket);
|
||||
}
|
||||
|
||||
} // namespace rtc
|
||||
|
|
|
@ -89,22 +89,6 @@ class ProxyServer : public sigslot::has_slots<> {
|
|||
std::vector<std::unique_ptr<ProxyBinding>> bindings_;
|
||||
};
|
||||
|
||||
// SocksProxyServer is a simple extension of ProxyServer to implement SOCKS.
|
||||
class SocksProxyServer : public ProxyServer {
|
||||
public:
|
||||
SocksProxyServer(SocketFactory* int_factory,
|
||||
const SocketAddress& int_addr,
|
||||
SocketFactory* ext_factory,
|
||||
const SocketAddress& ext_ip)
|
||||
: ProxyServer(int_factory, int_addr, ext_factory, ext_ip) {}
|
||||
|
||||
SocksProxyServer(const SocksProxyServer&) = delete;
|
||||
SocksProxyServer& operator=(const SocksProxyServer&) = delete;
|
||||
|
||||
protected:
|
||||
AsyncProxyServerSocket* WrapSocket(Socket* socket) override;
|
||||
};
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
#endif // RTC_BASE_PROXY_SERVER_H_
|
||||
|
|
|
@ -1,68 +0,0 @@
|
|||
/*
|
||||
* Copyright 2009 The WebRTC Project Authors. All rights reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "rtc_base/gunit.h"
|
||||
#include "rtc_base/proxy_server.h"
|
||||
#include "rtc_base/socket_adapters.h"
|
||||
#include "rtc_base/test_client.h"
|
||||
#include "rtc_base/test_echo_server.h"
|
||||
#include "rtc_base/virtual_socket_server.h"
|
||||
|
||||
using rtc::Socket;
|
||||
using rtc::SocketAddress;
|
||||
|
||||
static const SocketAddress kSocksProxyIntAddr("1.2.3.4", 1080);
|
||||
static const SocketAddress kSocksProxyExtAddr("1.2.3.5", 0);
|
||||
static const SocketAddress kBogusProxyIntAddr("1.2.3.4", 999);
|
||||
|
||||
// Sets up a virtual socket server and a SOCKS5 proxy server.
|
||||
class ProxyTest : public ::testing::Test {
|
||||
public:
|
||||
ProxyTest() : ss_(new rtc::VirtualSocketServer()), thread_(ss_.get()) {
|
||||
socks_.reset(new rtc::SocksProxyServer(ss_.get(), kSocksProxyIntAddr,
|
||||
ss_.get(), kSocksProxyExtAddr));
|
||||
}
|
||||
|
||||
rtc::SocketServer* ss() { return ss_.get(); }
|
||||
|
||||
private:
|
||||
std::unique_ptr<rtc::SocketServer> ss_;
|
||||
rtc::AutoSocketServerThread thread_;
|
||||
std::unique_ptr<rtc::SocksProxyServer> socks_;
|
||||
};
|
||||
|
||||
// Tests whether we can use a SOCKS5 proxy to connect to a server.
|
||||
TEST_F(ProxyTest, TestSocks5Connect) {
|
||||
rtc::Socket* socket =
|
||||
ss()->CreateSocket(kSocksProxyIntAddr.family(), SOCK_STREAM);
|
||||
rtc::AsyncSocksProxySocket* proxy_socket = new rtc::AsyncSocksProxySocket(
|
||||
socket, kSocksProxyIntAddr, "", rtc::CryptString());
|
||||
// TODO: IPv6-ize these tests when proxy supports IPv6.
|
||||
|
||||
rtc::TestEchoServer server(rtc::Thread::Current(),
|
||||
SocketAddress(INADDR_ANY, 0));
|
||||
|
||||
std::unique_ptr<rtc::AsyncTCPSocket> packet_socket(
|
||||
rtc::AsyncTCPSocket::Create(proxy_socket, SocketAddress(INADDR_ANY, 0),
|
||||
server.address()));
|
||||
EXPECT_TRUE(packet_socket != nullptr);
|
||||
rtc::TestClient client(std::move(packet_socket));
|
||||
|
||||
EXPECT_EQ(Socket::CS_CONNECTING, proxy_socket->GetState());
|
||||
EXPECT_TRUE(client.CheckConnected());
|
||||
EXPECT_EQ(Socket::CS_CONNECTED, proxy_socket->GetState());
|
||||
EXPECT_EQ(server.address(), client.remote_address());
|
||||
client.Send("foo", 3);
|
||||
EXPECT_TRUE(client.CheckNextPacket("foo", 3, nullptr));
|
||||
EXPECT_TRUE(client.CheckNoPacket());
|
||||
}
|
|
@ -55,135 +55,4 @@ void AsyncSSLServerSocket::ProcessInput(char* data, size_t* len) {
|
|||
BufferInput(false);
|
||||
}
|
||||
|
||||
AsyncSocksProxyServerSocket::AsyncSocksProxyServerSocket(Socket* socket)
|
||||
: AsyncProxyServerSocket(socket, kBufferSize), state_(SS_HELLO) {
|
||||
BufferInput(true);
|
||||
}
|
||||
|
||||
void AsyncSocksProxyServerSocket::ProcessInput(char* data, size_t* len) {
|
||||
RTC_DCHECK(state_ < SS_CONNECT_PENDING);
|
||||
|
||||
ByteBufferReader response(
|
||||
rtc::MakeArrayView(reinterpret_cast<const uint8_t*>(data), *len));
|
||||
if (state_ == SS_HELLO) {
|
||||
HandleHello(&response);
|
||||
} else if (state_ == SS_AUTH) {
|
||||
HandleAuth(&response);
|
||||
} else if (state_ == SS_CONNECT) {
|
||||
HandleConnect(&response);
|
||||
}
|
||||
|
||||
// Consume parsed data
|
||||
*len = response.Length();
|
||||
if (response.Length() > 0) {
|
||||
memmove(data, response.DataView().data(), *len);
|
||||
}
|
||||
}
|
||||
|
||||
void AsyncSocksProxyServerSocket::DirectSend(const ByteBufferWriter& buf) {
|
||||
BufferedReadAdapter::DirectSend(buf.Data(), buf.Length());
|
||||
}
|
||||
|
||||
void AsyncSocksProxyServerSocket::HandleHello(ByteBufferReader* request) {
|
||||
uint8_t ver, num_methods;
|
||||
if (!request->ReadUInt8(&ver) || !request->ReadUInt8(&num_methods)) {
|
||||
Error(0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ver != 5) {
|
||||
Error(0);
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle either no-auth (0) or user/pass auth (2)
|
||||
uint8_t method = 0xFF;
|
||||
if (num_methods > 0 && !request->ReadUInt8(&method)) {
|
||||
Error(0);
|
||||
return;
|
||||
}
|
||||
|
||||
SendHelloReply(method);
|
||||
if (method == 0) {
|
||||
state_ = SS_CONNECT;
|
||||
} else if (method == 2) {
|
||||
state_ = SS_AUTH;
|
||||
} else {
|
||||
state_ = SS_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
void AsyncSocksProxyServerSocket::SendHelloReply(uint8_t method) {
|
||||
ByteBufferWriter response;
|
||||
response.WriteUInt8(5); // Socks Version
|
||||
response.WriteUInt8(method); // Auth method
|
||||
DirectSend(response);
|
||||
}
|
||||
|
||||
void AsyncSocksProxyServerSocket::HandleAuth(ByteBufferReader* request) {
|
||||
uint8_t ver, user_len, pass_len;
|
||||
std::string user, pass;
|
||||
if (!request->ReadUInt8(&ver) || !request->ReadUInt8(&user_len) ||
|
||||
!request->ReadString(&user, user_len) || !request->ReadUInt8(&pass_len) ||
|
||||
!request->ReadString(&pass, pass_len)) {
|
||||
Error(0);
|
||||
return;
|
||||
}
|
||||
|
||||
SendAuthReply(0);
|
||||
state_ = SS_CONNECT;
|
||||
}
|
||||
|
||||
void AsyncSocksProxyServerSocket::SendAuthReply(uint8_t result) {
|
||||
ByteBufferWriter response;
|
||||
response.WriteUInt8(1); // Negotiation Version
|
||||
response.WriteUInt8(result);
|
||||
DirectSend(response);
|
||||
}
|
||||
|
||||
void AsyncSocksProxyServerSocket::HandleConnect(ByteBufferReader* request) {
|
||||
uint8_t ver, command, reserved, addr_type;
|
||||
uint32_t ip;
|
||||
uint16_t port;
|
||||
if (!request->ReadUInt8(&ver) || !request->ReadUInt8(&command) ||
|
||||
!request->ReadUInt8(&reserved) || !request->ReadUInt8(&addr_type) ||
|
||||
!request->ReadUInt32(&ip) || !request->ReadUInt16(&port)) {
|
||||
Error(0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ver != 5 || command != 1 || reserved != 0 || addr_type != 1) {
|
||||
Error(0);
|
||||
return;
|
||||
}
|
||||
|
||||
SignalConnectRequest(this, SocketAddress(ip, port));
|
||||
state_ = SS_CONNECT_PENDING;
|
||||
}
|
||||
|
||||
void AsyncSocksProxyServerSocket::SendConnectResult(int result,
|
||||
const SocketAddress& addr) {
|
||||
if (state_ != SS_CONNECT_PENDING)
|
||||
return;
|
||||
|
||||
ByteBufferWriter response;
|
||||
response.WriteUInt8(5); // Socks version
|
||||
response.WriteUInt8((result != 0)); // 0x01 is generic error
|
||||
response.WriteUInt8(0); // reserved
|
||||
response.WriteUInt8(1); // IPv4 address
|
||||
response.WriteUInt32(addr.ip());
|
||||
response.WriteUInt16(addr.port());
|
||||
DirectSend(response);
|
||||
BufferInput(false);
|
||||
state_ = SS_TUNNEL;
|
||||
}
|
||||
|
||||
void AsyncSocksProxyServerSocket::Error(int error) {
|
||||
state_ = SS_ERROR;
|
||||
BufferInput(false);
|
||||
Close();
|
||||
SetError(SOCKET_EACCES);
|
||||
SignalCloseEvent(this, error);
|
||||
}
|
||||
|
||||
} // namespace rtc
|
||||
|
|
|
@ -38,40 +38,6 @@ class AsyncSSLServerSocket : public BufferedReadAdapter {
|
|||
void ProcessInput(char* data, size_t* len) override;
|
||||
};
|
||||
|
||||
// Implements a proxy server socket for the SOCKS protocol.
|
||||
class AsyncSocksProxyServerSocket : public AsyncProxyServerSocket {
|
||||
public:
|
||||
explicit AsyncSocksProxyServerSocket(Socket* socket);
|
||||
|
||||
AsyncSocksProxyServerSocket(const AsyncSocksProxyServerSocket&) = delete;
|
||||
AsyncSocksProxyServerSocket& operator=(const AsyncSocksProxyServerSocket&) =
|
||||
delete;
|
||||
|
||||
private:
|
||||
void ProcessInput(char* data, size_t* len) override;
|
||||
void DirectSend(const ByteBufferWriter& buf);
|
||||
|
||||
void HandleHello(ByteBufferReader* request);
|
||||
void SendHelloReply(uint8_t method);
|
||||
void HandleAuth(ByteBufferReader* request);
|
||||
void SendAuthReply(uint8_t result);
|
||||
void HandleConnect(ByteBufferReader* request);
|
||||
void SendConnectResult(int result, const SocketAddress& addr) override;
|
||||
|
||||
void Error(int error);
|
||||
|
||||
static const int kBufferSize = 1024;
|
||||
enum State {
|
||||
SS_HELLO,
|
||||
SS_AUTH,
|
||||
SS_CONNECT,
|
||||
SS_CONNECT_PENDING,
|
||||
SS_TUNNEL,
|
||||
SS_ERROR
|
||||
};
|
||||
State state_;
|
||||
};
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
#endif // RTC_BASE_SERVER_SOCKET_ADAPTERS_H_
|
||||
|
|
|
@ -469,198 +469,4 @@ void AsyncHttpsProxySocket::Error(int error) {
|
|||
SignalCloseEvent(this, error);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AsyncSocksProxySocket::AsyncSocksProxySocket(Socket* socket,
|
||||
const SocketAddress& proxy,
|
||||
absl::string_view username,
|
||||
const CryptString& password)
|
||||
: BufferedReadAdapter(socket, 1024),
|
||||
state_(SS_ERROR),
|
||||
proxy_(proxy),
|
||||
user_(username),
|
||||
pass_(password) {}
|
||||
|
||||
AsyncSocksProxySocket::~AsyncSocksProxySocket() = default;
|
||||
|
||||
int AsyncSocksProxySocket::Connect(const SocketAddress& addr) {
|
||||
int ret;
|
||||
dest_ = addr;
|
||||
state_ = SS_INIT;
|
||||
BufferInput(true);
|
||||
ret = BufferedReadAdapter::Connect(proxy_);
|
||||
// TODO: Set state_ appropriately if Connect fails.
|
||||
return ret;
|
||||
}
|
||||
|
||||
SocketAddress AsyncSocksProxySocket::GetRemoteAddress() const {
|
||||
return dest_;
|
||||
}
|
||||
|
||||
int AsyncSocksProxySocket::Close() {
|
||||
state_ = SS_ERROR;
|
||||
dest_.Clear();
|
||||
return BufferedReadAdapter::Close();
|
||||
}
|
||||
|
||||
Socket::ConnState AsyncSocksProxySocket::GetState() const {
|
||||
if (state_ < SS_TUNNEL) {
|
||||
return CS_CONNECTING;
|
||||
} else if (state_ == SS_TUNNEL) {
|
||||
return CS_CONNECTED;
|
||||
} else {
|
||||
return CS_CLOSED;
|
||||
}
|
||||
}
|
||||
|
||||
void AsyncSocksProxySocket::OnConnectEvent(Socket* socket) {
|
||||
SendHello();
|
||||
}
|
||||
|
||||
void AsyncSocksProxySocket::ProcessInput(char* data, size_t* len) {
|
||||
RTC_DCHECK(state_ < SS_TUNNEL);
|
||||
|
||||
ByteBufferReader response(
|
||||
rtc::MakeArrayView(reinterpret_cast<uint8_t*>(data), *len));
|
||||
|
||||
if (state_ == SS_HELLO) {
|
||||
uint8_t ver, method;
|
||||
if (!response.ReadUInt8(&ver) || !response.ReadUInt8(&method))
|
||||
return;
|
||||
|
||||
if (ver != 5) {
|
||||
Error(0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (method == 0) {
|
||||
SendConnect();
|
||||
} else if (method == 2) {
|
||||
SendAuth();
|
||||
} else {
|
||||
Error(0);
|
||||
return;
|
||||
}
|
||||
} else if (state_ == SS_AUTH) {
|
||||
uint8_t ver, status;
|
||||
if (!response.ReadUInt8(&ver) || !response.ReadUInt8(&status))
|
||||
return;
|
||||
|
||||
if ((ver != 1) || (status != 0)) {
|
||||
Error(SOCKET_EACCES);
|
||||
return;
|
||||
}
|
||||
|
||||
SendConnect();
|
||||
} else if (state_ == SS_CONNECT) {
|
||||
uint8_t ver, rep, rsv, atyp;
|
||||
if (!response.ReadUInt8(&ver) || !response.ReadUInt8(&rep) ||
|
||||
!response.ReadUInt8(&rsv) || !response.ReadUInt8(&atyp))
|
||||
return;
|
||||
|
||||
if ((ver != 5) || (rep != 0)) {
|
||||
Error(0);
|
||||
return;
|
||||
}
|
||||
|
||||
uint16_t port;
|
||||
if (atyp == 1) {
|
||||
uint32_t addr;
|
||||
if (!response.ReadUInt32(&addr) || !response.ReadUInt16(&port))
|
||||
return;
|
||||
RTC_LOG(LS_VERBOSE) << "Bound on " << addr << ":" << port;
|
||||
} else if (atyp == 3) {
|
||||
uint8_t length;
|
||||
std::string addr;
|
||||
if (!response.ReadUInt8(&length) || !response.ReadString(&addr, length) ||
|
||||
!response.ReadUInt16(&port))
|
||||
return;
|
||||
RTC_LOG(LS_VERBOSE) << "Bound on " << addr << ":" << port;
|
||||
} else if (atyp == 4) {
|
||||
std::string addr;
|
||||
if (!response.ReadString(&addr, 16) || !response.ReadUInt16(&port))
|
||||
return;
|
||||
RTC_LOG(LS_VERBOSE) << "Bound on <IPV6>:" << port;
|
||||
} else {
|
||||
Error(0);
|
||||
return;
|
||||
}
|
||||
|
||||
state_ = SS_TUNNEL;
|
||||
}
|
||||
|
||||
// Consume parsed data
|
||||
*len = response.Length();
|
||||
memmove(data, response.Data(), *len);
|
||||
|
||||
if (state_ != SS_TUNNEL)
|
||||
return;
|
||||
|
||||
bool remainder = (*len > 0);
|
||||
BufferInput(false);
|
||||
SignalConnectEvent(this);
|
||||
|
||||
// FIX: if SignalConnect causes the socket to be destroyed, we are in trouble
|
||||
if (remainder)
|
||||
SignalReadEvent(this); // TODO: signal this??
|
||||
}
|
||||
|
||||
void AsyncSocksProxySocket::SendHello() {
|
||||
ByteBufferWriter request;
|
||||
request.WriteUInt8(5); // Socks Version
|
||||
if (user_.empty()) {
|
||||
request.WriteUInt8(1); // Authentication Mechanisms
|
||||
request.WriteUInt8(0); // No authentication
|
||||
} else {
|
||||
request.WriteUInt8(2); // Authentication Mechanisms
|
||||
request.WriteUInt8(0); // No authentication
|
||||
request.WriteUInt8(2); // Username/Password
|
||||
}
|
||||
DirectSend(request.Data(), request.Length());
|
||||
state_ = SS_HELLO;
|
||||
}
|
||||
|
||||
void AsyncSocksProxySocket::SendAuth() {
|
||||
ByteBufferWriterT<ZeroOnFreeBuffer<char>> request;
|
||||
request.WriteUInt8(1); // Negotiation Version
|
||||
request.WriteUInt8(static_cast<uint8_t>(user_.size()));
|
||||
request.WriteString(user_); // Username
|
||||
request.WriteUInt8(static_cast<uint8_t>(pass_.GetLength()));
|
||||
size_t len = pass_.GetLength() + 1;
|
||||
char* sensitive = new char[len];
|
||||
pass_.CopyTo(sensitive, true);
|
||||
request.WriteString(std::string(sensitive, pass_.GetLength())); // Password
|
||||
ExplicitZeroMemory(sensitive, len);
|
||||
delete[] sensitive;
|
||||
DirectSend(request.Data(), request.Length());
|
||||
state_ = SS_AUTH;
|
||||
}
|
||||
|
||||
void AsyncSocksProxySocket::SendConnect() {
|
||||
ByteBufferWriter request;
|
||||
request.WriteUInt8(5); // Socks Version
|
||||
request.WriteUInt8(1); // CONNECT
|
||||
request.WriteUInt8(0); // Reserved
|
||||
if (dest_.IsUnresolvedIP()) {
|
||||
std::string hostname = dest_.hostname();
|
||||
request.WriteUInt8(3); // DOMAINNAME
|
||||
request.WriteUInt8(static_cast<uint8_t>(hostname.size()));
|
||||
request.WriteString(hostname); // Destination Hostname
|
||||
} else {
|
||||
request.WriteUInt8(1); // IPV4
|
||||
request.WriteUInt32(dest_.ip()); // Destination IP
|
||||
}
|
||||
request.WriteUInt16(dest_.port()); // Destination Port
|
||||
DirectSend(request.Data(), request.Length());
|
||||
state_ = SS_CONNECT;
|
||||
}
|
||||
|
||||
void AsyncSocksProxySocket::Error(int error) {
|
||||
state_ = SS_ERROR;
|
||||
BufferInput(false);
|
||||
Close();
|
||||
SetError(SOCKET_EACCES);
|
||||
SignalCloseEvent(this, error);
|
||||
}
|
||||
|
||||
} // namespace rtc
|
||||
|
|
|
@ -137,42 +137,6 @@ class AsyncHttpsProxySocket : public BufferedReadAdapter {
|
|||
std::string unknown_mechanisms_;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Implements a socket adapter that speaks the SOCKS proxy protocol.
|
||||
class AsyncSocksProxySocket : public BufferedReadAdapter {
|
||||
public:
|
||||
AsyncSocksProxySocket(Socket* socket,
|
||||
const SocketAddress& proxy,
|
||||
absl::string_view username,
|
||||
const CryptString& password);
|
||||
~AsyncSocksProxySocket() override;
|
||||
|
||||
AsyncSocksProxySocket(const AsyncSocksProxySocket&) = delete;
|
||||
AsyncSocksProxySocket& operator=(const AsyncSocksProxySocket&) = delete;
|
||||
|
||||
int Connect(const SocketAddress& addr) override;
|
||||
SocketAddress GetRemoteAddress() const override;
|
||||
int Close() override;
|
||||
ConnState GetState() const override;
|
||||
|
||||
protected:
|
||||
void OnConnectEvent(Socket* socket) override;
|
||||
void ProcessInput(char* data, size_t* len) override;
|
||||
|
||||
void SendHello();
|
||||
void SendConnect();
|
||||
void SendAuth();
|
||||
void Error(int error);
|
||||
|
||||
private:
|
||||
enum State { SS_INIT, SS_HELLO, SS_AUTH, SS_CONNECT, SS_TUNNEL, SS_ERROR };
|
||||
State state_;
|
||||
SocketAddress proxy_, dest_;
|
||||
std::string user_;
|
||||
CryptString pass_;
|
||||
};
|
||||
|
||||
} // namespace rtc
|
||||
|
||||
#endif // RTC_BASE_SOCKET_ADAPTERS_H_
|
||||
|
|
Loading…
Reference in a new issue