tags:

views:

1059

answers:

3

I am receiving "INFO: The remote computer disconnected: Protocol error: packet too long: 65580" error, when I trying to execute:

sUpload("server.host.com", "username", "/home/localuser/.ssh/id_rsa", "filename", "");

The file does not get transferred to SFTP server (only zero-byte gets created on the other side). When SFTPing manually via Unix shell, everything is working fine. I read online that it may be a problem with BLOCK_SIZE in SftpClient, but first I could not find a setter method to alter the size and second, it appears that default value is 65535 anyway, which totally does not explain the 65580 value from the error message.

Any ideas?

I have the following utility method that uses Java Ssh Tools (j2ssh-core-0.2.9.jar):

private static void sUpload(String ftpServer, String user, String password,
String localFile, String remoteFile) throws IOException {
    String methodName = "sUpload: ";
    System.out.println(" START ftpServer="+ftpServer+" user="+user+" password="+password);

    int result = 0;
    System.out.println("ftpServer " + ftpServer);
    System.out.println("user  " + user);
    System.out.println("password  " + password);
    System.out.println("localFile " + localFile);
    System.out.println("remoteFile    " + remoteFile);

    SshClient ssh = new SshClient();

    ssh.connect(ftpServer);

    System.out.println("Server Connected  ");
    if (password.contains("\\") || password.contains("/")) {

        PublicKeyAuthenticationClient pk = 
            new PublicKeyAuthenticationClient();

        pk.setUsername(user);
        // Open up the private key file
        SshPrivateKeyFile file = SshPrivateKeyFile
                .parse(new File(password));
        SshPrivateKey key = file.toPrivateKey(null);
        pk.setKeyfile(password);
        pk.setKey(key);
        // Try the authentication
        result = ssh.authenticate(pk);

    } else {

        // Create a password authentication instance
        PasswordAuthenticationClient pwd = 
            new PasswordAuthenticationClient();
        // Get the users name
        pwd.setUsername(user);
        // Get the password
        pwd.setPassword(password);

        // Try the authentication
        result = ssh.authenticate(pwd);
    }

    System.out.println("Result fromssh.authenticate(pwd) " + result);
    // Evaluate the result
    if (result == AuthenticationProtocolState.COMPLETE) {

        // The connection is authenticated we can now do some real work!
        SftpClient sftp = ssh.openSftpClient();       
        System.out.println("openSftpClient");
        // Upload a file
        if(remoteFile != null && remoteFile.trim().length() > 0){
            sftp.put(localFile, remoteFile);
            System.out.println("======== no remote ======================================== file transfer success =======================================================================");
        }
        else    {
            System.out.println("================================================ file transfer starting =======================================================================");
            sftp.put(localFile);
            System.out.println("================================================ file transfer success =======================================================================");
        }


        // Quit
        sftp.quit();
        ssh.disconnect();
    }
    System.out.println(" END ");
}
A: 

You cannot change BLOCKSIZE. There are several places that block size is mentioned. All of them are either using a fixed value for some read or write buffer, or are calling getBlockSize() on a Cipher object, which is part of the JVM crypto subsystem.

I'm not able to reproduce the error you're seeing. SI tried with several differently sized files including one of the exact size you mentioned. Something like this is very susceptible to the client and server settings.

My gut instinct is that there is a bug in the j2ssh library relating to cipher block sizes which is creating a larger than allowed block by not taking into account a packet header somewhere. I suggest fiddling with the settings to see if you can force the client to use a different cipher. It might also be helpful to download the j2ssh source and try to debug into the problem directly. Determine whether the error is happening on the first, last or some middle packet.

Jherico
is there a way to set a protocol version using java sshtools? I'm googling for more info and it appears this may be caused by ssh protocol version that client is using.
Rocket Surgeon
no idea, but I don't see any obvious way.
Jherico
+1  A: 

The ssh client should tell the server what the desired max packet size is and the server should comply according to the specs.

Try against a different server and check the configuration of max packet size of your own server.

Niels Castle
I could not find any way to set max packet size on the client. Even so, if client is transmitting default value of 65535, why do we end up having server complain about 65580?
Rocket Surgeon
You would have to hardwire a new packet size into the source to change it on the j2sh client - but that shouldn't be necessary.See if you can change the max packet size <i>on the server side</i>. The specific server that you are communicating with might not accomodate 65k packets. As an alternative and to rule out a misbehaving server, try running your code against another server.
Niels Castle
A: 

Looks like the following code works - I used lower level "com.sshtools.j2ssh.sftp.SftpSubsystemClient" instead of "com.sshtools.j2ssh.SftpClient" and reading/writing files using input/output streams:

    System.out.println("Result fromssh.authenticate(pwd) " + result);
    // Evaluate the result
    if (result == AuthenticationProtocolState.COMPLETE) {
        SftpSubsystemClient sftpSubsystemClient = ssh.openSftpChannel();
        com.sshtools.j2ssh.connection.Channel sftpChannel = sftpSubsystemClient;
        System.out.println("Local packet size: " + sftpChannel.getLocalPacketSize());
        System.out.println("Remote packet size: " + sftpChannel.getRemotePacketSize());

        SftpFile file = sftpSubsystemClient.openFile(remoteFile, SftpSubsystemClient.OPEN_CREATE | SftpSubsystemClient.OPEN_WRITE);

        FileAttributes attrs = file.getAttributes();
        attrs.setPermissions("rwxrwxrwx");
        sftpSubsystemClient.setAttributes(file, attrs);

        final int bufferSize = 4096;
        System.out.println("Creating buffered streams");
        BufferedInputStream in = new BufferedInputStream(new FileInputStream(localFile), bufferSize);
        BufferedWriter out = new BufferedWriter(new OutputStreamWriter(new SftpFileOutputStream(file)));

        int c;            
        while ((c = in.read()) != -1) {
            out.write(c);
        }
        System.out.println("Done writing streams");
        out.close();
        in.close();
        sftpSubsystemClient.close();            
        ssh.disconnect();
    }
    System.out.println(" END ");

What's really interesting is that I am outputting remote and local packet sizes just for fun, and they are both equal to 65535. It really seems that this 65580 message is a bug in SSH server or SSH tools.

Rocket Surgeon