Skip to content
Snippets Groups Projects
Commit a0de0a40 authored by Torsten Grote's avatar Torsten Grote
Browse files

Merge branch 'socks-library' into 'master'

Use SOCKS socket library

See merge request briar/briar!1717
parents 73d95743 03adfd85
No related branches found
No related tags found
No related merge requests found
......@@ -17,6 +17,7 @@ dependencies {
implementation 'net.i2p.crypto:eddsa:0.2.0'
implementation 'org.whispersystems:curve25519-java:0.5.0'
implementation 'org.briarproject:jtorctl:0.5'
implementation 'org.briarproject:socks-socket:0.1'
//noinspection GradleDependency
implementation "com.squareup.okhttp3:okhttp:$okhttp_version"
......
package org.briarproject.bramble.socks;
import org.briarproject.bramble.api.plugin.TorSocksPort;
import org.briarproject.socks.SocksSocketFactory;
import java.net.InetSocketAddress;
......
package org.briarproject.bramble.socks;
import org.briarproject.bramble.util.ByteUtils;
import org.briarproject.bramble.util.IoUtils;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.util.Arrays;
class SocksSocket extends Socket {
private static final String[] ERRORS = {
"Succeeded",
"General SOCKS server failure",
"Connection not allowed by ruleset",
"Network unreachable",
"Host unreachable",
"Connection refused",
"TTL expired",
"Command not supported",
"Address type not supported"
};
@SuppressWarnings("MismatchedReadAndWriteOfArray")
private static final byte[] UNSPECIFIED_ADDRESS = new byte[4];
private final SocketAddress proxy;
private final int connectToProxyTimeout;
private final int extraConnectTimeout, extraSocketTimeout;
SocksSocket(SocketAddress proxy, int connectToProxyTimeout,
int extraConnectTimeout, int extraSocketTimeout) {
this.proxy = proxy;
this.connectToProxyTimeout = connectToProxyTimeout;
this.extraConnectTimeout = extraConnectTimeout;
this.extraSocketTimeout = extraSocketTimeout;
}
@Override
public void connect(SocketAddress endpoint, int timeout)
throws IOException {
// Validate the endpoint
if (!(endpoint instanceof InetSocketAddress))
throw new IllegalArgumentException();
InetSocketAddress inet = (InetSocketAddress) endpoint;
InetAddress address = inet.getAddress();
if (address != null
&& !Arrays.equals(address.getAddress(), UNSPECIFIED_ADDRESS)) {
throw new IllegalArgumentException();
}
String host = inet.getHostName();
if (host.length() > 255) throw new IllegalArgumentException();
int port = inet.getPort();
// Connect to the proxy
super.connect(proxy, connectToProxyTimeout);
OutputStream out = IoUtils.getOutputStream(this);
InputStream in = IoUtils.getInputStream(this);
// Request SOCKS 5 with no authentication
sendMethodRequest(out);
receiveMethodResponse(in);
// Use the supplied timeout temporarily, plus any configured extra
int oldTimeout = getSoTimeout();
setSoTimeout(timeout + extraConnectTimeout);
// Connect to the endpoint via the proxy
sendConnectRequest(out, host, port);
receiveConnectResponse(in);
// Restore the old timeout, plus any configured extra
setSoTimeout(oldTimeout + extraSocketTimeout);
}
private void sendMethodRequest(OutputStream out) throws IOException {
byte[] methodRequest = new byte[] {
5, // SOCKS version is 5
1, // Number of methods is 1
0 // Method is 0, no authentication
};
out.write(methodRequest);
out.flush();
}
private void receiveMethodResponse(InputStream in) throws IOException {
byte[] methodResponse = new byte[2];
IoUtils.read(in, methodResponse);
byte version = methodResponse[0];
byte method = methodResponse[1];
if (version != 5)
throw new IOException("Unsupported SOCKS version: " + version);
if (method == (byte) 255)
throw new IOException("Proxy requires authentication");
if (method != 0)
throw new IOException("Unsupported auth method: " + method);
}
private void sendConnectRequest(OutputStream out, String host, int port)
throws IOException {
byte[] connectRequest = new byte[7 + host.length()];
connectRequest[0] = 5; // SOCKS version is 5
connectRequest[1] = 1; // Command is 1, connect
connectRequest[3] = 3; // Address type is 3, domain name
connectRequest[4] = (byte) host.length(); // Length of domain name
for (int i = 0; i < host.length(); i++)
connectRequest[5 + i] = (byte) host.charAt(i);
ByteUtils.writeUint16(port, connectRequest, connectRequest.length - 2);
out.write(connectRequest);
out.flush();
}
private void receiveConnectResponse(InputStream in) throws IOException {
byte[] connectResponse = new byte[4];
IoUtils.read(in, connectResponse);
int version = connectResponse[0] & 0xFF;
int reply = connectResponse[1] & 0xFF;
int addressType = connectResponse[3] & 0xFF;
if (version != 5)
throw new IOException("Unsupported SOCKS version: " + version);
if (reply != 0) {
if (reply < ERRORS.length)
throw new IOException("Connection failed: " + ERRORS[reply]);
else throw new IOException("Connection failed: " + reply);
}
if (addressType == 1) IoUtils.read(in, new byte[4]); // IPv4
else if (addressType == 4) IoUtils.read(in, new byte[16]); // IPv6
else throw new IOException("Unsupported address type: " + addressType);
IoUtils.read(in, new byte[2]); // Port number
}
}
package org.briarproject.bramble.socks;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import javax.net.SocketFactory;
class SocksSocketFactory extends SocketFactory {
private final SocketAddress proxy;
private final int connectToProxyTimeout;
private final int extraConnectTimeout, extraSocketTimeout;
SocksSocketFactory(SocketAddress proxy, int connectToProxyTimeout,
int extraConnectTimeout, int extraSocketTimeout) {
this.proxy = proxy;
this.connectToProxyTimeout = connectToProxyTimeout;
this.extraConnectTimeout = extraConnectTimeout;
this.extraSocketTimeout = extraSocketTimeout;
}
@Override
public Socket createSocket() {
return new SocksSocket(proxy, connectToProxyTimeout,
extraConnectTimeout, extraSocketTimeout);
}
@Override
public Socket createSocket(String host, int port) throws IOException {
Socket socket = createSocket();
socket.connect(InetSocketAddress.createUnresolved(host, port));
return socket;
}
@Override
public Socket createSocket(InetAddress host, int port) {
throw new UnsupportedOperationException();
}
@Override
public Socket createSocket(String host, int port, InetAddress localHost,
int localPort) {
throw new UnsupportedOperationException();
}
@Override
public Socket createSocket(InetAddress address, int port,
InetAddress localAddress, int localPort) throws IOException {
throw new UnsupportedOperationException();
}
}
......@@ -36,6 +36,8 @@ dependencyVerification {
'org.bitlet:weupnp:0.1.4:weupnp-0.1.4.jar:88df7e6504929d00bdb832863761385c68ab92af945b04f0770b126270a444fb',
'org.bouncycastle:bcprov-jdk15to18:1.70:bcprov-jdk15to18-1.70.jar:7df4c54f29ce2dd616dc3b198ca4db3dfcc79e3cb397c084a0aff97b85c0bf38',
'org.briarproject:jtorctl:0.5:jtorctl-0.5.jar:43f8c7d390169772b9a2c82ab806c8414c136a2a8636c555e22754bb7260793b',
'org.briarproject:null-safety:0.1:null-safety-0.1.jar:161760de5e838cb982bafa973df820675d4397098e9a91637a36a306d43ba011',
'org.briarproject:socks-socket:0.1:socks-socket-0.1.jar:e5898822d10f5390363c5dddb945891648c92cf93ba50709e07f0d173ec0eb4b',
'org.checkerframework:checker-compat-qual:2.5.3:checker-compat-qual-2.5.3.jar:d76b9afea61c7c082908023f0cbc1427fab9abd2df915c8b8a3e7a509bccbc6d',
'org.checkerframework:checker-qual:2.5.2:checker-qual-2.5.2.jar:64b02691c8b9d4e7700f8ee2e742dce7ea2c6e81e662b7522c9ee3bf568c040a',
'org.codehaus.mojo.signature:java16:1.1:java16-1.1.signature:53799223a2c98dba2d0add810bed76315460df285c69e4f397ae6098f87dd619',
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment