package net.sourceforge.jsocks; import java.io.IOException; import java.io.InputStream; import java.io.InterruptedIOException; import java.io.OutputStream; import java.net.InetAddress; import java.net.Socket; import java.net.UnknownHostException; /** * Abstract class Proxy, base for classes Socks4Proxy and Socks5Proxy. Defines * methods for specifying default proxy, to be used by all classes of this * package. */ public abstract class Proxy { // Data members // protected InetRange directHosts = new InetRange(); public static final int SOCKS_SUCCESS = 0; public static final int SOCKS_FAILURE = 1; public static final int SOCKS_BADCONNECT = 2; public static final int SOCKS_BADNETWORK = 3; public static final int SOCKS_HOST_UNREACHABLE = 4; public static final int SOCKS_CONNECTION_REFUSED = 5; public static final int SOCKS_TTL_EXPIRE = 6; public static final int SOCKS_CMD_NOT_SUPPORTED = 7; public static final int SOCKS_ADDR_NOT_SUPPORTED = 8; public static final int SOCKS_NO_PROXY = 1 << 16; public static final int SOCKS_PROXY_NO_CONNECT = 2 << 16; public static final int SOCKS_PROXY_IO_ERROR = 3 << 16; public static final int SOCKS_AUTH_NOT_SUPPORTED = 4 << 16; // Public instance methods // ======================== public static final int SOCKS_AUTH_FAILURE = 5 << 16; public static final int SOCKS_JUST_ERROR = 6 << 16; public static final int SOCKS_DIRECT_FAILED = 7 << 16; // Public Static(Class) Methods // ============================== public static final int SOCKS_METHOD_NOTSUPPORTED = 8 << 16; public static final int SOCKS_CMD_CONNECT = 0x1; static final int SOCKS_CMD_BIND = 0x2; static final int SOCKS_CMD_UDP_ASSOCIATE = 0x3; /** * Get current default proxy. * * @return Current default proxy, or null if none is set. */ public static Proxy getDefaultProxy() { return defaultProxy; } /** * Parses strings in the form: host[:port:user:password], and creates proxy * from information obtained from parsing. * <p> * Defaults: port = 1080.<br> * If user specified but not password, creates Socks4Proxy, if user not * specified creates Socks5Proxy, if both user and password are speciefied * creates Socks5Proxy with user/password authentication. * * @param proxy_entry * String in the form host[:port:user:password] * @return Proxy created from the string, null if entry was somehow * invalid(host unknown for example, or empty string) */ public static Proxy parseProxy(String proxy_entry) { String proxy_host; int proxy_port = 1080; String proxy_user = null; String proxy_password = null; Proxy proxy; java.util.StringTokenizer st = new java.util.StringTokenizer( proxy_entry, ":"); if (st.countTokens() < 1) return null; proxy_host = st.nextToken(); if (st.hasMoreTokens()) try { proxy_port = Integer.parseInt(st.nextToken().trim()); } catch (NumberFormatException nfe) { } if (st.hasMoreTokens()) proxy_user = st.nextToken(); if (st.hasMoreTokens()) proxy_password = st.nextToken(); try { if (proxy_user == null) proxy = new Socks5Proxy(proxy_host, proxy_port); else if (proxy_password == null) proxy = new Socks4Proxy(proxy_host, proxy_port, proxy_user); else { proxy = new Socks5Proxy(proxy_host, proxy_port); /* * UserPasswordAuthentication upa = new * UserPasswordAuthentication( proxy_user, proxy_password); * * ((Socks5Proxy)proxy).setAuthenticationMethod(upa.METHOD_ID,upa * ); */ } } catch (UnknownHostException uhe) { return null; } return proxy; } /** * Sets SOCKS5 proxy as default. Default proxy only supports * no-authentication. * * @param ipAddress * Host address on which SOCKS5 server is running. * @param port * Port on which SOCKS5 server is running. */ public static void setDefaultProxy(InetAddress ipAddress, int port) { defaultProxy = new Socks5Proxy(ipAddress, port); } // Protected Methods // ================= /** * Sets SOCKS4 proxy as default. * * @param ipAddress * Host address on which SOCKS4 server is running. * @param port * Port on which SOCKS4 server is running. * @param user * Username to use for communications with proxy. */ public static void setDefaultProxy(InetAddress ipAddress, int port, String user) { defaultProxy = new Socks4Proxy(ipAddress, port, user); } /** * Sets default proxy. * * @param p * Proxy to use as default proxy. */ public static void setDefaultProxy(Proxy p) { defaultProxy = p; } /** * Sets SOCKS5 proxy as default. Default proxy only supports * no-authentication. * * @param hostName * Host name on which SOCKS5 server is running. * @param port * Port on which SOCKS5 server is running. */ public static void setDefaultProxy(String hostName, int port) throws UnknownHostException { defaultProxy = new Socks5Proxy(hostName, port); } /** * Sets SOCKS4 proxy as default. * * @param hostName * Host name on which SOCKS4 server is running. * @param port * Port on which SOCKS4 server is running. * @param user * Username to use for communications with proxy. */ public static void setDefaultProxy(String hostName, int port, String user) throws UnknownHostException { defaultProxy = new Socks4Proxy(hostName, port, user); } protected InetAddress proxyIP = null; protected String proxyHost = null; protected int proxyPort; protected Socket proxySocket = null; protected InputStream in; protected OutputStream out; protected int version; protected Proxy chainProxy = null; // Protected static/class variables protected static Proxy defaultProxy = null; Proxy(InetAddress proxyIP, int proxyPort) { this.proxyIP = proxyIP; this.proxyPort = proxyPort; } Proxy(Proxy p) { this.proxyIP = p.proxyIP; this.proxyPort = p.proxyPort; this.version = p.version; } Proxy(Proxy chainProxy, InetAddress proxyIP, int proxyPort) { this.chainProxy = chainProxy; this.proxyIP = proxyIP; this.proxyPort = proxyPort; } // Private methods // =============== // Constants // Constructors // ==================== Proxy(String proxyHost, int proxyPort) throws UnknownHostException { this.proxyHost = proxyHost; this.proxyIP = InetAddress.getByName(proxyHost); this.proxyPort = proxyPort; } protected ProxyMessage accept() throws IOException, SocksException { ProxyMessage msg; try { msg = formMessage(in); } catch (InterruptedIOException iioe) { throw iioe; } catch (IOException io_ex) { endSession(); throw new SocksException(SOCKS_PROXY_IO_ERROR, "While Trying accept:" + io_ex); } return msg; } protected ProxyMessage bind(InetAddress ip, int port) throws SocksException { try { startSession(); ProxyMessage request = formMessage(SOCKS_CMD_BIND, ip, port); return exchange(request); } catch (SocksException se) { endSession(); throw se; } } protected ProxyMessage bind(String host, int port) throws UnknownHostException, SocksException { try { startSession(); ProxyMessage request = formMessage(SOCKS_CMD_BIND, host, port); return exchange(request); } catch (SocksException se) { endSession(); throw se; } } protected ProxyMessage connect(InetAddress ip, int port) throws SocksException { try { startSession(); ProxyMessage request = formMessage(SOCKS_CMD_CONNECT, ip, port); return exchange(request); } catch (SocksException se) { endSession(); throw se; } } protected ProxyMessage connect(String host, int port) throws UnknownHostException, SocksException { try { startSession(); ProxyMessage request = formMessage(SOCKS_CMD_CONNECT, host, port); return exchange(request); } catch (SocksException se) { endSession(); throw se; } } protected abstract Proxy copy(); protected void endSession() { try { if (proxySocket != null) proxySocket.close(); proxySocket = null; } catch (IOException io_ex) { } } /** * Sends the request reads reply and returns it throws exception if * something wrong with IO or the reply code is not zero */ protected ProxyMessage exchange(ProxyMessage request) throws SocksException { ProxyMessage reply; try { request.write(out); reply = formMessage(in); } catch (SocksException s_ex) { throw s_ex; } catch (IOException ioe) { throw (new SocksException(SOCKS_PROXY_IO_ERROR, "" + ioe)); } return reply; } protected abstract ProxyMessage formMessage(InputStream in) throws SocksException, IOException; protected abstract ProxyMessage formMessage(int cmd, InetAddress ip, int port); protected abstract ProxyMessage formMessage(int cmd, String host, int port) throws UnknownHostException; /** * Get the ip address of the proxy server host. * * @return Proxy InetAddress. */ public InetAddress getInetAddress() { return proxyIP; } /** * Get the port on which proxy server is running. * * @return Proxy port. */ public int getPort() { return proxyPort; } /** * Reads the reply from the SOCKS server */ protected ProxyMessage readMsg() throws SocksException, IOException { return formMessage(in); } /** * Sends the request to SOCKS server */ protected void sendMsg(ProxyMessage msg) throws SocksException, IOException { msg.write(out); } protected void startSession() throws SocksException { try { proxySocket = new Socket(proxyIP, proxyPort); in = proxySocket.getInputStream(); out = proxySocket.getOutputStream(); } catch (SocksException se) { throw se; } catch (IOException io_ex) { throw new SocksException(SOCKS_PROXY_IO_ERROR, "" + io_ex); } } /** * Get string representation of this proxy. * * @returns string in the form:proxyHost:proxyPort \t Version versionNumber */ @Override public String toString() { return ("" + proxyIP.getHostName() + ":" + proxyPort + "\tVersion " + version); } protected ProxyMessage udpAssociate(InetAddress ip, int port) throws SocksException { try { startSession(); ProxyMessage request = formMessage(SOCKS_CMD_UDP_ASSOCIATE, ip, port); if (request != null) return exchange(request); } catch (SocksException se) { endSession(); throw se; } // Only get here if request was null endSession(); throw new SocksException(SOCKS_METHOD_NOTSUPPORTED, "This version of proxy does not support UDP associate, use version 5"); } protected ProxyMessage udpAssociate(String host, int port) throws UnknownHostException, SocksException { try { startSession(); ProxyMessage request = formMessage(SOCKS_CMD_UDP_ASSOCIATE, host, port); if (request != null) return exchange(request); } catch (SocksException se) { endSession(); throw se; } // Only get here if request was null endSession(); throw new SocksException(SOCKS_METHOD_NOTSUPPORTED, "This version of proxy does not support UDP associate, use version 5"); } }