route HttpClient over Socks5 proxy. requires apache http client. work in progress.

This commit is contained in:
danda 2016-07-25 17:04:18 -07:00
parent 96f69ebfdf
commit 909bf4cab1
5 changed files with 189 additions and 2 deletions

View file

@ -23,5 +23,12 @@
<artifactId>jtorproxy</artifactId> <artifactId>jtorproxy</artifactId>
<version>${project.parent.version}</version> <version>${project.parent.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5</version>
</dependency>
</dependencies> </dependencies>
</project> </project>

View file

@ -0,0 +1,15 @@
package io.bitsquare.http;
import org.apache.http.conn.DnsResolver;
import java.net.InetAddress;
import java.net.UnknownHostException;
// This class is adapted from
// http://stackoverflow.com/a/25203021/5616248
class FakeDnsResolver implements DnsResolver {
@Override
public InetAddress[] resolve(String host) throws UnknownHostException {
// Return some fake DNS record for every request, we won't be using it
return new InetAddress[] { InetAddress.getByAddress(new byte[] { 1, 1, 1, 1 }) };
}
}

View file

@ -1,24 +1,58 @@
package io.bitsquare.http; package io.bitsquare.http;
import com.runjva.sourceforge.jsocks.protocol.Socks5Proxy;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.IOException; import java.io.InputStream;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.IOException;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.URL; import java.net.URL;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
// TODO route over tor
public class HttpClient { public class HttpClient {
private static final Logger log = LoggerFactory.getLogger(HttpClient.class);
private final String baseUrl; private final String baseUrl;
private final Socks5Proxy proxy;
public HttpClient(String baseUrl) { public HttpClient(String baseUrl) {
this.baseUrl = baseUrl; this.baseUrl = baseUrl;
this.proxy = null;
}
public HttpClient(Socks5Proxy proxy, String baseUrl) {
this.baseUrl = baseUrl;
this.proxy = proxy;
} }
public String requestWithGET(String param) throws IOException, HttpException { public String requestWithGET(String param) throws IOException, HttpException {
return requestWithGETProxy(param);
// return proxy != null ? requestWithGETProxy(param) : requestWithGETNoProxy(param);
}
/**
* Make an HTTP Get request directly (not routed over socks5 proxy).
*/
private String requestWithGETNoProxy(String param) throws IOException, HttpException {
HttpURLConnection connection = null; HttpURLConnection connection = null;
try { try {
log.info( "Executing HTTP request " + baseUrl + param + " proxy: none.");
URL url = new URL(baseUrl + param); URL url = new URL(baseUrl + param);
connection = (HttpURLConnection) url.openConnection(); connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET"); connection.setRequestMethod("GET");
@ -38,6 +72,51 @@ public class HttpClient {
} }
} }
/**
* Make an HTTP Get request routed over socks5 proxy.
*/
private String requestWithGETProxy(String param) throws IOException, HttpException {
// This code is adapted from:
// http://stackoverflow.com/a/25203021/5616248
// Register our own SocketFactories to override createSocket() and connectSocket().
// connectSocket does NOT resolve hostname before passing it to proxy.
Registry<ConnectionSocketFactory> reg = RegistryBuilder.<ConnectionSocketFactory> create()
.register("http", new SocksConnectionSocketFactory())
.register("https", new SocksSSLConnectionSocketFactory(SSLContexts.createSystemDefault())).build();
// Use FakeDNSResolver if not resolving DNS locally.
// This prevents a local DNS lookup (which would be ignored anyway)
PoolingHttpClientConnectionManager cm = proxy.resolveAddrLocally() ?
new PoolingHttpClientConnectionManager(reg) :
new PoolingHttpClientConnectionManager(reg, new FakeDnsResolver());
CloseableHttpClient httpclient = HttpClients.custom().setConnectionManager(cm).build();
try {
// InetSocketAddress socksaddr = new InetSocketAddress(proxy.getInetAddress(), proxy.getPort());
// remove me: Use this to test with system-wide Tor proxy.
InetSocketAddress socksaddr = new InetSocketAddress("127.0.0.1", 9050);
HttpClientContext context = HttpClientContext.create();
context.setAttribute("socks.address", socksaddr);
HttpGet request = new HttpGet(baseUrl + param);
log.error( "Executing request " + request + " proxy: " + socksaddr);
CloseableHttpResponse response = httpclient.execute(request, context);
try {
InputStream stream = response.getEntity().getContent();
String buf = convertInputStreamToString(stream);
return buf;
} finally {
response.close();
}
} finally {
httpclient.close();
}
}
private String convertInputStreamToString(InputStream inputStream) throws IOException { private String convertInputStreamToString(InputStream inputStream) throws IOException {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
StringBuilder stringBuilder = new StringBuilder(); StringBuilder stringBuilder = new StringBuilder();

View file

@ -0,0 +1,38 @@
package io.bitsquare.http;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.Socket;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.HttpHost;
import org.apache.http.protocol.HttpContext;
// This class is adapted from
// http://stackoverflow.com/a/25203021/5616248
//
// This class routes connections over Socks, and avoids resolving hostnames locally.
class SocksConnectionSocketFactory extends PlainConnectionSocketFactory {
/**
* creates an unconnected Socks Proxy socket
*/
@Override
public Socket createSocket(final HttpContext context) throws IOException {
InetSocketAddress socksaddr = (InetSocketAddress) context.getAttribute("socks.address");
Proxy proxy = new Proxy(Proxy.Type.SOCKS, socksaddr);
return new Socket(proxy);
}
/**
* connects a Socks Proxy socket and passes hostname to proxy without resolving it locally.
*/
@Override
public Socket connectSocket(int connectTimeout, Socket socket, HttpHost host, InetSocketAddress remoteAddress,
InetSocketAddress localAddress, HttpContext context) throws IOException {
// Convert address to unresolved
InetSocketAddress unresolvedRemote = InetSocketAddress
.createUnresolved(host.getHostName(), remoteAddress.getPort());
return super.connectSocket(connectTimeout, socket, host, unresolvedRemote, localAddress, context);
}
}

View file

@ -0,0 +1,48 @@
package io.bitsquare.http;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.Socket;
import javax.net.ssl.SSLContext;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.HttpHost;
import org.apache.http.protocol.HttpContext;
// This class is adapted from
// http://stackoverflow.com/a/25203021/5616248
//
// This class routes connections over Socks, and avoids resolving hostnames locally.
class SocksSSLConnectionSocketFactory extends SSLConnectionSocketFactory {
public SocksSSLConnectionSocketFactory(final SSLContext sslContext) {
// Only allow connection's to site's with valid certs.
super(sslContext, STRICT_HOSTNAME_VERIFIER);
// Or to allow insecure (eg self-signed certs)
// super(sslContext, ALLOW_ALL_HOSTNAME_VERIFIER);
}
/**
* creates an unconnected Socks Proxy socket
*/
@Override
public Socket createSocket(final HttpContext context) throws IOException {
InetSocketAddress socksaddr = (InetSocketAddress) context.getAttribute("socks.address");
Proxy proxy = new Proxy(Proxy.Type.SOCKS, socksaddr);
return new Socket(proxy);
}
/**
* connects a Socks Proxy socket and passes hostname to proxy without resolving it locally.
*/
@Override
public Socket connectSocket(int connectTimeout, Socket socket, HttpHost host, InetSocketAddress remoteAddress,
InetSocketAddress localAddress, HttpContext context) throws IOException {
// Convert address to unresolved
InetSocketAddress unresolvedRemote = InetSocketAddress
.createUnresolved(host.getHostName(), remoteAddress.getPort());
return super.connectSocket(connectTimeout, socket, host, unresolvedRemote, localAddress, context);
}
}