SocketImpl 和 JUnit/Gradle

SocketImpl and JUnit/Gradle

我正在尝试让 Socks v4 在 java.net 中开箱即用,我似乎已经成功了! 我使用的代码大概是这样的:

    class SocketImplFactorySocks4 implements SocketImplFactory {
        @Override
        public SocketImpl createSocketImpl() {
            System.out.println("Socket implementation triggered");
            try {
                return socketSocks4Factory();
            } catch (Exception e) {
                e.printStackTrace();
                throw new Error("Can't go further");
            }
        }

        private SocketImpl socketSocks4Factory() throws
                [...] {
            Class<?> aClass = Class.forName("java.net.SocksSocketImpl");
            Constructor<?> cons = aClass.getDeclaredConstructor();
            if (!cons.isAccessible())
                cons.setAccessible(true);
            Object socket = cons.newInstance();
            Method method = socket.getClass().getDeclaredMethod("setV4");
            if (!method.isAccessible())
                method.setAccessible(true);
            method.invoke(socket);
            Field field = socket.getClass().getDeclaredField("useV4");
            field.setAccessible(true);
            Object value = field.get(socket);
            return (SocketImpl) socket;
        }

    }

长话短说,当我创建套接字并传递 -DsocksProxyHost 和 -DsocksProxyPort 时它起作用。

我的问题是当我在我的 junit 测试中使用相同的代码时,我可以通过 Reflections 检查 Socket.impl.useV4 设置为 true,socksProxy* 设置在系统范围内设置,但是当我使用我的套接字时, 它完全避免使用代理(我可以在 wireshark 中看到它)。

它是 JUnit 或 Gradle,但我已经达到了我的极限。请建议我下一步应该去哪里。 build.gradle.kts供参考:

tasks{
    test{
        systemProperty("socksProxyHost", "localhost")
        systemProperty("socksProxyPort", "8080")
    }
}

提前致谢!

好吧,我花了太多时间才弄明白,但我做到了。我最初的目标是测试我的 Socks v4 服务器代码,但我遇到了两个问题:

1) 尽管 Java Socket 支持 Socks v4 作为客户端,但默认情况下未启用。而且没有办法翻转开关。

2) 解决了 #1 之后,我尝试编写 E2E 测试来完成整个过程,但由于某种原因,它 避免进入 Socks 代理 ,即使切换(useV4)是真的。这就是我在 SO 上带来的。

为了解决第一个问题,我实现了SocketImplFactory(见上文问题)。 帮助解决主题问题的是我的管理背景,尽管它直到最近才开始出现。 :) 我分离了最初的嫌疑人(JUnit 和 Gradle)并在独立的 psvm 文件中进行了测试。测试没有成功,还是避免了通过代理。这就是它击中我的时候:localhost 的异常!

基本上,在 Java 核心库的深处有一个针对本地主机(127.0.0.1、:: 等)的硬编码异常。经过一些搜索,我遇到了 DsocksNonProxyHosts 选项。这没有帮助,正如您可能已经猜到的那样:) 最终我得到了 this 答案,其中提到我可能需要实施 ProxySelector。我做了什么:

    static class myProxySelector extends ProxySelector {

    @Override
    public List<Proxy> select(URI uri) {
        List<Proxy> proxyl = new ArrayList<Proxy>(1);
        InetSocketAddress saddr = InetSocketAddress.createUnresolved("localhost", 1080);
        Proxy proxy = SocksProxy.create(saddr, 4);
        proxyl.add(proxy);
        System.out.println("Selecting Proxy for " + uri.toASCIIString());
        return proxyl;
    }

    @Override
    public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {
        if (uri == null || sa == null || ioe == null) {
            throw new IllegalArgumentException("Arguments can't be null.");
        }
    }
}

整个套接字设置如下所示:

        private void setupSocket() throws IOException {
        Socket.setSocketImplFactory(new SocketImplFactorySocks4());
        ProxySelector proxySelector = new myProxySelector();
        ProxySelector.setDefault(proxySelector);
        proxy = new Proxy(Proxy.Type.SOCKS, new InetSocketAddress("127.0.0.1", 1080));
    }

现在我想要的一切都可以工作了:我既能对我的 socks4 代码进行 E2E 测试,又能在本地主机上进行测试。