Skip to content

Remote port forwarding not working #239

Closed
@anderserik

Description

@anderserik

Tested on commit c3f75cd
For the tests below, only remotehostPortForwarding() pass.


package com.hierynomus.sshj.connection.channel.forwarded;

import static org.junit.Assert.assertEquals;

import java.io.File;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.URL;
import java.util.concurrent.atomic.AtomicInteger;

import org.apache.sshd.server.forward.AcceptAllForwardingFilter;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;

import com.hierynomus.sshj.test.HttpServer;
import com.hierynomus.sshj.test.SshFixture;
import com.hierynomus.sshj.test.util.FileUtil;

import net.schmizz.sshj.DefaultConfig;
import net.schmizz.sshj.SSHClient;
import net.schmizz.sshj.connection.ConnectionException;
import net.schmizz.sshj.connection.channel.forwarded.RemotePortForwarder;
import net.schmizz.sshj.connection.channel.forwarded.RemotePortForwarder.Forward;
import net.schmizz.sshj.connection.channel.forwarded.SocketForwardingConnectListener;
import net.schmizz.sshj.transport.verification.PromiscuousVerifier;

public class RemotePortForwarderTest {

    // Credentials for an remote SSH Server to test against.
    private static final String REMOTE_HOST = "x.x.x.x";
    private static final String USER = "xxxx";
    private static final String PASSWORD = "yyyy";

    private static final int UPPER_RPF_PORT = 9999;
    private static final int LOWER_RPF_PORT = 9000;
    private static final AtomicInteger RPF_PORT = new AtomicInteger(LOWER_RPF_PORT);
    private static final InetSocketAddress HTTP_SERVER_SOCKET_ADDR = new InetSocketAddress("127.0.0.1", 8080);

    @Rule
    public SshFixture fixture = new SshFixture();

    @Rule
    public HttpServer httpServer = new HttpServer();

    @Before
    public void setup() throws IOException {
        fixture.getServer().setTcpipForwardingFilter(new AcceptAllForwardingFilter());
        File file = httpServer.getDocRoot().newFile("index.html");
        FileUtil.writeToFile(file, "<html><head/><body><h1>Hi!</h1></body></html>");
    }

    @Test
    public void localhostDynamicPortForwarding() throws IOException {
        SSHClient sshClient = getFixtureClient();
        int remotePort = shouldDynamicallyForwardPort(sshClient);
        httpGet("127.0.0.1", remotePort);
    }

    @Test
    public void remotehostDynamicPortForwarding() throws IOException {
        SSHClient sshClient = getClient();
        int remotePort = shouldDynamicallyForwardPort(sshClient);
        httpGet(REMOTE_HOST, remotePort);
        sshClient.disconnect();
    }

    @Test
    public void localhostPortForwarding() throws IOException {
        SSHClient sshClient = getFixtureClient();
        int remotePort = shouldForwardPort(sshClient);
        httpGet("127.0.0.1", remotePort);
    }

    @Test
    public void remotehostPortForwarding() throws IOException {
        SSHClient sshClient = getClient();
        int remotePort = shouldForwardPort(sshClient);
        httpGet(REMOTE_HOST, remotePort);
        sshClient.disconnect();
    }

    @Test
    public void httpTest() throws IOException {
        // Just to check that we have a working http server...
        httpGet("127.0.0.1", 8080);
    }

    private int shouldDynamicallyForwardPort(SSHClient sshClient) throws IOException {
        Forward forward = sshClient.getRemotePortForwarder().bind(
                // where the server should listen
                new RemotePortForwarder.Forward(0),
                // what we do with incoming connections that are forwarded to us
                new SocketForwardingConnectListener(HTTP_SERVER_SOCKET_ADDR));

        return forward.getPort();
    }

    private int shouldForwardPort(SSHClient sshClient) throws IOException {
        boolean portTaken = true;
        Forward forward = null;
        while (portTaken) {
            try {
                forward = sshClient.getRemotePortForwarder().bind(
                        // where the server should listen
                        new RemotePortForwarder.Forward(RPF_PORT.getAndIncrement()),
                        // what we do with incoming connections that are forwarded to us
                        new SocketForwardingConnectListener(HTTP_SERVER_SOCKET_ADDR));
                portTaken = false;
            } catch (ConnectionException e) {
                if (RPF_PORT.get() >= UPPER_RPF_PORT) {
                    System.out.println("Reached upper limit for remote port forwarder ports: " + UPPER_RPF_PORT);
                    throw e;
                }
                System.out.println(
                        "Failed to bind an remote port forwarder to port " + RPF_PORT.get() + "trying a new port");
            }
        }

        return forward.getPort();
    }

    private void httpGet(String server, int port) throws IOException {
        String urlString = "http://" + server + ":" + port;
        System.out.println("Trying: GET " + urlString);
        URL url = new URL(urlString);
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setConnectTimeout(1_000);
        connection.setRequestMethod("GET");
        assertEquals("Didn't get 200 OK", 200, connection.getResponseCode());
    }

    private SSHClient getClient() throws IOException {
        SSHClient sshClient = new SSHClient(new DefaultConfig());
        sshClient.addHostKeyVerifier(new PromiscuousVerifier());
        sshClient.loadKnownHosts();
        sshClient.connect(REMOTE_HOST, 22);
        sshClient.authPassword(USER, PASSWORD);

        return sshClient;
    }

    private SSHClient getFixtureClient() throws IOException {
        SSHClient sshClient = fixture.setupConnectedDefaultClient();
        sshClient.authPassword("jeroen", "jeroen");

        return sshClient;
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions