hierynomus/sshj

HTTP Proxy is not supported

missedone opened this issue · 13 comments

Hi Folks

as we work behind the firewall, the SSH connection need go over HTTP proxy, but I found SSHj only support SOCKS proxy. here is the code snappet with HTTP proxy

try (SSHClient ssh = new SSHClient()) {
            ssh.setConnectTimeout(60 * 1000);
            ssh.setTimeout(60 * 60 * 1000);
            ssh.getConnection().getKeepAlive().setKeepAliveInterval(30);
            ssh.loadKnownHosts();
            ssh.addHostKeyVerifier(new PromiscuousVerifier());

            ssh.connect(host, new Proxy(Proxy.Type.HTTP, new InetSocketAddress("16.85.88.10", 8080)));
            ssh.authPublickey(user, ssh.loadKeys(privateKey, null, null));

            try (Session session = ssh.startSession()) {
                final Session.Command cmd = session.exec("echo sleeping && date && sleep 3000 && date && echo awake");
                System.out.println(IOUtils.readFully(cmd.getInputStream()).toString());
                cmd.join(90, TimeUnit.MINUTES);
                System.out.println("\n** exit status: " + cmd.getExitStatus());
            }
        }

i got exception:

java.lang.IllegalArgumentException: Invalid Proxy
    at java.net.Socket.<init>(Socket.java:147)
    at net.schmizz.sshj.SocketClient.connect(SocketClient.java:57)
    at net.schmizz.sshj.SocketClient.connect(SocketClient.java:71)
    at net.schmizz.sshj.SocketClient.connect(SocketClient.java:107)
    at com.hp.es.cto.sp.remote.SshjTest.testKeepAlive(SshjTest.java:32)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)

by dig into the source code of java.net.Socket.Socket(Proxy), we can see it only support SOCKS and NO_PROXY proxy.

I saw both jsch and ganymed support HTTP proxy, so would you consider to add HTTP proxy support? thanks

You could use custom socket factory

I don't get it, if I look at my JDK's source code, I see the following in the constructor:

    public Socket(Proxy proxy) {
        // Create a copy of Proxy as a security measure
        if (proxy == null) {
            throw new IllegalArgumentException("Invalid Proxy");
        }
        Proxy p = proxy == Proxy.NO_PROXY ? Proxy.NO_PROXY
                                          : sun.net.ApplicationProxy.create(proxy);
        Proxy.Type type = p.type();
        if (type == Proxy.Type.SOCKS || type == Proxy.Type.HTTP) {

So it actually supports HTTP Proxies. Which JDK are you using?

right, i'm using Oracle JDK 1.7.x which is the version we used on our production
when I switch to JDK 1.8, it does works.
do you have any idea to make it back ported though i will check it via google search as well.
thanks

I might have found something... will try to implement this next week. In
the meantime though I'm going to release 0.11.0 without this.

Regards,
Jeroen

2015-01-23 5:35 GMT+01:00 Nick Tan notifications@github.com:

right, i'm using Oracle JDK 1.7.x which is the version we used on our
production
when I switch to JDK 1.8, it does works.
do you have any idea to make it back ported though i will check it via
google search as well.
thanks


Reply to this email directly or view it on GitHub
#170 (comment).

Thanks Jeroen

I don't understand why this needs its own implementation and doesn't rely on using the JDK internal HTTP tunneling support using the Socket(Proxy.Type.HTTP)constructor which then delegates to the java.net.HttpConnectSocketImpl implementation. I tend to say providing an proxy implementation should be out of scope for sshj. The change in fc535a5 breaks API compatibility for users that want to provide a custom socket factory implementation.

Hi David, I also thought that would work, unfortunately for JDK6 and 7, sockets with HTTP proxies are not implemented. See the code here:

    public Socket(Proxy proxy) {
        // Create a copy of Proxy as a security measure
        if (proxy == null) {
            throw new IllegalArgumentException("Invalid Proxy");
        }
        Proxy p = proxy == Proxy.NO_PROXY ? Proxy.NO_PROXY : sun.net.ApplicationProxy.create(proxy);
        if (p.type() == Proxy.Type.SOCKS) {
            SecurityManager security = System.getSecurityManager();
            InetSocketAddress epoint = (InetSocketAddress) p.address();
            if (epoint.getAddress() != null) {
                checkAddress (epoint.getAddress(), "Socket");
            }
            if (security != null) {
                if (epoint.isUnresolved())
                    epoint = new InetSocketAddress(epoint.getHostName(), epoint.getPort());
                if (epoint.isUnresolved())
                    security.checkConnect(epoint.getHostName(), epoint.getPort());
                else
                    security.checkConnect(epoint.getAddress().getHostAddress(),
                                  epoint.getPort());
            }
            impl = new SocksSocketImpl(p);
            impl.setSocket(this);
        } else {
            if (p == Proxy.NO_PROXY) {
                if (factory == null) {
                    impl = new PlainSocketImpl();
                    impl.setSocket(this);
                } else
                    setImpl();
            } else
                throw new IllegalArgumentException("Invalid Proxy");
        }

I've reopened the issue to actually correct the SocketFactory to correctly implement the SocketFactory interface so as not to break the external API as David mentions.

Yes, support was introduced with HttpConnectSocketImpl in 1.8. I still think it is acceptable for users that require this to run Java 1.8 or later that need this and default to the provided implementation in the JDK. Or they can write their own socket factory implementation and provide HTTP Connect proxy support.

Ok, changed the implementation for this, no custom SocketFactory anymore. The entire proxy support actually already bypassed the proxy factory. That should have been implemented differently from the start. I'll mark those methods deprecated and suggest that you should use a custom SocketFactory for that. For now, it will work with different versions of Java.

@dkocher Let me know whether you like this one better ;)

Thanks for taking my input into account. +1 for marking the constructors with proxy parameter as deprecated.

Thanks for contributing and noticing I broke the API 😉. Deprecations are marked in 4250c61