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}