From ed0a04753ade368c9f0a46e5444cf4c27b0c9d09 Mon Sep 17 00:00:00 2001 From: ggrandes Date: Thu, 13 Jan 2022 00:09:06 +0100 Subject: [PATCH] v1.1.0 updated dependencies (bugs and security) --- README.md | 2 +- jentunnel-core/pom.xml | 14 +- .../org/javastack/jentunnel/SSHClient.java | 25 +- .../CustomForwarderFactory.java | 17 - .../CustomForwardingFilter.java | 1215 ----------------- .../CustomKnownHostsServerKeyVerifier.java | 55 - jentunnel-gui/pom.xml | 2 +- pom.xml | 2 +- 8 files changed, 20 insertions(+), 1312 deletions(-) delete mode 100644 jentunnel-core/src/main/java/org/javastack/jentunnel/workaround_bug_sshd1033/CustomForwarderFactory.java delete mode 100644 jentunnel-core/src/main/java/org/javastack/jentunnel/workaround_bug_sshd1033/CustomForwardingFilter.java delete mode 100644 jentunnel-core/src/main/java/org/javastack/jentunnel/workaround_bug_sshd1063/CustomKnownHostsServerKeyVerifier.java diff --git a/README.md b/README.md index a03fb3c..4729219 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Manage SSH Tunnels made easy. Open Source Java project under Apache License v2.0 -### Current Stable Version is [1.0.2](https://github.com/ggrandes/jentunnel/releases) +### Current Stable Version is [1.1.0](https://github.com/ggrandes/jentunnel/releases) --- diff --git a/jentunnel-core/pom.xml b/jentunnel-core/pom.xml index 20c4277..1b6776f 100644 --- a/jentunnel-core/pom.xml +++ b/jentunnel-core/pom.xml @@ -6,7 +6,7 @@ org.javastack jentunnel - 1.0.2 + 1.1.0 .. @@ -15,13 +15,13 @@ ${project.basedir}/.. - 1.7.30 + 1.7.32 1.1.2 - 1.26 - 2.1.3 - 2.5.1 - 1.14 - 1.66 + 1.30 + 2.1.5 + 2.8.0 + 1.15 + 1.70 0.3.0 1.1.3 diff --git a/jentunnel-core/src/main/java/org/javastack/jentunnel/SSHClient.java b/jentunnel-core/src/main/java/org/javastack/jentunnel/SSHClient.java index 58edbc5..6e7734b 100644 --- a/jentunnel-core/src/main/java/org/javastack/jentunnel/SSHClient.java +++ b/jentunnel-core/src/main/java/org/javastack/jentunnel/SSHClient.java @@ -29,6 +29,7 @@ import java.nio.file.Paths; import java.security.GeneralSecurityException; import java.security.PublicKey; +import java.time.Duration; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -48,7 +49,6 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; -import org.apache.sshd.client.ClientFactoryManager; import org.apache.sshd.client.SshClient; import org.apache.sshd.client.channel.ClientChannel; import org.apache.sshd.client.channel.ClientChannelEvent; @@ -64,14 +64,14 @@ import org.apache.sshd.common.config.keys.KeyUtils; import org.apache.sshd.common.config.keys.writer.openssh.OpenSSHKeyPairResourceWriter; import org.apache.sshd.common.digest.BuiltinDigests; +import org.apache.sshd.common.forward.DefaultForwarderFactory; import org.apache.sshd.common.session.SessionListener; -import org.apache.sshd.common.util.io.NoCloseInputStream; -import org.apache.sshd.common.util.io.NoCloseOutputStream; +import org.apache.sshd.common.util.io.input.NoCloseInputStream; +import org.apache.sshd.common.util.io.output.NoCloseOutputStream; import org.apache.sshd.common.util.net.SshdSocketAddress; import org.apache.sshd.common.util.security.SecurityUtils; +import org.apache.sshd.core.CoreModuleProperties; import org.apache.sshd.server.forward.AcceptAllForwardingFilter; -import org.javastack.jentunnel.workaround_bug_sshd1033.CustomForwarderFactory; -import org.javastack.jentunnel.workaround_bug_sshd1063.CustomKnownHostsServerKeyVerifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -552,8 +552,7 @@ public void connect() throws IOException { if (!knownHost.exists()) { knownHost.createNewFile(); } - // FIXME Workaround Bug SSHD-1063 - KnownHostsServerKeyVerifier hostVerifier = new CustomKnownHostsServerKeyVerifier( + KnownHostsServerKeyVerifier hostVerifier = new KnownHostsServerKeyVerifier( ((clientSession, remoteAddress, serverKey) -> { log.warn("Unknown server {} publickey [{}][{}] ({} [{}])", // remoteAddress, // @@ -583,8 +582,7 @@ public void connect() throws IOException { remoteAddress, entry, expected, actual); }); client.setServerKeyVerifier(hostVerifier); - // FIXME Workaround Bug SSHD-1033 - client.setForwarderFactory(new CustomForwarderFactory()); + client.setForwarderFactory(new DefaultForwarderFactory()); // https://github.com/apache/mina-sshd/blob/master/docs/client-setup.md // TODO: Nuevo PublicKey Auth? // client.setClientIdentityLoader(ClientIdentityLoader.DEFAULT); @@ -601,12 +599,9 @@ public void connect() throws IOException { notify.notifyConnecting(self); } } - PropertyResolverUtils.updateProperty(client, ClientFactoryManager.HEARTBEAT_INTERVAL, - TimeUnit.SECONDS.toMillis(10L)); // DISABLE - PropertyResolverUtils.updateProperty(client, ClientFactoryManager.HEARTBEAT_REPLY_WAIT, - TimeUnit.SECONDS.toMillis(15L)); // DISABLE - PropertyResolverUtils.updateProperty(client, - ClientFactoryManager.DEFAULT_KEEP_ALIVE_HEARTBEAT_STRING, "keepalive@openssh.com"); + CoreModuleProperties.HEARTBEAT_INTERVAL.set(client, Duration.ofSeconds(10)); + CoreModuleProperties.HEARTBEAT_REPLY_WAIT.set(client, Duration.ofSeconds(15)); + CoreModuleProperties.HEARTBEAT_REQUEST.set(client, "keepalive@openssh.com"); // org.apache.sshd.client.session.ClientConnectionService // handleUnknownRequest(ClientConnectionService[ClientSessionImpl[test@/192.168.x.x:22]]) diff --git a/jentunnel-core/src/main/java/org/javastack/jentunnel/workaround_bug_sshd1033/CustomForwarderFactory.java b/jentunnel-core/src/main/java/org/javastack/jentunnel/workaround_bug_sshd1033/CustomForwarderFactory.java deleted file mode 100644 index a543f31..0000000 --- a/jentunnel-core/src/main/java/org/javastack/jentunnel/workaround_bug_sshd1033/CustomForwarderFactory.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.javastack.jentunnel.workaround_bug_sshd1033; - -import org.apache.sshd.common.forward.DefaultForwarderFactory; -import org.apache.sshd.common.forward.ForwardingFilter; -import org.apache.sshd.common.session.ConnectionService; - -/** - * FIXME: Workaround Bug SSHD-1033 - */ -public class CustomForwarderFactory extends DefaultForwarderFactory { - @Override - public ForwardingFilter create(ConnectionService service) { - ForwardingFilter forwarder = new CustomForwardingFilter(service); - forwarder.addPortForwardingEventListenerManager(this); - return forwarder; - } -} diff --git a/jentunnel-core/src/main/java/org/javastack/jentunnel/workaround_bug_sshd1033/CustomForwardingFilter.java b/jentunnel-core/src/main/java/org/javastack/jentunnel/workaround_bug_sshd1033/CustomForwardingFilter.java deleted file mode 100644 index c2e2af5..0000000 --- a/jentunnel-core/src/main/java/org/javastack/jentunnel/workaround_bug_sshd1033/CustomForwardingFilter.java +++ /dev/null @@ -1,1215 +0,0 @@ -package org.javastack.jentunnel.workaround_bug_sshd1033; - -import java.io.IOException; -import java.net.InetSocketAddress; -import java.net.SocketAddress; -import java.util.AbstractMap.SimpleImmutableEntry; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Comparator; -import java.util.EnumSet; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.NavigableSet; -import java.util.Objects; -import java.util.Set; -import java.util.TreeMap; -import java.util.concurrent.CopyOnWriteArraySet; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicLong; -import java.util.function.Consumer; -import java.util.stream.Collectors; - -import org.apache.sshd.client.channel.ClientChannelEvent; -import org.apache.sshd.client.channel.ClientChannelPendingMessagesQueue; -import org.apache.sshd.client.future.OpenFuture; -import org.apache.sshd.common.Closeable; -import org.apache.sshd.common.Factory; -import org.apache.sshd.common.FactoryManager; -import org.apache.sshd.common.RuntimeSshException; -import org.apache.sshd.common.SshConstants; -import org.apache.sshd.common.SshException; -import org.apache.sshd.common.forward.ForwardingFilter; -import org.apache.sshd.common.forward.LocalForwardingEntry; -import org.apache.sshd.common.forward.PortForwardingEventListener; -import org.apache.sshd.common.forward.PortForwardingEventListenerManager; -import org.apache.sshd.common.forward.PortForwardingEventListenerManagerHolder; -import org.apache.sshd.common.forward.SocksProxy; -import org.apache.sshd.common.forward.TcpipClientChannel; -import org.apache.sshd.common.forward.TcpipForwardingExceptionMarker; -import org.apache.sshd.common.io.IoAcceptor; -import org.apache.sshd.common.io.IoHandler; -import org.apache.sshd.common.io.IoHandlerFactory; -import org.apache.sshd.common.io.IoServiceFactory; -import org.apache.sshd.common.io.IoSession; -import org.apache.sshd.common.session.ConnectionService; -import org.apache.sshd.common.session.Session; -import org.apache.sshd.common.session.SessionHolder; -import org.apache.sshd.common.util.EventListenerUtils; -import org.apache.sshd.common.util.GenericUtils; -import org.apache.sshd.common.util.Invoker; -import org.apache.sshd.common.util.Readable; -import org.apache.sshd.common.util.ValidateUtils; -import org.apache.sshd.common.util.buffer.Buffer; -import org.apache.sshd.common.util.buffer.ByteArrayBuffer; -import org.apache.sshd.common.util.closeable.AbstractInnerCloseable; -import org.apache.sshd.common.util.net.SshdSocketAddress; -import org.apache.sshd.server.forward.TcpForwardingFilter; - -/** - * FIXME: Patched version of sshd-core:2.5.1:org.apache.sshd.common.forward.DefaultForwardingFilter - * Release will be available in sshd-core:2.6.0+ - */ -public class CustomForwardingFilter extends AbstractInnerCloseable - implements ForwardingFilter, SessionHolder, PortForwardingEventListenerManager { - - /** - * Used to configure the timeout (milliseconds) for receiving a response for the forwarding request - * - * @see #DEFAULT_FORWARD_REQUEST_TIMEOUT - */ - public static final String FORWARD_REQUEST_TIMEOUT = "tcpip-forward-request-timeout"; - - /** - * Default value for {@value #FORWARD_REQUEST_TIMEOUT} if none specified - */ - public static final long DEFAULT_FORWARD_REQUEST_TIMEOUT = TimeUnit.SECONDS.toMillis(15L); - - public static final Set STATIC_IO_MSG_RECEIVED_EVENTS = Collections - .unmodifiableSet(EnumSet.of(ClientChannelEvent.OPENED, ClientChannelEvent.CLOSED)); - - private final ConnectionService service; - private final IoHandlerFactory socksProxyIoHandlerFactory = () -> new SocksProxy(getConnectionService()); - private final Session sessionInstance; - - private final Object localLock = new Object(); - private final Map localToRemote = new TreeMap<>(Comparator.naturalOrder()); - private final Map boundLocals = new TreeMap<>(Comparator.naturalOrder()); - - private final Object dynamicLock = new Object(); - private final Map remoteToLocal = new TreeMap<>(Comparator.naturalOrder()); - private final Map dynamicLocal = new TreeMap<>(Comparator.naturalOrder()); - private final Map boundDynamic = new TreeMap<>(Comparator.naturalOrder()); - - private final Set localForwards = new HashSet<>(); - private final IoHandlerFactory staticIoHandlerFactory = StaticIoHandler::new; - private final Collection listeners = new CopyOnWriteArraySet<>(); - private final Collection managersHolder = new CopyOnWriteArraySet<>(); - private final PortForwardingEventListener listenerProxy; - - private IoAcceptor localAcceptor; - private IoAcceptor dynamicAcceptor; - - public CustomForwardingFilter(ConnectionService service) { - this.service = Objects.requireNonNull(service, "No connection service"); - this.sessionInstance = Objects.requireNonNull(service.getSession(), "No session"); - this.listenerProxy = EventListenerUtils.proxyWrapper(PortForwardingEventListener.class, listeners); - } - - @Override - public PortForwardingEventListener getPortForwardingEventListenerProxy() { - return listenerProxy; - } - - @Override - public void addPortForwardingEventListener(PortForwardingEventListener listener) { - listeners.add(PortForwardingEventListener.validateListener(listener)); - } - - @Override - public void removePortForwardingEventListener(PortForwardingEventListener listener) { - if (listener == null) { - return; - } - - listeners.remove(PortForwardingEventListener.validateListener(listener)); - } - - @Override - public Collection getRegisteredManagers() { - return managersHolder.isEmpty() ? Collections.emptyList() : new ArrayList<>(managersHolder); - } - - @Override - public boolean addPortForwardingEventListenerManager(PortForwardingEventListenerManager manager) { - return managersHolder.add(Objects.requireNonNull(manager, "No manager")); - } - - @Override - public boolean removePortForwardingEventListenerManager(PortForwardingEventListenerManager manager) { - if (manager == null) { - return false; - } - - return managersHolder.remove(manager); - } - - @Override - public Session getSession() { - return sessionInstance; - } - - public final ConnectionService getConnectionService() { - return service; - } - - protected Collection getDefaultListeners() { - Collection defaultListeners = new ArrayList<>(); - defaultListeners.add(getPortForwardingEventListenerProxy()); - - Session session = getSession(); - PortForwardingEventListener l = session.getPortForwardingEventListenerProxy(); - if (l != null) { - defaultListeners.add(l); - } - - FactoryManager manager = (session == null) ? null : session.getFactoryManager(); - l = (manager == null) ? null : manager.getPortForwardingEventListenerProxy(); - if (l != null) { - defaultListeners.add(l); - } - - return defaultListeners; - } - - @Override - public synchronized SshdSocketAddress startLocalPortForwarding(SshdSocketAddress local, - SshdSocketAddress remote) throws IOException { - Objects.requireNonNull(local, "Local address is null"); - ValidateUtils.checkTrue(local.getPort() >= 0, "Invalid local port: %s", local); - Objects.requireNonNull(remote, "Remote address is null"); - - if (isClosed() || isClosing()) { - throw new IllegalStateException("TcpipForwarder is closed or closing: " + state); - } - - InetSocketAddress bound = null; - int port; - signalEstablishingExplicitTunnel(local, remote, true); - try { - bound = doBind(local, getLocalIoAcceptor()); - port = bound.getPort(); - synchronized (localLock) { - SshdSocketAddress prevRemote = localToRemote.get(port); - if (prevRemote != null) { - throw new IOException("Multiple local port forwarding addressing on port=" + port - + ": current=" + remote + ", previous=" + prevRemote); - } - - InetSocketAddress prevBound = boundLocals.get(port); - if (prevBound != null) { - throw new IOException("Multiple local port forwarding bindings on port=" + port - + ": current=" + bound + ", previous=" + prevBound); - } - - localToRemote.put(port, remote); - boundLocals.put(port, bound); - } - } catch (IOException | RuntimeException e) { - try { - unbindLocalForwarding(local, remote, bound); - } catch (IOException | RuntimeException err) { - e.addSuppressed(err); - } - signalEstablishedExplicitTunnel(local, remote, true, null, e); - throw e; - } - - try { - SshdSocketAddress result = new SshdSocketAddress(bound.getHostString(), port); - if (log.isDebugEnabled()) { - log.debug("startLocalPortForwarding(" + local + " -> " + remote + "): " + result); - } - signalEstablishedExplicitTunnel(local, remote, true, result, null); - return result; - } catch (IOException | RuntimeException e) { - stopLocalPortForwarding(local); - throw e; - } - } - - @Override - public synchronized void stopLocalPortForwarding(SshdSocketAddress local) throws IOException { - Objects.requireNonNull(local, "Local address is null"); - - SshdSocketAddress remote; - InetSocketAddress bound; - int port = local.getPort(); - synchronized (localLock) { - remote = localToRemote.remove(port); - bound = boundLocals.remove(port); - } - - unbindLocalForwarding(local, remote, bound); - } - - protected void unbindLocalForwarding(SshdSocketAddress local, SshdSocketAddress remote, - InetSocketAddress bound) throws IOException { - if ((bound != null) && (localAcceptor != null)) { - if (log.isDebugEnabled()) { - log.debug("unbindLocalForwarding({} => {}) unbind {}", local, remote, bound); - } - - SshdSocketAddress boundAddress = new SshdSocketAddress(bound); - try { - signalTearingDownExplicitTunnel(boundAddress, true, remote); - } finally { - try { - localAcceptor.unbind(bound); - } catch (RuntimeException e) { - signalTornDownExplicitTunnel(boundAddress, true, remote, e); - throw e; - } - } - - signalTornDownExplicitTunnel(boundAddress, true, remote, null); - } else { - if (log.isDebugEnabled()) { - log.debug("unbindLocalForwarding({} => {}) no mapping({}) or acceptor({})", local, remote, - bound, localAcceptor); - } - } - } - - @Override - public synchronized SshdSocketAddress startRemotePortForwarding(SshdSocketAddress remote, - SshdSocketAddress local) throws IOException { - Objects.requireNonNull(local, "Local address is null"); - Objects.requireNonNull(remote, "Remote address is null"); - - String remoteHost = remote.getHostName(); - int remotePort = remote.getPort(); - Session session = getSession(); - Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_GLOBAL_REQUEST, - remoteHost.length() + Long.SIZE); - buffer.putString("tcpip-forward"); - buffer.putBoolean(true); // want reply - buffer.putString(remoteHost); - buffer.putInt(remotePort); - - long timeout = session.getLongProperty(FORWARD_REQUEST_TIMEOUT, DEFAULT_FORWARD_REQUEST_TIMEOUT); - Buffer result; - int port; - signalEstablishingExplicitTunnel(local, remote, false); - try { - result = session.request("tcpip-forward", buffer, timeout, TimeUnit.MILLISECONDS); - if (result == null) { - throw new SshException("Tcpip forwarding request denied by server"); - } - port = (remotePort == 0) ? result.getInt() : remote.getPort(); - // TODO: Is it really safe to only store the local address after the request ? - synchronized (remoteToLocal) { - SshdSocketAddress prev = remoteToLocal.get(port); - if (prev != null) { - throw new IOException("Multiple remote port forwarding bindings on port=" + port - + ": current=" + remote + ", previous=" + prev); - } - remoteToLocal.put(port, local); - } - - } catch (IOException | RuntimeException e) { - try { - stopRemotePortForwarding(remote); - } catch (IOException | RuntimeException err) { - e.addSuppressed(err); - } - signalEstablishedExplicitTunnel(local, remote, false, null, e); - throw e; - } - - try { - SshdSocketAddress bound = new SshdSocketAddress(remoteHost, port); - if (log.isDebugEnabled()) { - log.debug("startRemotePortForwarding(" + remote + " -> " + local + "): " + bound); - } - - signalEstablishedExplicitTunnel(local, remote, false, bound, null); - return bound; - } catch (IOException | RuntimeException e) { - stopRemotePortForwarding(remote); - throw e; - } - } - - @Override - public synchronized void stopRemotePortForwarding(SshdSocketAddress remote) throws IOException { - SshdSocketAddress bound; - int port = remote.getPort(); - synchronized (remoteToLocal) { - bound = remoteToLocal.remove(port); - } - - if (bound != null) { - if (log.isDebugEnabled()) { - log.debug("stopRemotePortForwarding(" + remote + ") cancel forwarding to " + bound); - } - - String remoteHost = remote.getHostName(); - Session session = getSession(); - Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_GLOBAL_REQUEST, - remoteHost.length() + Long.SIZE); - buffer.putString("cancel-tcpip-forward"); - buffer.putBoolean(false); // want reply - buffer.putString(remoteHost); - buffer.putInt(port); - - signalTearingDownExplicitTunnel(bound, false, remote); - try { - session.writePacket(buffer); - } catch (IOException | RuntimeException e) { - signalTornDownExplicitTunnel(bound, false, remote, e); - throw e; - } - - signalTornDownExplicitTunnel(bound, false, remote, null); - } else { - if (log.isDebugEnabled()) { - log.debug("stopRemotePortForwarding(" + remote + ") no binding found"); - } - } - } - - protected void signalTearingDownExplicitTunnel(SshdSocketAddress boundAddress, boolean localForwarding, - SshdSocketAddress remote) throws IOException { - try { - invokePortEventListenerSignaller(l -> { - signalTearingDownExplicitTunnel(l, boundAddress, localForwarding, remote); - return null; - }); - } catch (Throwable t) { - if (t instanceof RuntimeException) { - throw (RuntimeException) t; - } else if (t instanceof Error) { - throw (Error) t; - } else if (t instanceof IOException) { - throw (IOException) t; - } else { - throw new IOException("Failed (" + t.getClass().getSimpleName() + ")" - + " to signal tearing down explicit tunnel for local=" + localForwarding - + " on bound=" + boundAddress, t); - } - } - } - - protected void signalTearingDownExplicitTunnel(PortForwardingEventListener listener, - SshdSocketAddress boundAddress, boolean localForwarding, SshdSocketAddress remoteAddress) - throws IOException { - if (listener == null) { - return; - } - - listener.tearingDownExplicitTunnel(getSession(), boundAddress, localForwarding, remoteAddress); - } - - protected void signalTornDownExplicitTunnel(SshdSocketAddress boundAddress, boolean localForwarding, - SshdSocketAddress remoteAddress, Throwable reason) throws IOException { - try { - invokePortEventListenerSignaller(l -> { - signalTornDownExplicitTunnel(l, boundAddress, localForwarding, remoteAddress, reason); - return null; - }); - } catch (Throwable t) { - if (t instanceof RuntimeException) { - throw (RuntimeException) t; - } else if (t instanceof Error) { - throw (Error) t; - } else if (t instanceof IOException) { - throw (IOException) t; - } else { - throw new IOException("Failed (" + t.getClass().getSimpleName() + ")" - + " to signal torn down explicit tunnel local=" + localForwarding + " on bound=" - + boundAddress, t); - } - } - } - - protected void signalTornDownExplicitTunnel(PortForwardingEventListener listener, - SshdSocketAddress boundAddress, boolean localForwarding, SshdSocketAddress remoteAddress, - Throwable reason) throws IOException { - if (listener == null) { - return; - } - - listener.tornDownExplicitTunnel(getSession(), boundAddress, localForwarding, remoteAddress, reason); - } - - @Override - public synchronized SshdSocketAddress startDynamicPortForwarding(SshdSocketAddress local) - throws IOException { - Objects.requireNonNull(local, "Local address is null"); - ValidateUtils.checkTrue(local.getPort() >= 0, "Invalid local port: %s", local); - - if (isClosed() || isClosing()) { - throw new IllegalStateException("TcpipForwarder is closed or closing: " + state); - } - - SocksProxy proxy = null; - InetSocketAddress bound = null; - int port; - signalEstablishingDynamicTunnel(local); - try { - bound = doBind(local, getDynamicIoAcceptor()); - port = bound.getPort(); - synchronized (dynamicLock) { - SocksProxy prevProxy = dynamicLocal.get(port); - if (prevProxy != null) { - throw new IOException("Multiple dynamic port mappings found for port=" + port - + ": current=" + proxy + ", previous=" + prevProxy); - } - - InetSocketAddress prevBound = boundDynamic.get(port); - if (prevBound != null) { - throw new IOException("Multiple dynamic port bindings found for port=" + port - + ": current=" + bound + ", previous=" + prevBound); - } - - proxy = new SocksProxy(service); - dynamicLocal.put(port, proxy); - boundDynamic.put(port, bound); - } - } catch (IOException | RuntimeException e) { - try { - unbindDynamicForwarding(local, proxy, bound); - } catch (IOException | RuntimeException err) { - e.addSuppressed(err); - } - signalEstablishedDynamicTunnel(local, null, e); - throw e; - } - - try { - SshdSocketAddress result = new SshdSocketAddress(bound.getHostString(), port); - if (log.isDebugEnabled()) { - log.debug("startDynamicPortForwarding(" + local + "): " + result); - } - - signalEstablishedDynamicTunnel(local, result, null); - return result; - } catch (IOException | RuntimeException e) { - stopDynamicPortForwarding(local); - throw e; - } - } - - protected void signalEstablishedDynamicTunnel(SshdSocketAddress local, SshdSocketAddress boundAddress, - Throwable reason) throws IOException { - try { - invokePortEventListenerSignaller(l -> { - signalEstablishedDynamicTunnel(l, local, boundAddress, reason); - return null; - }); - } catch (Throwable t) { - if (t instanceof RuntimeException) { - throw (RuntimeException) t; - } else if (t instanceof Error) { - throw (Error) t; - } else if (t instanceof IOException) { - throw (IOException) t; - } else { - throw new IOException("Failed (" + t.getClass().getSimpleName() + ")" - + " to signal establishing dynamic tunnel for local=" + local + " on bound=" - + boundAddress, t); - } - } - } - - protected void signalEstablishedDynamicTunnel(PortForwardingEventListener listener, - SshdSocketAddress local, SshdSocketAddress boundAddress, Throwable reason) throws IOException { - if (listener == null) { - return; - } - - listener.establishedDynamicTunnel(getSession(), local, boundAddress, reason); - } - - protected void signalEstablishingDynamicTunnel(SshdSocketAddress local) throws IOException { - try { - invokePortEventListenerSignaller(l -> { - signalEstablishingDynamicTunnel(l, local); - return null; - }); - } catch (Throwable t) { - if (t instanceof RuntimeException) { - throw (RuntimeException) t; - } else if (t instanceof Error) { - throw (Error) t; - } else if (t instanceof IOException) { - throw (IOException) t; - } else { - throw new IOException("Failed (" + t.getClass().getSimpleName() + ")" - + " to signal establishing dynamic tunnel for local=" + local, t); - } - } - } - - protected void signalEstablishingDynamicTunnel(PortForwardingEventListener listener, - SshdSocketAddress local) throws IOException { - if (listener == null) { - return; - } - - listener.establishingDynamicTunnel(getSession(), local); - } - - @Override - public synchronized void stopDynamicPortForwarding(SshdSocketAddress local) throws IOException { - SocksProxy proxy; - InetSocketAddress bound; - int port = local.getPort(); - synchronized (dynamicLock) { - proxy = dynamicLocal.remove(port); - bound = boundDynamic.remove(port); - } - - unbindDynamicForwarding(local, proxy, bound); - } - - protected void unbindDynamicForwarding(SshdSocketAddress local, SocksProxy proxy, InetSocketAddress bound) - throws IOException { - boolean debugEnabled = log.isDebugEnabled(); - if ((bound != null) || (proxy != null)) { - - try { - signalTearingDownDynamicTunnel(local); - } finally { - try { - try { - if (proxy != null) { - if (debugEnabled) { - log.debug("stopDynamicPortForwarding({}) close proxy={}", local, proxy); - } - - proxy.close(true); - } - } finally { - if ((bound != null) && (dynamicAcceptor != null)) { - if (debugEnabled) { - log.debug("stopDynamicPortForwarding({}) unbind address={}", local, bound); - } - dynamicAcceptor.unbind(bound); - } else { - if (debugEnabled) { - log.debug("stopDynamicPortForwarding({}) no acceptor({}) or no binding({})", - local, dynamicAcceptor, bound); - } - } - } - } catch (RuntimeException e) { - signalTornDownDynamicTunnel(local, e); - throw e; - } - } - - signalTornDownDynamicTunnel(local, null); - } else { - if (debugEnabled) { - log.debug("stopDynamicPortForwarding({}) no binding found", local); - } - } - } - - protected void signalTearingDownDynamicTunnel(SshdSocketAddress address) throws IOException { - try { - invokePortEventListenerSignaller(l -> { - signalTearingDownDynamicTunnel(l, address); - return null; - }); - } catch (Throwable t) { - if (t instanceof RuntimeException) { - throw (RuntimeException) t; - } else if (t instanceof Error) { - throw (Error) t; - } else if (t instanceof IOException) { - throw (IOException) t; - } else { - throw new IOException("Failed (" + t.getClass().getSimpleName() + ")" - + " to signal tearing down dynamic tunnel for address=" + address, t); - } - } - } - - protected void signalTearingDownDynamicTunnel(PortForwardingEventListener listener, - SshdSocketAddress address) throws IOException { - if (listener == null) { - return; - } - - listener.tearingDownDynamicTunnel(getSession(), address); - } - - protected void signalTornDownDynamicTunnel(SshdSocketAddress address, Throwable reason) - throws IOException { - try { - invokePortEventListenerSignaller(l -> { - signalTornDownDynamicTunnel(l, address, reason); - return null; - }); - } catch (Throwable t) { - if (t instanceof RuntimeException) { - throw (RuntimeException) t; - } else if (t instanceof Error) { - throw (Error) t; - } else if (t instanceof IOException) { - throw (IOException) t; - } else { - throw new IOException("Failed (" + t.getClass().getSimpleName() + ")" - + " to signal torn down dynamic tunnel for address=" + address, t); - } - } - } - - protected void signalTornDownDynamicTunnel(PortForwardingEventListener listener, - SshdSocketAddress address, Throwable reason) throws IOException { - if (listener == null) { - return; - } - - listener.tornDownDynamicTunnel(getSession(), address, reason); - } - - @Override - public synchronized SshdSocketAddress getForwardedPort(int remotePort) { - synchronized (remoteToLocal) { - return remoteToLocal.get(remotePort); - } - } - - @Override - public synchronized SshdSocketAddress localPortForwardingRequested(SshdSocketAddress local) - throws IOException { - Objects.requireNonNull(local, "Local address is null"); - ValidateUtils.checkTrue(local.getPort() >= 0, "Invalid local port: %s", local); - - Session session = getSession(); - FactoryManager manager = Objects.requireNonNull(session.getFactoryManager(), "No factory manager"); - TcpForwardingFilter filter = manager.getTcpForwardingFilter(); - try { - if ((filter == null) || (!filter.canListen(local, session))) { - if (log.isDebugEnabled()) { - log.debug("localPortForwardingRequested(" + session + ")[" + local + "][haveFilter=" - + (filter != null) + "] rejected"); - } - return null; - } - } catch (Error e) { - log.warn("localPortForwardingRequested({})[{}] failed ({}) to consult forwarding filter: {}", - session, local, e.getClass().getSimpleName(), e.getMessage()); - if (log.isDebugEnabled()) { - log.warn("localPortForwardingRequested(" + session + ")[" + local - + "] filter consultation failure details", e); - } - throw new RuntimeSshException(e); - } - - signalEstablishingExplicitTunnel(local, null, true); - SshdSocketAddress result; - try { - InetSocketAddress bound = doBind(local, getLocalIoAcceptor()); - result = new SshdSocketAddress(bound.getHostString(), bound.getPort()); - if (log.isDebugEnabled()) { - log.debug("localPortForwardingRequested(" + local + "): " + result); - } - - boolean added; - synchronized (localForwards) { - // NOTE !!! it is crucial to use the bound address host name first - added = localForwards.add(new LocalForwardingEntry(result.getHostName(), local.getHostName(), - result.getPort())); - } - - if (!added) { - throw new IOException( - "Failed to add local port forwarding entry for " + local + " -> " + result); - } - } catch (IOException | RuntimeException e) { - try { - localPortForwardingCancelled(local); - } catch (IOException | RuntimeException err) { - e.addSuppressed(e); - } - signalEstablishedExplicitTunnel(local, null, true, null, e); - throw e; - } - - try { - signalEstablishedExplicitTunnel(local, null, true, result, null); - return result; - } catch (IOException | RuntimeException e) { - throw e; - } - } - - @Override - public synchronized void localPortForwardingCancelled(SshdSocketAddress local) throws IOException { - LocalForwardingEntry entry; - synchronized (localForwards) { - entry = LocalForwardingEntry.findMatchingEntry(local.getHostName(), local.getPort(), - localForwards); - if (entry != null) { - localForwards.remove(entry); - } - } - - if ((entry != null) && (localAcceptor != null)) { - if (log.isDebugEnabled()) { - log.debug("localPortForwardingCancelled(" + local + ") unbind " + entry); - } - - signalTearingDownExplicitTunnel(entry, true, null); - try { - localAcceptor.unbind(entry.toInetSocketAddress()); - } catch (RuntimeException e) { - signalTornDownExplicitTunnel(entry, true, null, e); - throw e; - } - - signalTornDownExplicitTunnel(entry, true, null, null); - } else { - if (log.isDebugEnabled()) { - log.debug("localPortForwardingCancelled(" + local + ") no match/acceptor: " + entry); - } - } - } - - protected void signalEstablishingExplicitTunnel(SshdSocketAddress local, SshdSocketAddress remote, - boolean localForwarding) throws IOException { - try { - invokePortEventListenerSignaller(l -> { - signalEstablishingExplicitTunnel(l, local, remote, localForwarding); - return null; - }); - } catch (Throwable t) { - if (t instanceof RuntimeException) { - throw (RuntimeException) t; - } else if (t instanceof Error) { - throw (Error) t; - } else if (t instanceof IOException) { - throw (IOException) t; - } else { - throw new IOException("Failed (" + t.getClass().getSimpleName() + ")" - + " to signal establishing explicit tunnel for local=" + local + ", remote=" + remote - + ", localForwarding=" + localForwarding, t); - } - } - } - - protected void signalEstablishingExplicitTunnel(PortForwardingEventListener listener, - SshdSocketAddress local, SshdSocketAddress remote, boolean localForwarding) throws IOException { - if (listener == null) { - return; - } - - listener.establishingExplicitTunnel(getSession(), local, remote, localForwarding); - } - - protected void signalEstablishedExplicitTunnel(SshdSocketAddress local, SshdSocketAddress remote, - boolean localForwarding, SshdSocketAddress boundAddress, Throwable reason) throws IOException { - try { - invokePortEventListenerSignaller(l -> { - signalEstablishedExplicitTunnel(l, local, remote, localForwarding, boundAddress, reason); - return null; - }); - } catch (Throwable t) { - if (t instanceof RuntimeException) { - throw (RuntimeException) t; - } else if (t instanceof Error) { - throw (Error) t; - } else if (t instanceof IOException) { - throw (IOException) t; - } else { - throw new IOException( - "Failed (" + t.getClass().getSimpleName() + ")" - + " to signal established explicit tunnel for local=" + local + ", remote=" - + remote + ", localForwarding=" + localForwarding + ", bound=" + boundAddress, - t); - } - } - } - - protected void signalEstablishedExplicitTunnel(PortForwardingEventListener listener, - SshdSocketAddress local, SshdSocketAddress remote, boolean localForwarding, - SshdSocketAddress boundAddress, Throwable reason) throws IOException { - if (listener == null) { - return; - } - - listener.establishedExplicitTunnel(getSession(), local, remote, localForwarding, boundAddress, - reason); - } - - protected void invokePortEventListenerSignaller(Invoker invoker) - throws Throwable { - Throwable err = null; - try { - invokePortEventListenerSignallerListeners(getDefaultListeners(), invoker); - } catch (Throwable t) { - Throwable e = GenericUtils.peelException(t); - err = GenericUtils.accumulateException(err, e); - } - - try { - invokePortEventListenerSignallerHolders(managersHolder, invoker); - } catch (Throwable t) { - Throwable e = GenericUtils.peelException(t); - err = GenericUtils.accumulateException(err, e); - } - - if (err != null) { - throw err; - } - } - - protected void invokePortEventListenerSignallerListeners( - Collection listeners, - Invoker invoker) throws Throwable { - if (GenericUtils.isEmpty(listeners)) { - return; - } - - Throwable err = null; - // Need to go over the hierarchy (session, factory managed, connection service, etc...) - for (PortForwardingEventListener l : listeners) { - if (l == null) { - continue; - } - - try { - invoker.invoke(l); - } catch (Throwable t) { - Throwable e = GenericUtils.peelException(t); - err = GenericUtils.accumulateException(err, e); - } - } - - if (err != null) { - throw err; - } - } - - protected void invokePortEventListenerSignallerHolders( - Collection holders, - Invoker invoker) throws Throwable { - if (GenericUtils.isEmpty(holders)) { - return; - } - - Throwable err = null; - // Need to go over the hierarchy (session, factory managed, connection service, etc...) - for (PortForwardingEventListenerManager m : holders) { - try { - PortForwardingEventListener listener = m.getPortForwardingEventListenerProxy(); - if (listener != null) { - invoker.invoke(listener); - } - } catch (Throwable t) { - Throwable e = GenericUtils.peelException(t); - err = GenericUtils.accumulateException(err, e); - } - - if (m instanceof PortForwardingEventListenerManagerHolder) { - try { - invokePortEventListenerSignallerHolders( - ((PortForwardingEventListenerManagerHolder) m).getRegisteredManagers(), invoker); - } catch (Throwable t) { - Throwable e = GenericUtils.peelException(t); - err = GenericUtils.accumulateException(err, e); - } - } - } - - if (err != null) { - throw err; - } - } - - @Override - protected synchronized Closeable getInnerCloseable() { - return builder().parallel(toString(), dynamicLocal.values()).close(localAcceptor) - .close(dynamicAcceptor).build(); - } - - @Override - protected void preClose() { - this.listeners.clear(); - this.managersHolder.clear(); - super.preClose(); - } - - protected IoAcceptor createIoAcceptor(Factory handlerFactory) { - Session session = getSession(); - FactoryManager manager = Objects.requireNonNull(session.getFactoryManager(), "No factory manager"); - IoServiceFactory factory = Objects.requireNonNull(manager.getIoServiceFactory(), - "No I/O service factory"); - IoHandler handler = handlerFactory.create(); - return factory.createAcceptor(handler); - } - - protected IoAcceptor getLocalIoAcceptor() { - if (localAcceptor == null) { - localAcceptor = createIoAcceptor(staticIoHandlerFactory); - } - return localAcceptor; - } - - protected IoAcceptor getDynamicIoAcceptor() { - if (dynamicAcceptor == null) { - dynamicAcceptor = createIoAcceptor(socksProxyIoHandlerFactory); - } - return dynamicAcceptor; - } - - /** - * @param address The request bind address - * @param acceptor An {@link IoAcceptor} to bind addresses - * @return The {@link InetSocketAddress} to which the binding occurred - * @throws IOException If failed to bind - */ - protected InetSocketAddress doBind(SshdSocketAddress address, IoAcceptor acceptor) throws IOException { - // TODO find a better way to determine the resulting bind address - what if multi-threaded calls... - Set before = acceptor.getBoundAddresses(); - try { - InetSocketAddress bindAddress = address.toInetSocketAddress(); - acceptor.bind(bindAddress); - - Set after = acceptor.getBoundAddresses(); - if (GenericUtils.size(after) > 0) { - after.removeAll(before); - } - if (GenericUtils.isEmpty(after)) { - throw new IOException( - "Error binding to " + address + "[" + bindAddress + "]: no local addresses bound"); - } - - if (after.size() > 1) { - throw new IOException( - "Multiple local addresses have been bound for " + address + "[" + bindAddress + "]"); - } - return (InetSocketAddress) GenericUtils.head(after); - } catch (IOException bindErr) { - Collection after = acceptor.getBoundAddresses(); - if (GenericUtils.isEmpty(after)) { - close(); - } - throw bindErr; - } - } - - @Override - public String toString() { - return getClass().getSimpleName() + "[" + getSession() + "]"; - } - - @SuppressWarnings("synthetic-access") - class StaticIoHandler implements IoHandler { - private final AtomicLong messagesCounter = new AtomicLong(0L); - private final boolean debugEnabled = log.isDebugEnabled(); - private final boolean traceEnabled = log.isTraceEnabled(); - - StaticIoHandler() { - super(); - } - - @Override - public void sessionCreated(IoSession session) throws Exception { - InetSocketAddress local = (InetSocketAddress) session.getLocalAddress(); - int localPort = local.getPort(); - SshdSocketAddress remote = localToRemote.get(localPort); - TcpipClientChannel.Type channelType = (remote == null) ? TcpipClientChannel.Type.Forwarded - : TcpipClientChannel.Type.Direct; - TcpipClientChannel channel = new TcpipClientChannel(channelType, session, remote); - session.setAttribute(TcpipClientChannel.class, channel); - - // Propagate original requested host name - see SSHD-792 - if (channelType == TcpipClientChannel.Type.Forwarded) { - SocketAddress accepted = session.getAcceptanceAddress(); - LocalForwardingEntry localEntry = null; - if (accepted instanceof InetSocketAddress) { - synchronized (localForwards) { - localEntry = LocalForwardingEntry.findMatchingEntry( - ((InetSocketAddress) accepted).getHostString(), localPort, localForwards); - } - } - - if (localEntry != null) { - if (debugEnabled) { - log.debug("sessionCreated({})[local={}, remote={}, accepted={}] localEntry={}", - session, local, remote, accepted, localEntry); - } - channel.updateLocalForwardingEntry(localEntry); - } else { - log.warn( - "sessionCreated({})[local={}, remote={}] cannot locate original local entry for accepted={}", - session, local, remote, accepted); - } - } else { - if (debugEnabled) { - log.debug("sessionCreated({}) local={}, remote={}", session, local, remote); - } - } - - service.registerChannel(channel); - channel.open().addListener(future -> { - Throwable t = future.getException(); - if (t != null) { - log.warn("Failed ({}) to open channel for session={}: {}", t.getClass().getSimpleName(), - session, t.getMessage()); - if (debugEnabled) { - log.debug("sessionCreated(" + session + ") channel=" + channel - + " open failure details", t); - } - CustomForwardingFilter.this.service.unregisterChannel(channel); - channel.close(false); - } - }); - } - - @Override - public void sessionClosed(IoSession session) throws Exception { - TcpipClientChannel channel = (TcpipClientChannel) session - .removeAttribute(TcpipClientChannel.class); - Throwable cause = (Throwable) session.removeAttribute(TcpipForwardingExceptionMarker.class); - if (debugEnabled) { - log.debug("sessionClosed({}) closing channel={} after {} messages - cause={}", session, - channel, messagesCounter, (cause == null) ? null : cause.getClass().getSimpleName()); - } - if (channel == null) { - return; - } - - if (cause != null) { - // If exception occurred close the channel immediately - channel.close(true); - } else { - /* - * Make sure channel is pending messages have all been sent in case the client was very fast - * and sent - * data + closed the connection before channel open was completed. - */ - OpenFuture openFuture = channel.getOpenFuture(); - Throwable err = openFuture.getException(); - ClientChannelPendingMessagesQueue queue = channel.getPendingMessagesQueue(); - OpenFuture completedFuture = queue.getCompletedFuture(); - if (err == null) { - err = completedFuture.getException(); - } - boolean immediately = err != null; - if (immediately) { - channel.close(true); - } else { - completedFuture.addListener(f -> { - Throwable thrown = f.getException(); - channel.close(immediately || (thrown != null)); - }); - } - } - } - - @Override - public void messageReceived(IoSession session, Readable message) throws Exception { - TcpipClientChannel channel = (TcpipClientChannel) session.getAttribute(TcpipClientChannel.class); - long totalMessages = messagesCounter.incrementAndGet(); - Buffer buffer = new ByteArrayBuffer(message.available() + Long.SIZE, false); - buffer.putBuffer(message); - - if (traceEnabled) { - log.trace("messageReceived({}) channel={}, count={}, handle len={}", session, channel, - totalMessages, message.available()); - } - - ClientChannelPendingMessagesQueue messagesQueue = channel.getPendingMessagesQueue(); - OpenFuture future = messagesQueue.getCompletedFuture(); - Consumer errHandler = future.isOpened() ? null : e -> { - try { - exceptionCaught(session, e); - } catch (Exception err) { - log.warn("messageReceived({}) failed ({}) to signal {}[{}] on channel={}: {}", session, - err.getClass().getSimpleName(), e.getClass().getSimpleName(), e.getMessage(), - channel, err.getMessage()); - } - }; - - int pendCount = messagesQueue.handleIncomingMessage(buffer, errHandler); - if (traceEnabled) { - log.trace("messageReceived({}) channel={} pend count={} after processing message", session, - channel, pendCount); - } - } - - @Override - public void exceptionCaught(IoSession session, Throwable cause) throws Exception { - session.setAttribute(TcpipForwardingExceptionMarker.class, cause); - log.warn("exceptionCaught({}) {}: {}", session, cause.getClass().getSimpleName(), - cause.getMessage()); - if (debugEnabled) { - log.warn("exceptionCaught(" + session + ") caught exception details", cause); - } - session.close(true); - } - } - - @Override - public SshdSocketAddress getBoundLocalPortForward(int port) { - ValidateUtils.checkTrue(port > 0, "Invalid local port: %d", port); - - Integer portKey = Integer.valueOf(port); - synchronized (localToRemote) { - return localToRemote.get(portKey); - } - } - - @Override - public List> getLocalForwardsBindings() { - synchronized (localToRemote) { - return localToRemote.isEmpty() ? Collections.emptyList() - : localToRemote.entrySet().stream() // return an immutable clone to avoid 'setValue' calls - // on a shared instance - .map(e -> new SimpleImmutableEntry<>(e.getKey(), e.getValue())) - .collect(Collectors.toCollection(() -> new ArrayList<>(localToRemote.size()))); - } - } - - @Override - public NavigableSet getStartedLocalPortForwards() { - synchronized (localToRemote) { - if (localToRemote.isEmpty()) { - return Collections.emptyNavigableSet(); - } - - return GenericUtils.asSortedSet(localToRemote.keySet()); - } - } - - @Override - public List> getRemoteForwardsBindings() { - synchronized (remoteToLocal) { - return remoteToLocal.isEmpty() ? Collections.emptyList() - : remoteToLocal.entrySet().stream() // return an immutable clone to avoid 'setValue' calls - // on a shared instance - .map(e -> new SimpleImmutableEntry<>(e.getKey(), e.getValue())) - .collect(Collectors.toCollection(() -> new ArrayList<>(remoteToLocal.size()))); - } - } - - @Override - public SshdSocketAddress getBoundRemotePortForward(int port) { - ValidateUtils.checkTrue(port > 0, "Invalid remote port: %d", port); - - Integer portKey = Integer.valueOf(port); - synchronized (remoteToLocal) { - return remoteToLocal.get(portKey); - } - } - - @Override - public NavigableSet getStartedRemotePortForwards() { - synchronized (remoteToLocal) { - if (remoteToLocal.isEmpty()) { - return Collections.emptyNavigableSet(); - } - - return GenericUtils.asSortedSet(remoteToLocal.keySet()); - } - } -} diff --git a/jentunnel-core/src/main/java/org/javastack/jentunnel/workaround_bug_sshd1063/CustomKnownHostsServerKeyVerifier.java b/jentunnel-core/src/main/java/org/javastack/jentunnel/workaround_bug_sshd1063/CustomKnownHostsServerKeyVerifier.java deleted file mode 100644 index 71a37fe..0000000 --- a/jentunnel-core/src/main/java/org/javastack/jentunnel/workaround_bug_sshd1063/CustomKnownHostsServerKeyVerifier.java +++ /dev/null @@ -1,55 +0,0 @@ -package org.javastack.jentunnel.workaround_bug_sshd1063; - -import java.io.IOException; -import java.net.SocketAddress; -import java.nio.file.Path; -import java.security.PublicKey; -import java.util.Collection; - -import org.apache.sshd.client.config.hosts.HostPatternsHolder; -import org.apache.sshd.client.config.hosts.KnownHostEntry; -import org.apache.sshd.client.keyverifier.KnownHostsServerKeyVerifier; -import org.apache.sshd.client.keyverifier.ServerKeyVerifier; -import org.apache.sshd.client.session.ClientSession; -import org.apache.sshd.common.config.keys.PublicKeyEntry; -import org.apache.sshd.common.util.GenericUtils; -import org.apache.sshd.common.util.net.SshdSocketAddress; - -/** - * FIXME: Workaround Bug SSHD-1063 - */ -public class CustomKnownHostsServerKeyVerifier extends KnownHostsServerKeyVerifier { - public CustomKnownHostsServerKeyVerifier(final ServerKeyVerifier delegate, final Path file) { - super(delegate, file); - } - - @Override - protected KnownHostEntry prepareKnownHostEntry(ClientSession clientSession, SocketAddress remoteAddress, - PublicKey serverKey) throws Exception { - Collection patterns = resolveHostNetworkIdentities(clientSession, remoteAddress); - if (GenericUtils.isEmpty(patterns)) { - return null; - } - - StringBuilder sb = new StringBuilder(Byte.MAX_VALUE); - for (SshdSocketAddress hostIdentity : patterns) { - if (sb.length() > 0) { - sb.append(','); - } - appendHostPattern(sb, hostIdentity.getHostName(), hostIdentity.getPort()); - } - - PublicKeyEntry.appendPublicKeyEntry(sb.append(' '), serverKey); - return KnownHostEntry.parseKnownHostEntry(sb.toString()); - } - - // FIXME: Workaround Bug SSHD-1063 - private A appendHostPattern(A sb, String host, int port) throws IOException { - sb.append(HostPatternsHolder.NON_STANDARD_PORT_PATTERN_ENCLOSURE_START_DELIM); - sb.append(host); - sb.append(HostPatternsHolder.NON_STANDARD_PORT_PATTERN_ENCLOSURE_END_DELIM); - sb.append(HostPatternsHolder.PORT_VALUE_DELIMITER); - sb.append(Integer.toString(port)); - return sb; - } -} diff --git a/jentunnel-gui/pom.xml b/jentunnel-gui/pom.xml index 7d966de..c53074d 100644 --- a/jentunnel-gui/pom.xml +++ b/jentunnel-gui/pom.xml @@ -6,7 +6,7 @@ org.javastack jentunnel - 1.0.2 + 1.1.0 .. diff --git a/pom.xml b/pom.xml index a5c7dd1..80ff874 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ org.javastack jentunnel pom - 1.0.2 + 1.1.0 Badges for Maven Central ${project.groupId}:${project.artifactId}