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