Implemented switch for waiting on server ident before sending client ident. (Fixes #118)

This commit is contained in:
Jeroen van Erp
2016-03-18 13:24:33 +01:00
parent 3c230a0fc4
commit 50403483da
3 changed files with 60 additions and 12 deletions

View File

@@ -155,4 +155,24 @@ public interface Config {
* @param keepAliveProvider keep-alive provider
*/
void setKeepAliveProvider(KeepAliveProvider keepAliveProvider);
/**
* Gets whether the client should first wait for a received server ident, before sending the client ident.
* <p/>
* <stong>NB:</stong> This is non-standard behaviour, and can potentially deadlock if the server also waits on the client ident.
*
* The default value is set to false.
*
* @return Whether to first wait for the server ident.
*/
boolean isWaitForServerIdentBeforeSendingClientIdent();
/**
* Sets whether the SSH client should wait for a received server ident, before sending the client ident.
* <p/>
* <stong>NB:</stong> This is non-standard behaviour, and can potentially deadlock if the server also waits on the client ident.
* @param waitForServerIdentBeforeSendingClientIdent Whether to wait for the server ident.
*/
void setWaitForServerIdentBeforeSendingClientIdent(boolean waitForServerIdentBeforeSendingClientIdent);
}

View File

@@ -44,6 +44,8 @@ public class ConfigImpl
private List<Factory.Named<Signature>> signatureFactories;
private List<Factory.Named<FileKeyProvider>> fileKeyProviderFactories;
private boolean waitForServerIdentBeforeSendingClientIdent = false;
@Override
public List<Factory.Named<Cipher>> getCipherFactories() {
return cipherFactories;
@@ -157,4 +159,14 @@ public class ConfigImpl
public void setKeepAliveProvider(KeepAliveProvider keepAliveProvider) {
this.keepAliveProvider = keepAliveProvider;
}
@Override
public boolean isWaitForServerIdentBeforeSendingClientIdent() {
return waitForServerIdentBeforeSendingClientIdent;
}
@Override
public void setWaitForServerIdentBeforeSendingClientIdent(boolean waitForServerIdentBeforeSendingClientIdent) {
this.waitForServerIdentBeforeSendingClientIdent = waitForServerIdentBeforeSendingClientIdent;
}
}

View File

@@ -152,19 +152,15 @@ public final class TransportImpl
try {
log.info("Client identity string: {}", clientID);
connInfo.out.write((clientID + "\r\n").getBytes(IOUtils.UTF8));
connInfo.out.flush();
// Read server's ID
final Buffer.PlainBuffer buf = new Buffer.PlainBuffer();
while ((serverID = readIdentification(buf)).isEmpty()) {
int b = connInfo.in.read();
if (b == -1)
throw new TransportException("Server closed connection during identification exchange");
buf.putByte((byte) b);
if (config.isWaitForServerIdentBeforeSendingClientIdent()) {
receiveServerIdent();
sendClientIdent();
} else {
sendClientIdent();
receiveServerIdent();
}
log.info("Server identity string: {}", serverID);
} catch (IOException e) {
@@ -174,6 +170,26 @@ public final class TransportImpl
reader.start();
}
private void receiveServerIdent() throws IOException {
final Buffer.PlainBuffer buf = new Buffer.PlainBuffer();
while ((serverID = readIdentification(buf)).isEmpty()) {
int b = connInfo.in.read();
if (b == -1)
throw new TransportException("Server closed connection during identification exchange");
buf.putByte((byte) b);
}
}
/**
* Receive the server identification string.
* @throws IOException If there was an error writing to the outputstream.
*/
private void sendClientIdent() throws IOException {
log.info("Client identity string: {}", clientID);
connInfo.out.write((clientID + "\r\n").getBytes(IOUtils.UTF8));
connInfo.out.flush();
}
/**
* Reads the identification string from the SSH server. This is the very first string that is sent upon connection
* by the server. It takes the form of, e.g. "SSH-2.0-OpenSSH_ver".