Skip to content

Commit d747de5

Browse files
committed
Add http proxy support to TLS helper
1 parent 73f8515 commit d747de5

2 files changed

Lines changed: 94 additions & 17 deletions

File tree

docs/spec/tls_helper.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ The invoking process may additionally set the following args:
3636
When passed a `--proxy` arg, the TLS helper MUST either use it for the
3737
connection or exit with a non-zero error code.
3838

39+
The invoking process must applying any no_proxy logic before invoking the TLS
40+
helper.
41+
3942
The TLS helper will also get a control socket at file descriptor `3`. This will
4043
be a unix domain socket. Except in case of an error, the helper MUST use the the
4144
control socket to send a single message with the payload `"socket"`, and with

modules/ggl-tls-helper/bin/ggl-tls-helper.c

Lines changed: 91 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@
1313
#include <ggl/socket.h>
1414
#include <netdb.h>
1515
#include <openssl/bio.h>
16+
#include <openssl/crypto.h>
1617
#include <openssl/err.h>
18+
#include <openssl/http.h>
1719
#include <openssl/opensslv.h>
1820
#include <openssl/prov_ssl.h>
1921
#include <openssl/ssl.h>
@@ -222,6 +224,53 @@ static void cleanup_ssl(SSL **ssl) {
222224
}
223225
}
224226

227+
static GglError parse_proxy_url(
228+
const char *proxy_url, char **host, char **port
229+
) {
230+
int use_ssl = 0;
231+
232+
if (!OSSL_HTTP_parse_url(
233+
proxy_url, &use_ssl, NULL, host, port, NULL, NULL, NULL, NULL
234+
)) {
235+
GGL_LOGE("Failed to parse proxy URL.");
236+
ERR_print_errors_cb(openssl_err_cb, NULL);
237+
return GGL_ERR_INVALID;
238+
}
239+
240+
if (use_ssl) {
241+
GGL_LOGE("HTTPS proxies are not supported in this task.");
242+
return GGL_ERR_INVALID;
243+
}
244+
245+
return GGL_ERR_OK;
246+
}
247+
248+
static GglError http_proxy_connect(
249+
BIO *proxy_bio, const char *target_host, const char *target_port
250+
) {
251+
GGL_LOGD("Sending HTTP CONNECT %s:%s to proxy.", target_host, target_port);
252+
253+
int proxy_connect_ret = OSSL_HTTP_proxy_connect(
254+
proxy_bio,
255+
target_host,
256+
target_port,
257+
NULL, // proxy_user
258+
NULL, // proxy_password
259+
60, // timeout
260+
NULL, // bio_err
261+
NULL // prog
262+
);
263+
264+
if (proxy_connect_ret != 1) {
265+
GGL_LOGE("Failed HTTP proxy CONNECT.");
266+
ERR_print_errors_cb(openssl_err_cb, NULL);
267+
return GGL_ERR_FAILURE;
268+
}
269+
270+
GGL_LOGD("HTTP proxy CONNECT successful.");
271+
return GGL_ERR_OK;
272+
}
273+
225274
static GglError tls_handshake(const char *endpoint, BIO *bio, SSL **ssl) {
226275
SSL_CTX *ssl_ctx = SSL_CTX_new(TLS_client_method());
227276
if (ssl_ctx == NULL) {
@@ -381,8 +430,26 @@ int main(int argc, char *argv[]) {
381430
// NOLINTNEXTLINE(concurrency-mt-unsafe)
382431
argp_parse(&argp, argc, argv, 0, 0, NULL);
383432

433+
GglError ret;
384434
int tcp_fd;
385-
GglError ret = create_tcp_connection(arg_endpoint, arg_port, &tcp_fd);
435+
bool using_proxy = false;
436+
437+
if (arg_proxy != NULL) {
438+
char *parse_host;
439+
char *parse_port;
440+
ret = parse_proxy_url(arg_proxy, &parse_host, &parse_port);
441+
if (ret != GGL_ERR_OK) {
442+
return 1;
443+
}
444+
using_proxy = true;
445+
const char *port = (parse_port != NULL) ? parse_port : "80";
446+
ret = create_tcp_connection(parse_host, port, &tcp_fd);
447+
448+
OPENSSL_free(parse_host);
449+
OPENSSL_free(parse_port);
450+
} else {
451+
ret = create_tcp_connection(arg_endpoint, arg_port, &tcp_fd);
452+
}
386453
if (ret != GGL_ERR_OK) {
387454
GGL_LOGE("Failed to create TCP connection.");
388455
return 1;
@@ -395,6 +462,13 @@ int main(int argc, char *argv[]) {
395462
return 1;
396463
}
397464

465+
if (using_proxy) {
466+
ret = http_proxy_connect(bio, arg_endpoint, arg_port);
467+
if (ret != GGL_ERR_OK) {
468+
return 1;
469+
}
470+
}
471+
398472
SSL *ssl = NULL;
399473
ret = tls_handshake(arg_endpoint, bio, &ssl);
400474
if (ret != GGL_ERR_OK) {
@@ -430,14 +504,14 @@ int main(int argc, char *argv[]) {
430504
return 0;
431505
}
432506

433-
GGL_LOGD("Preparing to proxy socket traffic.");
507+
GGL_LOGD("Preparing to relay socket traffic.");
434508

435509
// Close the parent's end of the socketpair
436510
(void) close(parent_fds[0]);
437-
int proxy_fd = parent_fds[1];
511+
int relay_fd = parent_fds[1];
438512

439-
// Proxy data between socketpair and TLS connection
440-
struct pollfd fds[2] = { { .fd = proxy_fd, .events = POLLIN },
513+
// Relay data between socketpair and TLS connection
514+
struct pollfd fds[2] = { { .fd = relay_fd, .events = POLLIN },
441515
{ .fd = tcp_fd, .events = POLLIN } };
442516

443517
uint8_t buffer[4096];
@@ -449,15 +523,15 @@ int main(int argc, char *argv[]) {
449523
return 1;
450524
}
451525

452-
// Data from proxy socket to TLS
526+
// Data from relay socket to TLS
453527
if (fds[0].revents & POLLIN) {
454528
GglBuffer buf = GGL_BUF(buffer);
455529
do {
456-
ret = ggl_file_read_partial(proxy_fd, &buf);
530+
ret = ggl_file_read_partial(relay_fd, &buf);
457531
} while (ret == GGL_ERR_RETRY);
458532

459533
if (ret == GGL_ERR_NODATA) {
460-
GGL_LOGD("Proxy socket closed.");
534+
GGL_LOGD("Relay socket closed.");
461535
int shutdown_ret = SSL_shutdown(ssl);
462536
if (shutdown_ret < 0) {
463537
GGL_LOGE("Openssl shutdown on network socket failed.");
@@ -466,7 +540,7 @@ int main(int argc, char *argv[]) {
466540
(void) shutdown(tcp_fd, SHUT_WR);
467541
fds[0].fd = -1;
468542
} else if (ret != GGL_ERR_OK) {
469-
GGL_LOGE("Proxy socket read error.");
543+
GGL_LOGE("Relay socket read error.");
470544
return 1;
471545
} else {
472546
size_t bytes_read = sizeof(buffer) - buf.len;
@@ -488,13 +562,13 @@ int main(int argc, char *argv[]) {
488562
}
489563
}
490564

491-
// Handle proxy socket errors
565+
// Handle relay socket errors
492566
if (fds[0].revents & (POLLHUP | POLLERR)) {
493-
GGL_LOGD("Proxy socket closed uncleanly.");
567+
GGL_LOGD("Relay socket closed uncleanly.");
494568
fds[0].fd = -1;
495569
}
496570

497-
// Data from TLS to proxy socket
571+
// Data from TLS to relay socket
498572
if (fds[1].revents & POLLIN) {
499573
int bytes = SSL_read(ssl, buffer, sizeof(buffer));
500574
if (bytes <= 0) {
@@ -524,16 +598,16 @@ int main(int argc, char *argv[]) {
524598
return 1;
525599
}
526600

527-
(void) shutdown(proxy_fd, SHUT_WR);
601+
(void) shutdown(relay_fd, SHUT_WR);
528602
fds[1].fd = -1;
529603
} else {
530604
GglBuffer buf = { .data = buffer, .len = (size_t) bytes };
531-
ret = ggl_socket_write(proxy_fd, buf);
605+
ret = ggl_socket_write(relay_fd, buf);
532606
if (ret == GGL_ERR_NOCONN) {
533-
GGL_LOGD("Proxy socket closed by peer during write.");
607+
GGL_LOGD("Relay socket closed by peer during write.");
534608
fds[1].fd = -1;
535609
} else if (ret != GGL_ERR_OK) {
536-
GGL_LOGE("Proxy socket write error.");
610+
GGL_LOGE("Relay socket write error.");
537611
return 1;
538612
}
539613
}
@@ -547,7 +621,7 @@ int main(int argc, char *argv[]) {
547621
}
548622

549623
close(tcp_fd);
550-
close(proxy_fd);
624+
close(relay_fd);
551625

552626
GGL_LOGD("TLS handling complete.");
553627
}

0 commit comments

Comments
 (0)