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

Rework socks5 authentication. #311

Closed
wants to merge 2 commits into from
Closed
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)
151 changes: 151 additions & 0 deletions chromium_src/net/socket/socks5_client_socket.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
// 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/socket/socks5_client_socket.cc"

#include "net/base/io_buffer.h"
#include "net/socket/socks5_client_socket.h"

namespace net {

SOCKS5ClientSocketAuth::SOCKS5ClientSocketAuth(
std::unique_ptr<ClientSocketHandle> transport_socket,
const HostResolver::RequestInfo& req_info,
const NetworkTrafficAnnotationTag& traffic_annotation,
const HostPortPair& proxy_host_port)
: SOCKS5ClientSocket(std::move(transport_socket), req_info,
traffic_annotation),
proxy_host_port_(proxy_host_port),
next_state_(STATE_INIT_WRITE) {
}

SOCKS5ClientSocketAuth::~SOCKS5ClientSocketAuth() = default;

const std::string& SOCKS5ClientSocketAuth::username() {
return proxy_host_port_.username();
}

const std::string& SOCKS5ClientSocketAuth::password() {
return proxy_host_port_.password();
}

bool SOCKS5ClientSocketAuth::do_auth() {
return username().size() != 0 || password().size() != 0;
}

uint8_t SOCKS5ClientSocketAuth::auth_method() {
if (!do_auth())
return 0x00;
return 0x02;
}

static const size_t kSOCKSAuthUsernamePasswordResponseLen = 2;

int SOCKS5ClientSocketAuth::Authenticate(
int rv, ClientSocketHandle& transport, NetLogWithSource& net_log,
CompletionCallback& callback) {
if (!do_auth()) {
DCHECK_EQ(OK, rv);
return OK;
}
do {
switch (next_state_) {
case STATE_INIT_WRITE: {
DCHECK_EQ(OK, rv);
// Initialize the buffer with 
// 0x01, usernamelen, username, passwordlen, password
size_t usernamelen = username().size();
size_t passwordlen = password().size();
buffer_ = std::string(1 + 1 + usernamelen + 1 + passwordlen, 0);
buffer_[0] = 0x01;
buffer_[1] = usernamelen;
buffer_.replace(2, usernamelen, username());
buffer_[2 + usernamelen] = passwordlen;
buffer_.replace(2 + usernamelen + 1, passwordlen, password());
DCHECK_EQ(buffer_.size(), 2 + usernamelen + 1 + passwordlen);
buffer_left_ = buffer_.size();
next_state_ = STATE_WRITE;
rv = OK;
break;
}
case STATE_WRITE:
DCHECK_EQ(OK, rv);
DCHECK_LT(0u, buffer_left_);
iobuf_ = new IOBuffer(buffer_left_);
memcpy(iobuf_->data(),
&buffer_.data()[buffer_.size() - buffer_left_],
buffer_left_);
next_state_ = STATE_WRITE_COMPLETE;
net_log.BeginEvent(NetLogEventType::SOCKS5_AUTH_WRITE);
rv = transport.socket()->Write(iobuf_.get(), buffer_left_, callback,
traffic_annotation_);
break;

case STATE_WRITE_COMPLETE:
// TODO(riastradh): Zero iobuf? Zero buffer?
net_log.EndEventWithNetErrorCode(NetLogEventType::SOCKS5_AUTH_WRITE,
std::max(rv, 0));
if (rv < 0) {
next_state_ = STATE_BAD;
return rv;
}
DCHECK_LE(static_cast<size_t>(rv), buffer_left_);
buffer_left_ -= rv;
next_state_ = (buffer_left_ == 0 ? STATE_INIT_READ : STATE_WRITE);
rv = OK;
break;

case STATE_INIT_READ:
DCHECK_EQ(OK, rv);
buffer_.clear();
buffer_left_ = kSOCKSAuthUsernamePasswordResponseLen;
iobuf_ = new IOBuffer(buffer_left_);
next_state_ = STATE_READ;
rv = OK;
break;

case STATE_READ:
DCHECK_EQ(OK, rv);
iobuf_ = new IOBuffer(buffer_left_);
next_state_ = STATE_READ_COMPLETE;
net_log.BeginEvent(NetLogEventType::SOCKS5_AUTH_READ);
rv = transport.socket()->Read(iobuf_.get(), buffer_left_, callback);
break;

case STATE_READ_COMPLETE:
net_log.EndEventWithNetErrorCode(NetLogEventType::SOCKS5_AUTH_READ,
std::max(rv, 0));
if (rv < 0) {
next_state_ = STATE_BAD;
return rv;
}
DCHECK_LE(static_cast<size_t>(rv), buffer_left_);
buffer_.append(iobuf_->data(), rv);
buffer_left_ -= rv;
next_state_ = (buffer_left_ == 0 ? STATE_DONE : STATE_READ);
rv = OK;
break;

case STATE_DONE: {
DCHECK_EQ(OK, rv);
DCHECK_EQ(buffer_.size(), kSOCKSAuthUsernamePasswordResponseLen);
static_assert(kSOCKSAuthUsernamePasswordResponseLen == 2, "bad size");
uint8_t ver = buffer_[0];
uint8_t status = buffer_[1];
next_state_ = STATE_BAD; // Caller had better stop here.
if (ver != 0x01 || status != 0x00)
return ERR_FAILED;
return OK;
}

case STATE_BAD:
default:
NOTREACHED() << "bad state";
return ERR_UNEXPECTED;
}
} while (rv != ERR_IO_PENDING);
return rv;
}

} // namespace net
46 changes: 46 additions & 0 deletions chromium_src/net/socket/socks5_client_socket.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// 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.

#ifndef BRAVE_NET_SOCKET_SOCKS5_CLIENT_SOCKET_AUTH_H_
#define BRAVE_NET_SOCKET_SOCKS5_CLIENT_SOCKET_AUTH_H_

#include "../../../../net/socket/socks5_client_socket.h"

namespace net {

class NET_EXPORT_PRIVATE SOCKS5ClientSocketAuth : public SOCKS5ClientSocket {
public:
SOCKS5ClientSocketAuth(std::unique_ptr<ClientSocketHandle> transport_socket,
const HostResolver::RequestInfo& req_info,
const NetworkTrafficAnnotationTag& traffic_annotation,
const HostPortPair& proxy_host_port);
~SOCKS5ClientSocketAuth() override;
private:
bool do_auth();
const std::string& username();
const std::string& password();
uint8_t auth_method() override;
int Authenticate(int rv,
ClientSocketHandle& transport, NetLogWithSource& net_log,
CompletionCallback& callback) override;
const HostPortPair proxy_host_port_;
enum {
STATE_INIT_WRITE = 0,
STATE_WRITE,
STATE_WRITE_COMPLETE,
STATE_INIT_READ,
STATE_READ,
STATE_READ_COMPLETE,
STATE_DONE,
STATE_BAD,
} next_state_;
scoped_refptr<IOBuffer> iobuf_;
std::string buffer_;
size_t buffer_left_;
DISALLOW_COPY_AND_ASSIGN(SOCKS5ClientSocketAuth);
};

} // namespace net

#endif // BRAVE_NET_SOCKET_SOCKS5_CLIENT_SOCKET_AUTH_H_
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'.
Loading