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