blob: 9587d8dfc0813a561d9a7818d0c92c172e590cc1 [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"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020034#include "rtc_base/bytebuffer.h"
35#include "rtc_base/checks.h"
36#include "rtc_base/httpcommon.h"
37#include "rtc_base/logging.h"
38#include "rtc_base/socketadapters.h"
Jonas Olsson366a50c2018-09-06 13:41:30 +020039#include "rtc_base/strings/string_builder.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020040#include "rtc_base/stringutils.h"
Joachim Bauch5b32f232018-03-07 20:02:26 +010041#include "rtc_base/zero_memory.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000042
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000043namespace rtc {
44
45BufferedReadAdapter::BufferedReadAdapter(AsyncSocket* socket, size_t size)
Yves Gerey665174f2018-06-19 15:03:05 +020046 : AsyncSocketAdapter(socket),
47 buffer_size_(size),
48 data_len_(0),
49 buffering_(false) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000050 buffer_ = new char[buffer_size_];
51}
52
53BufferedReadAdapter::~BufferedReadAdapter() {
Yves Gerey665174f2018-06-19 15:03:05 +020054 delete[] buffer_;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000055}
56
Yves Gerey665174f2018-06-19 15:03:05 +020057int BufferedReadAdapter::Send(const void* pv, size_t cb) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000058 if (buffering_) {
59 // TODO: Spoof error better; Signal Writeable
60 socket_->SetError(EWOULDBLOCK);
61 return -1;
62 }
63 return AsyncSocketAdapter::Send(pv, cb);
64}
65
Stefan Holmer9131efd2016-05-23 18:19:26 +020066int BufferedReadAdapter::Recv(void* pv, size_t cb, int64_t* timestamp) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000067 if (buffering_) {
68 socket_->SetError(EWOULDBLOCK);
69 return -1;
70 }
71
72 size_t read = 0;
73
74 if (data_len_) {
andresp@webrtc.orgff689be2015-02-12 11:54:26 +000075 read = std::min(cb, data_len_);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000076 memcpy(pv, buffer_, read);
77 data_len_ -= read;
78 if (data_len_ > 0) {
79 memmove(buffer_, buffer_ + read, data_len_);
80 }
Yves Gerey665174f2018-06-19 15:03:05 +020081 pv = static_cast<char*>(pv) + read;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000082 cb -= read;
83 }
84
85 // FIX: If cb == 0, we won't generate another read event
86
Stefan Holmer9131efd2016-05-23 18:19:26 +020087 int res = AsyncSocketAdapter::Recv(pv, cb, timestamp);
deadbeefc5d0d952015-07-16 10:22:21 -070088 if (res >= 0) {
89 // Read from socket and possibly buffer; return combined length
90 return res + static_cast<int>(read);
91 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000092
deadbeefc5d0d952015-07-16 10:22:21 -070093 if (read > 0) {
94 // Failed to read from socket, but still read something from buffer
95 return static_cast<int>(read);
96 }
97
98 // Didn't read anything; return error from socket
99 return res;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000100}
101
102void BufferedReadAdapter::BufferInput(bool on) {
103 buffering_ = on;
104}
105
Yves Gerey665174f2018-06-19 15:03:05 +0200106void BufferedReadAdapter::OnReadEvent(AsyncSocket* socket) {
nisseede5da42017-01-12 05:15:36 -0800107 RTC_DCHECK(socket == socket_);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000108
109 if (!buffering_) {
110 AsyncSocketAdapter::OnReadEvent(socket);
111 return;
112 }
113
114 if (data_len_ >= buffer_size_) {
Jonas Olsson45cc8902018-02-13 10:37:07 +0100115 RTC_LOG(LS_ERROR) << "Input buffer overflow";
nissec80e7412017-01-11 05:56:46 -0800116 RTC_NOTREACHED();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000117 data_len_ = 0;
118 }
119
Stefan Holmer9131efd2016-05-23 18:19:26 +0200120 int len =
121 socket_->Recv(buffer_ + data_len_, buffer_size_ - data_len_, nullptr);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000122 if (len < 0) {
123 // TODO: Do something better like forwarding the error to the user.
Mirko Bonadei675513b2017-11-09 11:09:25 +0100124 RTC_LOG_ERR(INFO) << "Recv";
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000125 return;
126 }
127
128 data_len_ += len;
129
130 ProcessInput(buffer_, &data_len_);
131}
132
133///////////////////////////////////////////////////////////////////////////////
134
135// This is a SSL v2 CLIENT_HELLO message.
136// TODO: Should this have a session id? The response doesn't have a
137// certificate, so the hello should have a session id.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200138static const uint8_t kSslClientHello[] = {
139 0x80, 0x46, // msg len
140 0x01, // CLIENT_HELLO
141 0x03, 0x01, // SSL 3.1
142 0x00, 0x2d, // ciphersuite len
143 0x00, 0x00, // session id len
144 0x00, 0x10, // challenge len
145 0x01, 0x00, 0x80, 0x03, 0x00, 0x80, 0x07, 0x00, 0xc0, // ciphersuites
146 0x06, 0x00, 0x40, 0x02, 0x00, 0x80, 0x04, 0x00, 0x80, //
147 0x00, 0x00, 0x04, 0x00, 0xfe, 0xff, 0x00, 0x00, 0x0a, //
148 0x00, 0xfe, 0xfe, 0x00, 0x00, 0x09, 0x00, 0x00, 0x64, //
149 0x00, 0x00, 0x62, 0x00, 0x00, 0x03, 0x00, 0x00, 0x06, //
150 0x1f, 0x17, 0x0c, 0xa6, 0x2f, 0x00, 0x78, 0xfc, // challenge
151 0x46, 0x55, 0x2e, 0xb1, 0x83, 0x39, 0xf1, 0xea //
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000152};
153
Niels Möller44153152018-12-17 14:04:05 +0100154// static
155ArrayView<const uint8_t> AsyncSSLSocket::SslClientHello() {
156 // Implicit conversion directly from kSslClientHello to ArrayView fails when
157 // built with gcc.
158 return {kSslClientHello, sizeof(kSslClientHello)};
159}
160
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000161// This is a TLSv1 SERVER_HELLO message.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200162static const uint8_t kSslServerHello[] = {
163 0x16, // handshake message
164 0x03, 0x01, // SSL 3.1
165 0x00, 0x4a, // message len
166 0x02, // SERVER_HELLO
167 0x00, 0x00, 0x46, // handshake len
168 0x03, 0x01, // SSL 3.1
169 0x42, 0x85, 0x45, 0xa7, 0x27, 0xa9, 0x5d, 0xa0, // server random
170 0xb3, 0xc5, 0xe7, 0x53, 0xda, 0x48, 0x2b, 0x3f, //
171 0xc6, 0x5a, 0xca, 0x89, 0xc1, 0x58, 0x52, 0xa1, //
172 0x78, 0x3c, 0x5b, 0x17, 0x46, 0x00, 0x85, 0x3f, //
173 0x20, // session id len
174 0x0e, 0xd3, 0x06, 0x72, 0x5b, 0x5b, 0x1b, 0x5f, // session id
175 0x15, 0xac, 0x13, 0xf9, 0x88, 0x53, 0x9d, 0x9b, //
176 0xe8, 0x3d, 0x7b, 0x0c, 0x30, 0x32, 0x6e, 0x38, //
177 0x4d, 0xa2, 0x75, 0x57, 0x41, 0x6c, 0x34, 0x5c, //
178 0x00, 0x04, // RSA/RC4-128/MD5
179 0x00 // null compression
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000180};
181
Niels Möller44153152018-12-17 14:04:05 +0100182// static
183ArrayView<const uint8_t> AsyncSSLSocket::SslServerHello() {
184 return {kSslServerHello, sizeof(kSslServerHello)};
185}
186
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000187AsyncSSLSocket::AsyncSSLSocket(AsyncSocket* socket)
Yves Gerey665174f2018-06-19 15:03:05 +0200188 : BufferedReadAdapter(socket, 1024) {}
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000189
190int AsyncSSLSocket::Connect(const SocketAddress& addr) {
191 // Begin buffering before we connect, so that there isn't a race condition
192 // between potential senders and receiving the OnConnectEvent signal
193 BufferInput(true);
194 return BufferedReadAdapter::Connect(addr);
195}
196
Yves Gerey665174f2018-06-19 15:03:05 +0200197void AsyncSSLSocket::OnConnectEvent(AsyncSocket* socket) {
nisseede5da42017-01-12 05:15:36 -0800198 RTC_DCHECK(socket == socket_);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000199 // TODO: we could buffer output too...
nissec16fa5e2017-02-07 07:18:43 -0800200 const int res = DirectSend(kSslClientHello, sizeof(kSslClientHello));
201 RTC_DCHECK_EQ(sizeof(kSslClientHello), res);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000202}
203
204void AsyncSSLSocket::ProcessInput(char* data, size_t* len) {
205 if (*len < sizeof(kSslServerHello))
206 return;
207
208 if (memcmp(kSslServerHello, data, sizeof(kSslServerHello)) != 0) {
209 Close();
210 SignalCloseEvent(this, 0); // TODO: error code?
211 return;
212 }
213
214 *len -= sizeof(kSslServerHello);
215 if (*len > 0) {
216 memmove(data, data + sizeof(kSslServerHello), *len);
217 }
218
219 bool remainder = (*len > 0);
220 BufferInput(false);
221 SignalConnectEvent(this);
222
223 // FIX: if SignalConnect causes the socket to be destroyed, we are in trouble
224 if (remainder)
225 SignalReadEvent(this);
226}
227
deadbeeff137e972017-03-23 15:45:49 -0700228///////////////////////////////////////////////////////////////////////////////
229
230AsyncHttpsProxySocket::AsyncHttpsProxySocket(AsyncSocket* socket,
231 const std::string& user_agent,
232 const SocketAddress& proxy,
233 const std::string& username,
234 const CryptString& password)
Yves Gerey665174f2018-06-19 15:03:05 +0200235 : BufferedReadAdapter(socket, 1024),
236 proxy_(proxy),
237 agent_(user_agent),
238 user_(username),
239 pass_(password),
240 force_connect_(false),
241 state_(PS_ERROR),
242 context_(0) {}
deadbeeff137e972017-03-23 15:45:49 -0700243
244AsyncHttpsProxySocket::~AsyncHttpsProxySocket() {
245 delete context_;
246}
247
248int AsyncHttpsProxySocket::Connect(const SocketAddress& addr) {
249 int ret;
Mirko Bonadei675513b2017-11-09 11:09:25 +0100250 RTC_LOG(LS_VERBOSE) << "AsyncHttpsProxySocket::Connect("
251 << proxy_.ToSensitiveString() << ")";
deadbeeff137e972017-03-23 15:45:49 -0700252 dest_ = addr;
253 state_ = PS_INIT;
254 if (ShouldIssueConnect()) {
255 BufferInput(true);
256 }
257 ret = BufferedReadAdapter::Connect(proxy_);
258 // TODO: Set state_ appropriately if Connect fails.
259 return ret;
260}
261
262SocketAddress AsyncHttpsProxySocket::GetRemoteAddress() const {
263 return dest_;
264}
265
266int AsyncHttpsProxySocket::Close() {
267 headers_.clear();
268 state_ = PS_ERROR;
269 dest_.Clear();
270 delete context_;
271 context_ = nullptr;
272 return BufferedReadAdapter::Close();
273}
274
275Socket::ConnState AsyncHttpsProxySocket::GetState() const {
276 if (state_ < PS_TUNNEL) {
277 return CS_CONNECTING;
278 } else if (state_ == PS_TUNNEL) {
279 return CS_CONNECTED;
280 } else {
281 return CS_CLOSED;
282 }
283}
284
Yves Gerey665174f2018-06-19 15:03:05 +0200285void AsyncHttpsProxySocket::OnConnectEvent(AsyncSocket* socket) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100286 RTC_LOG(LS_VERBOSE) << "AsyncHttpsProxySocket::OnConnectEvent";
deadbeeff137e972017-03-23 15:45:49 -0700287 if (!ShouldIssueConnect()) {
288 state_ = PS_TUNNEL;
289 BufferedReadAdapter::OnConnectEvent(socket);
290 return;
291 }
292 SendRequest();
293}
294
Yves Gerey665174f2018-06-19 15:03:05 +0200295void AsyncHttpsProxySocket::OnCloseEvent(AsyncSocket* socket, int err) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100296 RTC_LOG(LS_VERBOSE) << "AsyncHttpsProxySocket::OnCloseEvent(" << err << ")";
deadbeeff137e972017-03-23 15:45:49 -0700297 if ((state_ == PS_WAIT_CLOSE) && (err == 0)) {
298 state_ = PS_ERROR;
299 Connect(dest_);
300 } else {
301 BufferedReadAdapter::OnCloseEvent(socket, err);
302 }
303}
304
305void AsyncHttpsProxySocket::ProcessInput(char* data, size_t* len) {
306 size_t start = 0;
307 for (size_t pos = start; state_ < PS_TUNNEL && pos < *len;) {
308 if (state_ == PS_SKIP_BODY) {
309 size_t consume = std::min(*len - pos, content_length_);
310 pos += consume;
311 start = pos;
312 content_length_ -= consume;
313 if (content_length_ == 0) {
314 EndResponse();
315 }
316 continue;
317 }
318
319 if (data[pos++] != '\n')
320 continue;
321
322 size_t len = pos - start - 1;
323 if ((len > 0) && (data[start + len - 1] == '\r'))
324 --len;
325
326 data[start + len] = 0;
327 ProcessLine(data + start, len);
328 start = pos;
329 }
330
331 *len -= start;
332 if (*len > 0) {
333 memmove(data, data + start, *len);
334 }
335
336 if (state_ != PS_TUNNEL)
337 return;
338
339 bool remainder = (*len > 0);
340 BufferInput(false);
341 SignalConnectEvent(this);
342
343 // FIX: if SignalConnect causes the socket to be destroyed, we are in trouble
344 if (remainder)
345 SignalReadEvent(this); // TODO: signal this??
346}
347
348bool AsyncHttpsProxySocket::ShouldIssueConnect() const {
349 // TODO: Think about whether a more sophisticated test
350 // than dest port == 80 is needed.
351 return force_connect_ || (dest_.port() != 80);
352}
353
354void AsyncHttpsProxySocket::SendRequest() {
Jonas Olsson366a50c2018-09-06 13:41:30 +0200355 rtc::StringBuilder ss;
deadbeeff137e972017-03-23 15:45:49 -0700356 ss << "CONNECT " << dest_.ToString() << " HTTP/1.0\r\n";
357 ss << "User-Agent: " << agent_ << "\r\n";
358 ss << "Host: " << dest_.HostAsURIString() << "\r\n";
359 ss << "Content-Length: 0\r\n";
360 ss << "Proxy-Connection: Keep-Alive\r\n";
361 ss << headers_;
362 ss << "\r\n";
363 std::string str = ss.str();
364 DirectSend(str.c_str(), str.size());
365 state_ = PS_LEADER;
366 expect_close_ = true;
367 content_length_ = 0;
368 headers_.clear();
369
Mirko Bonadei675513b2017-11-09 11:09:25 +0100370 RTC_LOG(LS_VERBOSE) << "AsyncHttpsProxySocket >> " << str;
deadbeeff137e972017-03-23 15:45:49 -0700371}
372
Yves Gerey665174f2018-06-19 15:03:05 +0200373void AsyncHttpsProxySocket::ProcessLine(char* data, size_t len) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100374 RTC_LOG(LS_VERBOSE) << "AsyncHttpsProxySocket << " << data;
deadbeeff137e972017-03-23 15:45:49 -0700375
376 if (len == 0) {
377 if (state_ == PS_TUNNEL_HEADERS) {
378 state_ = PS_TUNNEL;
379 } else if (state_ == PS_ERROR_HEADERS) {
380 Error(defer_error_);
381 return;
382 } else if (state_ == PS_SKIP_HEADERS) {
383 if (content_length_) {
384 state_ = PS_SKIP_BODY;
385 } else {
386 EndResponse();
387 return;
388 }
389 } else {
390 static bool report = false;
391 if (!unknown_mechanisms_.empty() && !report) {
392 report = true;
393 std::string msg(
Yves Gerey665174f2018-06-19 15:03:05 +0200394 "Unable to connect to the Google Talk service due to an "
395 "incompatibility "
396 "with your proxy.\r\nPlease help us resolve this issue by "
397 "submitting the "
398 "following information to us using our technical issue submission "
399 "form "
400 "at:\r\n\r\n"
401 "http://www.google.com/support/talk/bin/request.py\r\n\r\n"
402 "We apologize for the inconvenience.\r\n\r\n"
403 "Information to submit to Google: ");
404 // std::string msg("Please report the following information to
405 // foo@bar.com:\r\nUnknown methods: ");
deadbeeff137e972017-03-23 15:45:49 -0700406 msg.append(unknown_mechanisms_);
Robin Raymondce1b1402018-11-22 20:10:11 -0500407#if defined(WEBRTC_WIN) && !defined(WINUWP)
deadbeeff137e972017-03-23 15:45:49 -0700408 MessageBoxA(0, msg.c_str(), "Oops!", MB_OK);
409#endif
410#if defined(WEBRTC_POSIX)
411 // TODO: Raise a signal so the UI can be separated.
Mirko Bonadei675513b2017-11-09 11:09:25 +0100412 RTC_LOG(LS_ERROR) << "Oops!\n\n" << msg;
deadbeeff137e972017-03-23 15:45:49 -0700413#endif
414 }
415 // Unexpected end of headers
416 Error(0);
417 return;
418 }
419 } else if (state_ == PS_LEADER) {
420 unsigned int code;
421 if (sscanf(data, "HTTP/%*u.%*u %u", &code) != 1) {
422 Error(0);
423 return;
424 }
425 switch (code) {
Yves Gerey665174f2018-06-19 15:03:05 +0200426 case 200:
427 // connection good!
428 state_ = PS_TUNNEL_HEADERS;
429 return;
deadbeeff137e972017-03-23 15:45:49 -0700430#if defined(HTTP_STATUS_PROXY_AUTH_REQ) && (HTTP_STATUS_PROXY_AUTH_REQ != 407)
431#error Wrong code for HTTP_STATUS_PROXY_AUTH_REQ
432#endif
Yves Gerey665174f2018-06-19 15:03:05 +0200433 case 407: // HTTP_STATUS_PROXY_AUTH_REQ
434 state_ = PS_AUTHENTICATE;
435 return;
436 default:
437 defer_error_ = 0;
438 state_ = PS_ERROR_HEADERS;
439 return;
deadbeeff137e972017-03-23 15:45:49 -0700440 }
Yves Gerey665174f2018-06-19 15:03:05 +0200441 } else if ((state_ == PS_AUTHENTICATE) &&
Niels Mölleraa3c1cc2018-11-02 10:54:56 +0100442 absl::StartsWithIgnoreCase(data, "Proxy-Authenticate:")) {
deadbeeff137e972017-03-23 15:45:49 -0700443 std::string response, auth_method;
Yves Gerey665174f2018-06-19 15:03:05 +0200444 switch (HttpAuthenticate(data + 19, len - 19, proxy_, "CONNECT", "/", user_,
445 pass_, context_, response, auth_method)) {
446 case HAR_IGNORE:
447 RTC_LOG(LS_VERBOSE) << "Ignoring Proxy-Authenticate: " << auth_method;
448 if (!unknown_mechanisms_.empty())
449 unknown_mechanisms_.append(", ");
450 unknown_mechanisms_.append(auth_method);
451 break;
452 case HAR_RESPONSE:
453 headers_ = "Proxy-Authorization: ";
454 headers_.append(response);
455 headers_.append("\r\n");
456 state_ = PS_SKIP_HEADERS;
457 unknown_mechanisms_.clear();
458 break;
459 case HAR_CREDENTIALS:
460 defer_error_ = SOCKET_EACCES;
461 state_ = PS_ERROR_HEADERS;
462 unknown_mechanisms_.clear();
463 break;
464 case HAR_ERROR:
465 defer_error_ = 0;
466 state_ = PS_ERROR_HEADERS;
467 unknown_mechanisms_.clear();
468 break;
deadbeeff137e972017-03-23 15:45:49 -0700469 }
Niels Mölleraa3c1cc2018-11-02 10:54:56 +0100470 } else if (absl::StartsWithIgnoreCase(data, "Content-Length:")) {
deadbeeff137e972017-03-23 15:45:49 -0700471 content_length_ = strtoul(data + 15, 0, 0);
Niels Mölleraa3c1cc2018-11-02 10:54:56 +0100472 } else if (absl::StartsWithIgnoreCase(data, "Proxy-Connection: Keep-Alive")) {
deadbeeff137e972017-03-23 15:45:49 -0700473 expect_close_ = false;
474 /*
Niels Mölleraa3c1cc2018-11-02 10:54:56 +0100475 } else if (absl::StartsWithIgnoreCase(data, "Connection: close") {
deadbeeff137e972017-03-23 15:45:49 -0700476 expect_close_ = true;
477 */
478 }
479}
480
481void AsyncHttpsProxySocket::EndResponse() {
482 if (!expect_close_) {
483 SendRequest();
484 return;
485 }
486
487 // No point in waiting for the server to close... let's close now
488 // TODO: Refactor out PS_WAIT_CLOSE
489 state_ = PS_WAIT_CLOSE;
490 BufferedReadAdapter::Close();
491 OnCloseEvent(this, 0);
492}
493
494void AsyncHttpsProxySocket::Error(int error) {
495 BufferInput(false);
496 Close();
497 SetError(error);
498 SignalCloseEvent(this, error);
499}
500
501///////////////////////////////////////////////////////////////////////////////
502
503AsyncSocksProxySocket::AsyncSocksProxySocket(AsyncSocket* socket,
504 const SocketAddress& proxy,
505 const std::string& username,
506 const CryptString& password)
Yves Gerey665174f2018-06-19 15:03:05 +0200507 : BufferedReadAdapter(socket, 1024),
508 state_(SS_ERROR),
509 proxy_(proxy),
510 user_(username),
511 pass_(password) {}
deadbeeff137e972017-03-23 15:45:49 -0700512
513AsyncSocksProxySocket::~AsyncSocksProxySocket() = default;
514
515int AsyncSocksProxySocket::Connect(const SocketAddress& addr) {
516 int ret;
517 dest_ = addr;
518 state_ = SS_INIT;
519 BufferInput(true);
520 ret = BufferedReadAdapter::Connect(proxy_);
521 // TODO: Set state_ appropriately if Connect fails.
522 return ret;
523}
524
525SocketAddress AsyncSocksProxySocket::GetRemoteAddress() const {
526 return dest_;
527}
528
529int AsyncSocksProxySocket::Close() {
530 state_ = SS_ERROR;
531 dest_.Clear();
532 return BufferedReadAdapter::Close();
533}
534
535Socket::ConnState AsyncSocksProxySocket::GetState() const {
536 if (state_ < SS_TUNNEL) {
537 return CS_CONNECTING;
538 } else if (state_ == SS_TUNNEL) {
539 return CS_CONNECTED;
540 } else {
541 return CS_CLOSED;
542 }
543}
544
545void AsyncSocksProxySocket::OnConnectEvent(AsyncSocket* socket) {
546 SendHello();
547}
548
549void AsyncSocksProxySocket::ProcessInput(char* data, size_t* len) {
550 RTC_DCHECK(state_ < SS_TUNNEL);
551
552 ByteBufferReader response(data, *len);
553
554 if (state_ == SS_HELLO) {
555 uint8_t ver, method;
Yves Gerey665174f2018-06-19 15:03:05 +0200556 if (!response.ReadUInt8(&ver) || !response.ReadUInt8(&method))
deadbeeff137e972017-03-23 15:45:49 -0700557 return;
558
559 if (ver != 5) {
560 Error(0);
561 return;
562 }
563
564 if (method == 0) {
565 SendConnect();
566 } else if (method == 2) {
567 SendAuth();
568 } else {
569 Error(0);
570 return;
571 }
572 } else if (state_ == SS_AUTH) {
573 uint8_t ver, status;
Yves Gerey665174f2018-06-19 15:03:05 +0200574 if (!response.ReadUInt8(&ver) || !response.ReadUInt8(&status))
deadbeeff137e972017-03-23 15:45:49 -0700575 return;
576
577 if ((ver != 1) || (status != 0)) {
578 Error(SOCKET_EACCES);
579 return;
580 }
581
582 SendConnect();
583 } else if (state_ == SS_CONNECT) {
584 uint8_t ver, rep, rsv, atyp;
Yves Gerey665174f2018-06-19 15:03:05 +0200585 if (!response.ReadUInt8(&ver) || !response.ReadUInt8(&rep) ||
586 !response.ReadUInt8(&rsv) || !response.ReadUInt8(&atyp))
deadbeeff137e972017-03-23 15:45:49 -0700587 return;
588
589 if ((ver != 5) || (rep != 0)) {
590 Error(0);
591 return;
592 }
593
594 uint16_t port;
595 if (atyp == 1) {
596 uint32_t addr;
Yves Gerey665174f2018-06-19 15:03:05 +0200597 if (!response.ReadUInt32(&addr) || !response.ReadUInt16(&port))
deadbeeff137e972017-03-23 15:45:49 -0700598 return;
Mirko Bonadei675513b2017-11-09 11:09:25 +0100599 RTC_LOG(LS_VERBOSE) << "Bound on " << addr << ":" << port;
deadbeeff137e972017-03-23 15:45:49 -0700600 } else if (atyp == 3) {
601 uint8_t len;
602 std::string addr;
Yves Gerey665174f2018-06-19 15:03:05 +0200603 if (!response.ReadUInt8(&len) || !response.ReadString(&addr, len) ||
deadbeeff137e972017-03-23 15:45:49 -0700604 !response.ReadUInt16(&port))
605 return;
Mirko Bonadei675513b2017-11-09 11:09:25 +0100606 RTC_LOG(LS_VERBOSE) << "Bound on " << addr << ":" << port;
deadbeeff137e972017-03-23 15:45:49 -0700607 } else if (atyp == 4) {
608 std::string addr;
Yves Gerey665174f2018-06-19 15:03:05 +0200609 if (!response.ReadString(&addr, 16) || !response.ReadUInt16(&port))
deadbeeff137e972017-03-23 15:45:49 -0700610 return;
Mirko Bonadei675513b2017-11-09 11:09:25 +0100611 RTC_LOG(LS_VERBOSE) << "Bound on <IPV6>:" << port;
deadbeeff137e972017-03-23 15:45:49 -0700612 } else {
613 Error(0);
614 return;
615 }
616
617 state_ = SS_TUNNEL;
618 }
619
620 // Consume parsed data
621 *len = response.Length();
622 memmove(data, response.Data(), *len);
623
624 if (state_ != SS_TUNNEL)
625 return;
626
627 bool remainder = (*len > 0);
628 BufferInput(false);
629 SignalConnectEvent(this);
630
631 // FIX: if SignalConnect causes the socket to be destroyed, we are in trouble
632 if (remainder)
633 SignalReadEvent(this); // TODO: signal this??
634}
635
636void AsyncSocksProxySocket::SendHello() {
637 ByteBufferWriter request;
Yves Gerey665174f2018-06-19 15:03:05 +0200638 request.WriteUInt8(5); // Socks Version
deadbeeff137e972017-03-23 15:45:49 -0700639 if (user_.empty()) {
640 request.WriteUInt8(1); // Authentication Mechanisms
641 request.WriteUInt8(0); // No authentication
642 } else {
643 request.WriteUInt8(2); // Authentication Mechanisms
644 request.WriteUInt8(0); // No authentication
645 request.WriteUInt8(2); // Username/Password
646 }
647 DirectSend(request.Data(), request.Length());
648 state_ = SS_HELLO;
649}
650
651void AsyncSocksProxySocket::SendAuth() {
Joachim Bauch4c6a30c2018-03-08 00:55:33 +0100652 ByteBufferWriterT<ZeroOnFreeBuffer<char>> request;
Yves Gerey665174f2018-06-19 15:03:05 +0200653 request.WriteUInt8(1); // Negotiation Version
deadbeeff137e972017-03-23 15:45:49 -0700654 request.WriteUInt8(static_cast<uint8_t>(user_.size()));
Yves Gerey665174f2018-06-19 15:03:05 +0200655 request.WriteString(user_); // Username
deadbeeff137e972017-03-23 15:45:49 -0700656 request.WriteUInt8(static_cast<uint8_t>(pass_.GetLength()));
657 size_t len = pass_.GetLength() + 1;
Yves Gerey665174f2018-06-19 15:03:05 +0200658 char* sensitive = new char[len];
deadbeeff137e972017-03-23 15:45:49 -0700659 pass_.CopyTo(sensitive, true);
Joachim Bauch5b32f232018-03-07 20:02:26 +0100660 request.WriteBytes(sensitive, pass_.GetLength()); // Password
661 ExplicitZeroMemory(sensitive, len);
Yves Gerey665174f2018-06-19 15:03:05 +0200662 delete[] sensitive;
deadbeeff137e972017-03-23 15:45:49 -0700663 DirectSend(request.Data(), request.Length());
664 state_ = SS_AUTH;
665}
666
667void AsyncSocksProxySocket::SendConnect() {
668 ByteBufferWriter request;
Yves Gerey665174f2018-06-19 15:03:05 +0200669 request.WriteUInt8(5); // Socks Version
670 request.WriteUInt8(1); // CONNECT
671 request.WriteUInt8(0); // Reserved
deadbeeff137e972017-03-23 15:45:49 -0700672 if (dest_.IsUnresolvedIP()) {
673 std::string hostname = dest_.hostname();
Yves Gerey665174f2018-06-19 15:03:05 +0200674 request.WriteUInt8(3); // DOMAINNAME
deadbeeff137e972017-03-23 15:45:49 -0700675 request.WriteUInt8(static_cast<uint8_t>(hostname.size()));
Yves Gerey665174f2018-06-19 15:03:05 +0200676 request.WriteString(hostname); // Destination Hostname
deadbeeff137e972017-03-23 15:45:49 -0700677 } else {
678 request.WriteUInt8(1); // IPV4
679 request.WriteUInt32(dest_.ip()); // Destination IP
680 }
681 request.WriteUInt16(dest_.port()); // Destination Port
682 DirectSend(request.Data(), request.Length());
683 state_ = SS_CONNECT;
684}
685
686void AsyncSocksProxySocket::Error(int error) {
687 state_ = SS_ERROR;
688 BufferInput(false);
689 Close();
690 SetError(SOCKET_EACCES);
691 SignalCloseEvent(this, error);
692}
693
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000694} // namespace rtc