Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.sshtools.synergy.ssh.ForwardingManager Maven / Gradle / Ivy
package com.sshtools.synergy.ssh;
/*-
* #%L
* Common API
* %%
* Copyright (C) 2002 - 2024 JADAPTIVE Limited
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* .
* #L%
*/
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.sshtools.common.events.Event;
import com.sshtools.common.events.EventCodes;
import com.sshtools.common.events.EventServiceImplementation;
import com.sshtools.common.logger.Log;
import com.sshtools.common.ssh.SshException;
/**
* This class provides management of remote forwarding requests.
*/
public class ForwardingManager {
public interface Listener {
}
final static String REMOTE_FORWARDS_KEY = "remoteForwards";
private ForwardingFactory> forwardingFactory;
private Map, List> portsByConnection = new HashMap, List>();
private List> remoteForwardRequestHandlers = Collections.synchronizedList(new ArrayList<>());
protected Map> listeningPorts = Collections
.synchronizedMap(new HashMap>());
public ForwardingManager() {
}
public ForwardingChannelFactory getFactory(String addressToBind, int portToBind) {
return listeningPorts.get(addressToBind + ":" + portToBind);
}
public ForwardingFactory> getForwardingFactory() {
return forwardingFactory;
}
public void setForwardingFactory(
ForwardingFactory> forwardingFactory) {
this.forwardingFactory = forwardingFactory;
}
public void addRemoteForwardRequestHandler(RemoteForwardRequestHandler handler) {
remoteForwardRequestHandlers.add(handler);
}
public void removeRemoteForwardRequestHandler(RemoteForwardRequestHandler handler) {
remoteForwardRequestHandlers.remove(handler);
}
public List> getRemoteForwardRequestHandlers() {
return Collections.unmodifiableList(remoteForwardRequestHandlers);
}
/**
* Is there an existing forwarding listening on a particular port?
*
* @param port
* int
* @return boolean
*/
public synchronized boolean isListening(int port) {
synchronized(listeningPorts) {
return listeningPorts.containsKey(String.valueOf(port))
|| listeningPorts.containsKey("0.0.0.0:" + port)
|| listeningPorts.containsKey("::" + port);
}
}
public void stopRemoteForwarding(ConnectionProtocol con) throws SshException {
synchronized(remoteForwardRequestHandlers) {
if(Log.isInfoEnabled()) {
Log.info("Canceling all remote forwarding for connection");
}
SshException exception = null;
@SuppressWarnings("unchecked")
var remoteForwards = (Map)con.getConnection().getProperty(REMOTE_FORWARDS_KEY);
if(remoteForwards != null) {
for(var m : remoteForwards.entrySet()) {
var a = m.getKey().split(":");
var addressToBind = a[0];
var portToBind = a.length > 1 ? Integer.parseInt(a[1]) : 0;
for(var handler : remoteForwardRequestHandlers) {
if(handler.isHandled(addressToBind, portToBind, m.getValue().getHostToConnect(), m.getValue().getPortToConnect(), con)) {
try {
handler.stopRemoteForward(addressToBind, portToBind, m.getValue().getHostToConnect(), m.getValue().getPortToConnect(), con);
} catch (SshException e) {
exception = e;
}
}
}
}
}
remoteForwards.clear();
con.getConnection().removeProperty(REMOTE_FORWARDS_KEY);
if(exception != null)
throw exception;
}
}
public void stopRemoteForwarding(String addressToBind, int portToBind, ConnectionProtocol connection) throws SshException {
synchronized(remoteForwardRequestHandlers) {
if(Log.isInfoEnabled()) {
Log.info("Canceling remote forwarding from " + addressToBind + ":" + portToBind);
}
@SuppressWarnings("unchecked")
var remoteForwards = (Map)connection.getConnection().getProperty(REMOTE_FORWARDS_KEY);
var remoteForwardKey = addressToBind + ":" + portToBind;
if(remoteForwards == null || !remoteForwards.containsKey(remoteForwardKey)) {
if(Log.isDebugEnabled())
Log.debug("No known remote forward for " + addressToBind + ":" + portToBind);
return;
}
var remoteForward = remoteForwards.get(remoteForwardKey);
for(var handler : remoteForwardRequestHandlers) {
if(handler.isHandled(addressToBind, portToBind, remoteForward.getHostToConnect(), remoteForward.getPortToConnect(), connection)) {
handler.stopRemoteForward(addressToBind, portToBind, remoteForward.getHostToConnect(), remoteForward.getPortToConnect(), connection);
remoteForwards.remove(addressToBind + ":" + portToBind);
if(remoteForwards.isEmpty())
connection.getConnection().removeProperty(REMOTE_FORWARDS_KEY);
return;
}
}
throw new SshException(SshException.INTERNAL_ERROR, "Nothing handled closing the remote forward.");
}
}
public int startRemoteForwarding(String addressToBind, int portToBind, String destinationHost,
int destinationPort, ConnectionProtocol con) throws SshException {
synchronized(remoteForwardRequestHandlers) {
for(var handler : remoteForwardRequestHandlers) {
if(handler.isHandled(addressToBind, portToBind, destinationHost, destinationPort, con)) {
portToBind = handler.startRemoteForward(addressToBind, portToBind, destinationHost, destinationPort, con);
@SuppressWarnings("unchecked")
var remoteForwards = (Map)con.getConnection().getProperty(REMOTE_FORWARDS_KEY);
if(remoteForwards == null) {
remoteForwards = new HashMap<>();
con.getConnection().setProperty(REMOTE_FORWARDS_KEY, remoteForwards);
}
remoteForwards.put(addressToBind + ":" + portToBind, new RemoteForward(destinationHost, destinationPort));
return portToBind;
}
}
throw new SshException(SshException.INTERNAL_ERROR, "Nothing handled the remote forwarding request.");
}
}
public synchronized int startListening(String addressToBind, int portToBind, Connection con, String destinationHost, int destinationPort) throws SshException {
String key = addressToBind + ":" + portToBind;
if (portToBind > 0 && isListening(portToBind)) {
throw new SshException("Port " + portToBind + " already in use", SshException.FORWARDING_ERROR);
}
var forwardingChannelFactory = forwardingFactory.createChannelFactory(destinationHost, destinationPort);
try {
portToBind = forwardingChannelFactory.bindInterface(addressToBind, portToBind, con.getConnectionProtocol(),
forwardingChannelFactory.getChannelType());
key = addressToBind + ":" + portToBind;
listeningPorts.put(key, forwardingChannelFactory);
if(!portsByConnection.containsKey(con)) {
portsByConnection.put(con, new ArrayList());
}
portsByConnection.get(con).add(key);
EventServiceImplementation.getInstance()
.fireEvent((new Event(this, forwardingChannelFactory.getStartedEventCode(), true))
.addAttribute(EventCodes.ATTRIBUTE_CONNECTION, con)
.addAttribute(EventCodes.ATTRIBUTE_FORWARDING_TUNNEL_ENTRANCE,
addressToBind + ":" + portToBind));
if(Log.isDebugEnabled())
Log.debug("Listening for new connections on " + addressToBind + ":" + portToBind);
return portToBind;
} catch (IOException ex) {
if(Log.isDebugEnabled())
Log.debug("Exception caught on socket bind", ex);
} catch (Throwable t) {
if(Log.isDebugEnabled())
Log.debug("Could not instantiate forwarding channel factory", t);
}
throw new SshException("Failed to start listening socket on " + addressToBind + (portToBind > 0 ? ":" + portToBind : ""),
SshException.FORWARDING_ERROR);
}
public void stopForwarding(Connection con) {
if (portsByConnection.containsKey(con)) {
List keys = new ArrayList(portsByConnection.get(con));
for (String key : keys) {
stopListening(key, true, con);
}
}
}
public void stopForwarding(String key, Connection con) {
if(portsByConnection.containsKey(con)) {
List keys = portsByConnection.get(con);
if(keys.contains(key)) {
stopListening(key, true, con);
}
}
}
/**
* Stop remote forwarding.
*
* @param addressToBind
* String
* @param portToBind
* int
* @param dropActiveTunnels
* boolean
* @param connection
* ConnectionProtocol
* @return boolean
*/
public synchronized boolean stopListening(String addressToBind, int portToBind, boolean dropActiveTunnels,
Connection connection) {
String key = addressToBind + ":" + String.valueOf(portToBind);
return stopListening(key, dropActiveTunnels, connection);
}
public synchronized boolean stopListening(String key, boolean dropActiveTunnels,
Connection connection) {
if(Log.isDebugEnabled()) {
Log.debug("Forwarding cancelled for address " + key);
}
if (listeningPorts.containsKey(key)) {
ForwardingChannelFactory ff = (ForwardingChannelFactory) listeningPorts.get(key);
if (ff.belongsTo(connection.getConnectionProtocol())) {
ff.stopListening(dropActiveTunnels);
portsByConnection.get(connection).remove(key);
listeningPorts.remove(key);
EventServiceImplementation.getInstance().fireEvent((new Event(this, ff.getStoppedEventCode(), true))
.addAttribute(EventCodes.ATTRIBUTE_CONNECTION, connection).addAttribute(
EventCodes.ATTRIBUTE_FORWARDING_TUNNEL_ENTRANCE, key));
if(Log.isDebugEnabled()) {
Log.debug("Stopped listening on " + key);
}
}
return true;
}
if(Log.isDebugEnabled()) {
Log.debug("Failed to stop listening on " + key);
}
return false;
}
public boolean startX11Forwarding(boolean singleConnection, String protocol, byte[] cookie, int screen,
ConnectionProtocol connection) {
return false;
}
}