blob: 2bcdcd8b16cdf1ab04a595ad0160618f0ef5aca4 [file] [log] [blame]
henrike@webrtc.orgf0488722014-05-13 18:00:26 +00001/*
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#if defined(_MSC_VER) && _MSC_VER < 1300
Yves Gerey665174f2018-06-19 15:03:05 +020012#pragma warning(disable : 4786)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000013#endif
14
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000015#include <errno.h>
Yves Gerey988cc082018-10-23 12:03:01 +020016#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
Yves Gerey665174f2018-06-19 15:03:05 +020019#include <time.h>
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000020
21#if defined(WEBRTC_WIN)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000022#include <windows.h>
23#include <winsock2.h>
24#include <ws2tcpip.h>
Yves Gerey988cc082018-10-23 12:03:01 +020025
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000026#define SECURITY_WIN32
27#include <security.h>
28#endif
29
andresp@webrtc.orgff689be2015-02-12 11:54:26 +000030#include <algorithm>
31
Niels Mölleraa3c1cc2018-11-02 10:54:56 +010032#include "absl/strings/match.h"
Yves Gerey988cc082018-10-23 12:03:01 +020033#include "rtc_base/buffer.h"
Steve Anton10542f22019-01-11 09:11:00 -080034#include "rtc_base/byte_buffer.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020035#include "rtc_base/checks.h"
Steve Anton10542f22019-01-11 09:11:00 -080036#include "rtc_base/http_common.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020037#include "rtc_base/logging.h"
Steve Anton10542f22019-01-11 09:11:00 -080038#include "rtc_base/socket_adapters.h"
Jonas Olsson366a50c2018-09-06 13:41:30 +020039#include "rtc_base/strings/string_builder.h"
Joachim Bauch5b32f232018-03-07 20:02:26 +010040#include "rtc_base/zero_memory.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000041
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000042namespace rtc {
43
44BufferedReadAdapter::BufferedReadAdapter(AsyncSocket* socket, size_t size)
Yves Gerey665174f2018-06-19 15:03:05 +020045 : AsyncSocketAdapter(socket),
46 buffer_size_(size),
47 data_len_(0),
48 buffering_(false) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000049 buffer_ = new char[buffer_size_];
50}
51
52BufferedReadAdapter::~BufferedReadAdapter() {
Yves Gerey665174f2018-06-19 15:03:05 +020053 delete[] buffer_;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000054}
55
Yves Gerey665174f2018-06-19 15:03:05 +020056int BufferedReadAdapter::Send(const void* pv, size_t cb) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000057 if (buffering_) {
58 // TODO: Spoof error better; Signal Writeable
59 socket_->SetError(EWOULDBLOCK);
60 return -1;
61 }
62 return AsyncSocketAdapter::Send(pv, cb);
63}
64
Stefan Holmer9131efd2016-05-23 18:19:26 +020065int BufferedReadAdapter::Recv(void* pv, size_t cb, int64_t* timestamp) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000066 if (buffering_) {
67 socket_->SetError(EWOULDBLOCK);
68 return -1;
69 }
70
71 size_t read = 0;
72
73 if (data_len_) {
andresp@webrtc.orgff689be2015-02-12 11:54:26 +000074 read = std::min(cb, data_len_);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000075 memcpy(pv, buffer_, read);
76 data_len_ -= read;
77 if (data_len_ > 0) {
78 memmove(buffer_, buffer_ + read, data_len_);
79 }
Yves Gerey665174f2018-06-19 15:03:05 +020080 pv = static_cast<char*>(pv) + read;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000081 cb -= read;
82 }
83
84 // FIX: If cb == 0, we won't generate another read event
85
Stefan Holmer9131efd2016-05-23 18:19:26 +020086 int res = AsyncSocketAdapter::Recv(pv, cb, timestamp);
deadbeefc5d0d952015-07-16 10:22:21 -070087 if (res >= 0) {
88 // Read from socket and possibly buffer; return combined length
89 return res + static_cast<int>(read);
90 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000091
deadbeefc5d0d952015-07-16 10:22:21 -070092 if (read > 0) {
93 // Failed to read from socket, but still read something from buffer
94 return static_cast<int>(read);
95 }
96
97 // Didn't read anything; return error from socket
98 return res;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000099}
100
101void BufferedReadAdapter::BufferInput(bool on) {
102 buffering_ = on;
103}
104
Yves Gerey665174f2018-06-19 15:03:05 +0200105void BufferedReadAdapter::OnReadEvent(AsyncSocket* socket) {
nisseede5da42017-01-12 05:15:36 -0800106 RTC_DCHECK(socket == socket_);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000107
108 if (!buffering_) {
109 AsyncSocketAdapter::OnReadEvent(socket);
110 return;
111 }
112
113 if (data_len_ >= buffer_size_) {
Jonas Olsson45cc8902018-02-13 10:37:07 +0100114 RTC_LOG(LS_ERROR) << "Input buffer overflow";
nissec80e7412017-01-11 05:56:46 -0800115 RTC_NOTREACHED();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000116 data_len_ = 0;
117 }
118
Stefan Holmer9131efd2016-05-23 18:19:26 +0200119 int len =
120 socket_->Recv(buffer_ + data_len_, buffer_size_ - data_len_, nullptr);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000121 if (len < 0) {
122 // TODO: Do something better like forwarding the error to the user.
Mirko Bonadei675513b2017-11-09 11:09:25 +0100123 RTC_LOG_ERR(INFO) << "Recv";
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000124 return;
125 }
126
127 data_len_ += len;
128
129 ProcessInput(buffer_, &data_len_);
130}
131
132///////////////////////////////////////////////////////////////////////////////
133
134// This is a SSL v2 CLIENT_HELLO message.
135// TODO: Should this have a session id? The response doesn't have a
136// certificate, so the hello should have a session id.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200137static const uint8_t kSslClientHello[] = {
138 0x80, 0x46, // msg len
139 0x01, // CLIENT_HELLO
140 0x03, 0x01, // SSL 3.1
141 0x00, 0x2d, // ciphersuite len
142 0x00, 0x00, // session id len
143 0x00, 0x10, // challenge len
144 0x01, 0x00, 0x80, 0x03, 0x00, 0x80, 0x07, 0x00, 0xc0, // ciphersuites
145 0x06, 0x00, 0x40, 0x02, 0x00, 0x80, 0x04, 0x00, 0x80, //
146 0x00, 0x00, 0x04, 0x00, 0xfe, 0xff, 0x00, 0x00, 0x0a, //
147 0x00, 0xfe, 0xfe, 0x00, 0x00, 0x09, 0x00, 0x00, 0x64, //
148 0x00, 0x00, 0x62, 0x00, 0x00, 0x03, 0x00, 0x00, 0x06, //
149 0x1f, 0x17, 0x0c, 0xa6, 0x2f, 0x00, 0x78, 0xfc, // challenge
150 0x46, 0x55, 0x2e, 0xb1, 0x83, 0x39, 0xf1, 0xea //
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000151};
152
Niels Möller44153152018-12-17 14:04:05 +0100153// static
154ArrayView<const uint8_t> AsyncSSLSocket::SslClientHello() {
155 // Implicit conversion directly from kSslClientHello to ArrayView fails when
156 // built with gcc.
157 return {kSslClientHello, sizeof(kSslClientHello)};
158}
159
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000160// This is a TLSv1 SERVER_HELLO message.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200161static const uint8_t kSslServerHello[] = {
162 0x16, // handshake message
163 0x03, 0x01, // SSL 3.1
164 0x00, 0x4a, // message len
165 0x02, // SERVER_HELLO
166 0x00, 0x00, 0x46, // handshake len
167 0x03, 0x01, // SSL 3.1
168 0x42, 0x85, 0x45, 0xa7, 0x27, 0xa9, 0x5d, 0xa0, // server random
169 0xb3, 0xc5, 0xe7, 0x53, 0xda, 0x48, 0x2b, 0x3f, //
170 0xc6, 0x5a, 0xca, 0x89, 0xc1, 0x58, 0x52, 0xa1, //
171 0x78, 0x3c, 0x5b, 0x17, 0x46, 0x00, 0x85, 0x3f, //
172 0x20, // session id len
173 0x0e, 0xd3, 0x06, 0x72, 0x5b, 0x5b, 0x1b, 0x5f, // session id
174 0x15, 0xac, 0x13, 0xf9, 0x88, 0x53, 0x9d, 0x9b, //
175 0xe8, 0x3d, 0x7b, 0x0c, 0x30, 0x32, 0x6e, 0x38, //
176 0x4d, 0xa2, 0x75, 0x57, 0x41, 0x6c, 0x34, 0x5c, //
177 0x00, 0x04, // RSA/RC4-128/MD5
178 0x00 // null compression
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000179};
180
Niels Möller44153152018-12-17 14:04:05 +0100181// static
182ArrayView<const uint8_t> AsyncSSLSocket::SslServerHello() {
183 return {kSslServerHello, sizeof(kSslServerHello)};
184}
185
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000186AsyncSSLSocket::AsyncSSLSocket(AsyncSocket* socket)
Yves Gerey665174f2018-06-19 15:03:05 +0200187 : BufferedReadAdapter(socket, 1024) {}
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000188
189int AsyncSSLSocket::Connect(const SocketAddress& addr) {
190 // Begin buffering before we connect, so that there isn't a race condition
191 // between potential senders and receiving the OnConnectEvent signal
192 BufferInput(true);
193 return BufferedReadAdapter::Connect(addr);
194}
195
Yves Gerey665174f2018-06-19 15:03:05 +0200196void AsyncSSLSocket::OnConnectEvent(AsyncSocket* socket) {
nisseede5da42017-01-12 05:15:36 -0800197 RTC_DCHECK(socket == socket_);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000198 // TODO: we could buffer output too...
nissec16fa5e2017-02-07 07:18:43 -0800199 const int res = DirectSend(kSslClientHello, sizeof(kSslClientHello));
200 RTC_DCHECK_EQ(sizeof(kSslClientHello), res);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000201}
202
203void AsyncSSLSocket::ProcessInput(char* data, size_t* len) {
204 if (*len < sizeof(kSslServerHello))
205 return;
206
207 if (memcmp(kSslServerHello, data, sizeof(kSslServerHello)) != 0) {
208 Close();
209 SignalCloseEvent(this, 0); // TODO: error code?
210 return;
211 }
212
213 *len -= sizeof(kSslServerHello);
214 if (*len > 0) {
215 memmove(data, data + sizeof(kSslServerHello), *len);
216 }
217
218 bool remainder = (*len > 0);
219 BufferInput(false);
220 SignalConnectEvent(this);
221
222 // FIX: if SignalConnect causes the socket to be destroyed, we are in trouble
223 if (remainder)
224 SignalReadEvent(this);
225}
226
deadbeeff137e972017-03-23 15:45:49 -0700227///////////////////////////////////////////////////////////////////////////////
228
229AsyncHttpsProxySocket::AsyncHttpsProxySocket(AsyncSocket* socket,
230 const std::string& user_agent,
231 const SocketAddress& proxy,
232 const std::string& username,
233 const CryptString& password)
Yves Gerey665174f2018-06-19 15:03:05 +0200234 : BufferedReadAdapter(socket, 1024),
235 proxy_(proxy),
236 agent_(user_agent),
237 user_(username),
238 pass_(password),
239 force_connect_(false),
240 state_(PS_ERROR),
241 context_(0) {}
deadbeeff137e972017-03-23 15:45:49 -0700242
243AsyncHttpsProxySocket::~AsyncHttpsProxySocket() {
244 delete context_;
245}
246
247int AsyncHttpsProxySocket::Connect(const SocketAddress& addr) {
248 int ret;
Mirko Bonadei675513b2017-11-09 11:09:25 +0100249 RTC_LOG(LS_VERBOSE) << "AsyncHttpsProxySocket::Connect("
250 << proxy_.ToSensitiveString() << ")";
deadbeeff137e972017-03-23 15:45:49 -0700251 dest_ = addr;
252 state_ = PS_INIT;
253 if (ShouldIssueConnect()) {
254 BufferInput(true);
255 }
256 ret = BufferedReadAdapter::Connect(proxy_);
257 // TODO: Set state_ appropriately if Connect fails.
258 return ret;
259}
260
261SocketAddress AsyncHttpsProxySocket::GetRemoteAddress() const {
262 return dest_;
263}
264
265int AsyncHttpsProxySocket::Close() {
266 headers_.clear();
267 state_ = PS_ERROR;
268 dest_.Clear();
269 delete context_;
270 context_ = nullptr;
271 return BufferedReadAdapter::Close();
272}
273
274Socket::ConnState AsyncHttpsProxySocket::GetState() const {
275 if (state_ < PS_TUNNEL) {
276 return CS_CONNECTING;
277 } else if (state_ == PS_TUNNEL) {
278 return CS_CONNECTED;
279 } else {
280 return CS_CLOSED;
281 }
282}
283
Yves Gerey665174f2018-06-19 15:03:05 +0200284void AsyncHttpsProxySocket::OnConnectEvent(AsyncSocket* socket) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100285 RTC_LOG(LS_VERBOSE) << "AsyncHttpsProxySocket::OnConnectEvent";
deadbeeff137e972017-03-23 15:45:49 -0700286 if (!ShouldIssueConnect()) {
287 state_ = PS_TUNNEL;
288 BufferedReadAdapter::OnConnectEvent(socket);
289 return;
290 }
291 SendRequest();
292}
293
Yves Gerey665174f2018-06-19 15:03:05 +0200294void AsyncHttpsProxySocket::OnCloseEvent(AsyncSocket* socket, int err) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100295 RTC_LOG(LS_VERBOSE) << "AsyncHttpsProxySocket::OnCloseEvent(" << err << ")";
deadbeeff137e972017-03-23 15:45:49 -0700296 if ((state_ == PS_WAIT_CLOSE) && (err == 0)) {
297 state_ = PS_ERROR;
298 Connect(dest_);
299 } else {
300 BufferedReadAdapter::OnCloseEvent(socket, err);
301 }
302}
303
304void AsyncHttpsProxySocket::ProcessInput(char* data, size_t* len) {
305 size_t start = 0;
306 for (size_t pos = start; state_ < PS_TUNNEL && pos < *len;) {
307 if (state_ == PS_SKIP_BODY) {
308 size_t consume = std::min(*len - pos, content_length_);
309 pos += consume;
310 start = pos;
311 content_length_ -= consume;
312 if (content_length_ == 0) {
313 EndResponse();
314 }
315 continue;
316 }
317
318 if (data[pos++] != '\n')
319 continue;
320
321 size_t len = pos - start - 1;
322 if ((len > 0) && (data[start + len - 1] == '\r'))
323 --len;
324
325 data[start + len] = 0;
326 ProcessLine(data + start, len);
327 start = pos;
328 }
329
330 *len -= start;
331 if (*len > 0) {
332 memmove(data, data + start, *len);
333 }
334
335 if (state_ != PS_TUNNEL)
336 return;
337
338 bool remainder = (*len > 0);
339 BufferInput(false);
340 SignalConnectEvent(this);
341
342 // FIX: if SignalConnect causes the socket to be destroyed, we are in trouble
343 if (remainder)
344 SignalReadEvent(this); // TODO: signal this??
345}
346
347bool AsyncHttpsProxySocket::ShouldIssueConnect() const {
348 // TODO: Think about whether a more sophisticated test
349 // than dest port == 80 is needed.
350 return force_connect_ || (dest_.port() != 80);
351}
352
353void AsyncHttpsProxySocket::SendRequest() {
Jonas Olsson366a50c2018-09-06 13:41:30 +0200354 rtc::StringBuilder ss;
deadbeeff137e972017-03-23 15:45:49 -0700355 ss << "CONNECT " << dest_.ToString() << " HTTP/1.0\r\n";
356 ss << "User-Agent: " << agent_ << "\r\n";
357 ss << "Host: " << dest_.HostAsURIString() << "\r\n";
358 ss << "Content-Length: 0\r\n";
359 ss << "Proxy-Connection: Keep-Alive\r\n";
360 ss << headers_;
361 ss << "\r\n";
362 std::string str = ss.str();
363 DirectSend(str.c_str(), str.size());
364 state_ = PS_LEADER;
365 expect_close_ = true;
366 content_length_ = 0;
367 headers_.clear();
368
Mirko Bonadei675513b2017-11-09 11:09:25 +0100369 RTC_LOG(LS_VERBOSE) << "AsyncHttpsProxySocket >> " << str;
deadbeeff137e972017-03-23 15:45:49 -0700370}
371
Yves Gerey665174f2018-06-19 15:03:05 +0200372void AsyncHttpsProxySocket::ProcessLine(char* data, size_t len) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100373 RTC_LOG(LS_VERBOSE) << "AsyncHttpsProxySocket << " << data;
deadbeeff137e972017-03-23 15:45:49 -0700374
375 if (len == 0) {
376 if (state_ == PS_TUNNEL_HEADERS) {
377 state_ = PS_TUNNEL;
378 } else if (state_ == PS_ERROR_HEADERS) {
379 Error(defer_error_);
380 return;
381 } else if (state_ == PS_SKIP_HEADERS) {
382 if (content_length_) {
383 state_ = PS_SKIP_BODY;
384 } else {
385 EndResponse();
386 return;
387 }
388 } else {
389 static bool report = false;
390 if (!unknown_mechanisms_.empty() && !report) {
391 report = true;
392 std::string msg(
Yves Gerey665174f2018-06-19 15:03:05 +0200393 "Unable to connect to the Google Talk service due to an "
394 "incompatibility "
395 "with your proxy.\r\nPlease help us resolve this issue by "
396 "submitting the "
397 "following information to us using our technical issue submission "
398 "form "
399 "at:\r\n\r\n"
400 "http://www.google.com/support/talk/bin/request.py\r\n\r\n"
401 "We apologize for the inconvenience.\r\n\r\n"
402 "Information to submit to Google: ");
403 // std::string msg("Please report the following information to
404 // foo@bar.com:\r\nUnknown methods: ");
deadbeeff137e972017-03-23 15:45:49 -0700405 msg.append(unknown_mechanisms_);
Robin Raymondce1b1402018-11-22 20:10:11 -0500406#if defined(WEBRTC_WIN) && !defined(WINUWP)
deadbeeff137e972017-03-23 15:45:49 -0700407 MessageBoxA(0, msg.c_str(), "Oops!", MB_OK);
408#endif
409#if defined(WEBRTC_POSIX)
410 // TODO: Raise a signal so the UI can be separated.
Mirko Bonadei675513b2017-11-09 11:09:25 +0100411 RTC_LOG(LS_ERROR) << "Oops!\n\n" << msg;
deadbeeff137e972017-03-23 15:45:49 -0700412#endif
413 }
414 // Unexpected end of headers
415 Error(0);
416 return;
417 }
418 } else if (state_ == PS_LEADER) {
419 unsigned int code;
420 if (sscanf(data, "HTTP/%*u.%*u %u", &code) != 1) {
421 Error(0);
422 return;
423 }
424 switch (code) {
Yves Gerey665174f2018-06-19 15:03:05 +0200425 case 200:
426 // connection good!
427 state_ = PS_TUNNEL_HEADERS;
428 return;
deadbeeff137e972017-03-23 15:45:49 -0700429#if defined(HTTP_STATUS_PROXY_AUTH_REQ) && (HTTP_STATUS_PROXY_AUTH_REQ != 407)
430#error Wrong code for HTTP_STATUS_PROXY_AUTH_REQ
431#endif
Yves Gerey665174f2018-06-19 15:03:05 +0200432 case 407: // HTTP_STATUS_PROXY_AUTH_REQ
433 state_ = PS_AUTHENTICATE;
434 return;
435 default:
436 defer_error_ = 0;
437 state_ = PS_ERROR_HEADERS;
438 return;
deadbeeff137e972017-03-23 15:45:49 -0700439 }
Yves Gerey665174f2018-06-19 15:03:05 +0200440 } else if ((state_ == PS_AUTHENTICATE) &&
Niels Mölleraa3c1cc2018-11-02 10:54:56 +0100441 absl::StartsWithIgnoreCase(data, "Proxy-Authenticate:")) {
deadbeeff137e972017-03-23 15:45:49 -0700442 std::string response, auth_method;
Yves Gerey665174f2018-06-19 15:03:05 +0200443 switch (HttpAuthenticate(data + 19, len - 19, proxy_, "CONNECT", "/", user_,
444 pass_, context_, response, auth_method)) {
445 case HAR_IGNORE:
446 RTC_LOG(LS_VERBOSE) << "Ignoring Proxy-Authenticate: " << auth_method;
447 if (!unknown_mechanisms_.empty())
448 unknown_mechanisms_.append(", ");
449 unknown_mechanisms_.append(auth_method);
450 break;
451 case HAR_RESPONSE:
452 headers_ = "Proxy-Authorization: ";
453 headers_.append(response);
454 headers_.append("\r\n");
455 state_ = PS_SKIP_HEADERS;
456 unknown_mechanisms_.clear();
457 break;
458 case HAR_CREDENTIALS:
459 defer_error_ = SOCKET_EACCES;
460 state_ = PS_ERROR_HEADERS;
461 unknown_mechanisms_.clear();
462 break;
463 case HAR_ERROR:
464 defer_error_ = 0;
465 state_ = PS_ERROR_HEADERS;
466 unknown_mechanisms_.clear();
467 break;
deadbeeff137e972017-03-23 15:45:49 -0700468 }
Niels Mölleraa3c1cc2018-11-02 10:54:56 +0100469 } else if (absl::StartsWithIgnoreCase(data, "Content-Length:")) {
deadbeeff137e972017-03-23 15:45:49 -0700470 content_length_ = strtoul(data + 15, 0, 0);
Niels Mölleraa3c1cc2018-11-02 10:54:56 +0100471 } else if (absl::StartsWithIgnoreCase(data, "Proxy-Connection: Keep-Alive")) {
deadbeeff137e972017-03-23 15:45:49 -0700472 expect_close_ = false;
473 /*
Niels Mölleraa3c1cc2018-11-02 10:54:56 +0100474 } else if (absl::StartsWithIgnoreCase(data, "Connection: close") {
deadbeeff137e972017-03-23 15:45:49 -0700475 expect_close_ = true;
476 */
477 }
478}
479
480void AsyncHttpsProxySocket::EndResponse() {
481 if (!expect_close_) {
482 SendRequest();
483 return;
484 }
485
486 // No point in waiting for the server to close... let's close now
487 // TODO: Refactor out PS_WAIT_CLOSE
488 state_ = PS_WAIT_CLOSE;
489 BufferedReadAdapter::Close();
490 OnCloseEvent(this, 0);
491}
492
493void AsyncHttpsProxySocket::Error(int error) {
494 BufferInput(false);
495 Close();
496 SetError(error);
497 SignalCloseEvent(this, error);
498}
499
500///////////////////////////////////////////////////////////////////////////////
501
502AsyncSocksProxySocket::AsyncSocksProxySocket(AsyncSocket* socket,
503 const SocketAddress& proxy,
504 const std::string& username,
505 const CryptString& password)
Yves Gerey665174f2018-06-19 15:03:05 +0200506 : BufferedReadAdapter(socket, 1024),
507 state_(SS_ERROR),
508 proxy_(proxy),
509 user_(username),
510 pass_(password) {}
deadbeeff137e972017-03-23 15:45:49 -0700511
512AsyncSocksProxySocket::~AsyncSocksProxySocket() = default;
513
514int AsyncSocksProxySocket::Connect(const SocketAddress& addr) {
515 int ret;
516 dest_ = addr;
517 state_ = SS_INIT;
518 BufferInput(true);
519 ret = BufferedReadAdapter::Connect(proxy_);
520 // TODO: Set state_ appropriately if Connect fails.
521 return ret;
522}
523
524SocketAddress AsyncSocksProxySocket::GetRemoteAddress() const {
525 return dest_;
526}
527
528int AsyncSocksProxySocket::Close() {
529 state_ = SS_ERROR;
530 dest_.Clear();
531 return BufferedReadAdapter::Close();
532}
533
534Socket::ConnState AsyncSocksProxySocket::GetState() const {
535 if (state_ < SS_TUNNEL) {
536 return CS_CONNECTING;
537 } else if (state_ == SS_TUNNEL) {
538 return CS_CONNECTED;
539 } else {
540 return CS_CLOSED;
541 }
542}
543
544void AsyncSocksProxySocket::OnConnectEvent(AsyncSocket* socket) {
545 SendHello();
546}
547
548void AsyncSocksProxySocket::ProcessInput(char* data, size_t* len) {
549 RTC_DCHECK(state_ < SS_TUNNEL);
550
551 ByteBufferReader response(data, *len);
552
553 if (state_ == SS_HELLO) {
554 uint8_t ver, method;
Yves Gerey665174f2018-06-19 15:03:05 +0200555 if (!response.ReadUInt8(&ver) || !response.ReadUInt8(&method))
deadbeeff137e972017-03-23 15:45:49 -0700556 return;
557
558 if (ver != 5) {
559 Error(0);
560 return;
561 }
562
563 if (method == 0) {
564 SendConnect();
565 } else if (method == 2) {
566 SendAuth();
567 } else {
568 Error(0);
569 return;
570 }
571 } else if (state_ == SS_AUTH) {
572 uint8_t ver, status;
Yves Gerey665174f2018-06-19 15:03:05 +0200573 if (!response.ReadUInt8(&ver) || !response.ReadUInt8(&status))
deadbeeff137e972017-03-23 15:45:49 -0700574 return;
575
576 if ((ver != 1) || (status != 0)) {
577 Error(SOCKET_EACCES);
578 return;
579 }
580
581 SendConnect();
582 } else if (state_ == SS_CONNECT) {
583 uint8_t ver, rep, rsv, atyp;
Yves Gerey665174f2018-06-19 15:03:05 +0200584 if (!response.ReadUInt8(&ver) || !response.ReadUInt8(&rep) ||
585 !response.ReadUInt8(&rsv) || !response.ReadUInt8(&atyp))
deadbeeff137e972017-03-23 15:45:49 -0700586 return;
587
588 if ((ver != 5) || (rep != 0)) {
589 Error(0);
590 return;
591 }
592
593 uint16_t port;
594 if (atyp == 1) {
595 uint32_t addr;
Yves Gerey665174f2018-06-19 15:03:05 +0200596 if (!response.ReadUInt32(&addr) || !response.ReadUInt16(&port))
deadbeeff137e972017-03-23 15:45:49 -0700597 return;
Mirko Bonadei675513b2017-11-09 11:09:25 +0100598 RTC_LOG(LS_VERBOSE) << "Bound on " << addr << ":" << port;
deadbeeff137e972017-03-23 15:45:49 -0700599 } else if (atyp == 3) {
600 uint8_t len;
601 std::string addr;
Yves Gerey665174f2018-06-19 15:03:05 +0200602 if (!response.ReadUInt8(&len) || !response.ReadString(&addr, len) ||
deadbeeff137e972017-03-23 15:45:49 -0700603 !response.ReadUInt16(&port))
604 return;
Mirko Bonadei675513b2017-11-09 11:09:25 +0100605 RTC_LOG(LS_VERBOSE) << "Bound on " << addr << ":" << port;
deadbeeff137e972017-03-23 15:45:49 -0700606 } else if (atyp == 4) {
607 std::string addr;
Yves Gerey665174f2018-06-19 15:03:05 +0200608 if (!response.ReadString(&addr, 16) || !response.ReadUInt16(&port))
deadbeeff137e972017-03-23 15:45:49 -0700609 return;
Mirko Bonadei675513b2017-11-09 11:09:25 +0100610 RTC_LOG(LS_VERBOSE) << "Bound on <IPV6>:" << port;
deadbeeff137e972017-03-23 15:45:49 -0700611 } else {
612 Error(0);
613 return;
614 }
615
616 state_ = SS_TUNNEL;
617 }
618
619 // Consume parsed data
620 *len = response.Length();
621 memmove(data, response.Data(), *len);
622
623 if (state_ != SS_TUNNEL)
624 return;
625
626 bool remainder = (*len > 0);
627 BufferInput(false);
628 SignalConnectEvent(this);
629
630 // FIX: if SignalConnect causes the socket to be destroyed, we are in trouble
631 if (remainder)
632 SignalReadEvent(this); // TODO: signal this??
633}
634
635void AsyncSocksProxySocket::SendHello() {
636 ByteBufferWriter request;
Yves Gerey665174f2018-06-19 15:03:05 +0200637 request.WriteUInt8(5); // Socks Version
deadbeeff137e972017-03-23 15:45:49 -0700638 if (user_.empty()) {
639 request.WriteUInt8(1); // Authentication Mechanisms
640 request.WriteUInt8(0); // No authentication
641 } else {
642 request.WriteUInt8(2); // Authentication Mechanisms
643 request.WriteUInt8(0); // No authentication
644 request.WriteUInt8(2); // Username/Password
645 }
646 DirectSend(request.Data(), request.Length());
647 state_ = SS_HELLO;
648}
649
650void AsyncSocksProxySocket::SendAuth() {
Joachim Bauch4c6a30c2018-03-08 00:55:33 +0100651 ByteBufferWriterT<ZeroOnFreeBuffer<char>> request;
Yves Gerey665174f2018-06-19 15:03:05 +0200652 request.WriteUInt8(1); // Negotiation Version
deadbeeff137e972017-03-23 15:45:49 -0700653 request.WriteUInt8(static_cast<uint8_t>(user_.size()));
Yves Gerey665174f2018-06-19 15:03:05 +0200654 request.WriteString(user_); // Username
deadbeeff137e972017-03-23 15:45:49 -0700655 request.WriteUInt8(static_cast<uint8_t>(pass_.GetLength()));
656 size_t len = pass_.GetLength() + 1;
Yves Gerey665174f2018-06-19 15:03:05 +0200657 char* sensitive = new char[len];
deadbeeff137e972017-03-23 15:45:49 -0700658 pass_.CopyTo(sensitive, true);
Joachim Bauch5b32f232018-03-07 20:02:26 +0100659 request.WriteBytes(sensitive, pass_.GetLength()); // Password
660 ExplicitZeroMemory(sensitive, len);
Yves Gerey665174f2018-06-19 15:03:05 +0200661 delete[] sensitive;
deadbeeff137e972017-03-23 15:45:49 -0700662 DirectSend(request.Data(), request.Length());
663 state_ = SS_AUTH;
664}
665
666void AsyncSocksProxySocket::SendConnect() {
667 ByteBufferWriter request;
Yves Gerey665174f2018-06-19 15:03:05 +0200668 request.WriteUInt8(5); // Socks Version
669 request.WriteUInt8(1); // CONNECT
670 request.WriteUInt8(0); // Reserved
deadbeeff137e972017-03-23 15:45:49 -0700671 if (dest_.IsUnresolvedIP()) {
672 std::string hostname = dest_.hostname();
Yves Gerey665174f2018-06-19 15:03:05 +0200673 request.WriteUInt8(3); // DOMAINNAME
deadbeeff137e972017-03-23 15:45:49 -0700674 request.WriteUInt8(static_cast<uint8_t>(hostname.size()));
Yves Gerey665174f2018-06-19 15:03:05 +0200675 request.WriteString(hostname); // Destination Hostname
deadbeeff137e972017-03-23 15:45:49 -0700676 } else {
677 request.WriteUInt8(1); // IPV4
678 request.WriteUInt32(dest_.ip()); // Destination IP
679 }
680 request.WriteUInt16(dest_.port()); // Destination Port
681 DirectSend(request.Data(), request.Length());
682 state_ = SS_CONNECT;
683}
684
685void AsyncSocksProxySocket::Error(int error) {
686 state_ = SS_ERROR;
687 BufferInput(false);
688 Close();
689 SetError(SOCKET_EACCES);
690 SignalCloseEvent(this, error);
691}
692
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000693} // namespace rtc