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 */