com.helger.jsch.tunnel.Tunnel Maven / Gradle / Ivy
/*
* Copyright (C) 2016-2024 Philip Helger (www.helger.com)
* philip[at]helger[dot]com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.helger.jsch.tunnel;
import java.util.Locale;
import javax.annotation.Nonnull;
import com.helger.commons.annotation.Nonempty;
import com.helger.commons.hashcode.HashCodeGenerator;
import com.helger.commons.string.StringHelper;
import com.helger.commons.string.ToStringGenerator;
/**
* Tunnel stores all the information needed to define an ssh port-forwarding
* tunnel.
*
* @see rfc4254
*/
public class Tunnel
{
private String m_sSpec;
private String m_sDestinationHostname;
private int m_nDestinationPort;
private String m_sLocalAlias;
private int m_nLocalPort;
private int m_nAssignedLocalPort;
/**
* Creates a Tunnel from a spec
string. For details on this
* string, see {@link #getSpec()}.
*
* Both localAlias
and localPort
are optional, in
* which case they default to localhost
and 0
* respectively.
*
*
* Examples:
*
*
* // Equivalaent to new Tunnel("localhost", 0, "foobar", 1234);
* new Tunnel ("foobar:1234");
* // Equivalaent to new Tunnel("localhost", 1234, "foobar", 1234);
* new Tunnel ("1234:foobar:1234");
* // Equivalaent to new Tunnel("local_foobar", 1234, "foobar", 1234);
* new Tunnel ("local_foobar:1234:foobar:1234");
*
*
* @param sSpec
* A tunnel spec string
* @see #Tunnel(String, int, String, int)
* @see rfc4254
*/
public Tunnel (@Nonnull @Nonempty final String sSpec)
{
final String [] aParts = StringHelper.getExplodedArray (':', sSpec, 4);
if (aParts.length == 4)
{
m_sLocalAlias = aParts[0];
m_nLocalPort = Integer.parseInt (aParts[1]);
m_sDestinationHostname = aParts[2];
m_nDestinationPort = Integer.parseInt (aParts[3]);
}
else
if (aParts.length == 3)
{
m_nLocalPort = Integer.parseInt (aParts[0]);
m_sDestinationHostname = aParts[1];
m_nDestinationPort = Integer.parseInt (aParts[2]);
}
else
if (aParts.length == 2)
{
// dynamically assigned port
m_nLocalPort = 0;
m_sDestinationHostname = aParts[0];
m_nDestinationPort = Integer.parseInt (aParts[1]);
}
else
throw new IllegalStateException ("Failed to parse Tunnel spec '" + sSpec + "'");
}
/**
* Creates a Tunnel to destinationPort
on
* destinationHostname
from a dynamically assigned port on
* localhost
. Simply calls
*
* @param destinationHostname
* The hostname to tunnel to
* @param destinationPort
* The port to tunnel to
* @see #Tunnel(int, String, int)
* @see rfc4254
*/
public Tunnel (final String destinationHostname, final int destinationPort)
{
this (0, destinationHostname, destinationPort);
}
/**
* Creates a Tunnel to destinationPort
on
* destinationHostname
from localPort
on
* localhost
.
*
* @param localPort
* The local port to bind to
* @param destinationHostname
* The hostname to tunnel to
* @param destinationPort
* The port to tunnel to
* @see #Tunnel(String, int, String, int)
* @see rfc4254
*/
public Tunnel (final int localPort, final String destinationHostname, final int destinationPort)
{
this (null, localPort, destinationHostname, destinationPort);
}
/**
* Creates a Tunnel to destinationPort
on
* destinationHostname
from localPort
on
* localAlias
.
*
* This is similar in behavior to the -L
option in ssh, with the
* exception that you can specify 0
for the local port in which
* case the port will be dynamically allocated and you can
* {@link #getAssignedLocalPort()} after the tunnel has been started.
*
*
* A common use case for localAlias
might be to link your
* loopback interfaces to names via an entries in /etc/hosts
* which would allow you to use the same port number for more than one tunnel.
* For example:
*
*
* 127.0.0.2 foo
* 127.0.0.3 bar
*
*
* Would allow you to have both of these open at the same time:
*
*
* new Tunnel ("foo", 1234, "remote_foo", 1234);
* new Tunnel ("bar", 1234, "remote_bar", 1234);
*
*
* @param localAlias
* The local interface to bind to
* @param localPort
* The local port to bind to
* @param destinationHostname
* The hostname to tunnel to
* @param destinationPort
* The port to tunnel to
* @see com.jcraft.jsch.Session#setPortForwardingL(String, int, String, int)
* @see rfc4254
*/
public Tunnel (final String localAlias, final int localPort, final String destinationHostname, final int destinationPort)
{
m_sLocalAlias = localAlias;
m_nLocalPort = localPort;
m_sDestinationHostname = destinationHostname;
m_nDestinationPort = destinationPort;
}
/**
* Returns the local port currently bound to. If 0
was specified
* as the port to bind to, this will return the dynamically allocated port,
* otherwise it will return the port specified.
*
* @return The local port currently bound to
*/
public int getAssignedLocalPort ()
{
return m_nAssignedLocalPort == 0 ? m_nLocalPort : m_nAssignedLocalPort;
}
/**
* Returns the hostname of the destination.
*
* @return The hostname of the destination
*/
public String getDestinationHostname ()
{
return m_sDestinationHostname;
}
/**
* Returns the port of the destination.
*
* @return The port of the destination
*/
public int getDestinationPort ()
{
return m_nDestinationPort;
}
/**
* Returns the local alias bound to. See
* rfc4254 for
* details on acceptible values.
*
* @return The local alias bound to
*/
public String getLocalAlias ()
{
return m_sLocalAlias;
}
/**
* Returns the port this tunnel was configured with. If you want to get the
* runtime port, use {@link #getAssignedLocalPort()}.
*
* @return The port this tunnel was configured with
*/
public int getLocalPort ()
{
return m_nLocalPort;
}
/**
* Returns the spec string (either calculated or specified) for this tunnel.
*
* A spec string is composed of 4 parts separated by a colon (:
* ):
*
* localAlias
(optional)
* localPort
(optional)
* destinationHostname
* destinationPort
*
*
* @return The spec string
*/
@Nonnull
public String getSpec ()
{
if (m_sSpec == null)
m_sSpec = getAsString ().toLowerCase (Locale.US);
return m_sSpec;
}
void setAssignedLocalPort (final int port)
{
m_nAssignedLocalPort = port;
}
@Nonnull
public String getAsString ()
{
return (m_sLocalAlias == null ? "" : m_sLocalAlias + ":") +
(m_nAssignedLocalPort == 0 ? Integer.toString (m_nLocalPort) : "(0)" + m_nAssignedLocalPort) +
":" +
m_sDestinationHostname +
":" +
m_nDestinationPort;
}
@Override
public boolean equals (final Object o)
{
if (o == this)
return true;
if (o == null || !getClass ().equals (o.getClass ()))
return false;
final Tunnel rhs = (Tunnel) o;
return getSpec ().equals (rhs.getSpec ());
}
@Override
public int hashCode ()
{
return new HashCodeGenerator (this).append (getSpec ()).getHashCode ();
}
@Override
public String toString ()
{
return new ToStringGenerator (this).append ("Spec", m_sSpec)
.append ("DestinationHostname", m_sDestinationHostname)
.append ("DestinationPort", m_nDestinationPort)
.append ("LocalAlias", m_sLocalAlias)
.append ("LocalPort", m_nLocalPort)
.append ("AssignedLocalPort", m_nAssignedLocalPort)
.getToString ();
}
}