Implement basic HTTP tunnel support in bssl client. For testing purposes. Change-Id: Ied1b130e805bcf8cc5d1bd30a1ba5049d6f13a6d Reviewed-on: https://boringssl-review.googlesource.com/17665 Commit-Queue: David Benjamin <davidben@google.com> Commit-Queue: Steven Valdez <svaldez@google.com> Reviewed-by: Steven Valdez <svaldez@google.com>
diff --git a/tool/client.cc b/tool/client.cc index c4a071d..74a7124 100644 --- a/tool/client.cc +++ b/tool/client.cc
@@ -127,6 +127,10 @@ "-ed25519", kBooleanArgument, "Advertise Ed25519 support", }, { + "-http-tunnel", kOptionalArgument, + "An HTTP proxy server to tunnel the TCP connection through", + }, + { "", kOptionalArgument, "", }, }; @@ -208,7 +212,12 @@ std::map<std::string, std::string> args_map, bool (*cb)(SSL *ssl, int sock)) { int sock = -1; - if (!Connect(&sock, args_map["-connect"])) { + if (args_map.count("-http-tunnel") != 0) { + if (!Connect(&sock, args_map["-http-tunnel"]) || + !DoHTTPTunnel(sock, args_map["-connect"])) { + return false; + } + } else if (!Connect(&sock, args_map["-connect"])) { return false; }
diff --git a/tool/transport_common.cc b/tool/transport_common.cc index 912e680..0fc7c3c 100644 --- a/tool/transport_common.cc +++ b/tool/transport_common.cc
@@ -70,10 +70,8 @@ return true; } -// Connect sets |*out_sock| to be a socket connected to the destination given -// in |hostname_and_port|, which should be of the form "www.example.com:123". -// It returns true on success and false otherwise. -bool Connect(int *out_sock, const std::string &hostname_and_port) { +static void SplitHostPort(std::string *out_hostname, std::string *out_port, + const std::string &hostname_and_port) { size_t colon_offset = hostname_and_port.find_last_of(':'); const size_t bracket_offset = hostname_and_port.find_last_of(']'); std::string hostname, port; @@ -85,12 +83,20 @@ } if (colon_offset == std::string::npos) { - hostname = hostname_and_port; - port = "443"; + *out_hostname = hostname_and_port; + *out_port = "443"; } else { - hostname = hostname_and_port.substr(0, colon_offset); - port = hostname_and_port.substr(colon_offset + 1); + *out_hostname = hostname_and_port.substr(0, colon_offset); + *out_port = hostname_and_port.substr(colon_offset + 1); } +} + +// Connect sets |*out_sock| to be a socket connected to the destination given +// in |hostname_and_port|, which should be of the form "www.example.com:123". +// It returns true on success and false otherwise. +bool Connect(int *out_sock, const std::string &hostname_and_port) { + std::string hostname, port; + SplitHostPort(&hostname, &port, hostname_and_port); // Handle IPv6 literals. if (hostname.size() >= 2 && hostname[0] == '[' && @@ -631,3 +637,31 @@ return true; } + +bool DoHTTPTunnel(int sock, const std::string &hostname_and_port) { + std::string hostname, port; + SplitHostPort(&hostname, &port, hostname_and_port); + + fprintf(stderr, "Establishing HTTP tunnel to %s:%s.\n", hostname.c_str(), + port.c_str()); + char buf[1024]; + snprintf(buf, sizeof(buf), "CONNECT %s:%s HTTP/1.0\r\n\r\n", hostname.c_str(), + port.c_str()); + if (!SendAll(sock, buf, strlen(buf))) { + return false; + } + + SocketLineReader line_reader(sock); + + // Read until an empty line, signaling the end of the HTTP response. + std::string line; + for (;;) { + if (!line_reader.Next(&line)) { + return false; + } + if (line.empty()) { + return true; + } + fprintf(stderr, "%s\n", line.c_str()); + } +}
diff --git a/tool/transport_common.h b/tool/transport_common.h index 7c157ba..b149671 100644 --- a/tool/transport_common.h +++ b/tool/transport_common.h
@@ -18,6 +18,8 @@ #include <openssl/ssl.h> #include <string.h> +#include <string> + // InitSocketLibrary calls the Windows socket init functions, if needed. bool InitSocketLibrary(); @@ -59,4 +61,8 @@ // returns true on success and false otherwise. bool DoSMTPStartTLS(int sock); +// DoHTTPTunnel sends an HTTP CONNECT request over |sock|. It returns true on +// success and false otherwise. +bool DoHTTPTunnel(int sock, const std::string &hostname_and_port); + #endif /* !OPENSSL_HEADER_TOOL_TRANSPORT_COMMON_H */