wget: initial support for ftps://
authorDenys Vlasenko <vda.linux@googlemail.com>
Tue, 6 Feb 2018 14:15:08 +0000 (15:15 +0100)
committerDenys Vlasenko <vda.linux@googlemail.com>
Tue, 6 Feb 2018 14:15:08 +0000 (15:15 +0100)
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 <vda.linux@googlemail.com>
include/libbb.h
networking/ssl_client.c
networking/tls.c
networking/wget.c

index 2bb3643667d937cd3d79fc06bd38ec725e513c50..a4eb6ee676ae473b16a11c1cef21d48be2f99e16 100644 (file)
@@ -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;
index d479846d7f8ec06ce767f8ad9fc2a823fef51946..eb84e7726f11089327d2037b46620e955532389e 100644 (file)
@@ -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;
 }
index 7936afca219ab838ad27800890d41d1b14e83ccf..da7b6058fde4af5ed2010b54f0f44ef6d7370b72 100644 (file)
@@ -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,
index 9300fa30b956b0dd79afdec0c4e3e2f86e7cebbe..daa728a9d070d486f895bb0ce1ad06d585bc30e6 100644 (file)
@@ -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);