From 403f2999f94937ba3f37db6d093832f636815bb9 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 6 Feb 2018 15:15:08 +0100 Subject: [PATCH] wget: initial support for ftps:// function old new delta spawn_ssl_client - 185 +185 parse_url 409 461 +52 packed_usage 32259 32278 +19 tls_run_copy_loop 293 306 +13 ssl_client_main 128 138 +10 showmode 330 338 +8 P_FTPS - 5 +5 filter_datapoints 177 179 +2 deflate 907 905 -2 decode_one_format 723 716 -7 wget_main 2591 2440 -151 ------------------------------------------------------------------------------ (add/remove: 2/0 grow/shrink: 6/3 up/down: 294/-160) Total: 134 bytes Signed-off-by: Denys Vlasenko --- include/libbb.h | 3 ++- networking/ssl_client.c | 14 ++++++++------ networking/tls.c | 4 +++- networking/wget.c | 37 +++++++++++++++++++++++++++++-------- 4 files changed, 42 insertions(+), 16 deletions(-) diff --git a/include/libbb.h b/include/libbb.h index 2bb364366..a4eb6ee67 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -772,7 +772,8 @@ static inline tls_state_t *new_tls_state(void) return tls; } void tls_handshake(tls_state_t *tls, const char *sni) FAST_FUNC; -void tls_run_copy_loop(tls_state_t *tls) FAST_FUNC; +#define TLSLOOP_EXIT_ON_LOCAL_EOF (1 << 0) +void tls_run_copy_loop(tls_state_t *tls, unsigned flags) FAST_FUNC; void socket_want_pktinfo(int fd) FAST_FUNC; diff --git a/networking/ssl_client.c b/networking/ssl_client.c index d479846d7..eb84e7726 100644 --- a/networking/ssl_client.c +++ b/networking/ssl_client.c @@ -15,7 +15,7 @@ //kbuild:lib-$(CONFIG_SSL_CLIENT) += ssl_client.o //usage:#define ssl_client_trivial_usage -//usage: "-s FD [-r FD] [-n SNI]" +//usage: "[-e] -s FD [-r FD] [-n SNI]" //usage:#define ssl_client_full_usage "" #include "libbb.h" @@ -30,26 +30,28 @@ int ssl_client_main(int argc UNUSED_PARAM, char **argv) // INIT_G(); tls = new_tls_state(); - opt = getopt32(argv, "s:#r:#n:", &tls->ofd, &tls->ifd, &sni); - if (!(opt & 2)) { + opt = getopt32(argv, "es:#r:#n:", &tls->ofd, &tls->ifd, &sni); + if (!(opt & (1<<2))) { /* -r N defaults to -s N */ tls->ifd = tls->ofd; } - if (!(opt & 3)) { + if (!(opt & (3<<1))) { if (!argv[1]) bb_show_usage(); /* Undocumented debug feature: without -s and -r, takes HOST arg and connects to it */ // // Talk to kernel.org: - // printf "GET / HTTP/1.1\r\nHost: kernel.org\r\n\r\n" | ./busybox ssl_client kernel.org + // printf "GET / HTTP/1.1\r\nHost: kernel.org\r\n\r\n" | busybox ssl_client kernel.org if (!sni) sni = argv[1]; tls->ifd = tls->ofd = create_and_connect_stream_or_die(argv[1], 443); } tls_handshake(tls, sni); - tls_run_copy_loop(tls); + + BUILD_BUG_ON(TLSLOOP_EXIT_ON_LOCAL_EOF != 1); + tls_run_copy_loop(tls, /*flags*/ opt & 1); return EXIT_SUCCESS; } diff --git a/networking/tls.c b/networking/tls.c index 7936afca2..da7b6058f 100644 --- a/networking/tls.c +++ b/networking/tls.c @@ -1727,7 +1727,7 @@ static void tls_xwrite(tls_state_t *tls, int len) // openssl s_server -key key.pem -cert server.pem -debug -tls1_2 -no_tls1 -no_tls1_1 -cipher NULL // openssl s_client -connect 127.0.0.1:4433 -debug -tls1_2 -no_tls1 -no_tls1_1 -cipher NULL-SHA256 -void FAST_FUNC tls_run_copy_loop(tls_state_t *tls) +void FAST_FUNC tls_run_copy_loop(tls_state_t *tls, unsigned flags) { int inbuf_size; const int INBUF_STEP = 4 * 1024; @@ -1762,6 +1762,8 @@ void FAST_FUNC tls_run_copy_loop(tls_state_t *tls) */ pfds[0].fd = -1; tls_free_outbuf(tls); /* mem usage optimization */ + if (flags & TLSLOOP_EXIT_ON_LOCAL_EOF) + break; } else { if (nread == inbuf_size) { /* TLS has per record overhead, if input comes fast, diff --git a/networking/wget.c b/networking/wget.c index 9300fa30b..daa728a9d 100644 --- a/networking/wget.c +++ b/networking/wget.c @@ -48,6 +48,7 @@ //config: //config:config FEATURE_WGET_HTTPS //config: bool "Support HTTPS using internal TLS code" +//it also enables FTPS support, but it's not well tested yet //config: default y //config: depends on WGET //config: select TLS @@ -176,6 +177,9 @@ struct host_info { static const char P_FTP[] ALIGN1 = "ftp"; static const char P_HTTP[] ALIGN1 = "http"; #if SSL_SUPPORTED +# if ENABLE_FEATURE_WGET_HTTPS +static const char P_FTPS[] ALIGN1 = "ftps"; +# endif static const char P_HTTPS[] ALIGN1 = "https"; #endif @@ -484,6 +488,12 @@ static void parse_url(const char *src_url, struct host_info *h) h->port = bb_lookup_port(P_FTP, "tcp", 21); } else #if SSL_SUPPORTED +# if ENABLE_FEATURE_WGET_HTTPS + if (strcmp(url, P_FTPS) == 0) { + h->port = bb_lookup_port(P_FTPS, "tcp", 990); + h->protocol = P_FTPS; + } else +# endif if (strcmp(url, P_HTTPS) == 0) { h->port = bb_lookup_port(P_HTTPS, "tcp", 443); h->protocol = P_HTTPS; @@ -678,7 +688,7 @@ static int spawn_https_helper_openssl(const char *host, unsigned port) #endif #if ENABLE_FEATURE_WGET_HTTPS -static void spawn_ssl_client(const char *host, int network_fd) +static void spawn_ssl_client(const char *host, int network_fd, int flags) { int sp[2]; int pid; @@ -703,17 +713,19 @@ static void spawn_ssl_client(const char *host, int network_fd) tls_state_t *tls = new_tls_state(); tls->ifd = tls->ofd = network_fd; tls_handshake(tls, servername); - tls_run_copy_loop(tls); + tls_run_copy_loop(tls, flags); exit(0); } else { - char *argv[5]; + char *argv[6]; + xmove_fd(network_fd, 3); argv[0] = (char*)"ssl_client"; argv[1] = (char*)"-s3"; //TODO: if (!is_ip_address(servername))... argv[2] = (char*)"-n"; argv[3] = servername; - argv[4] = NULL; + argv[4] = (flags & TLSLOOP_EXIT_ON_LOCAL_EOF ? (char*)"-e" : NULL); + argv[5] = NULL; BB_EXECVP(argv[0], argv); bb_perror_msg_and_die("can't execute '%s'", argv[0]); } @@ -737,6 +749,11 @@ static FILE* prepare_ftp_session(FILE **dfpp, struct host_info *target, len_and_ target->user = xstrdup("anonymous:busybox@"); sfp = open_socket(lsa); +#if ENABLE_FEATURE_WGET_HTTPS + if (target->protocol == P_FTPS) + spawn_ssl_client(target->host, fileno(sfp), TLSLOOP_EXIT_ON_LOCAL_EOF); +#endif + if (ftpcmd(NULL, NULL, sfp) != 220) bb_error_msg_and_die("%s", sanitize_string(G.wget_buf + 4)); @@ -794,6 +811,10 @@ static FILE* prepare_ftp_session(FILE **dfpp, struct host_info *target, len_and_ *dfpp = open_socket(lsa); + //For encrypted data, need to send "PROT P" and get "200 PROT now Private" response first + //Without it (or with "PROT C"), data is sent unencrypted + //spawn_ssl_client(target->host, fileno(*dfpp), /*flags*/ 0); + if (G.beg_range != 0) { sprintf(G.wget_buf, "REST %"OFF_FMT"u", G.beg_range); if (ftpcmd(G.wget_buf, NULL, sfp) == 350) @@ -981,7 +1002,7 @@ static void download_one_url(const char *url) /* Use the proxy if necessary */ use_proxy = (strcmp(G.proxy_flag, "off") != 0); if (use_proxy) { - proxy = getenv(target.protocol == P_FTP ? "ftp_proxy" : "http_proxy"); + proxy = getenv(target.protocol[0] == 'f' ? "ftp_proxy" : "http_proxy"); //FIXME: what if protocol is https? Ok to use http_proxy? use_proxy = (proxy && proxy[0]); if (use_proxy) @@ -1042,7 +1063,7 @@ static void download_one_url(const char *url) /*G.content_len = 0; - redundant, got_clen = 0 is enough */ G.got_clen = 0; G.chunked = 0; - if (use_proxy || target.protocol != P_FTP) { + if (use_proxy || target.protocol[0] != 'f' /*not ftp[s]*/) { /* * HTTP session */ @@ -1060,7 +1081,7 @@ static void download_one_url(const char *url) # if ENABLE_FEATURE_WGET_HTTPS if (fd < 0) { /* no openssl? try internal */ sfp = open_socket(lsa); - spawn_ssl_client(server.host, fileno(sfp)); + spawn_ssl_client(server.host, fileno(sfp), /*flags*/ 0); goto socket_opened; } # else @@ -1077,7 +1098,7 @@ static void download_one_url(const char *url) /* Only internal TLS support is configured */ sfp = open_socket(lsa); if (target.protocol == P_HTTPS) - spawn_ssl_client(server.host, fileno(sfp)); + spawn_ssl_client(server.host, fileno(sfp), /*flags*/ 0); #else /* ssl (https) support is not configured */ sfp = open_socket(lsa); -- 2.25.1