Return-Path: Delivered-To: apmail-commons-commits-archive@minotaur.apache.org Received: (qmail 88114 invoked from network); 8 Mar 2010 09:53:30 -0000 Received: from unknown (HELO mail.apache.org) (140.211.11.3) by 140.211.11.9 with SMTP; 8 Mar 2010 09:53:30 -0000 Received: (qmail 94290 invoked by uid 500); 8 Mar 2010 09:53:07 -0000 Delivered-To: apmail-commons-commits-archive@commons.apache.org Received: (qmail 93968 invoked by uid 500); 8 Mar 2010 09:53:06 -0000 Mailing-List: contact commits-help@commons.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@commons.apache.org Delivered-To: mailing list commits@commons.apache.org Received: (qmail 93961 invoked by uid 99); 8 Mar 2010 09:53:06 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 08 Mar 2010 09:53:06 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=10.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 08 Mar 2010 09:53:04 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id 2D8F623889ED; Mon, 8 Mar 2010 09:52:44 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r920251 - in /commons/proper/net/branches/NET_2_0/src/main/java/org/apache/commons/net/ftp: FTP.java FTPClient.java FTPCommand.java FTPReply.java Date: Mon, 08 Mar 2010 09:52:44 -0000 To: commits@commons.apache.org From: rwinston@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20100308095244.2D8F623889ED@eris.apache.org> Author: rwinston Date: Mon Mar 8 09:52:43 2010 New Revision: 920251 URL: http://svn.apache.org/viewvc?rev=920251&view=rev Log: NET-288: IPv6 EPRT/EPSV support Modified: commons/proper/net/branches/NET_2_0/src/main/java/org/apache/commons/net/ftp/FTP.java commons/proper/net/branches/NET_2_0/src/main/java/org/apache/commons/net/ftp/FTPClient.java commons/proper/net/branches/NET_2_0/src/main/java/org/apache/commons/net/ftp/FTPCommand.java commons/proper/net/branches/NET_2_0/src/main/java/org/apache/commons/net/ftp/FTPReply.java Modified: commons/proper/net/branches/NET_2_0/src/main/java/org/apache/commons/net/ftp/FTP.java URL: http://svn.apache.org/viewvc/commons/proper/net/branches/NET_2_0/src/main/java/org/apache/commons/net/ftp/FTP.java?rev=920251&r1=920250&r2=920251&view=diff ============================================================================== --- commons/proper/net/branches/NET_2_0/src/main/java/org/apache/commons/net/ftp/FTP.java (original) +++ commons/proper/net/branches/NET_2_0/src/main/java/org/apache/commons/net/ftp/FTP.java Mon Mar 8 09:52:43 2010 @@ -21,6 +21,8 @@ import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; +import java.net.Inet4Address; +import java.net.Inet6Address; import java.net.InetAddress; import java.net.Socket; import java.net.SocketException; @@ -857,6 +859,58 @@ } /*** + * A convenience method to send the FTP EPRT command to the server, + * receive the reply, and return the reply code. + * + * @see http://www.faqs.org/rfcs/rfc2428.html + * + * Examples: + * + *
    + *
  • EPRT |1|132.235.1.2|6275|
  • + *
  • EPRT |2|1080::8:800:200C:417A|5282|
  • + *
+ *
+ *

+ * @param host The host owning the port. + * @param port The new port. + * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int eprt(InetAddress host, int port) throws IOException + { + int num; + StringBuffer info = new StringBuffer(); + String h; + + // If IPv6, trim the zone index + h = host.getHostAddress(); + num = h.indexOf("%"); + if (num > 0) + h = h.substring(0, num); + + info.append("|"); + + if (host instanceof Inet4Address) + info.append("1"); + else if (host instanceof Inet6Address) + info.append("2"); + info.append("|"); + info.append(h); + info.append("|"); + info.append(port); + info.append("|"); + + return sendCommand(FTPCommand.EPRT, info.toString()); + } + + /*** * A convenience method to send the FTP PASV command to the server, * receive the reply, and return the reply code. Remember, it's up * to you to interpret the reply string containing the host/port @@ -876,6 +930,26 @@ return sendCommand(FTPCommand.PASV); } + /*** + * A convenience method to send the FTP EPSV command to the server, + * receive the reply, and return the reply code. Remember, it's up + * to you to interpret the reply string containing the host/port + * information. + *

+ * @return The reply code received from the server. + * @exception FTPConnectionClosedException + * If the FTP server prematurely closes the connection as a result + * of the client being idle or some other reason causing the server + * to send FTP reply code 421. This exception may be caught either + * as an IOException or independently as itself. + * @exception IOException If an I/O error occurs while either sending the + * command or receiving the server reply. + ***/ + public int epsv() throws IOException + { + return sendCommand(FTPCommand.EPSV); + } + /** * A convenience method to send the FTP TYPE command for text files * to the server, receive the reply, and return the reply code. Modified: commons/proper/net/branches/NET_2_0/src/main/java/org/apache/commons/net/ftp/FTPClient.java URL: http://svn.apache.org/viewvc/commons/proper/net/branches/NET_2_0/src/main/java/org/apache/commons/net/ftp/FTPClient.java?rev=920251&r1=920250&r2=920251&view=diff ============================================================================== --- commons/proper/net/branches/NET_2_0/src/main/java/org/apache/commons/net/ftp/FTPClient.java (original) +++ commons/proper/net/branches/NET_2_0/src/main/java/org/apache/commons/net/ftp/FTPClient.java Mon Mar 8 09:52:43 2010 @@ -23,6 +23,7 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; +import java.net.Inet6Address; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; @@ -119,11 +120,11 @@ * transfer modes, and file structures. *

* Because the handling of sockets on different platforms can differ - * significantly, the FTPClient automatically issues a new PORT command + * significantly, the FTPClient automatically issues a new PORT (or EPRT) command * prior to every transfer requiring that the server connect to the client's * data port. This ensures identical problem-free behavior on Windows, Unix, * and Macintosh platforms. Additionally, it relieves programmers from - * having to issue the PORT command themselves and dealing with platform + * having to issue the PORT (or EPRT) command themselves and dealing with platform * dependent issues. *

* Additionally, for security purposes, all data connections to the @@ -365,6 +366,40 @@ } + private void __parseExtendedPassiveModeReply(String reply) + throws MalformedServerReplyException + { + int port; + + reply = reply.substring(reply.indexOf('(') + 1, + reply.indexOf(')')).trim(); + + char delim1, delim2, delim3, delim4; + delim1 = reply.charAt(0); + delim2 = reply.charAt(1); + delim3 = reply.charAt(2); + delim4 = reply.charAt(reply.length()-1); + + if (!(delim1 == delim2) || !(delim2 == delim3) + || !(delim3 == delim4)) + throw new MalformedServerReplyException( + "Could not parse extended passive host information.\nServer Reply: " + reply); + try + { + port = Integer.parseInt(reply.substring(3, reply.length()-1)); + } + catch (NumberFormatException e) + { + throw new MalformedServerReplyException( + "Could not parse extended passive host information.\nServer Reply: " + reply); + } + + + // in EPSV mode, the passive host address is implicit + __passiveHost = getRemoteAddress().getHostAddress(); + __passivePort = port; + } + private boolean __storeFile(int command, String remote, InputStream local) throws IOException { @@ -460,13 +495,26 @@ ServerSocket server; server = _serverSocketFactory_.createServerSocket(0, 1, getLocalAddress()); - if (!FTPReply.isPositiveCompletion(port(getLocalAddress(), + // try EPRT first. If that fails, and the connection is over IPv4 + // fallback to PORT + + if (!FTPReply.isPositiveCompletion(eprt(getLocalAddress(), server.getLocalPort()))) { - server.close(); - return null; - } + if (getRemoteAddress() instanceof Inet6Address) + { + server.close(); + return null; + } + if (!FTPReply.isPositiveCompletion(port(getLocalAddress(), + server.getLocalPort()))) + { + server.close(); + return null; + } + } + if ((__restartOffset > 0) && !restart(__restartOffset)) { server.close(); @@ -494,10 +542,17 @@ else { // We must be in PASSIVE_LOCAL_DATA_CONNECTION_MODE - if (pasv() != FTPReply.ENTERING_PASSIVE_MODE) - return null; - - __parsePassiveModeReply(_replyLines.get(_replyLines.size() - 1)); + // If we are over an IPv6 connection, try EPSV + if (getRemoteAddress() instanceof Inet6Address) { + if (epsv() != FTPReply.ENTERING_EPSV_MODE) + return null; + __parseExtendedPassiveModeReply((String)_replyLines.get(0)); + } + else { + if (pasv() != FTPReply.ENTERING_PASSIVE_MODE) + return null; + __parsePassiveModeReply((String)_replyLines.get(0)); + } socket = _socketFactory_.createSocket(__passiveHost, __passivePort); if ((__restartOffset > 0) && !restart(__restartOffset)) Modified: commons/proper/net/branches/NET_2_0/src/main/java/org/apache/commons/net/ftp/FTPCommand.java URL: http://svn.apache.org/viewvc/commons/proper/net/branches/NET_2_0/src/main/java/org/apache/commons/net/ftp/FTPCommand.java?rev=920251&r1=920250&r2=920251&view=diff ============================================================================== --- commons/proper/net/branches/NET_2_0/src/main/java/org/apache/commons/net/ftp/FTPCommand.java (original) +++ commons/proper/net/branches/NET_2_0/src/main/java/org/apache/commons/net/ftp/FTPCommand.java Mon Mar 8 09:52:43 2010 @@ -70,6 +70,9 @@ /** @since 2.1 */ public static final int FEAT = 34; public static final int MFMT = 35; + public static final int EPSV = 36; + public static final int EPRT = 37; + public static final int USERNAME = USER; public static final int PASSWORD = PASS; @@ -118,8 +121,8 @@ "USER", "PASS", "ACCT", "CWD", "CDUP", "SMNT", "REIN", "QUIT", "PORT", "PASV", "TYPE", "STRU", "MODE", "RETR", "STOR", "STOU", "APPE", "ALLO", "REST", "RNFR", "RNTO", "ABOR", "DELE", "RMD", "MKD", "PWD", "LIST", - "NLST", "SITE", "SYST", "STAT", "HELP", "NOOP", "MDTM", "FEAT", "MFMT" - }; + "NLST", "SITE", "SYST", "STAT", "HELP", "NOOP", "MDTM", "FEAT", "MFMT", + "EPSV", "EPRT" }; /** * Retrieve the FTP protocol command string corresponding to a specified Modified: commons/proper/net/branches/NET_2_0/src/main/java/org/apache/commons/net/ftp/FTPReply.java URL: http://svn.apache.org/viewvc/commons/proper/net/branches/NET_2_0/src/main/java/org/apache/commons/net/ftp/FTPReply.java?rev=920251&r1=920250&r2=920251&view=diff ============================================================================== --- commons/proper/net/branches/NET_2_0/src/main/java/org/apache/commons/net/ftp/FTPReply.java (original) +++ commons/proper/net/branches/NET_2_0/src/main/java/org/apache/commons/net/ftp/FTPReply.java Mon Mar 8 09:52:43 2010 @@ -49,6 +49,7 @@ public static final int CODE_225 = 225; public static final int CODE_226 = 226; public static final int CODE_227 = 227; + public static final int CODE_229 = 229; public static final int CODE_230 = 230; public static final int CODE_250 = 250; public static final int CODE_257 = 257; @@ -90,6 +91,7 @@ public static final int DATA_CONNECTION_OPEN = CODE_225; public static final int CLOSING_DATA_CONNECTION = CODE_226; public static final int ENTERING_PASSIVE_MODE = CODE_227; + public static final int ENTERING_EPSV_MODE = CODE_229; public static final int USER_LOGGED_IN = CODE_230; public static final int FILE_ACTION_OK = CODE_250; public static final int PATHNAME_CREATED = CODE_257; @@ -157,6 +159,9 @@ /** @since 2.0 */ public static final int REQUESTED_PROT_LEVEL_NOT_SUPPORTED = CODE_536; + // IPv6 error codes + // Note this is also used as an FTPS error code reply + public static final int EXTENDED_PORT_FAILURE = CODE_522; // Cannot be instantiated private FTPReply()