blob: 814f23b290919ae2987ad4c7fab62bc837cd5e7a [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
12#pragma warning(disable:4786)
13#endif
14
15#include <time.h>
16#include <errno.h>
17
18#if defined(WEBRTC_WIN)
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000019#include <windows.h>
20#include <winsock2.h>
21#include <ws2tcpip.h>
22#define SECURITY_WIN32
23#include <security.h>
24#endif
25
andresp@webrtc.orgff689be2015-02-12 11:54:26 +000026#include <algorithm>
27
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020028#include "rtc_base/bytebuffer.h"
29#include "rtc_base/checks.h"
30#include "rtc_base/httpcommon.h"
31#include "rtc_base/logging.h"
32#include "rtc_base/socketadapters.h"
33#include "rtc_base/stringencode.h"
34#include "rtc_base/stringutils.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000035
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000036namespace rtc {
37
38BufferedReadAdapter::BufferedReadAdapter(AsyncSocket* socket, size_t size)
39 : AsyncSocketAdapter(socket), buffer_size_(size),
40 data_len_(0), buffering_(false) {
41 buffer_ = new char[buffer_size_];
42}
43
44BufferedReadAdapter::~BufferedReadAdapter() {
45 delete [] buffer_;
46}
47
48int BufferedReadAdapter::Send(const void *pv, size_t cb) {
49 if (buffering_) {
50 // TODO: Spoof error better; Signal Writeable
51 socket_->SetError(EWOULDBLOCK);
52 return -1;
53 }
54 return AsyncSocketAdapter::Send(pv, cb);
55}
56
Stefan Holmer9131efd2016-05-23 18:19:26 +020057int BufferedReadAdapter::Recv(void* pv, size_t cb, int64_t* timestamp) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000058 if (buffering_) {
59 socket_->SetError(EWOULDBLOCK);
60 return -1;
61 }
62
63 size_t read = 0;
64
65 if (data_len_) {
andresp@webrtc.orgff689be2015-02-12 11:54:26 +000066 read = std::min(cb, data_len_);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000067 memcpy(pv, buffer_, read);
68 data_len_ -= read;
69 if (data_len_ > 0) {
70 memmove(buffer_, buffer_ + read, data_len_);
71 }
72 pv = static_cast<char *>(pv) + read;
73 cb -= read;
74 }
75
76 // FIX: If cb == 0, we won't generate another read event
77
Stefan Holmer9131efd2016-05-23 18:19:26 +020078 int res = AsyncSocketAdapter::Recv(pv, cb, timestamp);
deadbeefc5d0d952015-07-16 10:22:21 -070079 if (res >= 0) {
80 // Read from socket and possibly buffer; return combined length
81 return res + static_cast<int>(read);
82 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000083
deadbeefc5d0d952015-07-16 10:22:21 -070084 if (read > 0) {
85 // Failed to read from socket, but still read something from buffer
86 return static_cast<int>(read);
87 }
88
89 // Didn't read anything; return error from socket
90 return res;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000091}
92
93void BufferedReadAdapter::BufferInput(bool on) {
94 buffering_ = on;
95}
96
97void BufferedReadAdapter::OnReadEvent(AsyncSocket * socket) {
nisseede5da42017-01-12 05:15:36 -080098 RTC_DCHECK(socket == socket_);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000099
100 if (!buffering_) {
101 AsyncSocketAdapter::OnReadEvent(socket);
102 return;
103 }
104
105 if (data_len_ >= buffer_size_) {
Jonas Olsson45cc8902018-02-13 10:37:07 +0100106 RTC_LOG(LS_ERROR) << "Input buffer overflow";
nissec80e7412017-01-11 05:56:46 -0800107 RTC_NOTREACHED();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000108 data_len_ = 0;
109 }
110
Stefan Holmer9131efd2016-05-23 18:19:26 +0200111 int len =
112 socket_->Recv(buffer_ + data_len_, buffer_size_ - data_len_, nullptr);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000113 if (len < 0) {
114 // TODO: Do something better like forwarding the error to the user.
Mirko Bonadei675513b2017-11-09 11:09:25 +0100115 RTC_LOG_ERR(INFO) << "Recv";
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000116 return;
117 }
118
119 data_len_ += len;
120
121 ProcessInput(buffer_, &data_len_);
122}
123
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +0000124AsyncProxyServerSocket::AsyncProxyServerSocket(AsyncSocket* socket,
125 size_t buffer_size)
126 : BufferedReadAdapter(socket, buffer_size) {
127}
128
129AsyncProxyServerSocket::~AsyncProxyServerSocket() = default;
130
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000131///////////////////////////////////////////////////////////////////////////////
132
133// This is a SSL v2 CLIENT_HELLO message.
134// TODO: Should this have a session id? The response doesn't have a
135// certificate, so the hello should have a session id.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200136static const uint8_t kSslClientHello[] = {
137 0x80, 0x46, // msg len
138 0x01, // CLIENT_HELLO
139 0x03, 0x01, // SSL 3.1
140 0x00, 0x2d, // ciphersuite len
141 0x00, 0x00, // session id len
142 0x00, 0x10, // challenge len
143 0x01, 0x00, 0x80, 0x03, 0x00, 0x80, 0x07, 0x00, 0xc0, // ciphersuites
144 0x06, 0x00, 0x40, 0x02, 0x00, 0x80, 0x04, 0x00, 0x80, //
145 0x00, 0x00, 0x04, 0x00, 0xfe, 0xff, 0x00, 0x00, 0x0a, //
146 0x00, 0xfe, 0xfe, 0x00, 0x00, 0x09, 0x00, 0x00, 0x64, //
147 0x00, 0x00, 0x62, 0x00, 0x00, 0x03, 0x00, 0x00, 0x06, //
148 0x1f, 0x17, 0x0c, 0xa6, 0x2f, 0x00, 0x78, 0xfc, // challenge
149 0x46, 0x55, 0x2e, 0xb1, 0x83, 0x39, 0xf1, 0xea //
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000150};
151
152// This is a TLSv1 SERVER_HELLO message.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200153static const uint8_t kSslServerHello[] = {
154 0x16, // handshake message
155 0x03, 0x01, // SSL 3.1
156 0x00, 0x4a, // message len
157 0x02, // SERVER_HELLO
158 0x00, 0x00, 0x46, // handshake len
159 0x03, 0x01, // SSL 3.1
160 0x42, 0x85, 0x45, 0xa7, 0x27, 0xa9, 0x5d, 0xa0, // server random
161 0xb3, 0xc5, 0xe7, 0x53, 0xda, 0x48, 0x2b, 0x3f, //
162 0xc6, 0x5a, 0xca, 0x89, 0xc1, 0x58, 0x52, 0xa1, //
163 0x78, 0x3c, 0x5b, 0x17, 0x46, 0x00, 0x85, 0x3f, //
164 0x20, // session id len
165 0x0e, 0xd3, 0x06, 0x72, 0x5b, 0x5b, 0x1b, 0x5f, // session id
166 0x15, 0xac, 0x13, 0xf9, 0x88, 0x53, 0x9d, 0x9b, //
167 0xe8, 0x3d, 0x7b, 0x0c, 0x30, 0x32, 0x6e, 0x38, //
168 0x4d, 0xa2, 0x75, 0x57, 0x41, 0x6c, 0x34, 0x5c, //
169 0x00, 0x04, // RSA/RC4-128/MD5
170 0x00 // null compression
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000171};
172
173AsyncSSLSocket::AsyncSSLSocket(AsyncSocket* socket)
174 : BufferedReadAdapter(socket, 1024) {
175}
176
177int AsyncSSLSocket::Connect(const SocketAddress& addr) {
178 // Begin buffering before we connect, so that there isn't a race condition
179 // between potential senders and receiving the OnConnectEvent signal
180 BufferInput(true);
181 return BufferedReadAdapter::Connect(addr);
182}
183
184void AsyncSSLSocket::OnConnectEvent(AsyncSocket * socket) {
nisseede5da42017-01-12 05:15:36 -0800185 RTC_DCHECK(socket == socket_);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000186 // TODO: we could buffer output too...
nissec16fa5e2017-02-07 07:18:43 -0800187 const int res = DirectSend(kSslClientHello, sizeof(kSslClientHello));
188 RTC_DCHECK_EQ(sizeof(kSslClientHello), res);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000189}
190
191void AsyncSSLSocket::ProcessInput(char* data, size_t* len) {
192 if (*len < sizeof(kSslServerHello))
193 return;
194
195 if (memcmp(kSslServerHello, data, sizeof(kSslServerHello)) != 0) {
196 Close();
197 SignalCloseEvent(this, 0); // TODO: error code?
198 return;
199 }
200
201 *len -= sizeof(kSslServerHello);
202 if (*len > 0) {
203 memmove(data, data + sizeof(kSslServerHello), *len);
204 }
205
206 bool remainder = (*len > 0);
207 BufferInput(false);
208 SignalConnectEvent(this);
209
210 // FIX: if SignalConnect causes the socket to be destroyed, we are in trouble
211 if (remainder)
212 SignalReadEvent(this);
213}
214
215AsyncSSLServerSocket::AsyncSSLServerSocket(AsyncSocket* socket)
216 : BufferedReadAdapter(socket, 1024) {
217 BufferInput(true);
218}
219
220void AsyncSSLServerSocket::ProcessInput(char* data, size_t* len) {
221 // We only accept client hello messages.
222 if (*len < sizeof(kSslClientHello)) {
223 return;
224 }
225
226 if (memcmp(kSslClientHello, data, sizeof(kSslClientHello)) != 0) {
227 Close();
228 SignalCloseEvent(this, 0);
229 return;
230 }
231
232 *len -= sizeof(kSslClientHello);
233
234 // Clients should not send more data until the handshake is completed.
nisseede5da42017-01-12 05:15:36 -0800235 RTC_DCHECK(*len == 0);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000236
237 // Send a server hello back to the client.
238 DirectSend(kSslServerHello, sizeof(kSslServerHello));
239
240 // Handshake completed for us, redirect input to our parent.
241 BufferInput(false);
242}
243
deadbeeff137e972017-03-23 15:45:49 -0700244///////////////////////////////////////////////////////////////////////////////
245
246AsyncHttpsProxySocket::AsyncHttpsProxySocket(AsyncSocket* socket,
247 const std::string& user_agent,
248 const SocketAddress& proxy,
249 const std::string& username,
250 const CryptString& password)
251 : BufferedReadAdapter(socket, 1024), proxy_(proxy), agent_(user_agent),
252 user_(username), pass_(password), force_connect_(false), state_(PS_ERROR),
253 context_(0) {
254}
255
256AsyncHttpsProxySocket::~AsyncHttpsProxySocket() {
257 delete context_;
258}
259
260int AsyncHttpsProxySocket::Connect(const SocketAddress& addr) {
261 int ret;
Mirko Bonadei675513b2017-11-09 11:09:25 +0100262 RTC_LOG(LS_VERBOSE) << "AsyncHttpsProxySocket::Connect("
263 << proxy_.ToSensitiveString() << ")";
deadbeeff137e972017-03-23 15:45:49 -0700264 dest_ = addr;
265 state_ = PS_INIT;
266 if (ShouldIssueConnect()) {
267 BufferInput(true);
268 }
269 ret = BufferedReadAdapter::Connect(proxy_);
270 // TODO: Set state_ appropriately if Connect fails.
271 return ret;
272}
273
274SocketAddress AsyncHttpsProxySocket::GetRemoteAddress() const {
275 return dest_;
276}
277
278int AsyncHttpsProxySocket::Close() {
279 headers_.clear();
280 state_ = PS_ERROR;
281 dest_.Clear();
282 delete context_;
283 context_ = nullptr;
284 return BufferedReadAdapter::Close();
285}
286
287Socket::ConnState AsyncHttpsProxySocket::GetState() const {
288 if (state_ < PS_TUNNEL) {
289 return CS_CONNECTING;
290 } else if (state_ == PS_TUNNEL) {
291 return CS_CONNECTED;
292 } else {
293 return CS_CLOSED;
294 }
295}
296
297void AsyncHttpsProxySocket::OnConnectEvent(AsyncSocket * socket) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100298 RTC_LOG(LS_VERBOSE) << "AsyncHttpsProxySocket::OnConnectEvent";
deadbeeff137e972017-03-23 15:45:49 -0700299 if (!ShouldIssueConnect()) {
300 state_ = PS_TUNNEL;
301 BufferedReadAdapter::OnConnectEvent(socket);
302 return;
303 }
304 SendRequest();
305}
306
307void AsyncHttpsProxySocket::OnCloseEvent(AsyncSocket * socket, int err) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100308 RTC_LOG(LS_VERBOSE) << "AsyncHttpsProxySocket::OnCloseEvent(" << err << ")";
deadbeeff137e972017-03-23 15:45:49 -0700309 if ((state_ == PS_WAIT_CLOSE) && (err == 0)) {
310 state_ = PS_ERROR;
311 Connect(dest_);
312 } else {
313 BufferedReadAdapter::OnCloseEvent(socket, err);
314 }
315}
316
317void AsyncHttpsProxySocket::ProcessInput(char* data, size_t* len) {
318 size_t start = 0;
319 for (size_t pos = start; state_ < PS_TUNNEL && pos < *len;) {
320 if (state_ == PS_SKIP_BODY) {
321 size_t consume = std::min(*len - pos, content_length_);
322 pos += consume;
323 start = pos;
324 content_length_ -= consume;
325 if (content_length_ == 0) {
326 EndResponse();
327 }
328 continue;
329 }
330
331 if (data[pos++] != '\n')
332 continue;
333
334 size_t len = pos - start - 1;
335 if ((len > 0) && (data[start + len - 1] == '\r'))
336 --len;
337
338 data[start + len] = 0;
339 ProcessLine(data + start, len);
340 start = pos;
341 }
342
343 *len -= start;
344 if (*len > 0) {
345 memmove(data, data + start, *len);
346 }
347
348 if (state_ != PS_TUNNEL)
349 return;
350
351 bool remainder = (*len > 0);
352 BufferInput(false);
353 SignalConnectEvent(this);
354
355 // FIX: if SignalConnect causes the socket to be destroyed, we are in trouble
356 if (remainder)
357 SignalReadEvent(this); // TODO: signal this??
358}
359
360bool AsyncHttpsProxySocket::ShouldIssueConnect() const {
361 // TODO: Think about whether a more sophisticated test
362 // than dest port == 80 is needed.
363 return force_connect_ || (dest_.port() != 80);
364}
365
366void AsyncHttpsProxySocket::SendRequest() {
367 std::stringstream ss;
368 ss << "CONNECT " << dest_.ToString() << " HTTP/1.0\r\n";
369 ss << "User-Agent: " << agent_ << "\r\n";
370 ss << "Host: " << dest_.HostAsURIString() << "\r\n";
371 ss << "Content-Length: 0\r\n";
372 ss << "Proxy-Connection: Keep-Alive\r\n";
373 ss << headers_;
374 ss << "\r\n";
375 std::string str = ss.str();
376 DirectSend(str.c_str(), str.size());
377 state_ = PS_LEADER;
378 expect_close_ = true;
379 content_length_ = 0;
380 headers_.clear();
381
Mirko Bonadei675513b2017-11-09 11:09:25 +0100382 RTC_LOG(LS_VERBOSE) << "AsyncHttpsProxySocket >> " << str;
deadbeeff137e972017-03-23 15:45:49 -0700383}
384
385void AsyncHttpsProxySocket::ProcessLine(char * data, size_t len) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100386 RTC_LOG(LS_VERBOSE) << "AsyncHttpsProxySocket << " << data;
deadbeeff137e972017-03-23 15:45:49 -0700387
388 if (len == 0) {
389 if (state_ == PS_TUNNEL_HEADERS) {
390 state_ = PS_TUNNEL;
391 } else if (state_ == PS_ERROR_HEADERS) {
392 Error(defer_error_);
393 return;
394 } else if (state_ == PS_SKIP_HEADERS) {
395 if (content_length_) {
396 state_ = PS_SKIP_BODY;
397 } else {
398 EndResponse();
399 return;
400 }
401 } else {
402 static bool report = false;
403 if (!unknown_mechanisms_.empty() && !report) {
404 report = true;
405 std::string msg(
406 "Unable to connect to the Google Talk service due to an incompatibility "
407 "with your proxy.\r\nPlease help us resolve this issue by submitting the "
408 "following information to us using our technical issue submission form "
409 "at:\r\n\r\n"
410 "http://www.google.com/support/talk/bin/request.py\r\n\r\n"
411 "We apologize for the inconvenience.\r\n\r\n"
412 "Information to submit to Google: "
413 );
414 //std::string msg("Please report the following information to foo@bar.com:\r\nUnknown methods: ");
415 msg.append(unknown_mechanisms_);
416#if defined(WEBRTC_WIN)
417 MessageBoxA(0, msg.c_str(), "Oops!", MB_OK);
418#endif
419#if defined(WEBRTC_POSIX)
420 // TODO: Raise a signal so the UI can be separated.
Mirko Bonadei675513b2017-11-09 11:09:25 +0100421 RTC_LOG(LS_ERROR) << "Oops!\n\n" << msg;
deadbeeff137e972017-03-23 15:45:49 -0700422#endif
423 }
424 // Unexpected end of headers
425 Error(0);
426 return;
427 }
428 } else if (state_ == PS_LEADER) {
429 unsigned int code;
430 if (sscanf(data, "HTTP/%*u.%*u %u", &code) != 1) {
431 Error(0);
432 return;
433 }
434 switch (code) {
435 case 200:
436 // connection good!
437 state_ = PS_TUNNEL_HEADERS;
438 return;
439#if defined(HTTP_STATUS_PROXY_AUTH_REQ) && (HTTP_STATUS_PROXY_AUTH_REQ != 407)
440#error Wrong code for HTTP_STATUS_PROXY_AUTH_REQ
441#endif
442 case 407: // HTTP_STATUS_PROXY_AUTH_REQ
443 state_ = PS_AUTHENTICATE;
444 return;
445 default:
446 defer_error_ = 0;
447 state_ = PS_ERROR_HEADERS;
448 return;
449 }
450 } else if ((state_ == PS_AUTHENTICATE)
451 && (_strnicmp(data, "Proxy-Authenticate:", 19) == 0)) {
452 std::string response, auth_method;
453 switch (HttpAuthenticate(data + 19, len - 19,
454 proxy_, "CONNECT", "/",
455 user_, pass_, context_, response, auth_method)) {
456 case HAR_IGNORE:
Mirko Bonadei675513b2017-11-09 11:09:25 +0100457 RTC_LOG(LS_VERBOSE) << "Ignoring Proxy-Authenticate: " << auth_method;
deadbeeff137e972017-03-23 15:45:49 -0700458 if (!unknown_mechanisms_.empty())
459 unknown_mechanisms_.append(", ");
460 unknown_mechanisms_.append(auth_method);
461 break;
462 case HAR_RESPONSE:
463 headers_ = "Proxy-Authorization: ";
464 headers_.append(response);
465 headers_.append("\r\n");
466 state_ = PS_SKIP_HEADERS;
467 unknown_mechanisms_.clear();
468 break;
469 case HAR_CREDENTIALS:
470 defer_error_ = SOCKET_EACCES;
471 state_ = PS_ERROR_HEADERS;
472 unknown_mechanisms_.clear();
473 break;
474 case HAR_ERROR:
475 defer_error_ = 0;
476 state_ = PS_ERROR_HEADERS;
477 unknown_mechanisms_.clear();
478 break;
479 }
480 } else if (_strnicmp(data, "Content-Length:", 15) == 0) {
481 content_length_ = strtoul(data + 15, 0, 0);
482 } else if (_strnicmp(data, "Proxy-Connection: Keep-Alive", 28) == 0) {
483 expect_close_ = false;
484 /*
485 } else if (_strnicmp(data, "Connection: close", 17) == 0) {
486 expect_close_ = true;
487 */
488 }
489}
490
491void AsyncHttpsProxySocket::EndResponse() {
492 if (!expect_close_) {
493 SendRequest();
494 return;
495 }
496
497 // No point in waiting for the server to close... let's close now
498 // TODO: Refactor out PS_WAIT_CLOSE
499 state_ = PS_WAIT_CLOSE;
500 BufferedReadAdapter::Close();
501 OnCloseEvent(this, 0);
502}
503
504void AsyncHttpsProxySocket::Error(int error) {
505 BufferInput(false);
506 Close();
507 SetError(error);
508 SignalCloseEvent(this, error);
509}
510
511///////////////////////////////////////////////////////////////////////////////
512
513AsyncSocksProxySocket::AsyncSocksProxySocket(AsyncSocket* socket,
514 const SocketAddress& proxy,
515 const std::string& username,
516 const CryptString& password)
517 : BufferedReadAdapter(socket, 1024), state_(SS_ERROR), proxy_(proxy),
518 user_(username), pass_(password) {
519}
520
521AsyncSocksProxySocket::~AsyncSocksProxySocket() = default;
522
523int AsyncSocksProxySocket::Connect(const SocketAddress& addr) {
524 int ret;
525 dest_ = addr;
526 state_ = SS_INIT;
527 BufferInput(true);
528 ret = BufferedReadAdapter::Connect(proxy_);
529 // TODO: Set state_ appropriately if Connect fails.
530 return ret;
531}
532
533SocketAddress AsyncSocksProxySocket::GetRemoteAddress() const {
534 return dest_;
535}
536
537int AsyncSocksProxySocket::Close() {
538 state_ = SS_ERROR;
539 dest_.Clear();
540 return BufferedReadAdapter::Close();
541}
542
543Socket::ConnState AsyncSocksProxySocket::GetState() const {
544 if (state_ < SS_TUNNEL) {
545 return CS_CONNECTING;
546 } else if (state_ == SS_TUNNEL) {
547 return CS_CONNECTED;
548 } else {
549 return CS_CLOSED;
550 }
551}
552
553void AsyncSocksProxySocket::OnConnectEvent(AsyncSocket* socket) {
554 SendHello();
555}
556
557void AsyncSocksProxySocket::ProcessInput(char* data, size_t* len) {
558 RTC_DCHECK(state_ < SS_TUNNEL);
559
560 ByteBufferReader response(data, *len);
561
562 if (state_ == SS_HELLO) {
563 uint8_t ver, method;
564 if (!response.ReadUInt8(&ver) ||
565 !response.ReadUInt8(&method))
566 return;
567
568 if (ver != 5) {
569 Error(0);
570 return;
571 }
572
573 if (method == 0) {
574 SendConnect();
575 } else if (method == 2) {
576 SendAuth();
577 } else {
578 Error(0);
579 return;
580 }
581 } else if (state_ == SS_AUTH) {
582 uint8_t ver, status;
583 if (!response.ReadUInt8(&ver) ||
584 !response.ReadUInt8(&status))
585 return;
586
587 if ((ver != 1) || (status != 0)) {
588 Error(SOCKET_EACCES);
589 return;
590 }
591
592 SendConnect();
593 } else if (state_ == SS_CONNECT) {
594 uint8_t ver, rep, rsv, atyp;
595 if (!response.ReadUInt8(&ver) ||
596 !response.ReadUInt8(&rep) ||
597 !response.ReadUInt8(&rsv) ||
598 !response.ReadUInt8(&atyp))
599 return;
600
601 if ((ver != 5) || (rep != 0)) {
602 Error(0);
603 return;
604 }
605
606 uint16_t port;
607 if (atyp == 1) {
608 uint32_t addr;
609 if (!response.ReadUInt32(&addr) ||
610 !response.ReadUInt16(&port))
611 return;
Mirko Bonadei675513b2017-11-09 11:09:25 +0100612 RTC_LOG(LS_VERBOSE) << "Bound on " << addr << ":" << port;
deadbeeff137e972017-03-23 15:45:49 -0700613 } else if (atyp == 3) {
614 uint8_t len;
615 std::string addr;
616 if (!response.ReadUInt8(&len) ||
617 !response.ReadString(&addr, len) ||
618 !response.ReadUInt16(&port))
619 return;
Mirko Bonadei675513b2017-11-09 11:09:25 +0100620 RTC_LOG(LS_VERBOSE) << "Bound on " << addr << ":" << port;
deadbeeff137e972017-03-23 15:45:49 -0700621 } else if (atyp == 4) {
622 std::string addr;
623 if (!response.ReadString(&addr, 16) ||
624 !response.ReadUInt16(&port))
625 return;
Mirko Bonadei675513b2017-11-09 11:09:25 +0100626 RTC_LOG(LS_VERBOSE) << "Bound on <IPV6>:" << port;
deadbeeff137e972017-03-23 15:45:49 -0700627 } else {
628 Error(0);
629 return;
630 }
631
632 state_ = SS_TUNNEL;
633 }
634
635 // Consume parsed data
636 *len = response.Length();
637 memmove(data, response.Data(), *len);
638
639 if (state_ != SS_TUNNEL)
640 return;
641
642 bool remainder = (*len > 0);
643 BufferInput(false);
644 SignalConnectEvent(this);
645
646 // FIX: if SignalConnect causes the socket to be destroyed, we are in trouble
647 if (remainder)
648 SignalReadEvent(this); // TODO: signal this??
649}
650
651void AsyncSocksProxySocket::SendHello() {
652 ByteBufferWriter request;
653 request.WriteUInt8(5); // Socks Version
654 if (user_.empty()) {
655 request.WriteUInt8(1); // Authentication Mechanisms
656 request.WriteUInt8(0); // No authentication
657 } else {
658 request.WriteUInt8(2); // Authentication Mechanisms
659 request.WriteUInt8(0); // No authentication
660 request.WriteUInt8(2); // Username/Password
661 }
662 DirectSend(request.Data(), request.Length());
663 state_ = SS_HELLO;
664}
665
666void AsyncSocksProxySocket::SendAuth() {
667 ByteBufferWriter request;
668 request.WriteUInt8(1); // Negotiation Version
669 request.WriteUInt8(static_cast<uint8_t>(user_.size()));
670 request.WriteString(user_); // Username
671 request.WriteUInt8(static_cast<uint8_t>(pass_.GetLength()));
672 size_t len = pass_.GetLength() + 1;
673 char * sensitive = new char[len];
674 pass_.CopyTo(sensitive, true);
675 request.WriteString(sensitive); // Password
676 memset(sensitive, 0, len);
677 delete [] sensitive;
678 DirectSend(request.Data(), request.Length());
679 state_ = SS_AUTH;
680}
681
682void AsyncSocksProxySocket::SendConnect() {
683 ByteBufferWriter request;
684 request.WriteUInt8(5); // Socks Version
685 request.WriteUInt8(1); // CONNECT
686 request.WriteUInt8(0); // Reserved
687 if (dest_.IsUnresolvedIP()) {
688 std::string hostname = dest_.hostname();
689 request.WriteUInt8(3); // DOMAINNAME
690 request.WriteUInt8(static_cast<uint8_t>(hostname.size()));
691 request.WriteString(hostname); // Destination Hostname
692 } else {
693 request.WriteUInt8(1); // IPV4
694 request.WriteUInt32(dest_.ip()); // Destination IP
695 }
696 request.WriteUInt16(dest_.port()); // Destination Port
697 DirectSend(request.Data(), request.Length());
698 state_ = SS_CONNECT;
699}
700
701void AsyncSocksProxySocket::Error(int error) {
702 state_ = SS_ERROR;
703 BufferInput(false);
704 Close();
705 SetError(SOCKET_EACCES);
706 SignalCloseEvent(this, error);
707}
708
709AsyncSocksProxyServerSocket::AsyncSocksProxyServerSocket(AsyncSocket* socket)
710 : AsyncProxyServerSocket(socket, kBufferSize), state_(SS_HELLO) {
711 BufferInput(true);
712}
713
714void AsyncSocksProxyServerSocket::ProcessInput(char* data, size_t* len) {
715 // TODO: See if the whole message has arrived
716 RTC_DCHECK(state_ < SS_CONNECT_PENDING);
717
718 ByteBufferReader response(data, *len);
719 if (state_ == SS_HELLO) {
720 HandleHello(&response);
721 } else if (state_ == SS_AUTH) {
722 HandleAuth(&response);
723 } else if (state_ == SS_CONNECT) {
724 HandleConnect(&response);
725 }
726
727 // Consume parsed data
728 *len = response.Length();
729 memmove(data, response.Data(), *len);
730}
731
732void AsyncSocksProxyServerSocket::DirectSend(const ByteBufferWriter& buf) {
733 BufferedReadAdapter::DirectSend(buf.Data(), buf.Length());
734}
735
736void AsyncSocksProxyServerSocket::HandleHello(ByteBufferReader* request) {
737 uint8_t ver, num_methods;
738 if (!request->ReadUInt8(&ver) ||
739 !request->ReadUInt8(&num_methods)) {
740 Error(0);
741 return;
742 }
743
744 if (ver != 5) {
745 Error(0);
746 return;
747 }
748
749 // Handle either no-auth (0) or user/pass auth (2)
750 uint8_t method = 0xFF;
751 if (num_methods > 0 && !request->ReadUInt8(&method)) {
752 Error(0);
753 return;
754 }
755
756 // TODO: Ask the server which method to use.
757 SendHelloReply(method);
758 if (method == 0) {
759 state_ = SS_CONNECT;
760 } else if (method == 2) {
761 state_ = SS_AUTH;
762 } else {
763 state_ = SS_ERROR;
764 }
765}
766
767void AsyncSocksProxyServerSocket::SendHelloReply(uint8_t method) {
768 ByteBufferWriter response;
769 response.WriteUInt8(5); // Socks Version
770 response.WriteUInt8(method); // Auth method
771 DirectSend(response);
772}
773
774void AsyncSocksProxyServerSocket::HandleAuth(ByteBufferReader* request) {
775 uint8_t ver, user_len, pass_len;
776 std::string user, pass;
777 if (!request->ReadUInt8(&ver) ||
778 !request->ReadUInt8(&user_len) ||
779 !request->ReadString(&user, user_len) ||
780 !request->ReadUInt8(&pass_len) ||
781 !request->ReadString(&pass, pass_len)) {
782 Error(0);
783 return;
784 }
785
786 // TODO: Allow for checking of credentials.
787 SendAuthReply(0);
788 state_ = SS_CONNECT;
789}
790
791void AsyncSocksProxyServerSocket::SendAuthReply(uint8_t result) {
792 ByteBufferWriter response;
793 response.WriteUInt8(1); // Negotiation Version
794 response.WriteUInt8(result);
795 DirectSend(response);
796}
797
798void AsyncSocksProxyServerSocket::HandleConnect(ByteBufferReader* request) {
799 uint8_t ver, command, reserved, addr_type;
800 uint32_t ip;
801 uint16_t port;
802 if (!request->ReadUInt8(&ver) ||
803 !request->ReadUInt8(&command) ||
804 !request->ReadUInt8(&reserved) ||
805 !request->ReadUInt8(&addr_type) ||
806 !request->ReadUInt32(&ip) ||
807 !request->ReadUInt16(&port)) {
808 Error(0);
809 return;
810 }
811
812 if (ver != 5 || command != 1 ||
813 reserved != 0 || addr_type != 1) {
814 Error(0);
815 return;
816 }
817
818 SignalConnectRequest(this, SocketAddress(ip, port));
819 state_ = SS_CONNECT_PENDING;
820}
821
822void AsyncSocksProxyServerSocket::SendConnectResult(int result,
823 const SocketAddress& addr) {
824 if (state_ != SS_CONNECT_PENDING)
825 return;
826
827 ByteBufferWriter response;
828 response.WriteUInt8(5); // Socks version
829 response.WriteUInt8((result != 0)); // 0x01 is generic error
830 response.WriteUInt8(0); // reserved
831 response.WriteUInt8(1); // IPv4 address
832 response.WriteUInt32(addr.ip());
833 response.WriteUInt16(addr.port());
834 DirectSend(response);
835 BufferInput(false);
836 state_ = SS_TUNNEL;
837}
838
839void AsyncSocksProxyServerSocket::Error(int error) {
840 state_ = SS_ERROR;
841 BufferInput(false);
842 Close();
843 SetError(SOCKET_EACCES);
844 SignalCloseEvent(this, error);
845}
846
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000847} // namespace rtc