diff options
| author | Denys Vlasenko <vda.linux@googlemail.com> | 2018-02-06 15:48:12 +0100 |
|---|---|---|
| committer | Denys Vlasenko <vda.linux@googlemail.com> | 2018-02-06 15:48:12 +0100 |
| commit | 1783ffa990814e2aac14e7ff5a4bbf2d5bebe3cc (patch) | |
| tree | 7e792db0260222476ec186db33fec49a22039731 | |
| parent | 403f2999f94937ba3f37db6d093832f636815bb9 (diff) | |
| download | busybox-w32-1783ffa990814e2aac14e7ff5a4bbf2d5bebe3cc.tar.gz busybox-w32-1783ffa990814e2aac14e7ff5a4bbf2d5bebe3cc.tar.bz2 busybox-w32-1783ffa990814e2aac14e7ff5a4bbf2d5bebe3cc.zip | |
wget: add EPSV support
function old new delta
parse_pasv_epsv - 151 +151
wget_main 2440 2382 -58
xconnect_ftpdata 223 94 -129
------------------------------------------------------------------------------
(add/remove: 2/0 grow/shrink: 0/2 up/down: 151/-187) Total: -36 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
| -rw-r--r-- | include/libbb.h | 1 | ||||
| -rw-r--r-- | networking/ftpgetput.c | 57 | ||||
| -rw-r--r-- | networking/parse_pasv_epsv.c | 66 | ||||
| -rw-r--r-- | networking/wget.c | 19 |
4 files changed, 82 insertions, 61 deletions
diff --git a/include/libbb.h b/include/libbb.h index a4eb6ee67..e2bedaf41 100644 --- a/include/libbb.h +++ b/include/libbb.h | |||
| @@ -787,6 +787,7 @@ ssize_t recv_from_to(int fd, void *buf, size_t len, int flags, | |||
| 787 | socklen_t sa_size) FAST_FUNC; | 787 | socklen_t sa_size) FAST_FUNC; |
| 788 | 788 | ||
| 789 | uint16_t inet_cksum(uint16_t *addr, int len) FAST_FUNC; | 789 | uint16_t inet_cksum(uint16_t *addr, int len) FAST_FUNC; |
| 790 | int parse_pasv_epsv(char *buf) FAST_FUNC; | ||
| 790 | 791 | ||
| 791 | /* 0 if argv[0] is NULL: */ | 792 | /* 0 if argv[0] is NULL: */ |
| 792 | unsigned string_array_len(char **argv) FAST_FUNC; | 793 | unsigned string_array_len(char **argv) FAST_FUNC; |
diff --git a/networking/ftpgetput.c b/networking/ftpgetput.c index 697955e82..cdad629da 100644 --- a/networking/ftpgetput.c +++ b/networking/ftpgetput.c | |||
| @@ -152,57 +152,16 @@ static void ftp_login(void) | |||
| 152 | 152 | ||
| 153 | static int xconnect_ftpdata(void) | 153 | static int xconnect_ftpdata(void) |
| 154 | { | 154 | { |
| 155 | char *buf_ptr; | 155 | int port_num; |
| 156 | unsigned port_num; | ||
| 157 | 156 | ||
| 158 | /* | 157 | if (ENABLE_FEATURE_IPV6 && ftpcmd("EPSV", NULL) == 229) { |
| 159 | PASV command will not work for IPv6. RFC2428 describes | 158 | /* good */ |
| 160 | IPv6-capable "extended PASV" - EPSV. | 159 | } else if (ftpcmd("PASV", NULL) != 227) { |
| 161 | 160 | ftp_die("PASV"); | |
| 162 | "EPSV [protocol]" asks server to bind to and listen on a data port | ||
| 163 | in specified protocol. Protocol is 1 for IPv4, 2 for IPv6. | ||
| 164 | If not specified, defaults to "same as used for control connection". | ||
| 165 | If server understood you, it should answer "229 <some text>(|||port|)" | ||
| 166 | where "|" are literal pipe chars and "port" is ASCII decimal port#. | ||
| 167 | |||
| 168 | There is also an IPv6-capable replacement for PORT (EPRT), | ||
| 169 | but we don't need that. | ||
| 170 | |||
| 171 | NB: PASV may still work for some servers even over IPv6. | ||
| 172 | For example, vsftp happily answers | ||
| 173 | "227 Entering Passive Mode (0,0,0,0,n,n)" and proceeds as usual. | ||
| 174 | */ | ||
| 175 | if (!ENABLE_FEATURE_IPV6 | ||
| 176 | || ftpcmd("EPSV", NULL) != 229 | ||
| 177 | ) { | ||
| 178 | /* maybe also go straight to PAST if lsa->u.sa.sa_family == AF_INET? */ | ||
| 179 | if (ftpcmd("PASV", NULL) != 227) { | ||
| 180 | ftp_die("PASV"); | ||
| 181 | } | ||
| 182 | |||
| 183 | /* Response is "NNN garbageN1,N2,N3,N4,P1,P2[)garbage]" | ||
| 184 | * Server's IP is N1.N2.N3.N4 (we ignore it) | ||
| 185 | * Server's port for data connection is P1*256+P2 */ | ||
| 186 | buf_ptr = strrchr(buf, ')'); | ||
| 187 | if (buf_ptr) *buf_ptr = '\0'; | ||
| 188 | |||
| 189 | buf_ptr = strrchr(buf, ','); | ||
| 190 | *buf_ptr = '\0'; | ||
| 191 | port_num = xatoul_range(buf_ptr + 1, 0, 255); | ||
| 192 | |||
| 193 | buf_ptr = strrchr(buf, ','); | ||
| 194 | *buf_ptr = '\0'; | ||
| 195 | port_num += xatoul_range(buf_ptr + 1, 0, 255) * 256; | ||
| 196 | } else { | ||
| 197 | /* Response is "NNN garbage(|||P1|)" | ||
| 198 | * Server's port for data connection is P1 */ | ||
| 199 | buf_ptr = strrchr(buf, '|'); | ||
| 200 | if (buf_ptr) *buf_ptr = '\0'; | ||
| 201 | |||
| 202 | buf_ptr = strrchr(buf, '|'); | ||
| 203 | *buf_ptr = '\0'; | ||
| 204 | port_num = xatoul_range(buf_ptr + 1, 0, 65535); | ||
| 205 | } | 161 | } |
| 162 | port_num = parse_pasv_epsv(buf); | ||
| 163 | if (port_num < 0) | ||
| 164 | ftp_die("PASV"); | ||
| 206 | 165 | ||
| 207 | set_nport(&lsa->u.sa, htons(port_num)); | 166 | set_nport(&lsa->u.sa, htons(port_num)); |
| 208 | return xconnect_stream(lsa); | 167 | return xconnect_stream(lsa); |
diff --git a/networking/parse_pasv_epsv.c b/networking/parse_pasv_epsv.c new file mode 100644 index 000000000..f32087152 --- /dev/null +++ b/networking/parse_pasv_epsv.c | |||
| @@ -0,0 +1,66 @@ | |||
| 1 | /* | ||
| 2 | * Utility routines. | ||
| 3 | * | ||
| 4 | * Copyright (C) 2018 Denys Vlasenko | ||
| 5 | * | ||
| 6 | * Licensed under GPLv2 or later, see file LICENSE in this source tree. | ||
| 7 | */ | ||
| 8 | //kbuild:lib-$(CONFIG_FTPGET) += ftpgetput.o | ||
| 9 | //kbuild:lib-$(CONFIG_FTPPUT) += ftpgetput.o | ||
| 10 | //kbuild:lib-$(CONFIG_WGET) += parse_pasv_epsv.o | ||
| 11 | |||
| 12 | #include "libbb.h" | ||
| 13 | |||
| 14 | int FAST_FUNC parse_pasv_epsv(char *buf) | ||
| 15 | { | ||
| 16 | /* | ||
| 17 | * PASV command will not work for IPv6. RFC2428 describes | ||
| 18 | * IPv6-capable "extended PASV" - EPSV. | ||
| 19 | * | ||
| 20 | * "EPSV [protocol]" asks server to bind to and listen on a data port | ||
| 21 | * in specified protocol. Protocol is 1 for IPv4, 2 for IPv6. | ||
| 22 | * If not specified, defaults to "same as used for control connection". | ||
| 23 | * If server understood you, it should answer "229 <some text>(|||port|)" | ||
| 24 | * where "|" are literal pipe chars and "port" is ASCII decimal port#. | ||
| 25 | * | ||
| 26 | * There is also an IPv6-capable replacement for PORT (EPRT), | ||
| 27 | * but we don't need that. | ||
| 28 | * | ||
| 29 | * NB: PASV may still work for some servers even over IPv6. | ||
| 30 | * For example, vsftp happily answers | ||
| 31 | * "227 Entering Passive Mode (0,0,0,0,n,n)" and proceeds as usual. | ||
| 32 | */ | ||
| 33 | char *ptr; | ||
| 34 | int port; | ||
| 35 | |||
| 36 | if (!ENABLE_FEATURE_IPV6 || buf[2] == '7' /* "227" */) { | ||
| 37 | /* Response is "227 garbageN1,N2,N3,N4,P1,P2[)garbage]" | ||
| 38 | * Server's IP is N1.N2.N3.N4 (we ignore it) | ||
| 39 | * Server's port for data connection is P1*256+P2 */ | ||
| 40 | ptr = strrchr(buf, ')'); | ||
| 41 | if (ptr) *ptr = '\0'; | ||
| 42 | |||
| 43 | ptr = strrchr(buf, ','); | ||
| 44 | if (!ptr) return -1; | ||
| 45 | *ptr = '\0'; | ||
| 46 | port = xatou_range(ptr + 1, 0, 255); | ||
| 47 | |||
| 48 | ptr = strrchr(buf, ','); | ||
| 49 | if (!ptr) return -1; | ||
| 50 | *ptr = '\0'; | ||
| 51 | port += xatou_range(ptr + 1, 0, 255) * 256; | ||
| 52 | } else { | ||
| 53 | /* Response is "229 garbage(|||P1|)" | ||
| 54 | * Server's port for data connection is P1 */ | ||
| 55 | ptr = strrchr(buf, '|'); | ||
| 56 | if (!ptr) return -1; | ||
| 57 | *ptr = '\0'; | ||
| 58 | |||
| 59 | ptr = strrchr(buf, '|'); | ||
| 60 | if (!ptr) return -1; | ||
| 61 | *ptr = '\0'; | ||
| 62 | port = xatou_range(ptr + 1, 0, 65535); | ||
| 63 | } | ||
| 64 | |||
| 65 | return port; | ||
| 66 | } | ||
diff --git a/networking/wget.c b/networking/wget.c index daa728a9d..7ca4bfb33 100644 --- a/networking/wget.c +++ b/networking/wget.c | |||
| @@ -791,22 +791,17 @@ static FILE* prepare_ftp_session(FILE **dfpp, struct host_info *target, len_and_ | |||
| 791 | /* | 791 | /* |
| 792 | * Entering passive mode | 792 | * Entering passive mode |
| 793 | */ | 793 | */ |
| 794 | if (ENABLE_FEATURE_IPV6 && ftpcmd("EPSV", NULL, sfp) == 229) { | ||
| 795 | /* good */ | ||
| 796 | } else | ||
| 794 | if (ftpcmd("PASV", NULL, sfp) != 227) { | 797 | if (ftpcmd("PASV", NULL, sfp) != 227) { |
| 795 | pasv_error: | 798 | pasv_error: |
| 796 | bb_error_msg_and_die("bad response to %s: %s", "PASV", sanitize_string(G.wget_buf)); | 799 | bb_error_msg_and_die("bad response to %s: %s", "PASV", sanitize_string(G.wget_buf)); |
| 797 | } | 800 | } |
| 798 | // Response is "227 garbageN1,N2,N3,N4,P1,P2[)garbage] | 801 | port = parse_pasv_epsv(G.wget_buf); |
| 799 | // Server's IP is N1.N2.N3.N4 (we ignore it) | 802 | if (port < 0) |
| 800 | // Server's port for data connection is P1*256+P2 | 803 | goto pasv_error; |
| 801 | str = strrchr(G.wget_buf, ')'); | 804 | |
| 802 | if (str) str[0] = '\0'; | ||
| 803 | str = strrchr(G.wget_buf, ','); | ||
| 804 | if (!str) goto pasv_error; | ||
| 805 | port = xatou_range(str+1, 0, 255); | ||
| 806 | *str = '\0'; | ||
| 807 | str = strrchr(G.wget_buf, ','); | ||
| 808 | if (!str) goto pasv_error; | ||
| 809 | port += xatou_range(str+1, 0, 255) * 256; | ||
| 810 | set_nport(&lsa->u.sa, htons(port)); | 805 | set_nport(&lsa->u.sa, htons(port)); |
| 811 | 806 | ||
| 812 | *dfpp = open_socket(lsa); | 807 | *dfpp = open_socket(lsa); |
