blob: 945192889142a8e04ed3f9d3d78cab2def852b47 [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
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +0000133AsyncProxyServerSocket::AsyncProxyServerSocket(AsyncSocket* socket,
134 size_t buffer_size)
Yves Gerey665174f2018-06-19 15:03:05 +0200135 : BufferedReadAdapter(socket, buffer_size) {}
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +0000136
137AsyncProxyServerSocket::~AsyncProxyServerSocket() = default;
138
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000139///////////////////////////////////////////////////////////////////////////////
140
141// This is a SSL v2 CLIENT_HELLO message.
142// TODO: Should this have a session id? The response doesn't have a
143// certificate, so the hello should have a session id.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200144static const uint8_t kSslClientHello[] = {
145 0x80, 0x46, // msg len
146 0x01, // CLIENT_HELLO
147 0x03, 0x01, // SSL 3.1
148 0x00, 0x2d, // ciphersuite len
149 0x00, 0x00, // session id len
150 0x00, 0x10, // challenge len
151 0x01, 0x00, 0x80, 0x03, 0x00, 0x80, 0x07, 0x00, 0xc0, // ciphersuites
152 0x06, 0x00, 0x40, 0x02, 0x00, 0x80, 0x04, 0x00, 0x80, //
153 0x00, 0x00, 0x04, 0x00, 0xfe, 0xff, 0x00, 0x00, 0x0a, //
154 0x00, 0xfe, 0xfe, 0x00, 0x00, 0x09, 0x00, 0x00, 0x64, //
155 0x00, 0x00, 0x62, 0x00, 0x00, 0x03, 0x00, 0x00, 0x06, //
156 0x1f, 0x17, 0x0c, 0xa6, 0x2f, 0x00, 0x78, 0xfc, // challenge
157 0x46, 0x55, 0x2e, 0xb1, 0x83, 0x39, 0xf1, 0xea //
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000158};
159
160// 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
181AsyncSSLSocket::AsyncSSLSocket(AsyncSocket* socket)
Yves Gerey665174f2018-06-19 15:03:05 +0200182 : BufferedReadAdapter(socket, 1024) {}
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000183
184int AsyncSSLSocket::Connect(const SocketAddress& addr) {
185 // Begin buffering before we connect, so that there isn't a race condition
186 // between potential senders and receiving the OnConnectEvent signal
187 BufferInput(true);
188 return BufferedReadAdapter::Connect(addr);
189}
190
Yves Gerey665174f2018-06-19 15:03:05 +0200191void AsyncSSLSocket::OnConnectEvent(AsyncSocket* socket) {
nisseede5da42017-01-12 05:15:36 -0800192 RTC_DCHECK(socket == socket_);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000193 // TODO: we could buffer output too...
nissec16fa5e2017-02-07 07:18:43 -0800194 const int res = DirectSend(kSslClientHello, sizeof(kSslClientHello));
195 RTC_DCHECK_EQ(sizeof(kSslClientHello), res);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000196}
197
198void AsyncSSLSocket::ProcessInput(char* data, size_t* len) {
199 if (*len < sizeof(kSslServerHello))
200 return;
201
202 if (memcmp(kSslServerHello, data, sizeof(kSslServerHello)) != 0) {
203 Close();
204 SignalCloseEvent(this, 0); // TODO: error code?
205 return;
206 }
207
208 *len -= sizeof(kSslServerHello);
209 if (*len > 0) {
210 memmove(data, data + sizeof(kSslServerHello), *len);
211 }
212
213 bool remainder = (*len > 0);
214 BufferInput(false);
215 SignalConnectEvent(this);
216
217 // FIX: if SignalConnect causes the socket to be destroyed, we are in trouble
218 if (remainder)
219 SignalReadEvent(this);
220}
221
222AsyncSSLServerSocket::AsyncSSLServerSocket(AsyncSocket* socket)
Yves Gerey665174f2018-06-19 15:03:05 +0200223 : BufferedReadAdapter(socket, 1024) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000224 BufferInput(true);
225}
226
227void AsyncSSLServerSocket::ProcessInput(char* data, size_t* len) {
228 // We only accept client hello messages.
229 if (*len < sizeof(kSslClientHello)) {
230 return;
231 }
232
233 if (memcmp(kSslClientHello, data, sizeof(kSslClientHello)) != 0) {
234 Close();
235 SignalCloseEvent(this, 0);
236 return;
237 }
238
239 *len -= sizeof(kSslClientHello);
240
241 // Clients should not send more data until the handshake is completed.
nisseede5da42017-01-12 05:15:36 -0800242 RTC_DCHECK(*len == 0);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000243
244 // Send a server hello back to the client.
245 DirectSend(kSslServerHello, sizeof(kSslServerHello));
246
247 // Handshake completed for us, redirect input to our parent.
248 BufferInput(false);
249}
250
deadbeeff137e972017-03-23 15:45:49 -0700251///////////////////////////////////////////////////////////////////////////////
252
253AsyncHttpsProxySocket::AsyncHttpsProxySocket(AsyncSocket* socket,
254 const std::string& user_agent,
255 const SocketAddress& proxy,
256 const std::string& username,
257 const CryptString& password)
Yves Gerey665174f2018-06-19 15:03:05 +0200258 : BufferedReadAdapter(socket, 1024),
259 proxy_(proxy),
260 agent_(user_agent),
261 user_(username),
262 pass_(password),
263 force_connect_(false),
264 state_(PS_ERROR),
265 context_(0) {}
deadbeeff137e972017-03-23 15:45:49 -0700266
267AsyncHttpsProxySocket::~AsyncHttpsProxySocket() {
268 delete context_;
269}
270
271int AsyncHttpsProxySocket::Connect(const SocketAddress& addr) {
272 int ret;
Mirko Bonadei675513b2017-11-09 11:09:25 +0100273 RTC_LOG(LS_VERBOSE) << "AsyncHttpsProxySocket::Connect("
274 << proxy_.ToSensitiveString() << ")";
deadbeeff137e972017-03-23 15:45:49 -0700275 dest_ = addr;
276 state_ = PS_INIT;
277 if (ShouldIssueConnect()) {
278 BufferInput(true);
279 }
280 ret = BufferedReadAdapter::Connect(proxy_);
281 // TODO: Set state_ appropriately if Connect fails.
282 return ret;
283}
284
285SocketAddress AsyncHttpsProxySocket::GetRemoteAddress() const {
286 return dest_;
287}
288
289int AsyncHttpsProxySocket::Close() {
290 headers_.clear();
291 state_ = PS_ERROR;
292 dest_.Clear();
293 delete context_;
294 context_ = nullptr;
295 return BufferedReadAdapter::Close();
296}
297
298Socket::ConnState AsyncHttpsProxySocket::GetState() const {
299 if (state_ < PS_TUNNEL) {
300 return CS_CONNECTING;
301 } else if (state_ == PS_TUNNEL) {
302 return CS_CONNECTED;
303 } else {
304 return CS_CLOSED;
305 }
306}
307
Yves Gerey665174f2018-06-19 15:03:05 +0200308void AsyncHttpsProxySocket::OnConnectEvent(AsyncSocket* socket) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100309 RTC_LOG(LS_VERBOSE) << "AsyncHttpsProxySocket::OnConnectEvent";
deadbeeff137e972017-03-23 15:45:49 -0700310 if (!ShouldIssueConnect()) {
311 state_ = PS_TUNNEL;
312 BufferedReadAdapter::OnConnectEvent(socket);
313 return;
314 }
315 SendRequest();
316}
317
Yves Gerey665174f2018-06-19 15:03:05 +0200318void AsyncHttpsProxySocket::OnCloseEvent(AsyncSocket* socket, int err) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100319 RTC_LOG(LS_VERBOSE) << "AsyncHttpsProxySocket::OnCloseEvent(" << err << ")";
deadbeeff137e972017-03-23 15:45:49 -0700320 if ((state_ == PS_WAIT_CLOSE) && (err == 0)) {
321 state_ = PS_ERROR;
322 Connect(dest_);
323 } else {
324 BufferedReadAdapter::OnCloseEvent(socket, err);
325 }
326}
327
328void AsyncHttpsProxySocket::ProcessInput(char* data, size_t* len) {
329 size_t start = 0;
330 for (size_t pos = start; state_ < PS_TUNNEL && pos < *len;) {
331 if (state_ == PS_SKIP_BODY) {
332 size_t consume = std::min(*len - pos, content_length_);
333 pos += consume;
334 start = pos;
335 content_length_ -= consume;
336 if (content_length_ == 0) {
337 EndResponse();
338 }
339 continue;
340 }
341
342 if (data[pos++] != '\n')
343 continue;
344
345 size_t len = pos - start - 1;
346 if ((len > 0) && (data[start + len - 1] == '\r'))
347 --len;
348
349 data[start + len] = 0;
350 ProcessLine(data + start, len);
351 start = pos;
352 }
353
354 *len -= start;
355 if (*len > 0) {
356 memmove(data, data + start, *len);
357 }
358
359 if (state_ != PS_TUNNEL)
360 return;
361
362 bool remainder = (*len > 0);
363 BufferInput(false);
364 SignalConnectEvent(this);
365
366 // FIX: if SignalConnect causes the socket to be destroyed, we are in trouble
367 if (remainder)
368 SignalReadEvent(this); // TODO: signal this??
369}
370
371bool AsyncHttpsProxySocket::ShouldIssueConnect() const {
372 // TODO: Think about whether a more sophisticated test
373 // than dest port == 80 is needed.
374 return force_connect_ || (dest_.port() != 80);
375}
376
377void AsyncHttpsProxySocket::SendRequest() {
Jonas Olsson366a50c2018-09-06 13:41:30 +0200378 rtc::StringBuilder ss;
deadbeeff137e972017-03-23 15:45:49 -0700379 ss << "CONNECT " << dest_.ToString() << " HTTP/1.0\r\n";
380 ss << "User-Agent: " << agent_ << "\r\n";
381 ss << "Host: " << dest_.HostAsURIString() << "\r\n";
382 ss << "Content-Length: 0\r\n";
383 ss << "Proxy-Connection: Keep-Alive\r\n";
384 ss << headers_;
385 ss << "\r\n";
386 std::string str = ss.str();
387 DirectSend(str.c_str(), str.size());
388 state_ = PS_LEADER;
389 expect_close_ = true;
390 content_length_ = 0;
391 headers_.clear();
392
Mirko Bonadei675513b2017-11-09 11:09:25 +0100393 RTC_LOG(LS_VERBOSE) << "AsyncHttpsProxySocket >> " << str;
deadbeeff137e972017-03-23 15:45:49 -0700394}
395
Yves Gerey665174f2018-06-19 15:03:05 +0200396void AsyncHttpsProxySocket::ProcessLine(char* data, size_t len) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100397 RTC_LOG(LS_VERBOSE) << "AsyncHttpsProxySocket << " << data;
deadbeeff137e972017-03-23 15:45:49 -0700398
399 if (len == 0) {
400 if (state_ == PS_TUNNEL_HEADERS) {
401 state_ = PS_TUNNEL;
402 } else if (state_ == PS_ERROR_HEADERS) {
403 Error(defer_error_);
404 return;
405 } else if (state_ == PS_SKIP_HEADERS) {
406 if (content_length_) {
407 state_ = PS_SKIP_BODY;
408 } else {
409 EndResponse();
410 return;
411 }
412 } else {
413 static bool report = false;
414 if (!unknown_mechanisms_.empty() && !report) {
415 report = true;
416 std::string msg(
Yves Gerey665174f2018-06-19 15:03:05 +0200417 "Unable to connect to the Google Talk service due to an "
418 "incompatibility "
419 "with your proxy.\r\nPlease help us resolve this issue by "
420 "submitting the "
421 "following information to us using our technical issue submission "
422 "form "
423 "at:\r\n\r\n"
424 "http://www.google.com/support/talk/bin/request.py\r\n\r\n"
425 "We apologize for the inconvenience.\r\n\r\n"
426 "Information to submit to Google: ");
427 // std::string msg("Please report the following information to
428 // foo@bar.com:\r\nUnknown methods: ");
deadbeeff137e972017-03-23 15:45:49 -0700429 msg.append(unknown_mechanisms_);
430#if defined(WEBRTC_WIN)
431 MessageBoxA(0, msg.c_str(), "Oops!", MB_OK);
432#endif
433#if defined(WEBRTC_POSIX)
434 // TODO: Raise a signal so the UI can be separated.
Mirko Bonadei675513b2017-11-09 11:09:25 +0100435 RTC_LOG(LS_ERROR) << "Oops!\n\n" << msg;
deadbeeff137e972017-03-23 15:45:49 -0700436#endif
437 }
438 // Unexpected end of headers
439 Error(0);
440 return;
441 }
442 } else if (state_ == PS_LEADER) {
443 unsigned int code;
444 if (sscanf(data, "HTTP/%*u.%*u %u", &code) != 1) {
445 Error(0);
446 return;
447 }
448 switch (code) {
Yves Gerey665174f2018-06-19 15:03:05 +0200449 case 200:
450 // connection good!
451 state_ = PS_TUNNEL_HEADERS;
452 return;
deadbeeff137e972017-03-23 15:45:49 -0700453#if defined(HTTP_STATUS_PROXY_AUTH_REQ) && (HTTP_STATUS_PROXY_AUTH_REQ != 407)
454#error Wrong code for HTTP_STATUS_PROXY_AUTH_REQ
455#endif
Yves Gerey665174f2018-06-19 15:03:05 +0200456 case 407: // HTTP_STATUS_PROXY_AUTH_REQ
457 state_ = PS_AUTHENTICATE;
458 return;
459 default:
460 defer_error_ = 0;
461 state_ = PS_ERROR_HEADERS;
462 return;
deadbeeff137e972017-03-23 15:45:49 -0700463 }
Yves Gerey665174f2018-06-19 15:03:05 +0200464 } else if ((state_ == PS_AUTHENTICATE) &&
Niels Mölleraa3c1cc2018-11-02 10:54:56 +0100465 absl::StartsWithIgnoreCase(data, "Proxy-Authenticate:")) {
deadbeeff137e972017-03-23 15:45:49 -0700466 std::string response, auth_method;
Yves Gerey665174f2018-06-19 15:03:05 +0200467 switch (HttpAuthenticate(data + 19, len - 19, proxy_, "CONNECT", "/", user_,
468 pass_, context_, response, auth_method)) {
469 case HAR_IGNORE:
470 RTC_LOG(LS_VERBOSE) << "Ignoring Proxy-Authenticate: " << auth_method;
471 if (!unknown_mechanisms_.empty())
472 unknown_mechanisms_.append(", ");
473 unknown_mechanisms_.append(auth_method);
474 break;
475 case HAR_RESPONSE:
476 headers_ = "Proxy-Authorization: ";
477 headers_.append(response);
478 headers_.append("\r\n");
479 state_ = PS_SKIP_HEADERS;
480 unknown_mechanisms_.clear();
481 break;
482 case HAR_CREDENTIALS:
483 defer_error_ = SOCKET_EACCES;
484 state_ = PS_ERROR_HEADERS;
485 unknown_mechanisms_.clear();
486 break;
487 case HAR_ERROR:
488 defer_error_ = 0;
489 state_ = PS_ERROR_HEADERS;
490 unknown_mechanisms_.clear();
491 break;
deadbeeff137e972017-03-23 15:45:49 -0700492 }
Niels Mölleraa3c1cc2018-11-02 10:54:56 +0100493 } else if (absl::StartsWithIgnoreCase(data, "Content-Length:")) {
deadbeeff137e972017-03-23 15:45:49 -0700494 content_length_ = strtoul(data + 15, 0, 0);
Niels Mölleraa3c1cc2018-11-02 10:54:56 +0100495 } else if (absl::StartsWithIgnoreCase(data, "Proxy-Connection: Keep-Alive")) {
deadbeeff137e972017-03-23 15:45:49 -0700496 expect_close_ = false;
497 /*
Niels Mölleraa3c1cc2018-11-02 10:54:56 +0100498 } else if (absl::StartsWithIgnoreCase(data, "Connection: close") {
deadbeeff137e972017-03-23 15:45:49 -0700499 expect_close_ = true;
500 */
501 }
502}
503
504void AsyncHttpsProxySocket::EndResponse() {
505 if (!expect_close_) {
506 SendRequest();
507 return;
508 }
509
510 // No point in waiting for the server to close... let's close now
511 // TODO: Refactor out PS_WAIT_CLOSE
512 state_ = PS_WAIT_CLOSE;
513 BufferedReadAdapter::Close();
514 OnCloseEvent(this, 0);
515}
516
517void AsyncHttpsProxySocket::Error(int error) {
518 BufferInput(false);
519 Close();
520 SetError(error);
521 SignalCloseEvent(this, error);
522}
523
524///////////////////////////////////////////////////////////////////////////////
525
526AsyncSocksProxySocket::AsyncSocksProxySocket(AsyncSocket* socket,
527 const SocketAddress& proxy,
528 const std::string& username,
529 const CryptString& password)
Yves Gerey665174f2018-06-19 15:03:05 +0200530 : BufferedReadAdapter(socket, 1024),
531 state_(SS_ERROR),
532 proxy_(proxy),
533 user_(username),
534 pass_(password) {}
deadbeeff137e972017-03-23 15:45:49 -0700535
536AsyncSocksProxySocket::~AsyncSocksProxySocket() = default;
537
538int AsyncSocksProxySocket::Connect(const SocketAddress& addr) {
539 int ret;
540 dest_ = addr;
541 state_ = SS_INIT;
542 BufferInput(true);
543 ret = BufferedReadAdapter::Connect(proxy_);
544 // TODO: Set state_ appropriately if Connect fails.
545 return ret;
546}
547
548SocketAddress AsyncSocksProxySocket::GetRemoteAddress() const {
549 return dest_;
550}
551
552int AsyncSocksProxySocket::Close() {
553 state_ = SS_ERROR;
554 dest_.Clear();
555 return BufferedReadAdapter::Close();
556}
557
558Socket::ConnState AsyncSocksProxySocket::GetState() const {
559 if (state_ < SS_TUNNEL) {
560 return CS_CONNECTING;
561 } else if (state_ == SS_TUNNEL) {
562 return CS_CONNECTED;
563 } else {
564 return CS_CLOSED;
565 }
566}
567
568void AsyncSocksProxySocket::OnConnectEvent(AsyncSocket* socket) {
569 SendHello();
570}
571
572void AsyncSocksProxySocket::ProcessInput(char* data, size_t* len) {
573 RTC_DCHECK(state_ < SS_TUNNEL);
574
575 ByteBufferReader response(data, *len);
576
577 if (state_ == SS_HELLO) {
578 uint8_t ver, method;
Yves Gerey665174f2018-06-19 15:03:05 +0200579 if (!response.ReadUInt8(&ver) || !response.ReadUInt8(&method))
deadbeeff137e972017-03-23 15:45:49 -0700580 return;
581
582 if (ver != 5) {
583 Error(0);
584 return;
585 }
586
587 if (method == 0) {
588 SendConnect();
589 } else if (method == 2) {
590 SendAuth();
591 } else {
592 Error(0);
593 return;
594 }
595 } else if (state_ == SS_AUTH) {
596 uint8_t ver, status;
Yves Gerey665174f2018-06-19 15:03:05 +0200597 if (!response.ReadUInt8(&ver) || !response.ReadUInt8(&status))
deadbeeff137e972017-03-23 15:45:49 -0700598 return;
599
600 if ((ver != 1) || (status != 0)) {
601 Error(SOCKET_EACCES);
602 return;
603 }
604
605 SendConnect();
606 } else if (state_ == SS_CONNECT) {
607 uint8_t ver, rep, rsv, atyp;
Yves Gerey665174f2018-06-19 15:03:05 +0200608 if (!response.ReadUInt8(&ver) || !response.ReadUInt8(&rep) ||
609 !response.ReadUInt8(&rsv) || !response.ReadUInt8(&atyp))
deadbeeff137e972017-03-23 15:45:49 -0700610 return;
611
612 if ((ver != 5) || (rep != 0)) {
613 Error(0);
614 return;
615 }
616
617 uint16_t port;
618 if (atyp == 1) {
619 uint32_t addr;
Yves Gerey665174f2018-06-19 15:03:05 +0200620 if (!response.ReadUInt32(&addr) || !response.ReadUInt16(&port))
deadbeeff137e972017-03-23 15:45:49 -0700621 return;
Mirko Bonadei675513b2017-11-09 11:09:25 +0100622 RTC_LOG(LS_VERBOSE) << "Bound on " << addr << ":" << port;
deadbeeff137e972017-03-23 15:45:49 -0700623 } else if (atyp == 3) {
624 uint8_t len;
625 std::string addr;
Yves Gerey665174f2018-06-19 15:03:05 +0200626 if (!response.ReadUInt8(&len) || !response.ReadString(&addr, len) ||
deadbeeff137e972017-03-23 15:45:49 -0700627 !response.ReadUInt16(&port))
628 return;
Mirko Bonadei675513b2017-11-09 11:09:25 +0100629 RTC_LOG(LS_VERBOSE) << "Bound on " << addr << ":" << port;
deadbeeff137e972017-03-23 15:45:49 -0700630 } else if (atyp == 4) {
631 std::string addr;
Yves Gerey665174f2018-06-19 15:03:05 +0200632 if (!response.ReadString(&addr, 16) || !response.ReadUInt16(&port))
deadbeeff137e972017-03-23 15:45:49 -0700633 return;
Mirko Bonadei675513b2017-11-09 11:09:25 +0100634 RTC_LOG(LS_VERBOSE) << "Bound on <IPV6>:" << port;
deadbeeff137e972017-03-23 15:45:49 -0700635 } else {
636 Error(0);
637 return;
638 }
639
640 state_ = SS_TUNNEL;
641 }
642
643 // Consume parsed data
644 *len = response.Length();
645 memmove(data, response.Data(), *len);
646
647 if (state_ != SS_TUNNEL)
648 return;
649
650 bool remainder = (*len > 0);
651 BufferInput(false);
652 SignalConnectEvent(this);
653
654 // FIX: if SignalConnect causes the socket to be destroyed, we are in trouble
655 if (remainder)
656 SignalReadEvent(this); // TODO: signal this??
657}
658
659void AsyncSocksProxySocket::SendHello() {
660 ByteBufferWriter request;
Yves Gerey665174f2018-06-19 15:03:05 +0200661 request.WriteUInt8(5); // Socks Version
deadbeeff137e972017-03-23 15:45:49 -0700662 if (user_.empty()) {
663 request.WriteUInt8(1); // Authentication Mechanisms
664 request.WriteUInt8(0); // No authentication
665 } else {
666 request.WriteUInt8(2); // Authentication Mechanisms
667 request.WriteUInt8(0); // No authentication
668 request.WriteUInt8(2); // Username/Password
669 }
670 DirectSend(request.Data(), request.Length());
671 state_ = SS_HELLO;
672}
673
674void AsyncSocksProxySocket::SendAuth() {
Joachim Bauch4c6a30c2018-03-08 00:55:33 +0100675 ByteBufferWriterT<ZeroOnFreeBuffer<char>> request;
Yves Gerey665174f2018-06-19 15:03:05 +0200676 request.WriteUInt8(1); // Negotiation Version
deadbeeff137e972017-03-23 15:45:49 -0700677 request.WriteUInt8(static_cast<uint8_t>(user_.size()));
Yves Gerey665174f2018-06-19 15:03:05 +0200678 request.WriteString(user_); // Username
deadbeeff137e972017-03-23 15:45:49 -0700679 request.WriteUInt8(static_cast<uint8_t>(pass_.GetLength()));
680 size_t len = pass_.GetLength() + 1;
Yves Gerey665174f2018-06-19 15:03:05 +0200681 char* sensitive = new char[len];
deadbeeff137e972017-03-23 15:45:49 -0700682 pass_.CopyTo(sensitive, true);
Joachim Bauch5b32f232018-03-07 20:02:26 +0100683 request.WriteBytes(sensitive, pass_.GetLength()); // Password
684 ExplicitZeroMemory(sensitive, len);
Yves Gerey665174f2018-06-19 15:03:05 +0200685 delete[] sensitive;
deadbeeff137e972017-03-23 15:45:49 -0700686 DirectSend(request.Data(), request.Length());
687 state_ = SS_AUTH;
688}
689
690void AsyncSocksProxySocket::SendConnect() {
691 ByteBufferWriter request;
Yves Gerey665174f2018-06-19 15:03:05 +0200692 request.WriteUInt8(5); // Socks Version
693 request.WriteUInt8(1); // CONNECT
694 request.WriteUInt8(0); // Reserved
deadbeeff137e972017-03-23 15:45:49 -0700695 if (dest_.IsUnresolvedIP()) {
696 std::string hostname = dest_.hostname();
Yves Gerey665174f2018-06-19 15:03:05 +0200697 request.WriteUInt8(3); // DOMAINNAME
deadbeeff137e972017-03-23 15:45:49 -0700698 request.WriteUInt8(static_cast<uint8_t>(hostname.size()));
Yves Gerey665174f2018-06-19 15:03:05 +0200699 request.WriteString(hostname); // Destination Hostname
deadbeeff137e972017-03-23 15:45:49 -0700700 } else {
701 request.WriteUInt8(1); // IPV4
702 request.WriteUInt32(dest_.ip()); // Destination IP
703 }
704 request.WriteUInt16(dest_.port()); // Destination Port
705 DirectSend(request.Data(), request.Length());
706 state_ = SS_CONNECT;
707}
708
709void AsyncSocksProxySocket::Error(int error) {
710 state_ = SS_ERROR;
711 BufferInput(false);
712 Close();
713 SetError(SOCKET_EACCES);
714 SignalCloseEvent(this, error);
715}
716
717AsyncSocksProxyServerSocket::AsyncSocksProxyServerSocket(AsyncSocket* socket)
718 : AsyncProxyServerSocket(socket, kBufferSize), state_(SS_HELLO) {
719 BufferInput(true);
720}
721
722void AsyncSocksProxyServerSocket::ProcessInput(char* data, size_t* len) {
723 // TODO: See if the whole message has arrived
724 RTC_DCHECK(state_ < SS_CONNECT_PENDING);
725
726 ByteBufferReader response(data, *len);
727 if (state_ == SS_HELLO) {
728 HandleHello(&response);
729 } else if (state_ == SS_AUTH) {
730 HandleAuth(&response);
731 } else if (state_ == SS_CONNECT) {
732 HandleConnect(&response);
733 }
734
735 // Consume parsed data
736 *len = response.Length();
737 memmove(data, response.Data(), *len);
738}
739
740void AsyncSocksProxyServerSocket::DirectSend(const ByteBufferWriter& buf) {
741 BufferedReadAdapter::DirectSend(buf.Data(), buf.Length());
742}
743
744void AsyncSocksProxyServerSocket::HandleHello(ByteBufferReader* request) {
745 uint8_t ver, num_methods;
Yves Gerey665174f2018-06-19 15:03:05 +0200746 if (!request->ReadUInt8(&ver) || !request->ReadUInt8(&num_methods)) {
deadbeeff137e972017-03-23 15:45:49 -0700747 Error(0);
748 return;
749 }
750
751 if (ver != 5) {
752 Error(0);
753 return;
754 }
755
756 // Handle either no-auth (0) or user/pass auth (2)
757 uint8_t method = 0xFF;
758 if (num_methods > 0 && !request->ReadUInt8(&method)) {
759 Error(0);
760 return;
761 }
762
763 // TODO: Ask the server which method to use.
764 SendHelloReply(method);
765 if (method == 0) {
766 state_ = SS_CONNECT;
767 } else if (method == 2) {
768 state_ = SS_AUTH;
769 } else {
770 state_ = SS_ERROR;
771 }
772}
773
774void AsyncSocksProxyServerSocket::SendHelloReply(uint8_t method) {
775 ByteBufferWriter response;
Yves Gerey665174f2018-06-19 15:03:05 +0200776 response.WriteUInt8(5); // Socks Version
deadbeeff137e972017-03-23 15:45:49 -0700777 response.WriteUInt8(method); // Auth method
778 DirectSend(response);
779}
780
781void AsyncSocksProxyServerSocket::HandleAuth(ByteBufferReader* request) {
782 uint8_t ver, user_len, pass_len;
783 std::string user, pass;
Yves Gerey665174f2018-06-19 15:03:05 +0200784 if (!request->ReadUInt8(&ver) || !request->ReadUInt8(&user_len) ||
785 !request->ReadString(&user, user_len) || !request->ReadUInt8(&pass_len) ||
deadbeeff137e972017-03-23 15:45:49 -0700786 !request->ReadString(&pass, pass_len)) {
787 Error(0);
788 return;
789 }
790
791 // TODO: Allow for checking of credentials.
792 SendAuthReply(0);
793 state_ = SS_CONNECT;
794}
795
796void AsyncSocksProxyServerSocket::SendAuthReply(uint8_t result) {
797 ByteBufferWriter response;
798 response.WriteUInt8(1); // Negotiation Version
799 response.WriteUInt8(result);
800 DirectSend(response);
801}
802
803void AsyncSocksProxyServerSocket::HandleConnect(ByteBufferReader* request) {
804 uint8_t ver, command, reserved, addr_type;
805 uint32_t ip;
806 uint16_t port;
Yves Gerey665174f2018-06-19 15:03:05 +0200807 if (!request->ReadUInt8(&ver) || !request->ReadUInt8(&command) ||
808 !request->ReadUInt8(&reserved) || !request->ReadUInt8(&addr_type) ||
809 !request->ReadUInt32(&ip) || !request->ReadUInt16(&port)) {
810 Error(0);
811 return;
deadbeeff137e972017-03-23 15:45:49 -0700812 }
813
Yves Gerey665174f2018-06-19 15:03:05 +0200814 if (ver != 5 || command != 1 || reserved != 0 || addr_type != 1) {
815 Error(0);
816 return;
deadbeeff137e972017-03-23 15:45:49 -0700817 }
818
819 SignalConnectRequest(this, SocketAddress(ip, port));
820 state_ = SS_CONNECT_PENDING;
821}
822
823void AsyncSocksProxyServerSocket::SendConnectResult(int result,
824 const SocketAddress& addr) {
825 if (state_ != SS_CONNECT_PENDING)
826 return;
827
828 ByteBufferWriter response;
Yves Gerey665174f2018-06-19 15:03:05 +0200829 response.WriteUInt8(5); // Socks version
deadbeeff137e972017-03-23 15:45:49 -0700830 response.WriteUInt8((result != 0)); // 0x01 is generic error
Yves Gerey665174f2018-06-19 15:03:05 +0200831 response.WriteUInt8(0); // reserved
832 response.WriteUInt8(1); // IPv4 address
deadbeeff137e972017-03-23 15:45:49 -0700833 response.WriteUInt32(addr.ip());
834 response.WriteUInt16(addr.port());
835 DirectSend(response);
836 BufferInput(false);
837 state_ = SS_TUNNEL;
838}
839
840void AsyncSocksProxyServerSocket::Error(int error) {
841 state_ = SS_ERROR;
842 BufferInput(false);
843 Close();
844 SetError(SOCKET_EACCES);
845 SignalCloseEvent(this, error);
846}
847
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000848} // namespace rtc