SocksSocketFactory.java

 1package eu.siacs.conversations.utils;
 2
 3import java.io.IOException;
 4import java.io.InputStream;
 5import java.io.OutputStream;
 6import java.net.InetAddress;
 7import java.net.InetSocketAddress;
 8import java.net.Socket;
 9import java.nio.ByteBuffer;
10
11import eu.siacs.conversations.Config;
12
13public class SocksSocketFactory {
14
15	private static final byte[] LOCALHOST = new byte[]{127,0,0,1};
16
17	public static void createSocksConnection(final Socket socket, final String destination, final int port) throws IOException {
18		final InputStream proxyIs = socket.getInputStream();
19		final OutputStream proxyOs = socket.getOutputStream();
20		proxyOs.write(new byte[]{0x05, 0x01, 0x00});
21		proxyOs.flush();
22		final byte[] handshake = new byte[2];
23		proxyIs.read(handshake);
24		if (handshake[0] != 0x05 || handshake[1] != 0x00) {
25			throw new SocksConnectionException("Socks 5 handshake failed");
26		}
27		final byte[] dest = destination.getBytes();
28		final ByteBuffer request = ByteBuffer.allocate(7 + dest.length);
29		request.put(new byte[]{0x05, 0x01, 0x00, 0x03});
30		request.put((byte) dest.length);
31		request.put(dest);
32		request.putShort((short) port);
33		proxyOs.write(request.array());
34		proxyOs.flush();
35		final byte[] response = new byte[7 + dest.length];
36		proxyIs.read(response);
37		if (response[1] != 0x00) {
38			if (response[1] == 0x04) {
39				throw new HostNotFoundException("Host unreachable");
40			}
41			if (response[1] == 0x05) {
42				throw new HostNotFoundException("Connection refused");
43			}
44			throw new SocksConnectionException("Unable to connect to destination "+(int) (response[1]));
45		}
46	}
47
48	public static boolean contains(byte needle, byte[] haystack) {
49		for(byte hay : haystack) {
50			if (hay == needle) {
51				return true;
52			}
53		}
54		return false;
55	}
56
57	private static Socket createSocket(InetSocketAddress address, String destination, int port) throws IOException {
58		Socket socket = new Socket();
59		try {
60			socket.connect(address, Config.CONNECT_TIMEOUT * 1000);
61		} catch (IOException e) {
62			throw new SocksProxyNotFoundException();
63		}
64		createSocksConnection(socket, destination, port);
65		return socket;
66	}
67
68	public static Socket createSocketOverTor(String destination, int port) throws IOException {
69		return createSocket(new InetSocketAddress(InetAddress.getByAddress(LOCALHOST), 9050), destination, port);
70	}
71
72	private static class SocksConnectionException extends IOException {
73		SocksConnectionException(String message) {
74			super(message);
75		}
76	}
77
78	public static class SocksProxyNotFoundException extends IOException {
79
80	}
81
82	public static class HostNotFoundException extends SocksConnectionException {
83		HostNotFoundException(String message) {
84			super(message);
85		}
86	}
87}