https://bz.apache.org/bugzilla/show_bug.cgi?id=70268

            Bug ID: 70268
           Summary: Regression] <scp> task fails with UnknownHostException
                    when destination path contains a Windows drive letter
                    (caused by Bug 59160 / PR #213)
           Product: Ant
           Version: 1.10.15
          Hardware: PC
            Status: NEW
          Severity: major
          Priority: P2
         Component: Optional Tasks
          Assignee: [email protected]
          Reporter: [email protected]
  Target Milestone: ---

Description of Problem:
Since the merge of PR #213 (fixing Bug 59160: "scp task does not support
ipv6"), the <scp> task fails when copying files to or from a Windows host where
the remote path contains a drive letter (e.g. C:/... or /C:/...).

Steps to Reproduce:
Execute an <scp> upload task targeting a remote Windows SSH server:

<scp todir="[email protected]:/C:/path/to/dir"
     password="secret"
     sftp="true">
    <fileset dir="target/upload" includes="*" />
</scp>
Actual Result:
The task fails immediately during connection establishment:

[scp] Connecting to 172.18.5.231:/C:22
[scp] Connecting to 172.18.5.231:/C port 22
com.jcraft.jsch.JSchException: java.net.UnknownHostException: 172.18.5.231:/C
Expected Result:
The host should be parsed as 172.18.5.231 and the remote path as
/C:/path/to/dir (as was the case in Ant 1.10.13 and earlier).

Root Cause Analysis:
In org.apache.tools.ant.taskdefs.optional.ssh.Scp#parseUri(String uri):

Before PR #213 (Ant <= 1.10.13):

final int indexOfPath = uri.indexOf(':', indexOfAt + 1);
Here, the colon immediately following the hostname was matched.

With PR #213 (commit 7c6c127 / Ant >= 1.10.15):

// For IPv6 addresses, the host part may contain more than one ":",
// look for the last occurrence
final int indexOfPath = uri.lastIndexOf(':');
if (indexOfPath <= indexOfAt) {
    throw new BuildException("no remote path in %s", uri);
}
setHost(uri.substring(indexOfAt + 1, indexOfPath));
PR #213 assumed that any extra : in the URI must belong to an IPv6 address.
However, when connecting to Windows systems (e.g. OpenSSH for Windows or SFTP),
remote paths commonly include drive letters (e.g. user@host:/C:/deploy or
user@host:C:/deploy).

uri.lastIndexOf(':') matches the colon of the drive letter (C:), causing Ant to
extract:

Host: 172.18.5.231:/C
Path: /path/to/dir
JSch then tries to resolve 172.18.5.231:/C as a DNS hostname, throwing
UnknownHostException.

Suggested Fix:
IPv6 addresses in URIs should either be enclosed in brackets (per RFC 3986 /
OpenSSH standard, e.g. [2001:db8::1]:/path), or Ant should check if the last
colon belongs to a Windows drive letter before splitting:

int indexOfPath;
if (uri.charAt(indexOfAt + 1) == '[') {
    // Standard IPv6 notation: user@[ipv6]:/path
    int closingBracket = uri.indexOf(']', indexOfAt + 1);
    if (closingBracket != -1 && uri.indexOf(':', closingBracket) != -1) {
        indexOfPath = uri.indexOf(':', closingBracket);
    } else {
        indexOfPath = uri.lastIndexOf(':');
    }
} else {
    // If not enclosed in brackets, check if last colon is part of a Windows
drive letter (:/?([A-Za-z]):)
    // or locate the first colon after host
    int firstColon = uri.indexOf(':', indexOfAt + 1);
    int lastColon = uri.lastIndexOf(':');
    if (firstColon != lastColon) {
        // Disambiguate between IPv6 host and Windows drive letter in path
        String potentialDrive = uri.substring(firstColon + 1, lastColon);
        if (potentialDrive.matches("^[A-Za-z]$") ||
potentialDrive.matches("^/[A-Za-z]$")) {
            // Last colon is a drive letter (e.g., host:C: or host:/C:); use
first colon
            indexOfPath = firstColon;
        } else {
            indexOfPath = lastColon;
        }
    } else {
        indexOfPath = firstColon;
    }
}

-- 
You are receiving this mail because:
You are the assignee for the bug.

Reply via email to