blob: ebe420ca0564b71b91e1fd059d09c3f090df9537 [file] [log] [blame]
Niels Möller44153152018-12-17 14:04:05 +01001/*
2 * Copyright 2004 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Jonas Olssona4d87372019-07-05 19:08:33 +020011#include "rtc_base/server_socket_adapters.h"
12
Niels Möller44153152018-12-17 14:04:05 +010013#include <string>
14
Steve Anton10542f22019-01-11 09:11:00 -080015#include "rtc_base/byte_buffer.h"
Niels Möller44153152018-12-17 14:04:05 +010016
17namespace rtc {
18
19AsyncProxyServerSocket::AsyncProxyServerSocket(AsyncSocket* socket,
20 size_t buffer_size)
21 : BufferedReadAdapter(socket, buffer_size) {}
22
23AsyncProxyServerSocket::~AsyncProxyServerSocket() = default;
24
25AsyncSSLServerSocket::AsyncSSLServerSocket(AsyncSocket* socket)
26 : BufferedReadAdapter(socket, 1024) {
27 BufferInput(true);
28}
29
30void AsyncSSLServerSocket::ProcessInput(char* data, size_t* len) {
31 // We only accept client hello messages.
32 const ArrayView<const uint8_t> client_hello =
33 AsyncSSLSocket::SslClientHello();
34 if (*len < client_hello.size()) {
35 return;
36 }
37
38 if (memcmp(client_hello.data(), data, client_hello.size()) != 0) {
39 Close();
40 SignalCloseEvent(this, 0);
41 return;
42 }
43
44 *len -= client_hello.size();
45
46 // Clients should not send more data until the handshake is completed.
47 RTC_DCHECK(*len == 0);
48
49 const ArrayView<const uint8_t> server_hello =
50 AsyncSSLSocket::SslServerHello();
51 // Send a server hello back to the client.
52 DirectSend(server_hello.data(), server_hello.size());
53
54 // Handshake completed for us, redirect input to our parent.
55 BufferInput(false);
56}
57
58AsyncSocksProxyServerSocket::AsyncSocksProxyServerSocket(AsyncSocket* socket)
59 : AsyncProxyServerSocket(socket, kBufferSize), state_(SS_HELLO) {
60 BufferInput(true);
61}
62
63void AsyncSocksProxyServerSocket::ProcessInput(char* data, size_t* len) {
64 RTC_DCHECK(state_ < SS_CONNECT_PENDING);
65
66 ByteBufferReader response(data, *len);
67 if (state_ == SS_HELLO) {
68 HandleHello(&response);
69 } else if (state_ == SS_AUTH) {
70 HandleAuth(&response);
71 } else if (state_ == SS_CONNECT) {
72 HandleConnect(&response);
73 }
74
75 // Consume parsed data
76 *len = response.Length();
77 memmove(data, response.Data(), *len);
78}
79
80void AsyncSocksProxyServerSocket::DirectSend(const ByteBufferWriter& buf) {
81 BufferedReadAdapter::DirectSend(buf.Data(), buf.Length());
82}
83
84void AsyncSocksProxyServerSocket::HandleHello(ByteBufferReader* request) {
85 uint8_t ver, num_methods;
86 if (!request->ReadUInt8(&ver) || !request->ReadUInt8(&num_methods)) {
87 Error(0);
88 return;
89 }
90
91 if (ver != 5) {
92 Error(0);
93 return;
94 }
95
96 // Handle either no-auth (0) or user/pass auth (2)
97 uint8_t method = 0xFF;
98 if (num_methods > 0 && !request->ReadUInt8(&method)) {
99 Error(0);
100 return;
101 }
102
103 SendHelloReply(method);
104 if (method == 0) {
105 state_ = SS_CONNECT;
106 } else if (method == 2) {
107 state_ = SS_AUTH;
108 } else {
109 state_ = SS_ERROR;
110 }
111}
112
113void AsyncSocksProxyServerSocket::SendHelloReply(uint8_t method) {
114 ByteBufferWriter response;
115 response.WriteUInt8(5); // Socks Version
116 response.WriteUInt8(method); // Auth method
117 DirectSend(response);
118}
119
120void AsyncSocksProxyServerSocket::HandleAuth(ByteBufferReader* request) {
121 uint8_t ver, user_len, pass_len;
122 std::string user, pass;
123 if (!request->ReadUInt8(&ver) || !request->ReadUInt8(&user_len) ||
124 !request->ReadString(&user, user_len) || !request->ReadUInt8(&pass_len) ||
125 !request->ReadString(&pass, pass_len)) {
126 Error(0);
127 return;
128 }
129
130 SendAuthReply(0);
131 state_ = SS_CONNECT;
132}
133
134void AsyncSocksProxyServerSocket::SendAuthReply(uint8_t result) {
135 ByteBufferWriter response;
136 response.WriteUInt8(1); // Negotiation Version
137 response.WriteUInt8(result);
138 DirectSend(response);
139}
140
141void AsyncSocksProxyServerSocket::HandleConnect(ByteBufferReader* request) {
142 uint8_t ver, command, reserved, addr_type;
143 uint32_t ip;
144 uint16_t port;
145 if (!request->ReadUInt8(&ver) || !request->ReadUInt8(&command) ||
146 !request->ReadUInt8(&reserved) || !request->ReadUInt8(&addr_type) ||
147 !request->ReadUInt32(&ip) || !request->ReadUInt16(&port)) {
148 Error(0);
149 return;
150 }
151
152 if (ver != 5 || command != 1 || reserved != 0 || addr_type != 1) {
153 Error(0);
154 return;
155 }
156
157 SignalConnectRequest(this, SocketAddress(ip, port));
158 state_ = SS_CONNECT_PENDING;
159}
160
161void AsyncSocksProxyServerSocket::SendConnectResult(int result,
162 const SocketAddress& addr) {
163 if (state_ != SS_CONNECT_PENDING)
164 return;
165
166 ByteBufferWriter response;
167 response.WriteUInt8(5); // Socks version
168 response.WriteUInt8((result != 0)); // 0x01 is generic error
169 response.WriteUInt8(0); // reserved
170 response.WriteUInt8(1); // IPv4 address
171 response.WriteUInt32(addr.ip());
172 response.WriteUInt16(addr.port());
173 DirectSend(response);
174 BufferInput(false);
175 state_ = SS_TUNNEL;
176}
177
178void AsyncSocksProxyServerSocket::Error(int error) {
179 state_ = SS_ERROR;
180 BufferInput(false);
181 Close();
182 SetError(SOCKET_EACCES);
183 SignalCloseEvent(this, error);
184}
185
186} // namespace rtc