@Override public long write(SSHPacket payload) throws TransportException { writeLock.lock(); try { if (kexer.isKexOngoing()) { // Only transport layer packets (1 to 49) allowed except SERVICE_REQUEST final Message m = Message.fromByte(payload.array()[payload.rpos()]); if (!m.in(1, 49) || m == Message.SERVICE_REQUEST) { assert m != Message.KEXINIT; kexer.waitForDone(); } } else if (encoder.getSequenceNumber() == 0) // We get here every 2**32th packet kexer.startKex(true); final long seq = encoder.encode(payload); try { connInfo.out.write(payload.array(), payload.rpos(), payload.available()); connInfo.out.flush(); } catch (IOException ioe) { throw new TransportException(ioe); } return seq; } finally { writeLock.unlock(); } }
public void die(Exception ex) { close.lock(); try { if (!close.isSet()) { log.error("Dying because - {}", ex); final SSHException causeOfDeath = SSHException.chainer.chain(ex); disconnectListener.notifyDisconnect( causeOfDeath.getDisconnectReason(), causeOfDeath.getMessage()); ErrorDeliveryUtil.alertEvents(causeOfDeath, close, serviceAccept); kexer.notifyError(causeOfDeath); getService().notifyError(causeOfDeath); setService(nullService); { // Perhaps can send disconnect packet to server final boolean didNotReceiveDisconnect = msg != Message.DISCONNECT; final boolean gotRequiredInfo = causeOfDeath.getDisconnectReason() != DisconnectReason.UNKNOWN; if (didNotReceiveDisconnect && gotRequiredInfo) sendDisconnect(causeOfDeath.getDisconnectReason(), causeOfDeath.getMessage()); } finishOff(); close.set(); } } finally { close.unlock(); } }
/** * Got an SSH_MSG_UNIMPLEMENTED, so lets see where we're at and act accordingly. * * @param packet The 'unimplemented' packet received * @throws TransportException */ private void gotUnimplemented(SSHPacket packet) throws SSHException { long seqNum = packet.readUInt32(); log.debug("Received SSH_MSG_UNIMPLEMENTED #{}", seqNum); if (kexer.isKexOngoing()) throw new TransportException("Received SSH_MSG_UNIMPLEMENTED while exchanging keys"); getService().notifyUnimplemented(seqNum); }
/** * This is where all incoming packets are handled. If they pertain to the transport layer, they * are handled here; otherwise they are delegated to the active service instance if any via {@link * Service#handle}. * * <p>Even among the transport layer specific packets, key exchange packets are delegated to * {@link KeyExchanger#handle}. * * <p>This method is called in the context of the {@link #reader} thread via {@link * Decoder#received} when a full packet has been decoded. * * @param msg the message identifer * @param buf buffer containg rest of the packet * @throws SSHException if an error occurs during handling (unrecoverable) */ @Override public void handle(Message msg, SSHPacket buf) throws SSHException { this.msg = msg; log.trace("Received packet {}", msg); if (msg.geq(50)) // not a transport layer packet service.handle(msg, buf); else if (msg.in(20, 21) || msg.in(30, 49)) // kex packet kexer.handle(msg, buf); else switch (msg) { case DISCONNECT: { gotDisconnect(buf); break; } case IGNORE: { log.debug("Received SSH_MSG_IGNORE"); break; } case UNIMPLEMENTED: { gotUnimplemented(buf); break; } case DEBUG: { gotDebug(buf); break; } case SERVICE_ACCEPT: { gotServiceAccept(); break; } case USERAUTH_BANNER: { log.debug("Received USERAUTH_BANNER"); break; } default: sendUnimplemented(); } }
@Override public byte[] getSessionID() { return kexer.getSessionID(); }
public boolean isKexDone() { return kexer.isKexDone(); }
@Override public void doKex() throws TransportException { kexer.startKex(true); }
@Override public void addAlgorithmsVerifier(AlgorithmsVerifier verifier) { kexer.addAlgorithmsVerifier(verifier); }
@Override public void addHostKeyVerifier(HostKeyVerifier hkv) { kexer.addHostKeyVerifier(hkv); }