protected boolean isEquivalent(SshdSocketAddress that) { if (that == null) { return false; } else if (that == this) { return true; } else { return (this.getPort() == that.getPort()) && Objects.equals(this.getHostName(), that.getHostName()); } }
@Override public synchronized void stopDynamicPortForwarding(SshdSocketAddress local) throws IOException { Closeable obj; synchronized (dynamicLocal) { obj = dynamicLocal.remove(local.getPort()); } if (obj != null) { if (log.isDebugEnabled()) { log.debug("stopDynamicPortForwarding(" + local + ") unbinding"); } obj.close(true); acceptor.unbind(local.toInetSocketAddress()); } else { if (log.isDebugEnabled()) { log.debug("stopDynamicPortForwarding(" + local + ") no binding found"); } } }
@Override public synchronized SshdSocketAddress localPortForwardingRequested(SshdSocketAddress local) throws IOException { ValidateUtils.checkNotNull(local, "Local address is null"); ValidateUtils.checkTrue(local.getPort() >= 0, "Invalid local port: %s", local); FactoryManager manager = session.getFactoryManager(); ForwardingFilter filter = manager.getTcpipForwardingFilter(); if ((filter == null) || (!filter.canListen(local, session))) { if (log.isDebugEnabled()) { log.debug( "localPortForwardingRequested(" + session + ")[" + local + "][haveFilter=" + (filter != null) + "] rejected"); } throw new IOException("Rejected address: " + local); } InetSocketAddress bound = doBind(local, staticIoHandlerFactory); SshdSocketAddress 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); } return result; }
@Override public synchronized void stopLocalPortForwarding(SshdSocketAddress local) throws IOException { ValidateUtils.checkNotNull(local, "Local address is null"); SshdSocketAddress bound; synchronized (localToRemote) { bound = localToRemote.remove(local.getPort()); } if ((bound != null) && (acceptor != null)) { if (log.isDebugEnabled()) { log.debug("stopLocalPortForwarding(" + local + ") unbind " + bound); } acceptor.unbind(bound.toInetSocketAddress()); } else { if (log.isDebugEnabled()) { log.debug("stopLocalPortForwarding(" + local + ") no mapping/acceptor for " + bound); } } }
@Override public synchronized SshdSocketAddress startRemotePortForwarding( SshdSocketAddress remote, SshdSocketAddress local) throws IOException { ValidateUtils.checkNotNull(local, "Local address is null"); ValidateUtils.checkNotNull(remote, "Remote address is null"); Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_GLOBAL_REQUEST); buffer.putString("tcpip-forward"); buffer.putBoolean(true); buffer.putString(remote.getHostName()); buffer.putInt(remote.getPort()); Buffer result = session.request(buffer); if (result == null) { throw new SshException("Tcpip forwarding request denied by server"); } int port = (remote.getPort() == 0) ? result.getInt() : remote.getPort(); // TODO: Is it really safe to only store the local address after the request ? SshdSocketAddress prev; synchronized (remoteToLocal) { prev = remoteToLocal.put(port, local); } if (prev != null) { throw new IOException( "Multiple remote port forwarding bindings on port=" + port + ": current=" + remote + ", previous=" + prev); } SshdSocketAddress bound = new SshdSocketAddress(remote.getHostName(), port); if (log.isDebugEnabled()) { log.debug("startRemotePortForwarding(" + remote + " -> " + local + "): " + bound); } return bound; }
@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) && (acceptor != null)) { if (log.isDebugEnabled()) { log.debug("localPortForwardingCancelled(" + local + ") unbind " + entry); } acceptor.unbind(entry.toInetSocketAddress()); } else { if (log.isDebugEnabled()) { log.debug("localPortForwardingCancelled(" + local + ") no match/acceptor: " + entry); } } }
@Override public synchronized void stopRemotePortForwarding(SshdSocketAddress remote) throws IOException { SshdSocketAddress bound; synchronized (remoteToLocal) { bound = remoteToLocal.remove(remote.getPort()); } if (bound != null) { if (log.isDebugEnabled()) { log.debug("stopRemotePortForwarding(" + remote + ") cancel forwarding to " + bound); } Buffer buffer = session.createBuffer(SshConstants.SSH_MSG_GLOBAL_REQUEST); buffer.putString("cancel-tcpip-forward"); buffer.putBoolean(false); buffer.putString(remote.getHostName()); buffer.putInt(remote.getPort()); session.writePacket(buffer); } else { if (log.isDebugEnabled()) { log.debug("stopRemotePortForwarding(" + remote + ") no binding found"); } } }
/** * @param address The request bind address * @param handlerFactory A {@link Factory} to create an {@link IoHandler} if necessary * @return The {@link InetSocketAddress} to which the binding occurred * @throws IOException If failed to bind */ private InetSocketAddress doBind( SshdSocketAddress address, Factory<? extends IoHandler> handlerFactory) throws IOException { if (acceptor == null) { FactoryManager manager = session.getFactoryManager(); IoServiceFactory factory = manager.getIoServiceFactory(); IoHandler handler = handlerFactory.create(); acceptor = factory.createAcceptor(handler); } // TODO find a better way to determine the resulting bind address - what if multi-threaded // calls... Set<SocketAddress> before = acceptor.getBoundAddresses(); try { InetSocketAddress bindAddress = address.toInetSocketAddress(); acceptor.bind(bindAddress); Set<SocketAddress> 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) after.iterator().next(); } catch (IOException bindErr) { Set<SocketAddress> after = acceptor.getBoundAddresses(); if (GenericUtils.isEmpty(after)) { close(); } throw bindErr; } }
@Override public synchronized SshdSocketAddress startDynamicPortForwarding(SshdSocketAddress local) throws IOException { ValidateUtils.checkNotNull(local, "Local address is null"); ValidateUtils.checkTrue(local.getPort() >= 0, "Invalid local port: %s", local); if (isClosed()) { throw new IllegalStateException("TcpipForwarder is closed"); } if (isClosing()) { throw new IllegalStateException("TcpipForwarder is closing"); } SocksProxy socksProxy = new SocksProxy(service); SocksProxy prev; InetSocketAddress bound = doBind(local, socksProxyIoHandlerFactory); int port = bound.getPort(); synchronized (dynamicLocal) { prev = dynamicLocal.put(port, socksProxy); } if (prev != null) { throw new IOException( "Multiple dynamic port mappings found for port=" + port + ": current=" + socksProxy + ", previous=" + prev); } SshdSocketAddress result = new SshdSocketAddress(bound.getHostString(), port); if (log.isDebugEnabled()) { log.debug("startDynamicPortForwarding(" + local + "): " + result); } return result; }
@Override public synchronized SshdSocketAddress startLocalPortForwarding( SshdSocketAddress local, SshdSocketAddress remote) throws IOException { ValidateUtils.checkNotNull(local, "Local address is null"); ValidateUtils.checkTrue(local.getPort() >= 0, "Invalid local port: %s", local); ValidateUtils.checkNotNull(remote, "Remote address is null"); if (isClosed()) { throw new IllegalStateException("TcpipForwarder is closed"); } if (isClosing()) { throw new IllegalStateException("TcpipForwarder is closing"); } InetSocketAddress bound = doBind(local, staticIoHandlerFactory); int port = bound.getPort(); SshdSocketAddress prev; synchronized (localToRemote) { prev = localToRemote.put(port, remote); } if (prev != null) { throw new IOException( "Multiple local port forwarding bindings on port=" + port + ": current=" + remote + ", previous=" + prev); } SshdSocketAddress result = new SshdSocketAddress(bound.getHostString(), port); if (log.isDebugEnabled()) { log.debug("startLocalPortForwarding(" + local + " -> " + remote + "): " + result); } return result; }