package eu.siacs.conversations.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 eu.siacs.conversations.Config; public class SocksSocketFactory { private static final byte[] LOCALHOST = new byte[]{127,0,0,1}; 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.getByAddress(LOCALHOST), 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); } } }