[PATCH] networking/ftpgetput.c: Make ftp client code RFC compliant for IPv4 and IPv6

Kev Kitchens kitchens.sync at me.com
Sun Apr 7 23:53:46 UTC 2013


This fixes two of the TODOs in this file. FTP client will now first try EPSV (RFC2428) when going into passive mode, falling back to PASV if the command isn't supported. Also, FTP client will connect to the IP address specified in the
response from PASV rather than ignoring it (RFC 959).

--- networking/ftpgetput.c
+++ networking/ftpgetput.c
@@ -147,45 +147,61 @@ static void ftp_login(void)
 static int xconnect_ftpdata(void)
 {
 	char *buf_ptr;
+	char *addr_ptr;
 	unsigned port_num;
 
-/*
-TODO: PASV command will not work for IPv6. RFC2428 describes
-IPv6-capable "extended PASV" - EPSV.
+	if (ftpcmd("EPSV", NULL) != 229) {
+		if (verbose_flag) {
+			bb_error_msg("EPSV failed, trying PASV.");
+		}
+
+		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);
 
-"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#.
+		buf_ptr = strrchr(buf, ',');
+		*buf_ptr = '\0';
+		port_num += xatoul_range(buf_ptr + 1, 0, 255) * 256;
 
-There is also an IPv6-capable replacement for PORT (EPRT),
-but we don't need that.
+		buf_ptr = strrchr(buf, '(');
+		*buf_ptr = '\0';
+		addr_ptr = buf_ptr + 1;
 
-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.
+		buf_ptr = strrchr(addr_ptr, ',');
+		*buf_ptr = '.';
 
-TODO2: need to stop ignoring IP address in PASV response.
-*/
+		buf_ptr = strrchr(addr_ptr, ',');
+		*buf_ptr = '.';
 
-	if (ftpcmd("PASV", NULL) != 227) {
-		ftp_die("PASV");
+		buf_ptr = strrchr(addr_ptr, ',');
+		*buf_ptr = '.';
+
+		if (verbose_flag) {
+		  printf("Connecting to %s:%u\n", addr_ptr, port_num);
+		}
+
+		lsa = xdotted2sockaddr(addr_ptr, port_num);
+		return xconnect_stream(lsa);
 	}
 
-	/* 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, ')');
+	/* 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, 255);
-
-	buf_ptr = strrchr(buf, ',');
+	buf_ptr = strrchr(buf, '|');
 	*buf_ptr = '\0';
-	port_num += xatoul_range(buf_ptr + 1, 0, 255) * 256;
+	port_num = xatoul_range(buf_ptr + 1, 0, 65535);
 
 	set_nport(&lsa->u.sa, htons(port_num));
 	return xconnect_stream(lsa);


More information about the busybox mailing list