diff options
-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); |