aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/libbb.h1
-rw-r--r--networking/ftpgetput.c57
-rw-r--r--networking/parse_pasv_epsv.c66
-rw-r--r--networking/wget.c19
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
789uint16_t inet_cksum(uint16_t *addr, int len) FAST_FUNC; 789uint16_t inet_cksum(uint16_t *addr, int len) FAST_FUNC;
790int parse_pasv_epsv(char *buf) FAST_FUNC;
790 791
791/* 0 if argv[0] is NULL: */ 792/* 0 if argv[0] is NULL: */
792unsigned string_array_len(char **argv) FAST_FUNC; 793unsigned 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
153static int xconnect_ftpdata(void) 153static 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) {
159PASV command will not work for IPv6. RFC2428 describes 158 /* good */
160IPv6-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
163in specified protocol. Protocol is 1 for IPv4, 2 for IPv6.
164If not specified, defaults to "same as used for control connection".
165If server understood you, it should answer "229 <some text>(|||port|)"
166where "|" are literal pipe chars and "port" is ASCII decimal port#.
167
168There is also an IPv6-capable replacement for PORT (EPRT),
169but we don't need that.
170
171NB: PASV may still work for some servers even over IPv6.
172For 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
14int 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);