SOCKS5 proxy is widely available proxy server, for example it is built into the OpenSSH.
To start a local proxy server, let's open an SSH connection to a remote server with proxy port parameter -D 1080
.
ssh -D 1080 100.100.100.100
We may start tcpdump, listening on the loopback (lo0
) interface, to observe traffic going through the proxy server.
sudo tcpdump -A -i lo0 port 1080
Then, test the proxy server with curl.
curl --proxy socks5://localhost:1080 https://ifconfig.me/ip
The IP address of the server should be returned.
Global proxy settings
If we need to send all outgoing connections via PROXY server, we may set the proxy to the Java application globally.
java -DsocksProxyHost=localhost -DsocksProxyPort=1080 MyApp
Configuring proxy programmatically
In all examples bellow, the core component of channelling communication through proxy server is to instantiate a socket with a proxy parameter java.net.Socket(Proxy proxy)
.
Native URLConnection
The relatively low-level java.net.URLConnection
propagates proxy into the socket, via its openConnection()
method.
var url = new URL("https://ifconfig.me/ip");
var proxyAddress = new InetSocketAddress("localhost", 1080);
var proxy = new Proxy(Proxy.Type.SOCKS, proxyAddress);
var connection = (URLConnection) url.openConnection(proxy);
try (var inputStream = connection.getInputStream()) {
var bytes = inputStream.readAllBytes();
var content = new String(bytes);
System.out.println("IP: " + content);
}
Apache HttpClient 5
There's no builtin support for the SOCKS proxy in the HttpClient at the moment. So, we have to extend a socket factory and pass it into the connection manager.
Please be aware that example bellow supports only https connections! For http connection, the PlainConnectionSocketFactory
has to be extended. Unfortunately, the PoolingHttpClientConnectionManagerBuilder
API does not provide a way for configuring the plain socket factory, so the connection manager would have to be instantiated manually. See the PoolingHttpClientConnectionManagerBuilder.build()
for more details.
var url = "https://ifconfig.me/ip";
var proxyAddress = new InetSocketAddress("localhost", 1080);
var connectionManager = PoolingHttpClientConnectionManagerBuilder.create()
.setSSLSocketFactory(createSSLConnectionSocketFactory(proxyAddress))
.build();
try (var client = HttpClients.custom().setConnectionManager(connectionManager).build()) {
var httpGet = new HttpGet(url);
var response = client.execute(httpGet, new BasicHttpClientResponseHandler());
System.out.println("IP: " + response);
}
private static SSLConnectionSocketFactory createSSLConnectionSocketFactory(InetSocketAddress proxyAddress) {
return new SSLConnectionSocketFactory(SSLContexts.createDefault(), HttpsSupport.getDefaultHostnameVerifier()) {
@Override
public Socket createSocket(HttpContext context) {
return new Socket(new Proxy(Proxy.Type.SOCKS, proxyAddress));
}
};
}
OkHttp client
Even though the OkHttpClient is implemented in Kotlin, which makes its API usage from Java sometimes awkward, it provides native support for SOCKS proxy.
var url = "https://ifconfig.me/ip";
var proxyAddress = new InetSocketAddress("localhost", 1080);
var proxy = new Proxy(Proxy.Type.SOCKS, proxyAddress);
// In Kotlin, the builder's fluent API may be used.
var builder = new OkHttpClient.Builder();
builder.setProxy$okhttp(proxy);
var client = builder.build();
var request = new Request.Builder().url(url).build();
try (var response = client.newCall(request).execute()) {
var body = response.body();
Objects.requireNonNull(body);
System.out.println("IP: " + body.string());
}
Java 11 HttpClient
As of this moment, SOCKS proxies are not supported by native HttpClient: bugs.openjdk.org/JDK-8214516
Please be aware, if SOCKS proxy is configured, the HttpClient will swallow it silently and makes a direct call to the server!
Additional resources
All examples above are implemented in a SOCKS5-Demo project on GitHub