aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/java/de/pixart/messenger/utils/SocksSocketFactory.java
blob: 2e060594b5432fb71237d7699b65e6c79fabadc8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
package de.pixart.messenger.utils;

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.nio.ByteBuffer;

import de.pixart.messenger.Config;

public class SocksSocketFactory {

    public static void createSocksConnection(final Socket socket, final String destination, final int port) throws IOException {
        final InputStream proxyIs = socket.getInputStream();
        final OutputStream proxyOs = socket.getOutputStream();
        proxyOs.write(new byte[]{0x05, 0x01, 0x00});
        proxyOs.flush();
        final byte[] handshake = new byte[2];
        proxyIs.read(handshake);
        if (handshake[0] != 0x05 || handshake[1] != 0x00) {
            throw new SocksConnectionException("Socks 5 handshake failed");
        }
        final byte[] dest = destination.getBytes();
        final ByteBuffer request = ByteBuffer.allocate(7 + dest.length);
        request.put(new byte[]{0x05, 0x01, 0x00, 0x03});
        request.put((byte) dest.length);
        request.put(dest);
        request.putShort((short) port);
        proxyOs.write(request.array());
        proxyOs.flush();
        final byte[] response = new byte[7 + dest.length];
        proxyIs.read(response);
        if (response[1] != 0x00) {
            if (response[1] == 0x04) {
                throw new HostNotFoundException("Host unreachable");
            }
            if (response[1] == 0x05) {
                throw new HostNotFoundException("Connection refused");
            }
            throw new SocksConnectionException("Unable to connect to destination " + (int) (response[1]));
        }
    }

    public static boolean contains(byte needle, byte[] haystack) {
        for (byte hay : haystack) {
            if (hay == needle) {
                return true;
            }
        }
        return false;
    }

    private static Socket createSocket(InetSocketAddress address, String destination, int port) throws IOException {
        Socket socket = new Socket();
        try {
            socket.connect(address, Config.CONNECT_TIMEOUT * 1000);
        } catch (IOException e) {
            throw new SocksProxyNotFoundException();
        }
        createSocksConnection(socket, destination, port);
        return socket;
    }

    public static Socket createSocketOverTor(String destination, int port) throws IOException {
        return createSocket(new InetSocketAddress(InetAddress.getLocalHost(), 9050), destination, port);
    }

    private static class SocksConnectionException extends IOException {
        SocksConnectionException(String message) {
            super(message);
        }
    }

    public static class SocksProxyNotFoundException extends IOException {

    }

    public static class HostNotFoundException extends SocksConnectionException {
        HostNotFoundException(String message) {
            super(message);
        }
    }
}