[git commit] wget: add EPSV support

Denys Vlasenko vda.linux at googlemail.com
Tue Feb 6 14:48:12 UTC 2018


commit: https://git.busybox.net/busybox/commit/?id=1783ffa990814e2aac14e7ff5a4bbf2d5bebe3cc
branch: https://git.busybox.net/busybox/commit/?id=refs/heads/master

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 at googlemail.com>
---
 include/libbb.h              |  1 +
 networking/ftpgetput.c       | 57 ++++++--------------------------------
 networking/parse_pasv_epsv.c | 66 ++++++++++++++++++++++++++++++++++++++++++++
 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,
 		socklen_t sa_size) FAST_FUNC;
 
 uint16_t inet_cksum(uint16_t *addr, int len) FAST_FUNC;
+int parse_pasv_epsv(char *buf) FAST_FUNC;
 
 /* 0 if argv[0] is NULL: */
 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)
 
 static int xconnect_ftpdata(void)
 {
-	char *buf_ptr;
-	unsigned port_num;
+	int port_num;
 
-/*
-PASV command will not work for IPv6. RFC2428 describes
-IPv6-capable "extended PASV" - EPSV.
-
-"EPSV [protocol]" asks server to bind to and listen on a data port
-in specified protocol. Protocol is 1 for IPv4, 2 for IPv6.
-If not specified, defaults to "same as used for control connection".
-If server understood you, it should answer "229 <some text>(|||port|)"
-where "|" are literal pipe chars and "port" is ASCII decimal port#.
-
-There is also an IPv6-capable replacement for PORT (EPRT),
-but we don't need that.
-
-NB: PASV may still work for some servers even over IPv6.
-For example, vsftp happily answers
-"227 Entering Passive Mode (0,0,0,0,n,n)" and proceeds as usual.
-*/
-	if (!ENABLE_FEATURE_IPV6
-	 || ftpcmd("EPSV", NULL) != 229
-	) {
-/* maybe also go straight to PAST if lsa->u.sa.sa_family == AF_INET? */
-		if (ftpcmd("PASV", NULL) != 227) {
-			ftp_die("PASV");
-		}
-
-		/* Response is "NNN garbageN1,N2,N3,N4,P1,P2[)garbage]"
-		 * Server's IP is N1.N2.N3.N4 (we ignore it)
-		 * Server's port for data connection is P1*256+P2 */
-		buf_ptr = strrchr(buf, ')');
-		if (buf_ptr) *buf_ptr = '\0';
-
-		buf_ptr = strrchr(buf, ',');
-		*buf_ptr = '\0';
-		port_num = xatoul_range(buf_ptr + 1, 0, 255);
-
-		buf_ptr = strrchr(buf, ',');
-		*buf_ptr = '\0';
-		port_num += xatoul_range(buf_ptr + 1, 0, 255) * 256;
-	} else {
-		/* Response is "NNN garbage(|||P1|)"
-		 * Server's port for data connection is P1 */
-		buf_ptr = strrchr(buf, '|');
-		if (buf_ptr) *buf_ptr = '\0';
-
-		buf_ptr = strrchr(buf, '|');
-		*buf_ptr = '\0';
-		port_num = xatoul_range(buf_ptr + 1, 0, 65535);
+	if (ENABLE_FEATURE_IPV6 && ftpcmd("EPSV", NULL) == 229) {
+		/* good */
+	} else if (ftpcmd("PASV", NULL) != 227) {
+		ftp_die("PASV");
 	}
+	port_num = parse_pasv_epsv(buf);
+	if (port_num < 0)
+		ftp_die("PASV");
 
 	set_nport(&lsa->u.sa, htons(port_num));
 	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 @@
+/*
+ * Utility routines.
+ *
+ * Copyright (C) 2018 Denys Vlasenko
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
+ */
+//kbuild:lib-$(CONFIG_FTPGET) += ftpgetput.o
+//kbuild:lib-$(CONFIG_FTPPUT) += ftpgetput.o
+//kbuild:lib-$(CONFIG_WGET) += parse_pasv_epsv.o
+
+#include "libbb.h"
+
+int FAST_FUNC parse_pasv_epsv(char *buf)
+{
+/*
+ * PASV command will not work for IPv6. RFC2428 describes
+ * IPv6-capable "extended PASV" - EPSV.
+ *
+ * "EPSV [protocol]" asks server to bind to and listen on a data port
+ * in specified protocol. Protocol is 1 for IPv4, 2 for IPv6.
+ * If not specified, defaults to "same as used for control connection".
+ * If server understood you, it should answer "229 <some text>(|||port|)"
+ * where "|" are literal pipe chars and "port" is ASCII decimal port#.
+ *
+ * There is also an IPv6-capable replacement for PORT (EPRT),
+ * but we don't need that.
+ *
+ * NB: PASV may still work for some servers even over IPv6.
+ * For example, vsftp happily answers
+ * "227 Entering Passive Mode (0,0,0,0,n,n)" and proceeds as usual.
+ */
+	char *ptr;
+	int port;
+
+	if (!ENABLE_FEATURE_IPV6 || buf[2] == '7' /* "227" */) {
+		/* Response is "227 garbageN1,N2,N3,N4,P1,P2[)garbage]"
+		 * Server's IP is N1.N2.N3.N4 (we ignore it)
+		 * Server's port for data connection is P1*256+P2 */
+		ptr = strrchr(buf, ')');
+		if (ptr) *ptr = '\0';
+
+		ptr = strrchr(buf, ',');
+		if (!ptr) return -1;
+		*ptr = '\0';
+		port = xatou_range(ptr + 1, 0, 255);
+
+		ptr = strrchr(buf, ',');
+		if (!ptr) return -1;
+		*ptr = '\0';
+		port += xatou_range(ptr + 1, 0, 255) * 256;
+	} else {
+		/* Response is "229 garbage(|||P1|)"
+		 * Server's port for data connection is P1 */
+		ptr = strrchr(buf, '|');
+		if (!ptr) return -1;
+		*ptr = '\0';
+
+		ptr = strrchr(buf, '|');
+		if (!ptr) return -1;
+		*ptr = '\0';
+		port = xatou_range(ptr + 1, 0, 65535);
+	}
+
+	return port;
+}
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_
 	/*
 	 * Entering passive mode
 	 */
+	if (ENABLE_FEATURE_IPV6 && ftpcmd("EPSV", NULL, sfp) == 229) {
+		/* good */
+	} else
 	if (ftpcmd("PASV", NULL, sfp) != 227) {
  pasv_error:
 		bb_error_msg_and_die("bad response to %s: %s", "PASV", sanitize_string(G.wget_buf));
 	}
-	// Response is "227 garbageN1,N2,N3,N4,P1,P2[)garbage]
-	// Server's IP is N1.N2.N3.N4 (we ignore it)
-	// Server's port for data connection is P1*256+P2
-	str = strrchr(G.wget_buf, ')');
-	if (str) str[0] = '\0';
-	str = strrchr(G.wget_buf, ',');
-	if (!str) goto pasv_error;
-	port = xatou_range(str+1, 0, 255);
-	*str = '\0';
-	str = strrchr(G.wget_buf, ',');
-	if (!str) goto pasv_error;
-	port += xatou_range(str+1, 0, 255) * 256;
+	port = parse_pasv_epsv(G.wget_buf);
+	if (port < 0)
+		goto pasv_error;
+
 	set_nport(&lsa->u.sa, htons(port));
 
 	*dfpp = open_socket(lsa);


More information about the busybox-cvs mailing list