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