Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Port SOCKS5 authentication from muon. #290

Merged
merged 2 commits into from
Jul 30, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions chromium_src/net/base/host_port_pair.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Copyright 2018 The Brave Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "../../../../net/base/host_port_pair.cc"

#include "net/base/host_port_pair.h"

#include "base/strings/string_number_conversions.h"

namespace net {

HostPortPair::~HostPortPair() = default;
HostPortPair::HostPortPair(const HostPortPair& host_port) = default;

HostPortPair::HostPortPair(const std::string& username,
const std::string& password,
const std::string& in_host, uint16_t in_port)
: username_(username), password_(password),
host_(in_host), port_(in_port) {
}

std::string HostPortPair::ToString() const {
std::string ret;
if (username_.size() != 0 || password_.size() != 0) {
ret += username_;
if (password_.size() != 0) {
ret += ':';
ret += password_;
}
ret += '@';
}
ret += HostForURL();
ret += ':';
ret += base::UintToString(port_);
return ret;
}

} // namespace net
83 changes: 83 additions & 0 deletions chromium_src/net/base/url_util.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "../../../../net/base/url_util.cc"

#include <iostream>
#include <string>

#include "base/strings/string_piece.h"
#include "url/third_party/mozilla/url_parse.h"
#include "url/url_canon_ip.h"

namespace net {

// Copypasta of ParseHostAndPort that extracts the username and
// password instead of rejecting them.
bool ParseAuthHostAndPort(base::StringPiece input,
std::string* username,
std::string* password,
std::string* host,
int* port) {
if (input.empty())
return false;

url::Component auth_component(0, input.size());
url::Component username_component;
url::Component password_component;
url::Component hostname_component;
url::Component port_component;

url::ParseAuthority(input.data(), auth_component, &username_component,
&password_component, &hostname_component,
&port_component);

if (!hostname_component.is_nonempty())
return false; // Failed parsing.

int parsed_port_number = -1;
if (port_component.is_nonempty()) {
parsed_port_number = url::ParsePort(input.data(), port_component);

// If parsing failed, port_number will be either PORT_INVALID or
// PORT_UNSPECIFIED, both of which are negative.
if (parsed_port_number < 0)
return false; // Failed parsing the port number.
}

if (port_component.len == 0)
return false; // Reject inputs like "foo:"

unsigned char tmp_ipv6_addr[16];

// If the hostname starts with a bracket, it is either an IPv6 literal or
// invalid. If it is an IPv6 literal then strip the brackets.
if (hostname_component.len > 0 && input[hostname_component.begin] == '[') {
if (input[hostname_component.end() - 1] == ']' &&
url::IPv6AddressToNumber(input.data(), hostname_component,
tmp_ipv6_addr)) {
// Strip the brackets.
hostname_component.begin++;
hostname_component.len -= 2;
} else {
return false;
}
}

// Pass results back to caller.
if (username_component.is_valid()) {
username->assign(input.data() + username_component.begin,
username_component.len);
}
if (password_component.is_valid()) {
password->assign(input.data() + password_component.begin,
password_component.len);
}
host->assign(input.data() + hostname_component.begin, hostname_component.len);
*port = parsed_port_number;

return true; // Success.
}

}
24 changes: 24 additions & 0 deletions chromium_src/net/base/url_util.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef BRAVE_NET_BASE_URL_AUTH_UTIL_H_
#define BRAVE_NET_BASE_URL_AUTH_UTIL_H_

#include "../../../../net/base/url_util.h"

#include "base/strings/string_piece_forward.h"
#include "net/base/net_export.h"

namespace net {

NET_EXPORT bool ParseAuthHostAndPort(
base::StringPiece input,
std::string* username,
std::string* password,
std::string* host,
int* port);

}

#endif // BRAVE_NET_BASE_URL_AUTH_UTIL_H_
11 changes: 11 additions & 0 deletions chromium_src/net/log/net_log_event_type_list.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Copyright 2018 The Brave Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "../../../../net/log/net_log_event_type_list.h"

// The time spent sending authentication to the SOCKS server
EVENT_TYPE(SOCKS5_AUTH_WRITE)

// The time spent waiting for the authentication response from the SOCKS server
EVENT_TYPE(SOCKS5_AUTH_READ)
19 changes: 19 additions & 0 deletions patches/net-base-host_port_pair.cc.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
diff --git a/net/base/host_port_pair.cc b/net/base/host_port_pair.cc
index ec8248449dbcd4156e361fcc8781ce0712f26a02..fd8af49cfa6f41c56b7218a71048dd077e072f6e 100644
--- a/net/base/host_port_pair.cc
+++ b/net/base/host_port_pair.cc
@@ -50,12 +50,14 @@ HostPortPair HostPortPair::FromString(const std::string& str) {
return host_port_pair;
}

+#if !defined(BRAVE_CHROMIUM_BUILD)
std::string HostPortPair::ToString() const {
std::string ret(HostForURL());
ret += ':';
ret += base::UintToString(port_);
return ret;
}
+#endif

std::string HostPortPair::HostForURL() const {
// TODO(rtenneti): Add support for |host| to have '\0'.
53 changes: 53 additions & 0 deletions patches/net-base-host_port_pair.h.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
diff --git a/net/base/host_port_pair.h b/net/base/host_port_pair.h
index a5ee6bda3ff542624b484b7a11811b708fec3e11..084616da28ba3569cc75d1b0fef51a0b89a9f54e 100644
--- a/net/base/host_port_pair.h
+++ b/net/base/host_port_pair.h
@@ -24,6 +24,13 @@ class NET_EXPORT HostPortPair {
// If |in_host| represents an IPv6 address, it should not bracket the address.
HostPortPair(const std::string& in_host, uint16_t in_port);

+ // Brave addition. Nudges HostPortPair past Chromium's style
+ // threshold for in-line constructors and destructors.
+ HostPortPair(const std::string& username, const std::string& password,
+ const std::string& in_host, uint16_t in_port);
+ ~HostPortPair();
+ HostPortPair(const HostPortPair&);
+
// Creates a HostPortPair for the origin of |url|.
static HostPortPair FromURL(const GURL& url);

@@ -37,18 +44,23 @@ class NET_EXPORT HostPortPair {
// TODO(willchan): Define a functor instead.
// Comparator function so this can be placed in a std::map.
bool operator<(const HostPortPair& other) const {
- return std::tie(port_, host_) < std::tie(other.port_, other.host_);
+ return std::tie(port_, host_, username_, password_) <
+ std::tie(other.port_, other.host_, other.username_, other.password_);
}

// Equality test of contents. (Probably another violation of style guide).
bool Equals(const HostPortPair& other) const {
- return host_ == other.host_ && port_ == other.port_;
+ return username_ == other.username_ && password_ == other.password_ &&
+ host_ == other.host_ && port_ == other.port_;
}

bool IsEmpty() const {
return host_.empty() && port_ == 0;
}

+ const std::string& username() const { return username_; }
+ const std::string& password() const { return password_; }
+
const std::string& host() const {
return host_;
}
@@ -72,6 +84,8 @@ class NET_EXPORT HostPortPair {
size_t EstimateMemoryUsage() const;

private:
+ std::string username_;
+ std::string password_;
// If |host_| represents an IPv6 address, this string will not contain
// brackets around the address.
std::string host_;
29 changes: 29 additions & 0 deletions patches/net-base-proxy_server.cc.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
diff --git a/net/base/proxy_server.cc b/net/base/proxy_server.cc
index da31a40fbe8dc454dd24cb368c3af7d0b8c3506d..85f8ee0367f949809e18bd7ec1eab0010975a87d 100644
--- a/net/base/proxy_server.cc
+++ b/net/base/proxy_server.cc
@@ -223,10 +223,13 @@ ProxyServer ProxyServer::FromSchemeHostAndPort(
HostPortPair host_port_pair;

if (scheme != SCHEME_INVALID && scheme != SCHEME_DIRECT) {
+ std::string username;
+ std::string password;
std::string host;
int port = -1;
// If the scheme has a host/port, parse it.
- bool ok = ParseHostAndPort(host_and_port, &host, &port);
+ bool ok = ParseAuthHostAndPort(host_and_port, &username, &password,
+ &host, &port);
if (!ok)
return ProxyServer(); // Invalid -- failed parsing <host>[":"<port>]

@@ -234,7 +237,8 @@ ProxyServer ProxyServer::FromSchemeHostAndPort(
if (port == -1)
port = GetDefaultPortForScheme(scheme);

- host_port_pair = HostPortPair(host, static_cast<uint16_t>(port));
+ host_port_pair = HostPortPair(username, password, host,
+ static_cast<uint16_t>(port));
}

return ProxyServer(scheme, host_port_pair);
73 changes: 73 additions & 0 deletions patches/net-socket-socks5_client_socket.cc.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
diff --git a/net/socket/socks5_client_socket.cc b/net/socket/socks5_client_socket.cc
index 784bcef533288d1eced7daa5b470b8d99550cd98..490766ba173a5f15f618a8fcdd0de8bfa8c5328d 100644
--- a/net/socket/socks5_client_socket.cc
+++ b/net/socket/socks5_client_socket.cc
@@ -241,6 +241,9 @@ int SOCKS5ClientSocket::DoLoop(int last_io_result) {
net_log_.EndEventWithNetErrorCode(NetLogEventType::SOCKS5_GREET_READ,
rv);
break;
+ case STATE_AUTH:
+ rv = DoAuth(rv);
+ break;
case STATE_HANDSHAKE_WRITE:
DCHECK_EQ(OK, rv);
net_log_.BeginEvent(NetLogEventType::SOCKS5_HANDSHAKE_WRITE);
@@ -270,8 +273,6 @@ int SOCKS5ClientSocket::DoLoop(int last_io_result) {
return rv;
}

-const char kSOCKS5GreetWriteData[] = { 0x05, 0x01, 0x00 }; // no authentication
-
int SOCKS5ClientSocket::DoGreetWrite() {
// Since we only have 1 byte to send the hostname length in, if the
// URL has a hostname longer than 255 characters we can't send it.
@@ -281,8 +282,12 @@ int SOCKS5ClientSocket::DoGreetWrite() {
}

if (buffer_.empty()) {
- buffer_ = std::string(kSOCKS5GreetWriteData,
- arraysize(kSOCKS5GreetWriteData));
+ const char greeting[] = {
+ 0x05, // SOCKS version
+ 0x01, // number of authentication methods
+ auth_method(),
+ };
+ buffer_ = std::string(greeting, sizeof(greeting));
bytes_sent_ = 0;
}

@@ -341,14 +346,32 @@ int SOCKS5ClientSocket::DoGreetReadComplete(int result) {
NetLog::IntCallback("version", buffer_[0]));
return ERR_SOCKS_CONNECTION_FAILED;
}
- if (buffer_[1] != 0x00) {
+ if (buffer_[1] != auth_method()) {
net_log_.AddEvent(NetLogEventType::SOCKS_UNEXPECTED_AUTH,
NetLog::IntCallback("method", buffer_[1]));
return ERR_SOCKS_CONNECTION_FAILED;
}

buffer_.clear();
- next_state_ = STATE_HANDSHAKE_WRITE;
+ next_state_ = STATE_AUTH;
+ return OK;
+}
+
+int SOCKS5ClientSocket::DoAuth(int rv) {
+ rv = Authenticate(rv, *transport_, net_log_, io_callback_);
+ next_state_ = (rv == OK ? STATE_HANDSHAKE_WRITE : STATE_AUTH);
+ return rv;
+}
+
+uint8_t SOCKS5ClientSocket::auth_method() {
+ return 0x00;
+}
+
+int SOCKS5ClientSocket::Authenticate(int rv,
+ ClientSocketHandle& socket,
+ NetLogWithSource& net_log,
+ CompletionCallback& callback) {
+ DCHECK_EQ(OK, rv);
return OK;
}

42 changes: 42 additions & 0 deletions patches/net-socket-socks5_client_socket.h.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
diff --git a/net/socket/socks5_client_socket.h b/net/socket/socks5_client_socket.h
index b6e59ae6b07823087e44ffc40fb7d2d54c6a7c3e..98ee500609b2a72970387324a09da102b7230c14 100644
--- a/net/socket/socks5_client_socket.h
+++ b/net/socket/socks5_client_socket.h
@@ -20,6 +20,7 @@
#include "net/base/net_export.h"
#include "net/dns/host_resolver.h"
#include "net/log/net_log_with_source.h"
+#include "net/socket/socks_client_socket_pool.h"
#include "net/socket/stream_socket.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
#include "url/gurl.h"
@@ -79,11 +80,14 @@ class NET_EXPORT_PRIVATE SOCKS5ClientSocket : public StreamSocket {
int GetLocalAddress(IPEndPoint* address) const override;

private:
+ friend class SOCKS5ClientSocketAuth;
enum State {
STATE_GREET_WRITE,
STATE_GREET_WRITE_COMPLETE,
STATE_GREET_READ,
STATE_GREET_READ_COMPLETE,
+ STATE_AUTH,
+ STATE_AUTH_COMPLETE,
STATE_HANDSHAKE_WRITE,
STATE_HANDSHAKE_WRITE_COMPLETE,
STATE_HANDSHAKE_READ,
@@ -118,6 +122,14 @@ class NET_EXPORT_PRIVATE SOCKS5ClientSocket : public StreamSocket {
int DoGreetReadComplete(int result);
int DoGreetWrite();
int DoGreetWriteComplete(int result);
+ int DoAuth(int result);
+
+ // Authentication hooks.
+ virtual uint8_t auth_method();
+ virtual int Authenticate(int result,
+ ClientSocketHandle& socket,
+ NetLogWithSource& net_log,
+ CompletionCallback& callback);

// Writes the SOCKS handshake buffer into |handshake|
// and return OK on success.
Loading