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 * @param keepAliveProvider keep-alive provider
*/ */
void setKeepAliveProvider(KeepAliveProvider keepAliveProvider); 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<Signature>> signatureFactories;
private List<Factory.Named<FileKeyProvider>> fileKeyProviderFactories; private List<Factory.Named<FileKeyProvider>> fileKeyProviderFactories;
private boolean waitForServerIdentBeforeSendingClientIdent = false;
@Override @Override
public List<Factory.Named<Cipher>> getCipherFactories() { public List<Factory.Named<Cipher>> getCipherFactories() {
return cipherFactories; return cipherFactories;
@@ -157,4 +159,14 @@ public class ConfigImpl
public void setKeepAliveProvider(KeepAliveProvider keepAliveProvider) { public void setKeepAliveProvider(KeepAliveProvider keepAliveProvider) {
this.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 { try {
log.info("Client identity string: {}", clientID); if (config.isWaitForServerIdentBeforeSendingClientIdent()) {
connInfo.out.write((clientID + "\r\n").getBytes(IOUtils.UTF8)); receiveServerIdent();
connInfo.out.flush(); sendClientIdent();
} else {
// Read server's ID sendClientIdent();
final Buffer.PlainBuffer buf = new Buffer.PlainBuffer(); receiveServerIdent();
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);
} }
log.info("Server identity string: {}", serverID); log.info("Server identity string: {}", serverID);
} catch (IOException e) { } catch (IOException e) {
@@ -174,6 +170,26 @@ public final class TransportImpl
reader.start(); 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 * 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". * by the server. It takes the form of, e.g. "SSH-2.0-OpenSSH_ver".