Mercurial > 510Connectbot
changeset 349:205ee2873330
update jsocks to 2011-03-19
line wrap: on
line diff
--- a/TODO Fri Aug 01 10:25:44 2014 -0700 +++ b/TODO Fri Aug 01 11:23:10 2014 -0700 @@ -51,8 +51,14 @@ ================================== +update jsocks to 2011-03-19 version + +================================== + TODO: +change all System.*.println -> android log.d() calls + possible merge of irssi? https://github.com/irssiconnectbot/irssiconnectbot
--- a/src/net/sourceforge/jsocks/Authentication.java Fri Aug 01 10:25:44 2014 -0700 +++ b/src/net/sourceforge/jsocks/Authentication.java Fri Aug 01 11:23:10 2014 -0700 @@ -1,34 +1,34 @@ -package net.sourceforge.jsocks; - -/** - The Authentication interface provides for performing method specific - authentication for SOCKS5 connections. -*/ -public interface Authentication { - /** - This method is called when SOCKS5 server have selected a particular - authentication method, for whch an implementaion have been registered. - - <p> - This method should return an array {inputstream,outputstream - [,UDPEncapsulation]}. The reason for that is that SOCKS5 protocol - allows to have method specific encapsulation of data on the socket for - purposes of integrity or security. And this encapsulation should be - performed by those streams returned from the method. It is also possible - to encapsulate datagrams. If authentication method supports such - encapsulation an instance of the UDPEncapsulation interface should be - returned as third element of the array, otherwise either null should be - returned as third element, or array should contain only 2 elements. - - @param methodId Authentication method selected by the server. - @param proxySocket Socket used to conect to the proxy. - @return Two or three element array containing - Input/Output streams which should be used on this connection. - Third argument is optional and should contain an instance - of UDPEncapsulation. It should be provided if the authentication - method used requires any encapsulation to be done on the - datagrams. - */ - Object[] doSocksAuthentication(int methodId, java.net.Socket proxySocket) - throws java.io.IOException; -} +package net.sourceforge.jsocks; + +/** + The Authentication interface provides for performing method specific + authentication for SOCKS5 connections. +*/ +public interface Authentication{ + /** + This method is called when SOCKS5 server have selected a particular + authentication method, for whch an implementaion have been registered. + + <p> + This method should return an array {inputstream,outputstream + [,UDPEncapsulation]}. The reason for that is that SOCKS5 protocol + allows to have method specific encapsulation of data on the socket for + purposes of integrity or security. And this encapsulation should be + performed by those streams returned from the method. It is also possible + to encapsulate datagrams. If authentication method supports such + encapsulation an instance of the UDPEncapsulation interface should be + returned as third element of the array, otherwise either null should be + returned as third element, or array should contain only 2 elements. + + @param methodId Authentication method selected by the server. + @param proxySocket Socket used to conect to the proxy. + @return Two or three element array containing + Input/Output streams which should be used on this connection. + Third argument is optional and should contain an instance + of UDPEncapsulation. It should be provided if the authentication + method used requires any encapsulation to be done on the + datagrams. + */ + Object[] doSocksAuthentication(int methodId,java.net.Socket proxySocket) + throws java.io.IOException; +}
--- a/src/net/sourceforge/jsocks/AuthenticationNone.java Fri Aug 01 10:25:44 2014 -0700 +++ b/src/net/sourceforge/jsocks/AuthenticationNone.java Fri Aug 01 11:23:10 2014 -0700 @@ -1,17 +1,17 @@ -package net.sourceforge.jsocks; - -/** - SOCKS5 none authentication. Dummy class does almost nothing. -*/ -public class AuthenticationNone implements Authentication { - - public Object[] doSocksAuthentication(int methodId, - java.net.Socket proxySocket) - throws java.io.IOException { - if (methodId != 0) return null; - - return new Object[] { proxySocket.getInputStream(), - proxySocket.getOutputStream() - }; - } -} +package net.sourceforge.jsocks; + +/** + SOCKS5 none authentication. Dummy class does almost nothing. +*/ +public class AuthenticationNone implements Authentication{ + + public Object[] doSocksAuthentication(int methodId, + java.net.Socket proxySocket) + throws java.io.IOException{ + + if(methodId!=0) return null; + + return new Object[] { proxySocket.getInputStream(), + proxySocket.getOutputStream()}; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/net/sourceforge/jsocks/CProxy.java Fri Aug 01 11:23:10 2014 -0700 @@ -0,0 +1,488 @@ +package net.sourceforge.jsocks; +import java.net.*; +import java.io.*; +import java.util.Hashtable; +import java.util.Enumeration; + +/** + Abstract class CProxy, base for classes Socks4Proxy and Socks5Proxy. + Defines methods for specifying default proxy, to be + used by all classes of this package. +*/ + +public abstract class CProxy{ + +//Data members + protected InetRange directHosts = new InetRange(); + + 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 CProxy chainProxy = null; + + +//Protected static/class variables + protected static CProxy defaultProxy = null; + +//Constructors +//==================== + CProxy(CProxy chainProxy, + String proxyHost,int proxyPort)throws UnknownHostException{ + this.chainProxy = chainProxy; + this.proxyHost = proxyHost; + + if(chainProxy == null) + this.proxyIP = InetAddress.getByName(proxyHost); + + this.proxyPort = proxyPort; + } + + + CProxy(String proxyHost,int proxyPort)throws UnknownHostException{ + this(null,proxyHost,proxyPort); + } + + CProxy(CProxy chainProxy,InetAddress proxyIP,int proxyPort){ + this.chainProxy = chainProxy; + this.proxyIP = proxyIP; + this.proxyPort = proxyPort; + } + + CProxy(InetAddress proxyIP,int proxyPort){ + this(null,proxyIP,proxyPort); + } + + CProxy(CProxy p){ + this.proxyIP = p.proxyIP; + this.proxyPort = p.proxyPort; + this.version = p.version; + this.directHosts = p.directHosts; + } + +//Public instance methods +//======================== + + /** + Get the port on which proxy server is running. + * @return CProxy port. + */ + public int getPort(){ + return proxyPort; + } + /** + Get the ip address of the proxy server host. + * @return CProxy InetAddress. + */ + public InetAddress getInetAddress(){ + return proxyIP; + } + /** + * Adds given ip to the list of direct addresses. + * This machine will be accessed without using proxy. + */ + public void addDirect(InetAddress ip){ + directHosts.add(ip); + } + /** + * Adds host to the list of direct addresses. + * This machine will be accessed without using proxy. + */ + public boolean addDirect(String host){ + return directHosts.add(host); + } + /** + * Adds given range of addresses to the lsit of direct addresses, + * machines within this range will be accessed without using proxy. + */ + public void addDirect(InetAddress from,InetAddress to){ + directHosts.add(from,to); + } + /** + * Sets given InetRange as the list of direct address, previous + * list will be discarded, any changes done previously with + * addDirect(Inetaddress) will be lost. + * The machines in this range will be accessed without using proxy. + * @param ir InetRange which should be used to look up direct addresses. + * @see InetRange + */ + public void setDirect(InetRange ir){ + directHosts = ir; + } + + /** + Get the list of direct hosts. + * @return Current range of direct address as InetRange object. + * @see InetRange + */ + public InetRange getDirect(){ + return directHosts; + } + /** + Check wether the given host is on the list of direct address. + @param host Host name to check. + * @return true if the given host is specified as the direct addresses. + */ + public boolean isDirect(String host){ + return directHosts.contains(host); + } + /** + Check wether the given host is on the list of direct addresses. + @param host Host address to check. + * @return true if the given host is specified as the direct address. + */ + public boolean isDirect(InetAddress host){ + return directHosts.contains(host); + } + /** + Set the proxy which should be used to connect to given proxy. + @param chainProxy CProxy to use to connect to this proxy. + */ + public void setChainProxy(CProxy chainProxy){ + this.chainProxy = chainProxy; + } + + /** + Get proxy which is used to connect to this proxy. + @return CProxy which is used to connect to this proxy, or null + if proxy is to be contacted directly. + */ + public CProxy getChainProxy(){ + return chainProxy; + } + + /** + Get string representation of this proxy. + * @returns string in the form:proxyHost:proxyPort \t Version versionNumber + */ + public String toString(){ + return (""+proxyIP.getHostName()+":"+proxyPort+"\tVersion "+version); + } + + +//Public Static(Class) Methods +//============================== + + /** + * 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); + } + + /** + * 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 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 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); + } + /** + * Sets default proxy. + @param p CProxy to use as default proxy. + */ + public static void setDefaultProxy(CProxy p){ + defaultProxy = p; + } + + /** + Get current default proxy. + * @return Current default proxy, or null if none is set. + */ + public static CProxy 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 CProxy created from the string, null if entry was somehow + invalid(host unknown for example, or empty string) + */ + public static CProxy parseProxy(String proxy_entry){ + + String proxy_host; + int proxy_port = 1080; + String proxy_user = null; + String proxy_password = null; + CProxy 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; + } + + +//Protected Methods +//================= + + protected void startSession()throws SocksException{ + try{ + if(chainProxy == null) + proxySocket = new Socket(proxyIP,proxyPort); + else if(proxyIP != null) + proxySocket = new SocksSocket(chainProxy,proxyIP,proxyPort); + else + proxySocket = new SocksSocket(chainProxy,proxyHost,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); + } + } + + protected abstract CProxy copy(); + protected abstract ProxyMessage formMessage(int cmd,InetAddress ip,int port); + protected abstract ProxyMessage formMessage(int cmd,String host,int port) + throws UnknownHostException; + protected abstract ProxyMessage formMessage(InputStream in) + throws SocksException, + IOException; + + + 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 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 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 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"); + } + + + protected void endSession(){ + try{ + if(proxySocket!=null) proxySocket.close(); + proxySocket = null; + }catch(IOException io_ex){ + } + } + + /** + *Sends the request to SOCKS server + */ + protected void sendMsg(ProxyMessage msg)throws SocksException, + IOException{ + msg.write(out); + } + + /** + * Reads the reply from the SOCKS server + */ + protected ProxyMessage readMsg()throws SocksException, + IOException{ + return formMessage(in); + } + /** + *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; + } + + +//Private methods +//=============== + + +//Constants + + 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 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 final int SOCKS_METHOD_NOTSUPPORTED =8<<16; + + + static final int SOCKS_CMD_CONNECT =0x1; + static final int SOCKS_CMD_BIND =0x2; + static final int SOCKS_CMD_UDP_ASSOCIATE =0x3; + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/net/sourceforge/jsocks/InetRange.java Fri Aug 01 11:23:10 2014 -0700 @@ -0,0 +1,440 @@ +package net.sourceforge.jsocks; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.*; + +/** + * Class InetRange provides the means of defining the range of inetaddresses. + * It's used by Proxy class to store and look up addresses of machines, that + * should be contacted directly rather then through the proxy. + * <P> + * InetRange provides several methods to add either standalone addresses, or + * ranges (e.g. 100.200.300.0:100.200.300.255, which covers all addresses + * on on someones local network). It also provides methods for checking wether + * given address is in this range. Any number of ranges and standalone + * addresses can be added to the range. + */ +public class InetRange implements Cloneable{ + + Hashtable host_names; + Vector all; + Vector end_names; + + boolean useSeparateThread = true; + + /** + * Creates the empty range. + */ + public InetRange(){ + all = new Vector(); + host_names = new Hashtable(); + end_names = new Vector(); + } + + /** + * Adds another host or range to this range. + The String can be one of those: + <UL> + <li> Host name. eg.(Athena.myhost.com or 45.54.56.65) + + <li> Range in the form .myhost.net.au <BR> + In which case anything that ends with .myhost.net.au will + be considered in the range. + + <li> Range in the form ddd.ddd.ddd. <BR> + This will be treated as range ddd.ddd.ddd.0 to ddd.ddd.ddd.255. + It is not necessary to specify 3 first bytes you can use just + one or two. For example 130. will cover address between 130.0.0.0 + and 13.255.255.255. + + <li> Range in the form host_from[: \t\n\r\f]host_to. <br> + That is two hostnames or ips separated by either whitespace + or colon. + </UL> + */ + public synchronized boolean add(String s){ + if(s == null) return false; + + s = s.trim(); + if(s.length() == 0) return false; + + Object[] entry; + + if(s.charAt(s.length()-1) == '.'){ + //thing like: 111.222.33. + //it is being treated as range 111.222.33.000 - 111.222.33.255 + + int[] addr = ip2intarray(s); + long from,to; + from = to = 0; + + if(addr == null) return false; + for(int i = 0; i< 4;++i){ + if(addr[i]>=0) + from += (((long)addr[i]) << 8*(3-i)); + else{ + to = from; + while(i<4) + to += 255l << 8*(3-i++); + break; + } + } + entry = new Object[] {s,null,new Long(from),new Long(to)}; + all.addElement(entry); + + }else if(s.charAt(0) == '.'){ + //Thing like: .myhost.com + + end_names.addElement(s); + all.addElement(new Object[]{s,null,null,null}); + }else{ + StringTokenizer tokens = new StringTokenizer(s," \t\r\n\f:"); + if(tokens.countTokens() > 1){ + entry = new Object[] {s,null,null,null}; + resolve(entry,tokens.nextToken(),tokens.nextToken()); + all.addElement(entry); + }else{ + entry = new Object[] {s,null,null,null}; + all.addElement(entry); + host_names.put(s,entry); + resolve(entry); + } + + } + + return true; + } + + /** + * Adds another ip for this range. + @param ip IP os the host which should be added to this range. + */ + public synchronized void add(InetAddress ip){ + long from, to; + from = to = ip2long(ip); + all.addElement(new Object[]{ip.getHostName(),ip,new Long(from), + new Long(to)}); + } + + /** + * Adds another range of ips for this range.Any host with ip address + greater than or equal to the address of from and smaller than or equal + to the address of to will be included in the range. + @param from IP from where range starts(including). + @param to IP where range ends(including). + */ + public synchronized void add(InetAddress from,InetAddress to){ + all.addElement(new Object[]{from.getHostAddress()+":"+to.getHostAddress() + ,null,new Long(ip2long(from)), + new Long(ip2long(to))}); + } + + /** + * Checks wether the givan host is in the range. Attempts to resolve + host name if required. + @param host Host name to check. + @return true If host is in the range, false otherwise. + * @see InetRange#contains(String,boolean) + */ + public synchronized boolean contains(String host){ + return contains(host,true); + } + + /** + * Checks wether the given host is in the range. + * <P> + * Algorithm: <BR> + * <ol> + * <li>Look up if the hostname is in the range (in the Hashtable). + * <li>Check if it ends with one of the speciefied endings. + * <li>Check if it is ip(eg.130.220.35.98). If it is check if it is + * in the range. + * <li>If attemptResolve is true, host is name, rather than ip, and + * all previous attempts failed, try to resolve the hostname, and + * check wether the ip associated with the host is in the range.It + * also repeats all previos steps with the hostname obtained from + * InetAddress, but the name is not allways the full name,it is + * quite likely to be the same. Well it was on my machine. + * </ol> + @param host Host name to check. + @param attemptResolve Wether to lookup ip address which corresponds + to the host,if required. + @return true If host is in the range, false otherwise. + */ + public synchronized boolean contains(String host,boolean attemptResolve){ + if(all.size() ==0) return false; //Empty range + + host = host.trim(); + if(host.length() == 0) return false; + + if(checkHost(host)) return true; + if(checkHostEnding(host)) return true; + + long l = host2long(host); + if(l >=0) return contains(l); + + if(!attemptResolve) return false; + + try{ + InetAddress ip = InetAddress.getByName(host); + return contains(ip); + }catch(UnknownHostException uhe){ + + } + + return false; + } + + /** + * Checks wether the given ip is in the range. + @param ip Address of the host to check. + @return true If host is in the range, false otherwise. + */ + public synchronized boolean contains(InetAddress ip){ + if(checkHostEnding(ip.getHostName())) return true; + if(checkHost(ip.getHostName())) return true; + return contains(ip2long(ip)); + } + /** + Get all entries in the range as strings. <BR> + These strings can be used to delete entries from the range + with remove function. + @return Array of entries as strings. + @see InetRange#remove(String) + */ + public synchronized String[] getAll(){ + int size = all.size(); + Object entry[]; + String all_names[] = new String[size]; + + for(int i=0;i<size;++i){ + entry = (Object[]) all.elementAt(i); + all_names[i] = (String) entry[0]; + } + return all_names; + } + /** + Removes an entry from this range.<BR> + @param s Entry to remove. + @return true if successfull. + */ + public synchronized boolean remove(String s){ + Enumeration eEnum = all.elements(); + while(eEnum.hasMoreElements()){ + Object[] entry = (Object[]) eEnum.nextElement(); + if(s.equals(entry[0])){ + all.removeElement(entry); + end_names.removeElement(s); + host_names.remove(s); + return true; + } + } + return false; + } + + /** Get string representaion of this Range.*/ + public String toString(){ + String all[] = getAll(); + if(all.length == 0) return ""; + + String s = all[0]; + for(int i=1;i<all.length;++i) + s += "; "+all[i]; + return s; + } + + /** Creates a clone of this Object*/ + public Object clone(){ + InetRange new_range = new InetRange(); + new_range.all = (Vector)all.clone(); + new_range.end_names = (Vector) end_names.clone(); + new_range.host_names = (Hashtable)host_names.clone(); + return new_range; + } + + +//Private methods +///////////////// + /** + * Same as previous but used internally, to avoid + * unnecessary convertion of IPs, when checking subranges + */ + private synchronized boolean contains(long ip){ + Enumeration eEnum = all.elements(); + while(eEnum.hasMoreElements()){ + Object[] obj = (Object[]) eEnum.nextElement(); + Long from = obj[2]==null?null:(Long)obj[2]; + Long to = obj[3]==null?null:(Long)obj[3]; + if(from != null && from.longValue()<= ip + && to.longValue() >= ip) return true; + + } + return false; + } + + private boolean checkHost(String host){ + return host_names.containsKey(host); + } + private boolean checkHostEnding(String host){ + Enumeration eEnum = end_names.elements(); + while(eEnum.hasMoreElements()){ + if(host.endsWith((String) eEnum.nextElement())) return true; + } + return false; + } + private void resolve(Object[] entry){ + //First check if it's in the form ddd.ddd.ddd.ddd. + long ip = host2long((String) entry[0]); + if(ip >= 0){ + entry[2] = entry[3] = new Long(ip); + }else{ + InetRangeResolver res = new InetRangeResolver(entry); + res.resolve(useSeparateThread); + } + } + private void resolve(Object[] entry,String from,String to){ + long f,t; + if((f=host2long(from))>= 0 && (t=host2long(to)) >= 0){ + entry[2] = new Long(f); + entry[3] = new Long(t); + }else{ + InetRangeResolver res = new InetRangeResolver(entry,from,to); + res.resolve(useSeparateThread); + } + } + + + +//Class methods +/////////////// + + //Converts ipv4 to long value(unsigned int) + /////////////////////////////////////////// + static long ip2long(InetAddress ip){ + long l=0; + byte[] addr = ip.getAddress(); + + if(addr.length ==4){ //IPV4 + for(int i=0;i<4;++i) + l += (((long)addr[i] &0xFF) << 8*(3-i)); + }else{ //IPV6 + return 0; //Have no idea how to deal with those + } + return l; + } + + + long host2long(String host){ + long ip=0; + + //check if it's ddd.ddd.ddd.ddd + if(!Character.isDigit(host.charAt(0))) return -1; + + int[] addr = ip2intarray(host); + if(addr == null) return -1; + + for(int i=0;i<addr.length;++i) + ip += ((long)(addr[i]>=0 ? addr[i] : 0)) << 8*(3-i); + + return ip; + } + + static int[] ip2intarray(String host){ + int[] address = {-1,-1,-1,-1}; + int i=0; + StringTokenizer tokens = new StringTokenizer(host,"."); + if(tokens.countTokens() > 4) return null; + while(tokens.hasMoreTokens()){ + try{ + address[i++] = Integer.parseInt(tokens.nextToken()) & 0xFF; + }catch(NumberFormatException nfe){ + return null; + } + + } + return address; + } + + +/* +//* This was the test main function +//********************************** + + public static void main(String args[])throws UnknownHostException{ + int i; + + InetRange ir = new InetRange(); + + + for(i=0;i<args.length;++i){ + System.out.println("Adding:" + args[i]); + ir.add(args[i]); + } + + String host; + java.io.DataInputStream din = new java.io.DataInputStream(System.in); + try{ + host = din.readLine(); + while(host!=null){ + if(ir.contains(host)){ + System.out.println("Range contains ip:"+host); + }else{ + System.out.println(host+" is not in the range"); + } + host = din.readLine(); + } + }catch(java.io.IOException io_ex){ + io_ex.printStackTrace(); + } + } +********************/ + +} + + +class InetRangeResolver implements Runnable{ + + Object[] entry; + + String from, to; + + InetRangeResolver(Object[] entry){ + this.entry = entry; + from = to = null; + } + InetRangeResolver(Object[] entry,String from,String to){ + this.entry = entry; + this.from = from; + this.to = to; + } + public final void resolve(){ + resolve(true); + } + public final void resolve(boolean inSeparateThread){ + if(inSeparateThread){ + Thread t = new Thread(this); + t.start(); + }else + run(); + + } + public void run(){ + try{ + if(from == null){ + InetAddress ip = InetAddress.getByName((String) entry[0]); + entry[1] = ip; + Long l = new Long(InetRange.ip2long(ip)); + entry[2] = entry[3] = l; + }else{ + InetAddress f = InetAddress.getByName(from); + InetAddress t = InetAddress.getByName(to); + entry[2] = new Long(InetRange.ip2long(f)); + entry[3] = new Long(InetRange.ip2long(t)); + + } + }catch(UnknownHostException uhe){ + //System.err.println("Resolve failed for "+from+','+to+','+entry[0]); + } + } + +}
--- a/src/net/sourceforge/jsocks/Proxy.java Fri Aug 01 10:25:44 2014 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,428 +0,0 @@ -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(); - - 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; - -//Constructors -//==================== - Proxy(String proxyHost, int proxyPort) throws UnknownHostException { - this.proxyHost = proxyHost; - this.proxyIP = InetAddress.getByName(proxyHost); - this.proxyPort = proxyPort; - } - - Proxy(Proxy chainProxy, InetAddress proxyIP, int proxyPort) { - this.chainProxy = chainProxy; - this.proxyIP = proxyIP; - this.proxyPort = proxyPort; - } - - 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; - } - -//Public instance methods -//======================== - - /** - Get the port on which proxy server is running. - * @return Proxy port. - */ - public int getPort() { - return proxyPort; - } - /** - Get the ip address of the proxy server host. - * @return Proxy InetAddress. - */ - public InetAddress getInetAddress() { - return proxyIP; - } - - /** - Get string representation of this proxy. - * @returns string in the form:proxyHost:proxyPort \t Version versionNumber - */ - public String toString() { - return ("" + proxyIP.getHostName() + ":" + proxyPort + "\tVersion " + version); - } - - -//Public Static(Class) Methods -//============================== - - /** - * 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); - } - - /** - * 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 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 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); - } - /** - * Sets default proxy. - @param p Proxy to use as default proxy. - */ - public static void setDefaultProxy(Proxy p) { - defaultProxy = p; - } - - /** - 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; - } - - -//Protected Methods -//================= - - 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); - } - } - - protected abstract Proxy copy(); - protected abstract ProxyMessage formMessage(int cmd, InetAddress ip, int port); - protected abstract ProxyMessage formMessage(int cmd, String host, int port) - throws UnknownHostException; - protected abstract ProxyMessage formMessage(InputStream in) - throws SocksException, - IOException; - - - 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 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 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 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"); - } - - - protected void endSession() { - try { - if (proxySocket != null) proxySocket.close(); - - proxySocket = null; - } - catch (IOException io_ex) { - } - } - - /** - *Sends the request to SOCKS server - */ - protected void sendMsg(ProxyMessage msg)throws SocksException, - IOException { - msg.write(out); - } - - /** - * Reads the reply from the SOCKS server - */ - protected ProxyMessage readMsg()throws SocksException, - IOException { - return formMessage(in); - } - /** - *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; - } - - -//Private methods -//=============== - - -//Constants - - 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 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 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; - -}
--- a/src/net/sourceforge/jsocks/ProxyMessage.java Fri Aug 01 10:25:44 2014 -0700 +++ b/src/net/sourceforge/jsocks/ProxyMessage.java Fri Aug 01 11:23:10 2014 -0700 @@ -1,111 +1,110 @@ -package net.sourceforge.jsocks; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.InetAddress; -import java.net.UnknownHostException; - -/** - Abstract class which describes SOCKS4/5 response/request. -*/ -public abstract class ProxyMessage { - /** Host as an IP address */ - public InetAddress ip = null; - /** SOCKS version, or version of the response for SOCKS4*/ - public int version; - /** Port field of the request/response*/ - public int port; - /** Request/response code as an int*/ - public int command; - /** Host as string.*/ - public String host = null; - /** User field for SOCKS4 request messages*/ - public String user = null; - - ProxyMessage(int command, InetAddress ip, int port) { - this.command = command; - this.ip = ip; - this.port = port; - } - - ProxyMessage() { - } - - - /** - Initialises Message from the stream. Reads server response from - given stream. - @param in Input stream to read response from. - @throws SocksException If server response code is not SOCKS_SUCCESS(0), or - if any error with protocol occurs. - @throws IOException If any error happens with I/O. - */ - public abstract void read(InputStream in) - throws SocksException, - IOException; - - - /** - Initialises Message from the stream. Reads server response or client - request from given stream. - - @param in Input stream to read response from. - @param clinetMode If true read server response, else read client request. - @throws SocksException If server response code is not SOCKS_SUCCESS(0) and - reading in client mode, or if any error with protocol occurs. - @throws IOException If any error happens with I/O. - */ - public abstract void read(InputStream in, boolean client_mode) - throws SocksException, - IOException; - - - /** - Writes the message to the stream. - @param out Output stream to which message should be written. - */ - public abstract void write(OutputStream out)throws SocksException, - IOException; - - /** - Get the Address field of this message as InetAddress object. - @return Host address or null, if one can't be determined. - */ - public InetAddress getInetAddress() throws UnknownHostException { - return ip; - } - - - /** - Get string representaion of this message. - @return string representation of this message. - */ - public String toString() { - return - "Proxy Message:\n" + - "Version:" + version + "\n" + - "Command:" + command + "\n" + - "IP: " + ip + "\n" + - "Port: " + port + "\n" + - "User: " + user + "\n" ; - } - -//Package methods -////////////////// - - static final String bytes2IPV4(byte[] addr, int offset) { - String hostName = "" + (addr[offset] & 0xFF); - - for (int i = offset + 1; i < offset + 4; ++i) - hostName += "." + (addr[i] & 0xFF); - - return hostName; - } - - static final String bytes2IPV6(byte[] addr, int offset) { - //Have no idea how they look like! - return null; - } - -} +package net.sourceforge.jsocks; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.DataInputStream; +import java.net.InetAddress; +import java.net.UnknownHostException; + +/** + Abstract class which describes SOCKS4/5 response/request. +*/ +public abstract class ProxyMessage{ + /** Host as an IP address */ + public InetAddress ip=null; + /** SOCKS version, or version of the response for SOCKS4*/ + public int version; + /** Port field of the request/response*/ + public int port; + /** Request/response code as an int*/ + public int command; + /** Host as string.*/ + public String host=null; + /** User field for SOCKS4 request messages*/ + public String user=null; + + ProxyMessage(int command,InetAddress ip,int port){ + this.command = command; + this.ip = ip; + this.port = port; + } + + ProxyMessage(){ + } + + + /** + Initialises Message from the stream. Reads server response from + given stream. + @param in Input stream to read response from. + @throws SocksException If server response code is not SOCKS_SUCCESS(0), or + if any error with protocol occurs. + @throws IOException If any error happens with I/O. + */ + public abstract void read(InputStream in) + throws SocksException, + IOException; + + + /** + Initialises Message from the stream. Reads server response or client + request from given stream. + + @param in Input stream to read response from. + @param clinetMode If true read server response, else read client request. + @throws SocksException If server response code is not SOCKS_SUCCESS(0) and + reading in client mode, or if any error with protocol occurs. + @throws IOException If any error happens with I/O. + */ + public abstract void read(InputStream in,boolean client_mode) + throws SocksException, + IOException; + + + /** + Writes the message to the stream. + @param out Output stream to which message should be written. + */ + public abstract void write(OutputStream out)throws SocksException, + IOException; + + /** + Get the Address field of this message as InetAddress object. + @return Host address or null, if one can't be determined. + */ + public InetAddress getInetAddress() throws UnknownHostException{ + return ip; + } + + + /** + Get string representaion of this message. + @return string representation of this message. + */ + public String toString(){ + return + "Proxy Message:\n"+ + "Version:"+ version+"\n"+ + "Command:"+ command+"\n"+ + "IP: "+ ip+"\n"+ + "Port: "+ port+"\n"+ + "User: "+ user+"\n" ; + } + +//Package methods +////////////////// + + static final String bytes2IPV4(byte[] addr,int offset){ + String hostName = ""+(addr[offset] & 0xFF); + for(int i = offset+1;i<offset+4;++i) + hostName+="."+(addr[i] & 0xFF); + return hostName; + } + + static final String bytes2IPV6(byte[] addr,int offset){ + //Have no idea how they look like! + return null; + } + +}
--- a/src/net/sourceforge/jsocks/ProxyServer.java Fri Aug 01 10:25:44 2014 -0700 +++ b/src/net/sourceforge/jsocks/ProxyServer.java Fri Aug 01 11:23:10 2014 -0700 @@ -1,639 +1,604 @@ -package net.sourceforge.jsocks; -import java.io.EOFException; -import java.io.IOException; -import java.io.InputStream; -import java.io.InterruptedIOException; -import java.io.OutputStream; -import java.io.PrintStream; -import java.io.PushbackInputStream; -import java.net.ConnectException; -import java.net.InetAddress; -import java.net.NoRouteToHostException; -import java.net.ServerSocket; -import java.net.Socket; - -import net.sourceforge.jsocks.server.ServerAuthenticator; - -/** - SOCKS4 and SOCKS5 proxy, handles both protocols simultaniously. - Implements all SOCKS commands, including UDP relaying. - <p> - In order to use it you will need to implement ServerAuthenticator - interface. There is an implementation of this interface which does - no authentication ServerAuthenticatorNone, but it is very dangerous - to use, as it will give access to your local network to anybody - in the world. One should never use this authentication scheme unless - one have pretty good reason to do so. - There is a couple of other authentication schemes in socks.server package. - @see socks.server.ServerAuthenticator -*/ -public class ProxyServer implements Runnable { - - ServerAuthenticator auth; - ProxyMessage msg = null; - - Socket sock = null, remote_sock = null; - ServerSocket ss = null; - UDPRelayServer relayServer = null; - InputStream in, remote_in; - OutputStream out, remote_out; - - int mode; - static final int START_MODE = 0; - static final int ACCEPT_MODE = 1; - static final int PIPE_MODE = 2; - static final int ABORT_MODE = 3; - - static final int BUF_SIZE = 8192; - - Thread pipe_thread1, pipe_thread2; - long lastReadTime; - - protected static int iddleTimeout = 180000; //3 minutes - static int acceptTimeout = 180000; //3 minutes - - static PrintStream log = null; - static Proxy proxy; - - -//Public Constructors -///////////////////// - - - /** - Creates a proxy server with given Authentication scheme. - @param auth Authentication scheme to be used. - */ - public ProxyServer(ServerAuthenticator auth) { - this.auth = auth; - } - -//Other constructors -//////////////////// - - protected ProxyServer(ServerAuthenticator auth, Socket s) { - this.auth = auth; - this.sock = s; - mode = START_MODE; - } - -//Public methods -///////////////// - - /** - Set the logging stream. Specifying null disables logging. - */ - public static void setLog(OutputStream out) { - if (out == null) { - log = null; - } - else { - log = new PrintStream(out, true); - } - - UDPRelayServer.log = log; - } - - /** - Set proxy. - <p> - Allows Proxy chaining so that one Proxy server is connected to another - and so on. If proxy supports SOCKSv4, then only some SOCKSv5 requests - can be handled, UDP would not work, however CONNECT and BIND will be - translated. - - @param p Proxy which should be used to handle user requests. - */ - public static void setProxy(Proxy p) { - proxy = p; - UDPRelayServer.proxy = proxy; - } - - /** - Get proxy. - @return Proxy wich is used to handle user requests. - */ - public static Proxy getProxy() { - return proxy; - } - - /** - Sets the timeout for connections, how long shoud server wait - for data to arrive before dropping the connection.<br> - Zero timeout implies infinity.<br> - Default timeout is 3 minutes. - */ - public static void setIddleTimeout(int timeout) { - iddleTimeout = timeout; - } - /** - Sets the timeout for BIND command, how long the server should - wait for the incoming connection.<br> - Zero timeout implies infinity.<br> - Default timeout is 3 minutes. - */ - public static void setAcceptTimeout(int timeout) { - acceptTimeout = timeout; - } - - /** - Sets the timeout for UDPRelay server.<br> - Zero timeout implies infinity.<br> - Default timeout is 3 minutes. - */ - public static void setUDPTimeout(int timeout) { - UDPRelayServer.setTimeout(timeout); - } - - /** - Sets the size of the datagrams used in the UDPRelayServer.<br> - Default size is 64K, a bit more than maximum possible size of the - datagram. - */ - public static void setDatagramSize(int size) { - UDPRelayServer.setDatagramSize(size); - } - - - /** - Start the Proxy server at given port.<br> - This methods blocks. - */ - public void start(int port) { - start(port, 5, null); - } - - /** - Create a server with the specified port, listen backlog, and local - IP address to bind to. The localIP argument can be used on a multi-homed - host for a ServerSocket that will only accept connect requests to one of - its addresses. If localIP is null, it will default accepting connections - on any/all local addresses. The port must be between 0 and 65535, - inclusive. <br> - This methods blocks. - */ - public void start(int port, int backlog, InetAddress localIP) { - try { - ss = new ServerSocket(port, backlog, localIP); - log("Starting SOCKS Proxy on:" + ss.getInetAddress().getHostAddress() + ":" - + ss.getLocalPort()); - - while (true) { - Socket s = ss.accept(); - log("Accepted from:" + s.getInetAddress().getHostName() + ":" - + s.getPort()); - ProxyServer ps = new ProxyServer(auth, s); - (new Thread(ps)).start(); - } - } - catch (IOException ioe) { - ioe.printStackTrace(); - } - finally { - } - } - - /** - Stop server operation.It would be wise to interrupt thread running the - server afterwards. - */ - public void stop() { - try { - if (ss != null) ss.close(); - } - catch (IOException ioe) { - } - } - -//Runnable interface -//////////////////// - public void run() { - switch (mode) { - case START_MODE: - try { - startSession(); - } - catch (IOException ioe) { - handleException(ioe); - //ioe.printStackTrace(); - } - finally { - abort(); - - if (auth != null) auth.endSession(); - - log("Main thread(client->remote)stopped."); - } - - break; - - case ACCEPT_MODE: - try { - doAccept(); - mode = PIPE_MODE; - pipe_thread1.interrupt(); //Tell other thread that connection have - //been accepted. - pipe(remote_in, out); - } - catch (IOException ioe) { - //log("Accept exception:"+ioe); - handleException(ioe); - } - finally { - abort(); - log("Accept thread(remote->client) stopped"); - } - - break; - - case PIPE_MODE: - try { - pipe(remote_in, out); - } - catch (IOException ioe) { - } - finally { - abort(); - log("Support thread(remote->client) stopped"); - } - - break; - - case ABORT_MODE: - break; - - default: - log("Unexpected MODE " + mode); - } - } - -//Private methods -///////////////// - private void startSession() throws IOException { - sock.setSoTimeout(iddleTimeout); - - try { - auth = auth.startSession(sock); - } - catch (IOException ioe) { - log("Auth throwed exception:" + ioe); - auth = null; - return; - } - - if (auth == null) { //Authentication failed - log("Authentication failed"); - return; - } - - in = auth.getInputStream(); - out = auth.getOutputStream(); - msg = readMsg(in); - handleRequest(msg); - } - - protected void handleRequest(ProxyMessage msg) - throws IOException { - if (!auth.checkRequest(msg)) throw new - SocksException(Proxy.SOCKS_FAILURE); - - if (msg.ip == null) { - if (msg instanceof Socks5Message) { - msg.ip = InetAddress.getByName(msg.host); - } - else - throw new SocksException(Proxy.SOCKS_FAILURE); - } - - log(msg); - - switch (msg.command) { - case Proxy.SOCKS_CMD_CONNECT: - onConnect(msg); - break; - - case Proxy.SOCKS_CMD_BIND: - onBind(msg); - break; - - case Proxy.SOCKS_CMD_UDP_ASSOCIATE: - onUDP(msg); - break; - - default: - throw new SocksException(Proxy.SOCKS_CMD_NOT_SUPPORTED); - } - } - - private void handleException(IOException ioe) { - //If we couldn't read the request, return; - if (msg == null) return; - - //If have been aborted by other thread - if (mode == ABORT_MODE) return; - - //If the request was successfully completed, but exception happened later - if (mode == PIPE_MODE) return; - - int error_code = Proxy.SOCKS_FAILURE; - - if (ioe instanceof SocksException) - error_code = ((SocksException)ioe).errCode; - else if (ioe instanceof NoRouteToHostException) - error_code = Proxy.SOCKS_HOST_UNREACHABLE; - else if (ioe instanceof ConnectException) - error_code = Proxy.SOCKS_CONNECTION_REFUSED; - else if (ioe instanceof InterruptedIOException) - error_code = Proxy.SOCKS_TTL_EXPIRE; - - if (error_code > Proxy.SOCKS_ADDR_NOT_SUPPORTED || error_code < 0) { - error_code = Proxy.SOCKS_FAILURE; - } - - sendErrorMessage(error_code); - } - - private void onConnect(ProxyMessage msg) throws IOException { - Socket s; - ProxyMessage response = null; - s = new Socket(msg.ip, msg.port); - log("Connected to " + s.getInetAddress() + ":" + s.getPort()); - - if (msg instanceof Socks5Message) { - response = new Socks5Message(Proxy.SOCKS_SUCCESS, - s.getLocalAddress(), - s.getLocalPort()); - } - else { - response = new Socks4Message(Socks4Message.REPLY_OK, - s.getLocalAddress(), s.getLocalPort()); - } - - response.write(out); - startPipe(s); - } - - private void onBind(ProxyMessage msg) throws IOException { - ProxyMessage response = null; - - if (proxy == null) - ss = new ServerSocket(0); - else - ss = new SocksServerSocket(proxy, msg.ip, msg.port); - - ss.setSoTimeout(acceptTimeout); - log("Trying accept on " + ss.getInetAddress() + ":" + ss.getLocalPort()); - - if (msg.version == 5) - response = new Socks5Message(Proxy.SOCKS_SUCCESS, ss.getInetAddress(), - ss.getLocalPort()); - else - response = new Socks4Message(Socks4Message.REPLY_OK, - ss.getInetAddress(), - ss.getLocalPort()); - - response.write(out); - mode = ACCEPT_MODE; - pipe_thread1 = Thread.currentThread(); - pipe_thread2 = new Thread(this); - pipe_thread2.start(); - //Make timeout infinit. - sock.setSoTimeout(0); - int eof = 0; - - try { - while ((eof = in.read()) >= 0) { - if (mode != ACCEPT_MODE) { - if (mode != PIPE_MODE) return; //Accept failed - - remote_out.write(eof); - break; - } - } - } - catch (EOFException eofe) { - //System.out.println("EOF exception"); - return;//Connection closed while we were trying to accept. - } - catch (InterruptedIOException iioe) { - //Accept thread interrupted us. - //System.out.println("Interrupted"); - if (mode != PIPE_MODE) - return;//If accept thread was not successfull return. - } - finally { - //System.out.println("Finnaly!"); - } - - if (eof < 0) //Connection closed while we were trying to accept; - return; - - //Do not restore timeout, instead timeout is set on the - //remote socket. It does not make any difference. - pipe(in, remote_out); - } - - private void onUDP(ProxyMessage msg) throws IOException { - if (msg.ip.getHostAddress().equals("0.0.0.0")) - msg.ip = sock.getInetAddress(); - - log("Creating UDP relay server for " + msg.ip + ":" + msg.port); - relayServer = new UDPRelayServer(msg.ip, msg.port, - Thread.currentThread(), sock, auth); - ProxyMessage response; - response = new Socks5Message(Proxy.SOCKS_SUCCESS, - relayServer.relayIP, relayServer.relayPort); - response.write(out); - relayServer.start(); - //Make timeout infinit. - sock.setSoTimeout(0); - - try { - while (in.read() >= 0) /*do nothing*/; - } - catch (EOFException eofe) { - } - } - -//Private methods -////////////////// - - private void doAccept() throws IOException { - Socket s; - long startTime = System.currentTimeMillis(); - - while (true) { - s = ss.accept(); - - if (s.getInetAddress().equals(msg.ip)) { - //got the connection from the right host - //Close listenning socket. - ss.close(); - break; - } - else if (ss instanceof SocksServerSocket) { - //We can't accept more then one connection - s.close(); - ss.close(); - throw new SocksException(Proxy.SOCKS_FAILURE); - } - else { - if (acceptTimeout != 0) { //If timeout is not infinit - int newTimeout = acceptTimeout - (int)(System.currentTimeMillis() - - startTime); - - if (newTimeout <= 0) throw new InterruptedIOException( - "In doAccept()"); - - ss.setSoTimeout(newTimeout); - } - - s.close(); //Drop all connections from other hosts - } - } - - //Accepted connection - remote_sock = s; - remote_in = s.getInputStream(); - remote_out = s.getOutputStream(); - //Set timeout - remote_sock.setSoTimeout(iddleTimeout); - log("Accepted from " + s.getInetAddress() + ":" + s.getPort()); - ProxyMessage response; - - if (msg.version == 5) - response = new Socks5Message(Proxy.SOCKS_SUCCESS, s.getInetAddress(), - s.getPort()); - else - response = new Socks4Message(Socks4Message.REPLY_OK, - s.getInetAddress(), s.getPort()); - - response.write(out); - } - - protected ProxyMessage readMsg(InputStream in) throws IOException { - PushbackInputStream push_in; - - if (in instanceof PushbackInputStream) - push_in = (PushbackInputStream) in; - else - push_in = new PushbackInputStream(in); - - int version = push_in.read(); - push_in.unread(version); - ProxyMessage msg; - - if (version == 5) { - msg = new Socks5Message(push_in, false); - } - else if (version == 4) { - msg = new Socks4Message(push_in, false); - } - else { - throw new SocksException(Proxy.SOCKS_FAILURE); - } - - return msg; - } - - private void startPipe(Socket s) { - mode = PIPE_MODE; - remote_sock = s; - - try { - remote_in = s.getInputStream(); - remote_out = s.getOutputStream(); - pipe_thread1 = Thread.currentThread(); - pipe_thread2 = new Thread(this); - pipe_thread2.start(); - pipe(in, remote_out); - } - catch (IOException ioe) { - } - } - - private void sendErrorMessage(int error_code) { - ProxyMessage err_msg; - - if (msg instanceof Socks4Message) - err_msg = new Socks4Message(Socks4Message.REPLY_REJECTED); - else - err_msg = new Socks5Message(error_code); - - try { - err_msg.write(out); - } - catch (IOException ioe) {} - } - - private synchronized void abort() { - if (mode == ABORT_MODE) return; - - mode = ABORT_MODE; - - try { - log("Aborting operation"); - - if (remote_sock != null) remote_sock.close(); - - if (sock != null) sock.close(); - - if (relayServer != null) relayServer.stop(); - - if (ss != null) ss.close(); - - if (pipe_thread1 != null) pipe_thread1.interrupt(); - - if (pipe_thread2 != null) pipe_thread2.interrupt(); - } - catch (IOException ioe) {} - } - - static final void log(String s) { - if (log != null) { - log.println(s); - log.flush(); - } - } - - static final void log(ProxyMessage msg) { - log("Request version:" + msg.version + - "\tCommand: " + command2String(msg.command)); - log("IP:" + msg.ip + "\tPort:" + msg.port + - (msg.version == 4 ? "\tUser:" + msg.user : "")); - } - - private void pipe(InputStream in, OutputStream out) throws IOException { - lastReadTime = System.currentTimeMillis(); - byte[] buf = new byte[BUF_SIZE]; - int len = 0; - - while (len >= 0) { - try { - if (len != 0) { - out.write(buf, 0, len); - out.flush(); - } - - len = in.read(buf); - lastReadTime = System.currentTimeMillis(); - } - catch (InterruptedIOException iioe) { - if (iddleTimeout == 0) return; //Other thread interrupted us. - - long timeSinceRead = System.currentTimeMillis() - lastReadTime; - - if (timeSinceRead >= iddleTimeout - 1000) //-1s for adjustment. - return; - - len = 0; - } - } - } - static final String command_names[] = {"CONNECT", "BIND", "UDP_ASSOCIATE"}; - - static final String command2String(int cmd) { - if (cmd > 0 && cmd < 4) return command_names[cmd - 1]; - else return "Unknown Command " + cmd; - } -} +package net.sourceforge.jsocks; +import net.sourceforge.jsocks.server.ServerAuthenticator; +import java.net.*; +import java.io.*; + +/** + SOCKS4 and SOCKS5 proxy, handles both protocols simultaniously. + Implements all SOCKS commands, including UDP relaying. + <p> + In order to use it you will need to implement ServerAuthenticator + interface. There is an implementation of this interface which does + no authentication ServerAuthenticatorNone, but it is very dangerous + to use, as it will give access to your local network to anybody + in the world. One should never use this authentication scheme unless + one have pretty good reason to do so. + There is a couple of other authentication schemes in socks.server package. + @see socks.server.ServerAuthenticator +*/ +public class ProxyServer implements Runnable{ + + ServerAuthenticator auth; + ProxyMessage msg = null; + + Socket sock=null,remote_sock=null; + ServerSocket ss=null; + UDPRelayServer relayServer = null; + InputStream in,remote_in; + OutputStream out,remote_out; + + int mode; + static final int START_MODE = 0; + static final int ACCEPT_MODE = 1; + static final int PIPE_MODE = 2; + static final int ABORT_MODE = 3; + + static final int BUF_SIZE = 8192; + + Thread pipe_thread1,pipe_thread2; + long lastReadTime; + + static int iddleTimeout = 180000; //3 minutes + static int acceptTimeout = 180000; //3 minutes + + static PrintStream log = null; + static CProxy proxy; + + +//Public Constructors +///////////////////// + + + /** + Creates a proxy server with given Authentication scheme. + @param auth Authentication scheme to be used. + */ + public ProxyServer(ServerAuthenticator auth){ + this.auth = auth; + } + +//Other constructors +//////////////////// + + ProxyServer(ServerAuthenticator auth,Socket s){ + this.auth = auth; + this.sock = s; + mode = START_MODE; + } + +//Public methods +///////////////// + + /** + Set the logging stream. Specifying null disables logging. + */ + public static void setLog(OutputStream out){ + if(out == null){ + log = null; + }else{ + log = new PrintStream(out,true); + } + + UDPRelayServer.log = log; + } + + /** + Set proxy. + <p> + Allows CProxy chaining so that one CProxy server is connected to another + and so on. If proxy supports SOCKSv4, then only some SOCKSv5 requests + can be handled, UDP would not work, however CONNECT and BIND will be + translated. + + @param p CProxy which should be used to handle user requests. + */ + public static void setProxy(CProxy p){ + proxy =p; + UDPRelayServer.proxy = proxy; + } + + /** + Get proxy. + @return CProxy wich is used to handle user requests. + */ + public static CProxy getProxy(){ + return proxy; + } + + /** + Sets the timeout for connections, how long shoud server wait + for data to arrive before dropping the connection.<br> + Zero timeout implies infinity.<br> + Default timeout is 3 minutes. + */ + public static void setIddleTimeout(int timeout){ + iddleTimeout = timeout; + } + /** + Sets the timeout for BIND command, how long the server should + wait for the incoming connection.<br> + Zero timeout implies infinity.<br> + Default timeout is 3 minutes. + */ + public static void setAcceptTimeout(int timeout){ + acceptTimeout = timeout; + } + + /** + Sets the timeout for UDPRelay server.<br> + Zero timeout implies infinity.<br> + Default timeout is 3 minutes. + */ + public static void setUDPTimeout(int timeout){ + UDPRelayServer.setTimeout(timeout); + } + + /** + Sets the size of the datagrams used in the UDPRelayServer.<br> + Default size is 64K, a bit more than maximum possible size of the + datagram. + */ + public static void setDatagramSize(int size){ + UDPRelayServer.setDatagramSize(size); + } + + + /** + Start the CProxy server at given port.<br> + This methods blocks. + */ + public void start(int port){ + start(port,5,null); + } + + /** + Create a server with the specified port, listen backlog, and local + IP address to bind to. The localIP argument can be used on a multi-homed + host for a ServerSocket that will only accept connect requests to one of + its addresses. If localIP is null, it will default accepting connections + on any/all local addresses. The port must be between 0 and 65535, + inclusive. <br> + This methods blocks. + */ + public void start(int port,int backlog,InetAddress localIP){ + try{ + ss = new ServerSocket(port,backlog,localIP); + log("Starting SOCKS Proxy on:"+ss.getInetAddress().getHostAddress()+":" + +ss.getLocalPort()); + while(true){ + Socket s = ss.accept(); + log("Accepted from:"+s.getInetAddress().getHostName()+":" + +s.getPort()); + ProxyServer ps = new ProxyServer(auth,s); + (new Thread(ps)).start(); + } + }catch(IOException ioe){ + ioe.printStackTrace(); + }finally{ + } + } + + /** + Stop server operation.It would be wise to interrupt thread running the + server afterwards. + */ + public void stop(){ + try{ + if(ss != null) ss.close(); + }catch(IOException ioe){ + } + } + +//Runnable interface +//////////////////// + public void run(){ + switch(mode){ + case START_MODE: + try{ + startSession(); + }catch(IOException ioe){ + handleException(ioe); + //ioe.printStackTrace(); + }finally{ + abort(); + if(auth!=null) auth.endSession(); + log("Main thread(client->remote)stopped."); + } + break; + case ACCEPT_MODE: + try{ + doAccept(); + mode = PIPE_MODE; + pipe_thread1.interrupt(); //Tell other thread that connection have + //been accepted. + pipe(remote_in,out); + }catch(IOException ioe){ + //log("Accept exception:"+ioe); + handleException(ioe); + }finally{ + abort(); + log("Accept thread(remote->client) stopped"); + } + break; + case PIPE_MODE: + try{ + pipe(remote_in,out); + }catch(IOException ioe){ + }finally{ + abort(); + log("Support thread(remote->client) stopped"); + } + break; + case ABORT_MODE: + break; + default: + log("Unexpected MODE "+mode); + } + } + +//Private methods +///////////////// + private void startSession() throws IOException{ + sock.setSoTimeout(iddleTimeout); + + try{ + auth = auth.startSession(sock); + }catch(IOException ioe){ + log("Auth throwed exception:"+ioe); + auth = null; + return; + } + + if(auth == null){ //Authentication failed + log("Authentication failed"); + return; + } + + in = auth.getInputStream(); + out = auth.getOutputStream(); + + msg = readMsg(in); + handleRequest(msg); + } + + private void handleRequest(ProxyMessage msg) + throws IOException{ + if(!auth.checkRequest(msg)) throw new + SocksException(CProxy.SOCKS_FAILURE); + + if(msg.ip == null){ + if(msg instanceof Socks5Message){ + msg.ip = InetAddress.getByName(msg.host); + }else + throw new SocksException(CProxy.SOCKS_FAILURE); + } + log(msg); + + switch(msg.command){ + case CProxy.SOCKS_CMD_CONNECT: + onConnect(msg); + break; + case CProxy.SOCKS_CMD_BIND: + onBind(msg); + break; + case CProxy.SOCKS_CMD_UDP_ASSOCIATE: + onUDP(msg); + break; + default: + throw new SocksException(CProxy.SOCKS_CMD_NOT_SUPPORTED); + } + } + + private void handleException(IOException ioe){ + //If we couldn't read the request, return; + if(msg == null) return; + //If have been aborted by other thread + if(mode == ABORT_MODE) return; + //If the request was successfully completed, but exception happened later + if(mode == PIPE_MODE) return; + + int error_code = CProxy.SOCKS_FAILURE; + + if(ioe instanceof SocksException) + error_code = ((SocksException)ioe).errCode; + else if(ioe instanceof NoRouteToHostException) + error_code = CProxy.SOCKS_HOST_UNREACHABLE; + else if(ioe instanceof ConnectException) + error_code = CProxy.SOCKS_CONNECTION_REFUSED; + else if(ioe instanceof InterruptedIOException) + error_code = CProxy.SOCKS_TTL_EXPIRE; + + if(error_code > CProxy.SOCKS_ADDR_NOT_SUPPORTED || error_code < 0){ + error_code = CProxy.SOCKS_FAILURE; + } + + sendErrorMessage(error_code); + } + + private void onConnect(ProxyMessage msg) throws IOException { + Socket s = null; + ProxyMessage response = null; + int iSock5Cmd = CProxy.SOCKS_FAILURE; //defaulting to failure + int iSock4Msg = Socks4Message.REPLY_NO_CONNECT; + InetAddress sIp = null; int iPort = 0; + + try { + if (proxy == null) { + s = new Socket(msg.ip, msg.port); + } else { + s = new SocksSocket(proxy, msg.ip, msg.port); + } + log("Connected to " + s.getInetAddress() + ":" + s.getPort()); + + iSock5Cmd = CProxy.SOCKS_SUCCESS; iSock4Msg = Socks4Message.REPLY_OK; + sIp = s.getInetAddress(); iPort = s.getPort(); + + } + catch (Exception sE) { + log("Failed connecting to remote socket. Exception: " + sE.getLocalizedMessage()); + + //TBD Pick proper socks error for corresponding socket error, below is too generic + iSock5Cmd = CProxy.SOCKS_CONNECTION_REFUSED; iSock4Msg = Socks4Message.REPLY_NO_CONNECT; + } + + if (msg instanceof Socks5Message) { + response = new Socks5Message(iSock5Cmd, sIp, iPort); + } else { + response = new Socks4Message(iSock4Msg, sIp, iPort); + } + + response.write(out); + + if (s != null) { + startPipe(s); + } + else { + throw (new RuntimeException("onConnect() Failed to create Socket()")); + } + + return; + } + + + private void onBind(ProxyMessage msg) throws IOException{ + ProxyMessage response = null; + + if(proxy == null) + ss = new ServerSocket(0); + else + ss = new SocksServerSocket(proxy, msg.ip, msg.port); + + ss.setSoTimeout(acceptTimeout); + + log("Trying accept on "+ss.getInetAddress()+":"+ss.getLocalPort()); + + if(msg.version == 5) + response = new Socks5Message(CProxy.SOCKS_SUCCESS,ss.getInetAddress(), + ss.getLocalPort()); + else + response = new Socks4Message(Socks4Message.REPLY_OK, + ss.getInetAddress(), + ss.getLocalPort()); + response.write(out); + + mode = ACCEPT_MODE; + + pipe_thread1 = Thread.currentThread(); + pipe_thread2 = new Thread(this); + pipe_thread2.start(); + + //Make timeout infinit. + sock.setSoTimeout(0); + int eof=0; + + try{ + while((eof=in.read())>=0){ + if(mode != ACCEPT_MODE){ + if(mode != PIPE_MODE) return;//Accept failed + + remote_out.write(eof); + break; + } + } + }catch(EOFException eofe){ + //System.out.println("EOF exception"); + return;//Connection closed while we were trying to accept. + }catch(InterruptedIOException iioe){ + //Accept thread interrupted us. + //System.out.println("Interrupted"); + if(mode != PIPE_MODE) + return;//If accept thread was not successfull return. + }finally{ + //System.out.println("Finnaly!"); + } + + if(eof < 0)//Connection closed while we were trying to accept; + return; + + //Do not restore timeout, instead timeout is set on the + //remote socket. It does not make any difference. + + pipe(in,remote_out); + } + + private void onUDP(ProxyMessage msg) throws IOException{ + if(msg.ip.getHostAddress().equals("0.0.0.0")) + msg.ip = sock.getInetAddress(); + log("Creating UDP relay server for "+msg.ip+":"+msg.port); + relayServer = new UDPRelayServer(msg.ip,msg.port, + Thread.currentThread(),sock,auth); + + ProxyMessage response; + + response = new Socks5Message(CProxy.SOCKS_SUCCESS, + relayServer.relayIP,relayServer.relayPort); + + response.write(out); + + relayServer.start(); + + //Make timeout infinit. + sock.setSoTimeout(0); + try{ + while(in.read()>=0) /*do nothing*/; + }catch(EOFException eofe){ + } + } + +//Private methods +////////////////// + + private void doAccept() throws IOException{ + Socket s; + long startTime = System.currentTimeMillis(); + + while(true){ + s = ss.accept(); + if(s.getInetAddress().equals(msg.ip)){ + //got the connection from the right host + //Close listenning socket. + ss.close(); + break; + }else if(ss instanceof SocksServerSocket){ + //We can't accept more then one connection + s.close(); + ss.close(); + throw new SocksException(CProxy.SOCKS_FAILURE); + }else{ + if(acceptTimeout!=0){ //If timeout is not infinit + int newTimeout = acceptTimeout-(int)(System.currentTimeMillis()- + startTime); + if(newTimeout <= 0) throw new InterruptedIOException( + "In doAccept()"); + ss.setSoTimeout(newTimeout); + } + s.close(); //Drop all connections from other hosts + } + } + + //Accepted connection + remote_sock = s; + remote_in = s.getInputStream(); + remote_out = s.getOutputStream(); + + //Set timeout + remote_sock.setSoTimeout(iddleTimeout); + + log("Accepted from "+s.getInetAddress()+":"+s.getPort()); + + ProxyMessage response; + + if(msg.version == 5) + response = new Socks5Message(CProxy.SOCKS_SUCCESS, s.getInetAddress(), + s.getPort()); + else + response = new Socks4Message(Socks4Message.REPLY_OK, + s.getInetAddress(), s.getPort()); + response.write(out); + } + + private ProxyMessage readMsg(InputStream in) throws IOException{ + PushbackInputStream push_in; + if(in instanceof PushbackInputStream) + push_in = (PushbackInputStream) in; + else + push_in = new PushbackInputStream(in); + + int version = push_in.read(); + push_in.unread(version); + + + ProxyMessage msg; + + if(version == 5){ + msg = new Socks5Message(push_in,false); + }else if(version == 4){ + msg = new Socks4Message(push_in,false); + }else{ + throw new SocksException(CProxy.SOCKS_FAILURE); + } + return msg; + } + + private void startPipe(Socket s){ + mode = PIPE_MODE; + remote_sock = s; + try{ + remote_in = s.getInputStream(); + remote_out = s.getOutputStream(); + pipe_thread1 = Thread.currentThread(); + pipe_thread2 = new Thread(this); + pipe_thread2.start(); + pipe(in,remote_out); + }catch(IOException ioe){ + } + } + + private void sendErrorMessage(int error_code){ + ProxyMessage err_msg; + if(msg instanceof Socks4Message) + err_msg = new Socks4Message(Socks4Message.REPLY_REJECTED); + else + err_msg = new Socks5Message(error_code); + try{ + err_msg.write(out); + }catch(IOException ioe){} + } + + private synchronized void abort(){ + if(mode == ABORT_MODE) return; + mode = ABORT_MODE; + try{ + log("Aborting operation"); + if(remote_sock != null) remote_sock.close(); + if(sock != null) sock.close(); + if(relayServer!=null) relayServer.stop(); + if(ss!=null) ss.close(); + if(pipe_thread1 != null) pipe_thread1.interrupt(); + if(pipe_thread2 != null) pipe_thread2.interrupt(); + }catch(IOException ioe){} + } + + static final void log(String s){ + if(log != null){ + log.println(s); + log.flush(); + } + } + + static final void log(ProxyMessage msg){ + log("Request version:"+msg.version+ + "\tCommand: "+command2String(msg.command)); + log("IP:"+msg.ip +"\tPort:"+msg.port+ + (msg.version==4?"\tUser:"+msg.user:"")); + } + + private void pipe(InputStream in,OutputStream out) throws IOException{ + lastReadTime = System.currentTimeMillis(); + byte[] buf = new byte[BUF_SIZE]; + int len = 0; + while(len >= 0){ + try{ + if(len!=0){ + out.write(buf,0,len); + out.flush(); + } + len= in.read(buf); + lastReadTime = System.currentTimeMillis(); + }catch(InterruptedIOException iioe){ + if(iddleTimeout == 0) return;//Other thread interrupted us. + long timeSinceRead = System.currentTimeMillis() - lastReadTime; + if(timeSinceRead >= iddleTimeout - 1000) //-1s for adjustment. + return; + len = 0; + + } + } + } + static final String command_names[] = {"CONNECT","BIND","UDP_ASSOCIATE"}; + + static final String command2String(int cmd){ + if(cmd > 0 && cmd < 4) return command_names[cmd-1]; + else return "Unknown Command "+cmd; + } +}
--- a/src/net/sourceforge/jsocks/Socks4Message.java Fri Aug 01 10:25:44 2014 -0700 +++ b/src/net/sourceforge/jsocks/Socks4Message.java Fri Aug 01 11:23:10 2014 -0700 @@ -1,182 +1,157 @@ -package net.sourceforge.jsocks; -import java.io.DataInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.InetAddress; -import java.net.UnknownHostException; - -/** - SOCKS4 Reply/Request message. -*/ - -public class Socks4Message extends ProxyMessage { - - private byte[] msgBytes; - private int msgLength; - - /** - * Server failed reply, cmd command for failed request - */ - public Socks4Message(int cmd) { - super(cmd, null, 0); - this.user = null; - msgLength = 2; - msgBytes = new byte[2]; - msgBytes[0] = (byte) 0; - msgBytes[1] = (byte) command; - } - - /** - * Server successfull reply - */ - public Socks4Message(int cmd, InetAddress ip, int port) { - this(0, cmd, ip, port, null); - } - - /** - * Client request - */ - public Socks4Message(int cmd, InetAddress ip, int port, String user) { - this(SOCKS_VERSION, cmd, ip, port, user); - } - - /** - * Most general constructor - */ - public Socks4Message(int version, int cmd, - InetAddress ip, int port, String user) { - super(cmd, ip, port); - this.user = user; - this.version = version; - msgLength = user == null ? 8 : 9 + user.length(); - msgBytes = new byte[msgLength]; - msgBytes[0] = (byte) version; - msgBytes[1] = (byte) command; - msgBytes[2] = (byte)(port >> 8); - msgBytes[3] = (byte) port; - byte[] addr; - - if (ip != null) - addr = ip.getAddress(); - else { - addr = new byte[4]; - addr[0] = addr[1] = addr[2] = addr[3] = 0; - } - - System.arraycopy(addr, 0, msgBytes, 4, 4); - - if (user != null) { - byte[] buf = user.getBytes(); - System.arraycopy(buf, 0, msgBytes, 8, buf.length); - msgBytes[msgBytes.length - 1 ] = 0; - } - } - - /** - *Initialise from the stream - *If clientMode is true attempts to read a server response - *otherwise reads a client request - *see read for more detail - */ - public Socks4Message(InputStream in, boolean clientMode) throws IOException { - msgBytes = null; - read(in, clientMode); - } - - @Override - public void read(InputStream in) throws IOException { - read(in, true); - } - - @Override - public void read(InputStream in, boolean clientMode) throws IOException { - boolean mode4a = false; - DataInputStream d_in = new DataInputStream(in); - version = d_in.readUnsignedByte(); - command = d_in.readUnsignedByte(); - - if (clientMode && command != REPLY_OK) { - String errMsg; - - if (command > REPLY_OK && command < REPLY_BAD_IDENTD) - errMsg = replyMessage[command - REPLY_OK]; - else - errMsg = "Unknown Reply Code"; - - throw new SocksException(command, errMsg); - } - - port = d_in.readUnsignedShort(); - byte[] addr = new byte[4]; - d_in.readFully(addr); - - if (addr[0] == 0 && addr[1] == 0 && addr[2] == 0 && addr[3] != 0) - mode4a = true; - else { - ip = bytes2IP(addr); - host = ip.getHostName(); - } - - if (!clientMode) { - StringBuilder sb = new StringBuilder(); - int b; - - while ((b = in.read()) != 0) - sb.append((char) b); - - user = sb.toString(); - - if (mode4a) { - sb.setLength(0); - - while ((b = in.read()) != 0) - sb.append((char) b); - - host = sb.toString(); - } - } - } - @Override - public void write(OutputStream out) throws IOException { - if (msgBytes == null) { - Socks4Message msg = new Socks4Message(version, command, ip, port, user); - msgBytes = msg.msgBytes; - msgLength = msg.msgLength; - } - - out.write(msgBytes); - } - - //Class methods - static InetAddress bytes2IP(byte[] addr) { - String s = bytes2IPV4(addr, 0); - - try { - return InetAddress.getByName(s); - } - catch (UnknownHostException uh_ex) { - return null; - } - } - - //Constants - - static final String[] replyMessage = { - "Request Granted", - "Request Rejected or Failed", - "Failed request, can't connect to Identd", - "Failed request, bad user name" - }; - - static final int SOCKS_VERSION = 4; - - public final static int REQUEST_CONNECT = 1; - public final static int REQUEST_BIND = 2; - - public final static int REPLY_OK = 90; - public final static int REPLY_REJECTED = 91; - public final static int REPLY_NO_CONNECT = 92; - public final static int REPLY_BAD_IDENTD = 93; - -} +package net.sourceforge.jsocks; +import java.io.*; +import java.net.*; + +/** + SOCKS4 Reply/Request message. +*/ + +class Socks4Message extends ProxyMessage{ + + private byte[] msgBytes; + private int msgLength; + + /** + * Server failed reply, cmd command for failed request + */ + public Socks4Message(int cmd){ + super(cmd,null,0); + this.user = null; + + msgLength = 2; + msgBytes = new byte[2]; + + msgBytes[0] = (byte) 0; + msgBytes[1] = (byte) command; + } + + /** + * Server successfull reply + */ + public Socks4Message(int cmd,InetAddress ip,int port){ + this(0,cmd,ip,port,null); + } + + /** + * Client request + */ + public Socks4Message(int cmd,InetAddress ip,int port,String user){ + this(SOCKS_VERSION,cmd,ip,port,user); + } + + /** + * Most general constructor + */ + public Socks4Message(int version, int cmd, + InetAddress ip,int port,String user){ + super(cmd,ip,port); + this.user = user; + this.version = version; + + msgLength = user == null?8:9+user.length(); + msgBytes = new byte[msgLength]; + + msgBytes[0] = (byte) version; + msgBytes[1] = (byte) command; + msgBytes[2] = (byte) (port >> 8); + msgBytes[3] = (byte) port; + + byte[] addr; + + if(ip != null) + addr = ip.getAddress(); + else{ + addr = new byte[4]; + addr[0]=addr[1]=addr[2]=addr[3]=0; + } + System.arraycopy(addr,0,msgBytes,4,4); + + if(user != null){ + byte[] buf = user.getBytes(); + System.arraycopy(buf,0,msgBytes,8,buf.length); + msgBytes[msgBytes.length -1 ] = 0; + } + } + + /** + *Initialise from the stream + *If clientMode is true attempts to read a server response + *otherwise reads a client request + *see read for more detail + */ + public Socks4Message(InputStream in, boolean clientMode) throws IOException{ + msgBytes = null; + read(in,clientMode); + } + + public void read(InputStream in) throws IOException{ + read(in,true); + } + + public void read(InputStream in, boolean clientMode) throws IOException{ + DataInputStream d_in = new DataInputStream(in); + version= d_in.readUnsignedByte(); + command = d_in.readUnsignedByte(); + if(clientMode && command != REPLY_OK){ + String errMsg; + if(command >REPLY_OK && command < REPLY_BAD_IDENTD) + errMsg = replyMessage[command-REPLY_OK]; + else + errMsg = "Unknown Reply Code"; + throw new SocksException(command,errMsg); + } + port = d_in.readUnsignedShort(); + byte[] addr = new byte[4]; + d_in.readFully(addr); + ip=bytes2IP(addr); + host = ip.getHostName(); + if(!clientMode){ + int b = in.read(); + //Hope there are no idiots with user name bigger than this + byte[] userBytes = new byte[256]; + int i = 0; + for(i =0;i<userBytes.length && b>0;++i){ + userBytes[i] = (byte) b; + b = in.read(); + } + user = new String(userBytes,0,i); + } + } + public void write(OutputStream out) throws IOException{ + if(msgBytes == null){ + Socks4Message msg = new Socks4Message(version,command,ip,port,user); + msgBytes = msg.msgBytes; + msgLength = msg.msgLength; + } + out.write(msgBytes); + } + + //Class methods + static InetAddress bytes2IP(byte[] addr){ + String s = bytes2IPV4(addr,0); + try{ + return InetAddress.getByName(s); + }catch(UnknownHostException uh_ex){ + return null; + } + } + + //Constants + + static final String[] replyMessage ={ + "Request Granted", + "Request Rejected or Failed", + "Failed request, can't connect to Identd", + "Failed request, bad user name"}; + + static final int SOCKS_VERSION = 4; + + public final static int REQUEST_CONNECT = 1; + public final static int REQUEST_BIND = 2; + + public final static int REPLY_OK = 90; + public final static int REPLY_REJECTED = 91; + public final static int REPLY_NO_CONNECT = 92; + public final static int REPLY_BAD_IDENTD = 93; + +}
--- a/src/net/sourceforge/jsocks/Socks4Proxy.java Fri Aug 01 10:25:44 2014 -0700 +++ b/src/net/sourceforge/jsocks/Socks4Proxy.java Fri Aug 01 11:23:10 2014 -0700 @@ -1,110 +1,121 @@ -package net.sourceforge.jsocks; -import java.io.IOException; -import java.io.InputStream; -import java.net.InetAddress; -import java.net.UnknownHostException; - -/** - Proxy which describes SOCKS4 proxy. -*/ - -public class Socks4Proxy extends Proxy implements Cloneable { - -//Data members - String user; - -//Public Constructors -//==================== - - /** - Creates the SOCKS4 proxy - @param p Proxy to use to connect to this proxy, allows proxy chaining. - @param proxyHost Address of the proxy server. - @param proxyPort Port of the proxy server - @param user User name to use for identification purposes. - @throws UnknownHostException If proxyHost can't be resolved. - */ - public Socks4Proxy(String proxyHost, int proxyPort, String user) - throws UnknownHostException { - super(proxyHost, proxyPort); - this.user = new String(user); - version = 4; - } - - /** - Creates the SOCKS4 proxy - @param p Proxy to use to connect to this proxy, allows proxy chaining. - @param proxyIP Address of the proxy server. - @param proxyPort Port of the proxy server - @param user User name to use for identification purposes. - */ - public Socks4Proxy(Proxy p, InetAddress proxyIP, int proxyPort, String user) { - super(p, proxyIP, proxyPort); - this.user = new String(user); - version = 4; - } - - /** - Creates the SOCKS4 proxy - @param proxyIP Address of the proxy server. - @param proxyPort Port of the proxy server - @param user User name to use for identification purposes. - */ - public Socks4Proxy(InetAddress proxyIP, int proxyPort, String user) { - this(null, proxyIP, proxyPort, user); - } - -//Public instance methods -//======================== - - /** - * Creates a clone of this proxy. Changes made to the clone should not - * affect this object. - */ - public Object clone() { - Socks4Proxy newProxy = new Socks4Proxy(proxyIP, proxyPort, user); - newProxy.chainProxy = chainProxy; - return newProxy; - } - - -//Public Static(Class) Methods -//============================== - - -//Protected Methods -//================= - - protected Proxy copy() { - Socks4Proxy copy = new Socks4Proxy(proxyIP, proxyPort, user); - copy.chainProxy = chainProxy; - return copy; - } - - protected ProxyMessage formMessage(int cmd, InetAddress ip, int port) { - switch (cmd) { - case SOCKS_CMD_CONNECT: - cmd = Socks4Message.REQUEST_CONNECT; - break; - - case SOCKS_CMD_BIND: - cmd = Socks4Message.REQUEST_BIND; - break; - - default: - return null; - } - - return new Socks4Message(cmd, ip, port, user); - } - protected ProxyMessage formMessage(int cmd, String host, int port) - throws UnknownHostException { - return formMessage(cmd, InetAddress.getByName(host), port); - } - protected ProxyMessage formMessage(InputStream in) - throws SocksException, - IOException { - return new Socks4Message(in, true); - } - -} +package net.sourceforge.jsocks; +import java.net.*; +import java.io.*; +import java.util.Hashtable; +import java.util.Enumeration; + +/** + CProxy which describes SOCKS4 proxy. +*/ + +public class Socks4Proxy extends CProxy implements Cloneable{ + +//Data members + String user; + +//Public Constructors +//==================== + + /** + Creates the SOCKS4 proxy + @param p CProxy to use to connect to this proxy, allows proxy chaining. + @param proxyHost Address of the proxy server. + @param proxyPort Port of the proxy server + @param user User name to use for identification purposes. + @throws UnknownHostException If proxyHost can't be resolved. + */ + public Socks4Proxy(CProxy p,String proxyHost,int proxyPort,String user) + throws UnknownHostException{ + super(p,proxyHost,proxyPort); + this.user = new String(user); + version = 4; + } + + /** + Creates the SOCKS4 proxy + @param proxyHost Address of the proxy server. + @param proxyPort Port of the proxy server + @param user User name to use for identification purposes. + @throws UnknownHostException If proxyHost can't be resolved. + */ + public Socks4Proxy(String proxyHost,int proxyPort,String user) + throws UnknownHostException{ + this(null,proxyHost,proxyPort,user); + } + + /** + Creates the SOCKS4 proxy + @param p CProxy to use to connect to this proxy, allows proxy chaining. + @param proxyIP Address of the proxy server. + @param proxyPort Port of the proxy server + @param user User name to use for identification purposes. + */ + public Socks4Proxy(CProxy p,InetAddress proxyIP,int proxyPort,String user){ + super(p,proxyIP,proxyPort); + this.user = new String(user); + version = 4; + } + + /** + Creates the SOCKS4 proxy + @param proxyIP Address of the proxy server. + @param proxyPort Port of the proxy server + @param user User name to use for identification purposes. + */ + public Socks4Proxy(InetAddress proxyIP,int proxyPort,String user){ + this(null,proxyIP,proxyPort,user); + } + +//Public instance methods +//======================== + + /** + * Creates a clone of this proxy. Changes made to the clone should not + * affect this object. + */ + public Object clone(){ + Socks4Proxy newProxy = new Socks4Proxy(proxyIP,proxyPort,user); + newProxy.directHosts = (InetRange)directHosts.clone(); + newProxy.chainProxy = chainProxy; + return newProxy; + } + + +//Public Static(Class) Methods +//============================== + + +//Protected Methods +//================= + + protected CProxy copy(){ + Socks4Proxy copy = new Socks4Proxy(proxyIP,proxyPort,user); + copy.directHosts = this.directHosts; + copy.chainProxy = chainProxy; + return copy; + } + + protected ProxyMessage formMessage(int cmd,InetAddress ip,int port){ + switch(cmd){ + case SOCKS_CMD_CONNECT: + cmd = Socks4Message.REQUEST_CONNECT; + break; + case SOCKS_CMD_BIND: + cmd = Socks4Message.REQUEST_BIND; + break; + default: + return null; + } + return new Socks4Message(cmd,ip,port,user); + } + protected ProxyMessage formMessage(int cmd,String host,int port) + throws UnknownHostException{ + return formMessage(cmd,InetAddress.getByName(host),port); + } + protected ProxyMessage formMessage(InputStream in) + throws SocksException, + IOException{ + return new Socks4Message(in,true); + } + +}
--- a/src/net/sourceforge/jsocks/Socks5DatagramSocket.java Fri Aug 01 10:25:44 2014 -0700 +++ b/src/net/sourceforge/jsocks/Socks5DatagramSocket.java Fri Aug 01 11:23:10 2014 -0700 @@ -1,462 +1,487 @@ -package net.sourceforge.jsocks; -import java.net.*; -import java.io.*; - -/** - Datagram socket to interract through the firewall.<BR> - Can be used same way as the normal DatagramSocket. One should - be carefull though with the datagram sizes used, as additional data - is present in both incomming and outgoing datagrams. - <p> - SOCKS5 protocol allows to send host address as either: - <ul> - <li> IPV4, normal 4 byte address. (10 bytes header size) - <li> IPV6, version 6 ip address (not supported by Java as for now). - 22 bytes header size. - <li> Host name,(7+length of the host name bytes header size). - </ul> - As with other Socks equivalents, direct addresses are handled - transparently, that is data will be send directly when required - by the proxy settings. - <p> - <b>NOTE:</b><br> - Unlike other SOCKS Sockets, it <b>does not</b> support proxy chaining, - and will throw an exception if proxy has a chain proxy attached. The - reason for that is not my laziness, but rather the restrictions of - the SOCKSv5 protocol. Basicaly SOCKSv5 proxy server, needs to know from - which host:port datagrams will be send for association, and returns address - to which datagrams should be send by the client, but it does not - inform client from which host:port it is going to send datagrams, in fact - there is even no guarantee they will be send at all and from the same address - each time. - - */ -public class Socks5DatagramSocket extends DatagramSocket { - - InetAddress relayIP; - int relayPort; - Socks5Proxy proxy; - private boolean server_mode = false; - UDPEncapsulation encapsulation; - - - /** - Construct Datagram socket for communication over SOCKS5 proxy - server. This constructor uses default proxy, the one set with - Proxy.setDefaultProxy() method. If default proxy is not set or - it is set to version4 proxy, which does not support datagram - forwarding, throws SocksException. - - */ - public Socks5DatagramSocket() throws SocksException, - IOException { - this(Proxy.defaultProxy, 0, null); - } - /** - Construct Datagram socket for communication over SOCKS5 proxy - server. And binds it to the specified local port. - This constructor uses default proxy, the one set with - Proxy.setDefaultProxy() method. If default proxy is not set or - it is set to version4 proxy, which does not support datagram - forwarding, throws SocksException. - */ - public Socks5DatagramSocket(int port) throws SocksException, - IOException { - this(Proxy.defaultProxy, port, null); - } - /** - Construct Datagram socket for communication over SOCKS5 proxy - server. And binds it to the specified local port and address. - This constructor uses default proxy, the one set with - Proxy.setDefaultProxy() method. If default proxy is not set or - it is set to version4 proxy, which does not support datagram - forwarding, throws SocksException. - */ - public Socks5DatagramSocket(int port, InetAddress ip) throws SocksException, - IOException { - this(Proxy.defaultProxy, port, ip); - } - - /** - Constructs datagram socket for communication over specified proxy. - And binds it to the given local address and port. Address of null - and port of 0, signify any availabale port/address. - Might throw SocksException, if: - <ol> - <li> Given version of proxy does not support UDP_ASSOCIATE. - <li> Proxy can't be reached. - <li> Authorization fails. - <li> Proxy does not want to perform udp forwarding, for any reason. - </ol> - Might throw IOException if binding dtagram socket to given address/port - fails. - See java.net.DatagramSocket for more details. - */ - public Socks5DatagramSocket(Proxy p, int port, InetAddress ip) - throws SocksException, - IOException { - super(port, ip); - - if (p == null) throw new SocksException(Proxy.SOCKS_NO_PROXY); - - if (!(p instanceof Socks5Proxy)) - throw new SocksException(-1, "Datagram Socket needs Proxy version 5"); - - if (p.chainProxy != null) - throw new SocksException(Proxy.SOCKS_JUST_ERROR, - "Datagram Sockets do not support proxy chaining."); - - proxy = (Socks5Proxy) p.copy(); - ProxyMessage msg = proxy.udpAssociate(super.getLocalAddress(), - super.getLocalPort()); - relayIP = msg.ip; - - if (relayIP.getHostAddress().equals("0.0.0.0")) relayIP = proxy.proxyIP; - - relayPort = msg.port; - encapsulation = proxy.udp_encapsulation; - //debug("Datagram Socket:"+getLocalAddress()+":"+getLocalPort()+"\n"); - //debug("Socks5Datagram: "+relayIP+":"+relayPort+"\n"); - } - - /** - Used by UDPRelayServer. - */ - Socks5DatagramSocket(boolean server_mode, UDPEncapsulation encapsulation, - InetAddress relayIP, int relayPort) - throws IOException { - super(); - this.server_mode = server_mode; - this.relayIP = relayIP; - this.relayPort = relayPort; - this.encapsulation = encapsulation; - this.proxy = null; - } - - /** - Sends the Datagram either through the proxy or directly depending - on current proxy settings and destination address. <BR> - - <B> NOTE: </B> DatagramPacket size should be at least 10 bytes less - than the systems limit. - - <P> - See documentation on java.net.DatagramSocket - for full details on how to use this method. - @param dp Datagram to send. - @throws IOException If error happens with I/O. - */ - public void send(DatagramPacket dp) throws IOException { - //If the host should be accessed directly, send it as is. - if (!server_mode) { - super.send(dp); - //debug("Sending directly:"); - return; - } - - byte[] head = formHeader(dp.getAddress(), dp.getPort()); - byte[] buf = new byte[head.length + dp.getLength()]; - byte[] data = dp.getData(); - //Merge head and data - System.arraycopy(head, 0, buf, 0, head.length); - //System.arraycopy(data,dp.getOffset(),buf,head.length,dp.getLength()); - System.arraycopy(data, 0, buf, head.length, dp.getLength()); - - if (encapsulation != null) - buf = encapsulation.udpEncapsulate(buf, true); - - super.send(new DatagramPacket(buf, buf.length, relayIP, relayPort)); - } - /** - This method allows to send datagram packets with address type DOMAINNAME. - SOCKS5 allows to specify host as names rather than ip addresses.Using - this method one can send udp datagrams through the proxy, without having - to know the ip address of the destination host. - <p> - If proxy specified for that socket has an option resolveAddrLocally set - to true host will be resolved, and the datagram will be send with address - type IPV4, if resolve fails, UnknownHostException is thrown. - @param dp Datagram to send, it should contain valid port and data - @param host Host name to which datagram should be send. - @throws IOException If error happens with I/O, or the host can't be - resolved when proxy settings say that hosts should be resolved locally. - @see Socks5Proxy#resolveAddrLocally(boolean) - */ - public void send(DatagramPacket dp, String host) throws IOException { - dp.setAddress(InetAddress.getByName(host)); - super.send(dp); - } - - /** - * Receives udp packet. If packet have arrived from the proxy relay server, - * it is processed and address and port of the packet are set to the - * address and port of sending host.<BR> - * If the packet arrived from anywhere else it is not changed.<br> - * <B> NOTE: </B> DatagramPacket size should be at least 10 bytes bigger - * than the largest packet you expect (this is for IPV4 addresses). - * For hostnames and IPV6 it is even more. - @param dp Datagram in which all relevent information will be copied. - */ - public void receive(DatagramPacket dp) throws IOException { - super.receive(dp); - - if (server_mode) { - //Drop all datagrams not from relayIP/relayPort - int init_length = dp.getLength(); - int initTimeout = getSoTimeout(); - long startTime = System.currentTimeMillis(); - - while (!relayIP.equals(dp.getAddress()) || - relayPort != dp.getPort()) { - //Restore datagram size - dp.setLength(init_length); - - //If there is a non-infinit timeout on this socket - //Make sure that it happens no matter how often unexpected - //packets arrive. - if (initTimeout != 0) { - int newTimeout = initTimeout - (int)(System.currentTimeMillis() - - startTime); - - if (newTimeout <= 0) throw new InterruptedIOException( - "In Socks5DatagramSocket->receive()"); - - setSoTimeout(newTimeout); - } - - super.receive(dp); - } - - //Restore timeout settings - if (initTimeout != 0) setSoTimeout(initTimeout); - } - else if (!relayIP.equals(dp.getAddress()) || - relayPort != dp.getPort()) - return; // Recieved direct packet - - //If the datagram is not from the relay server, return it it as is. - byte[] data; - data = dp.getData(); - - if (encapsulation != null) - data = encapsulation.udpEncapsulate(data, false); - - int offset = 0; //Java 1.1 - //int offset = dp.getOffset(); //Java 1.2 - ByteArrayInputStream bIn = new ByteArrayInputStream(data, offset, - dp.getLength()); - ProxyMessage msg = new Socks5Message(bIn); - dp.setPort(msg.port); - dp.setAddress(msg.getInetAddress()); - //what wasn't read by the Message is the data - int data_length = bIn.available(); - //Shift data to the left - System.arraycopy(data, offset + dp.getLength() - data_length, - data, offset, data_length); - dp.setLength(data_length); - } - - /** - * Returns port assigned by the proxy, to which datagrams are relayed. - * It is not the same port to which other party should send datagrams. - @return Port assigned by socks server to which datagrams are send - for association. - */ - public int getLocalPort() { - if (server_mode) return super.getLocalPort(); - - return relayPort; - } - /** - * Address assigned by the proxy, to which datagrams are send for relay. - * It is not necesseraly the same address, to which other party should send - * datagrams. - @return Address to which datagrams are send for association. - */ - public InetAddress getLocalAddress() { - if (server_mode) return super.getLocalAddress(); - - return relayIP; - } - - /** - * Closes datagram socket, and proxy connection. - */ - public void close() { - if (!server_mode) proxy.endSession(); - - super.close(); - } - - /** - This method checks wether proxy still runs udp forwarding service - for this socket. - <p> - This methods checks wether the primary connection to proxy server - is active. If it is, chances are that proxy continues to forward - datagrams being send from this socket. If it was closed, most likely - datagrams are no longer being forwarded by the server. - <p> - Proxy might decide to stop forwarding datagrams, in which case it - should close primary connection. This method allows to check, wether - this have been done. - <p> - You can specify timeout for which we should be checking EOF condition - on the primary connection. Timeout is in milliseconds. Specifying 0 as - timeout implies infinity, in which case method will block, until - connection to proxy is closed or an error happens, and then return false. - <p> - One possible scenario is to call isProxyactive(0) in separate thread, - and once it returned notify other threads about this event. - - @param timeout For how long this method should block, before returning. - @return true if connection to proxy is active, false if eof or error - condition have been encountered on the connection. - */ - public boolean isProxyAlive(int timeout) { - if (server_mode) return false; - - if (proxy != null) { - try { - proxy.proxySocket.setSoTimeout(timeout); - int eof = proxy.in.read(); - - if (eof < 0) return false; // EOF encountered. - else return true; // This really should not happen - } - catch (InterruptedIOException iioe) { - return true; // read timed out. - } - catch (IOException ioe) { - return false; - } - } - - return false; - } - -//PRIVATE METHODS -////////////////// - - - private byte[] formHeader(InetAddress ip, int port) { - Socks5Message request = new Socks5Message(0, ip, port); - request.data[0] = 0; - return request.data; - } - - - /*====================================================================== - - //Mainly Test functions - ////////////////////// - - private String bytes2String(byte[] b){ - String s=""; - char[] hex_digit = { '0','1','2','3','4','5','6','7','8','9', - 'A','B','C','D','E','F'}; - for(int i=0;i<b.length;++i){ - int i1 = (b[i] & 0xF0) >> 4; - int i2 = b[i] & 0xF; - s+=hex_digit[i1]; - s+=hex_digit[i2]; - s+=" "; - } - return s; - } - private static final void debug(String s){ - if(DEBUG) - System.out.print(s); - } - - private static final boolean DEBUG = true; - - - public static void usage(){ - System.err.print( - "Usage: java Socks.SocksDatagramSocket host port [socksHost socksPort]\n"); - } - - static final int defaultProxyPort = 1080; //Default Port - static final String defaultProxyHost = "www-proxy"; //Default proxy - - public static void main(String args[]){ - int port; - String host; - int proxyPort; - String proxyHost; - InetAddress ip; - - if(args.length > 1 && args.length < 5){ - try{ - - host = args[0]; - port = Integer.parseInt(args[1]); - - proxyPort =(args.length > 3)? Integer.parseInt(args[3]) - : defaultProxyPort; - - host = args[0]; - ip = InetAddress.getByName(host); - - proxyHost =(args.length > 2)? args[2] - : defaultProxyHost; - - Proxy.setDefaultProxy(proxyHost,proxyPort); - Proxy p = Proxy.getDefaultProxy(); - p.addDirect("lux"); - - - DatagramSocket ds = new Socks5DatagramSocket(); - - - BufferedReader in = new BufferedReader( - new InputStreamReader(System.in)); - String s; - - System.out.print("Enter line:"); - s = in.readLine(); - - while(s != null){ - byte[] data = (s+"\r\n").getBytes(); - DatagramPacket dp = new DatagramPacket(data,0,data.length, - ip,port); - System.out.println("Sending to: "+ip+":"+port); - ds.send(dp); - dp = new DatagramPacket(new byte[1024],1024); - - System.out.println("Trying to recieve on port:"+ - ds.getLocalPort()); - ds.receive(dp); - System.out.print("Recieved:\n"+ - "From:"+dp.getAddress()+":"+dp.getPort()+ - "\n\n"+ - new String(dp.getData(),dp.getOffset(),dp.getLength())+"\n" - ); - System.out.print("Enter line:"); - s = in.readLine(); - - } - ds.close(); - System.exit(1); - - }catch(SocksException s_ex){ - System.err.println("SocksException:"+s_ex); - s_ex.printStackTrace(); - System.exit(1); - }catch(IOException io_ex){ - io_ex.printStackTrace(); - System.exit(1); - }catch(NumberFormatException num_ex){ - usage(); - num_ex.printStackTrace(); - System.exit(1); - } - - }else{ - usage(); - } - } - */ - -} +package net.sourceforge.jsocks; +import java.net.*; +import java.io.*; + +/** + Datagram socket to interract through the firewall.<BR> + Can be used same way as the normal DatagramSocket. One should + be carefull though with the datagram sizes used, as additional data + is present in both incomming and outgoing datagrams. + <p> + SOCKS5 protocol allows to send host address as either: + <ul> + <li> IPV4, normal 4 byte address. (10 bytes header size) + <li> IPV6, version 6 ip address (not supported by Java as for now). + 22 bytes header size. + <li> Host name,(7+length of the host name bytes header size). + </ul> + As with other Socks equivalents, direct addresses are handled + transparently, that is data will be send directly when required + by the proxy settings. + <p> + <b>NOTE:</b><br> + Unlike other SOCKS Sockets, it <b>does not</b> support proxy chaining, + and will throw an exception if proxy has a chain proxy attached. The + reason for that is not my laziness, but rather the restrictions of + the SOCKSv5 protocol. Basicaly SOCKSv5 proxy server, needs to know from + which host:port datagrams will be send for association, and returns address + to which datagrams should be send by the client, but it does not + inform client from which host:port it is going to send datagrams, in fact + there is even no guarantee they will be send at all and from the same address + each time. + + */ +public class Socks5DatagramSocket extends DatagramSocket{ + + InetAddress relayIP; + int relayPort; + Socks5Proxy proxy; + private boolean server_mode = false; + UDPEncapsulation encapsulation; + + + /** + Construct Datagram socket for communication over SOCKS5 proxy + server. This constructor uses default proxy, the one set with + CProxy.setDefaultProxy() method. If default proxy is not set or + it is set to version4 proxy, which does not support datagram + forwarding, throws SocksException. + + */ + public Socks5DatagramSocket() throws SocksException, + IOException{ + this(CProxy.defaultProxy,0,null); + } + /** + Construct Datagram socket for communication over SOCKS5 proxy + server. And binds it to the specified local port. + This constructor uses default proxy, the one set with + CProxy.setDefaultProxy() method. If default proxy is not set or + it is set to version4 proxy, which does not support datagram + forwarding, throws SocksException. + */ + public Socks5DatagramSocket(int port) throws SocksException, + IOException{ + this(CProxy.defaultProxy,port,null); + } + /** + Construct Datagram socket for communication over SOCKS5 proxy + server. And binds it to the specified local port and address. + This constructor uses default proxy, the one set with + CProxy.setDefaultProxy() method. If default proxy is not set or + it is set to version4 proxy, which does not support datagram + forwarding, throws SocksException. + */ + public Socks5DatagramSocket(int port,InetAddress ip) throws SocksException, + IOException{ + this(CProxy.defaultProxy,port,ip); + } + + /** + Constructs datagram socket for communication over specified proxy. + And binds it to the given local address and port. Address of null + and port of 0, signify any availabale port/address. + Might throw SocksException, if: + <ol> + <li> Given version of proxy does not support UDP_ASSOCIATE. + <li> CProxy can't be reached. + <li> Authorization fails. + <li> CProxy does not want to perform udp forwarding, for any reason. + </ol> + Might throw IOException if binding dtagram socket to given address/port + fails. + See java.net.DatagramSocket for more details. + */ + public Socks5DatagramSocket(CProxy p,int port,InetAddress ip) + throws SocksException, + IOException{ + super(port,ip); + if(p == null) throw new SocksException(CProxy.SOCKS_NO_PROXY); + if(!(p instanceof Socks5Proxy)) + throw new SocksException(-1,"Datagram Socket needs Proxy version 5"); + + if(p.chainProxy != null) + throw new SocksException(CProxy.SOCKS_JUST_ERROR, + "Datagram Sockets do not support proxy chaining."); + + proxy =(Socks5Proxy) p.copy(); + + ProxyMessage msg = proxy.udpAssociate(super.getLocalAddress(), + super.getLocalPort()); + relayIP = msg.ip; + if(relayIP.getHostAddress().equals("0.0.0.0")) relayIP = proxy.proxyIP; + relayPort = msg.port; + + encapsulation = proxy.udp_encapsulation; + + //debug("Datagram Socket:"+getLocalAddress()+":"+getLocalPort()+"\n"); + //debug("Socks5Datagram: "+relayIP+":"+relayPort+"\n"); + } + + /** + Used by UDPRelayServer. + */ + Socks5DatagramSocket(boolean server_mode,UDPEncapsulation encapsulation, + InetAddress relayIP,int relayPort) + throws IOException{ + super(); + this.server_mode = server_mode; + this.relayIP = relayIP; + this.relayPort = relayPort; + this.encapsulation = encapsulation; + this.proxy = null; + } + + /** + Sends the Datagram either through the proxy or directly depending + on current proxy settings and destination address. <BR> + + <B> NOTE: </B> DatagramPacket size should be at least 10 bytes less + than the systems limit. + + <P> + See documentation on java.net.DatagramSocket + for full details on how to use this method. + @param dp Datagram to send. + @throws IOException If error happens with I/O. + */ + public void send(DatagramPacket dp) throws IOException{ + //If the host should be accessed directly, send it as is. + if(!server_mode && proxy.isDirect(dp.getAddress())){ + super.send(dp); + //debug("Sending directly:"); + return; + } + + byte[] head = formHeader(dp.getAddress(),dp.getPort()); + byte[] buf = new byte[head.length + dp.getLength()]; + byte[] data = dp.getData(); + //Merge head and data + System.arraycopy(head,0,buf,0,head.length); + //System.arraycopy(data,dp.getOffset(),buf,head.length,dp.getLength()); + System.arraycopy(data,0,buf,head.length,dp.getLength()); + + if(encapsulation != null) + buf = encapsulation.udpEncapsulate(buf,true); + + super.send(new DatagramPacket(buf,buf.length,relayIP,relayPort)); + } + /** + This method allows to send datagram packets with address type DOMAINNAME. + SOCKS5 allows to specify host as names rather than ip addresses.Using + this method one can send udp datagrams through the proxy, without having + to know the ip address of the destination host. + <p> + If proxy specified for that socket has an option resolveAddrLocally set + to true host will be resolved, and the datagram will be send with address + type IPV4, if resolve fails, UnknownHostException is thrown. + @param dp Datagram to send, it should contain valid port and data + @param host Host name to which datagram should be send. + @throws IOException If error happens with I/O, or the host can't be + resolved when proxy settings say that hosts should be resolved locally. + @see Socks5Proxy#resolveAddrLocally(boolean) + */ + public void send(DatagramPacket dp, String host) throws IOException{ + if(proxy.isDirect(host)){ + dp.setAddress(InetAddress.getByName(host)); + super.send(dp); + return; + } + + if(((Socks5Proxy)proxy).resolveAddrLocally){ + dp.setAddress(InetAddress.getByName(host)); + } + + byte[] head = formHeader(host,dp.getPort()); + byte[] buf = new byte[head.length + dp.getLength()]; + byte[] data = dp.getData(); + //Merge head and data + System.arraycopy(head,0,buf,0,head.length); + //System.arraycopy(data,dp.getOffset(),buf,head.length,dp.getLength()); + System.arraycopy(data,0,buf,head.length,dp.getLength()); + + if(encapsulation != null) + buf = encapsulation.udpEncapsulate(buf,true); + + super.send(new DatagramPacket(buf,buf.length,relayIP,relayPort)); + } + + /** + * Receives udp packet. If packet have arrived from the proxy relay server, + * it is processed and address and port of the packet are set to the + * address and port of sending host.<BR> + * If the packet arrived from anywhere else it is not changed.<br> + * <B> NOTE: </B> DatagramPacket size should be at least 10 bytes bigger + * than the largest packet you expect (this is for IPV4 addresses). + * For hostnames and IPV6 it is even more. + @param dp Datagram in which all relevent information will be copied. + */ + public void receive(DatagramPacket dp) throws IOException{ + super.receive(dp); + + if(server_mode){ + //Drop all datagrams not from relayIP/relayPort + int init_length = dp.getLength(); + int initTimeout = getSoTimeout(); + long startTime = System.currentTimeMillis(); + + while(!relayIP.equals(dp.getAddress()) || + relayPort != dp.getPort()){ + + //Restore datagram size + dp.setLength(init_length); + + //If there is a non-infinit timeout on this socket + //Make sure that it happens no matter how often unexpected + //packets arrive. + if(initTimeout != 0){ + int newTimeout = initTimeout - (int)(System.currentTimeMillis() - + startTime); + if(newTimeout <= 0) throw new InterruptedIOException( + "In Socks5DatagramSocket->receive()"); + setSoTimeout(newTimeout); + } + + super.receive(dp); + } + + //Restore timeout settings + if(initTimeout != 0) setSoTimeout(initTimeout); + + }else if(!relayIP.equals(dp.getAddress()) || + relayPort != dp.getPort()) + return; // Recieved direct packet + //If the datagram is not from the relay server, return it it as is. + + byte[] data; + data = dp.getData(); + + if(encapsulation != null) + data = encapsulation.udpEncapsulate(data,false); + + int offset = 0; //Java 1.1 + //int offset = dp.getOffset(); //Java 1.2 + + ByteArrayInputStream bIn = new ByteArrayInputStream(data,offset, + dp.getLength()); + + + ProxyMessage msg = new Socks5Message(bIn); + dp.setPort(msg.port); + dp.setAddress(msg.getInetAddress()); + + //what wasn't read by the Message is the data + int data_length = bIn.available(); + //Shift data to the left + System.arraycopy(data,offset+dp.getLength()-data_length, + data,offset,data_length); + + + dp.setLength(data_length); + } + + /** + * Returns port assigned by the proxy, to which datagrams are relayed. + * It is not the same port to which other party should send datagrams. + @return Port assigned by socks server to which datagrams are send + for association. + */ + public int getLocalPort(){ + if(server_mode) return super.getLocalPort(); + return relayPort; + } + /** + * Address assigned by the proxy, to which datagrams are send for relay. + * It is not necesseraly the same address, to which other party should send + * datagrams. + @return Address to which datagrams are send for association. + */ + public InetAddress getLocalAddress(){ + if(server_mode) return super.getLocalAddress(); + return relayIP; + } + + /** + * Closes datagram socket, and proxy connection. + */ + public void close(){ + if(!server_mode) proxy.endSession(); + super.close(); + } + + /** + This method checks wether proxy still runs udp forwarding service + for this socket. + <p> + This methods checks wether the primary connection to proxy server + is active. If it is, chances are that proxy continues to forward + datagrams being send from this socket. If it was closed, most likely + datagrams are no longer being forwarded by the server. + <p> + CProxy might decide to stop forwarding datagrams, in which case it + should close primary connection. This method allows to check, wether + this have been done. + <p> + You can specify timeout for which we should be checking EOF condition + on the primary connection. Timeout is in milliseconds. Specifying 0 as + timeout implies infinity, in which case method will block, until + connection to proxy is closed or an error happens, and then return false. + <p> + One possible scenario is to call isProxyactive(0) in separate thread, + and once it returned notify other threads about this event. + + @param timeout For how long this method should block, before returning. + @return true if connection to proxy is active, false if eof or error + condition have been encountered on the connection. + */ + public boolean isProxyAlive(int timeout){ + if(server_mode) return false; + if(proxy != null){ + try{ + proxy.proxySocket.setSoTimeout(timeout); + + int eof = proxy.in.read(); + if(eof < 0) return false; // EOF encountered. + else return true; // This really should not happen + + }catch(InterruptedIOException iioe){ + return true; // read timed out. + }catch(IOException ioe){ + return false; + } + } + return false; + } + +//PRIVATE METHODS +////////////////// + + + private byte[] formHeader(InetAddress ip, int port){ + Socks5Message request = new Socks5Message(0,ip,port); + request.data[0] = 0; + return request.data; + } + + + private byte[] formHeader(String host,int port){ + Socks5Message request = new Socks5Message(0,host,port); + request.data[0] = 0; + return request.data; + } + + +/*====================================================================== + +//Mainly Test functions +////////////////////// + + private String bytes2String(byte[] b){ + String s=""; + char[] hex_digit = { '0','1','2','3','4','5','6','7','8','9', + 'A','B','C','D','E','F'}; + for(int i=0;i<b.length;++i){ + int i1 = (b[i] & 0xF0) >> 4; + int i2 = b[i] & 0xF; + s+=hex_digit[i1]; + s+=hex_digit[i2]; + s+=" "; + } + return s; + } + private static final void debug(String s){ + if(DEBUG) + System.out.print(s); + } + + private static final boolean DEBUG = true; + + + public static void usage(){ + System.err.print( + "Usage: java Socks.SocksDatagramSocket host port [socksHost socksPort]\n"); + } + + static final int defaultProxyPort = 1080; //Default Port + static final String defaultProxyHost = "www-proxy"; //Default proxy + + public static void main(String args[]){ + int port; + String host; + int proxyPort; + String proxyHost; + InetAddress ip; + + if(args.length > 1 && args.length < 5){ + try{ + + host = args[0]; + port = Integer.parseInt(args[1]); + + proxyPort =(args.length > 3)? Integer.parseInt(args[3]) + : defaultProxyPort; + + host = args[0]; + ip = InetAddress.getByName(host); + + proxyHost =(args.length > 2)? args[2] + : defaultProxyHost; + + CProxy.setDefaultProxy(proxyHost,proxyPort); + CProxy p = CProxy.getDefaultProxy(); + p.addDirect("lux"); + + + DatagramSocket ds = new Socks5DatagramSocket(); + + + BufferedReader in = new BufferedReader( + new InputStreamReader(System.in)); + String s; + + System.out.print("Enter line:"); + s = in.readLine(); + + while(s != null){ + byte[] data = (s+"\r\n").getBytes(); + DatagramPacket dp = new DatagramPacket(data,0,data.length, + ip,port); + System.out.println("Sending to: "+ip+":"+port); + ds.send(dp); + dp = new DatagramPacket(new byte[1024],1024); + + System.out.println("Trying to recieve on port:"+ + ds.getLocalPort()); + ds.receive(dp); + System.out.print("Recieved:\n"+ + "From:"+dp.getAddress()+":"+dp.getPort()+ + "\n\n"+ + new String(dp.getData(),dp.getOffset(),dp.getLength())+"\n" + ); + System.out.print("Enter line:"); + s = in.readLine(); + + } + ds.close(); + System.exit(1); + + }catch(SocksException s_ex){ + System.err.println("SocksException:"+s_ex); + s_ex.printStackTrace(); + System.exit(1); + }catch(IOException io_ex){ + io_ex.printStackTrace(); + System.exit(1); + }catch(NumberFormatException num_ex){ + usage(); + num_ex.printStackTrace(); + System.exit(1); + } + + }else{ + usage(); + } + } +*/ + +}
--- a/src/net/sourceforge/jsocks/Socks5Message.java Fri Aug 01 10:25:44 2014 -0700 +++ b/src/net/sourceforge/jsocks/Socks5Message.java Fri Aug 01 11:23:10 2014 -0700 @@ -1,292 +1,291 @@ -package net.sourceforge.jsocks; - -import java.io.DataInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.InetAddress; -import java.net.UnknownHostException; - -/** - SOCKS5 request/response message. -*/ - -public class Socks5Message extends ProxyMessage { - /** Address type of given message*/ - public int addrType; - - byte[] data; - - /** - Server error response. - @param cmd Error code. - */ - public Socks5Message(int cmd) { - super(cmd, null, 0); - data = new byte[3]; - data[0] = SOCKS_VERSION; //Version. - data[1] = (byte)cmd; //Reply code for some kind of failure. - data[2] = 0; //Reserved byte. - } - - /** - Construct client request or server response. - @param cmd - Request/Response code. - @param ip - IP field. - @paarm port - port field. - */ - public Socks5Message(int cmd, InetAddress ip, int port) { - super(cmd, ip, port); - this.host = ip == null ? "0.0.0.0" : ip.getHostName(); - this.version = SOCKS_VERSION; - byte[] addr; - - if (ip == null) { - addr = new byte[4]; - addr[0] = addr[1] = addr[2] = addr[3] = 0; - } - else - addr = ip.getAddress(); - - addrType = addr.length == 4 ? SOCKS_ATYP_IPV4 - : SOCKS_ATYP_IPV6; - data = new byte[6 + addr.length]; - data[0] = (byte) SOCKS_VERSION; //Version - data[1] = (byte) command; //Command - data[2] = (byte) 0; //Reserved byte - data[3] = (byte) addrType; //Address type - //Put Address - System.arraycopy(addr, 0, data, 4, addr.length); - //Put port - data[data.length - 2] = (byte)(port >> 8); - data[data.length - 1] = (byte)(port); - } - - - /** - Construct client request or server response. - @param cmd - Request/Response code. - @param hostName - IP field as hostName, uses ADDR_TYPE of HOSTNAME. - @paarm port - port field. - */ - public Socks5Message(int cmd, String hostName, int port) { - super(cmd, null, port); - this.host = hostName; - this.version = SOCKS_VERSION; - //System.out.println("Doing ATYP_DOMAINNAME"); - addrType = SOCKS_ATYP_DOMAINNAME; - byte addr[] = hostName.getBytes(); - data = new byte[7 + addr.length]; - data[0] = (byte) SOCKS_VERSION; //Version - data[1] = (byte) command; //Command - data[2] = (byte) 0; //Reserved byte - data[3] = (byte) SOCKS_ATYP_DOMAINNAME; //Address type - data[4] = (byte) addr.length; //Length of the address - //Put Address - System.arraycopy(addr, 0, data, 5, addr.length); - //Put port - data[data.length - 2] = (byte)(port >> 8); - data[data.length - 1] = (byte)(port); - } - - /** - Initialises Message from the stream. Reads server response from - given stream. - @param in Input stream to read response from. - @throws SocksException If server response code is not SOCKS_SUCCESS(0), or - if any error with protocol occurs. - @throws IOException If any error happens with I/O. - */ - public Socks5Message(InputStream in) throws SocksException, - IOException { - this(in, true); - } - - /** - Initialises Message from the stream. Reads server response or client - request from given stream. - - @param in Input stream to read response from. - @param clinetMode If true read server response, else read client request. - @throws SocksException If server response code is not SOCKS_SUCCESS(0) and - reading in client mode, or if any error with protocol occurs. - @throws IOException If any error happens with I/O. - */ - public Socks5Message(InputStream in, boolean clientMode)throws SocksException, - IOException { - read(in, clientMode); - } - - - /** - Initialises Message from the stream. Reads server response from - given stream. - @param in Input stream to read response from. - @throws SocksException If server response code is not SOCKS_SUCCESS(0), or - if any error with protocol occurs. - @throws IOException If any error happens with I/O. - */ - public void read(InputStream in) throws SocksException, - IOException { - read(in, true); - } - - - /** - Initialises Message from the stream. Reads server response or client - request from given stream. - - @param in Input stream to read response from. - @param clinetMode If true read server response, else read client request. - @throws SocksException If server response code is not SOCKS_SUCCESS(0) and - reading in client mode, or if any error with protocol occurs. - @throws IOException If any error happens with I/O. - */ - public void read(InputStream in, boolean clientMode) throws SocksException, - IOException { - data = null; - ip = null; - DataInputStream di = new DataInputStream(in); - version = di.readUnsignedByte(); - command = di.readUnsignedByte(); - - if (clientMode && command != 0) - throw new SocksException(command); - - @SuppressWarnings("unused") - int reserved = di.readUnsignedByte(); - addrType = di.readUnsignedByte(); - byte addr[]; - - switch (addrType) { - case SOCKS_ATYP_IPV4: - addr = new byte[4]; - di.readFully(addr); - host = bytes2IPV4(addr, 0); - break; - - case SOCKS_ATYP_IPV6: - addr = new byte[SOCKS_IPV6_LENGTH];//I believe it is 16 bytes,huge! - di.readFully(addr); - host = bytes2IPV6(addr, 0); - break; - - case SOCKS_ATYP_DOMAINNAME: - //System.out.println("Reading ATYP_DOMAINNAME"); - addr = new byte[di.readUnsignedByte()];//Next byte shows the length - di.readFully(addr); - host = new String(addr); - break; - - default: - throw(new SocksException(Proxy.SOCKS_JUST_ERROR)); - } - - port = di.readUnsignedShort(); - - if (addrType != SOCKS_ATYP_DOMAINNAME && doResolveIP) { - try { - ip = InetAddress.getByName(host); - } - catch (UnknownHostException uh_ex) { - } - } - } - - /** - Writes the message to the stream. - @param out Output stream to which message should be written. - */ - public void write(OutputStream out)throws SocksException, - IOException { - if (data == null) { - Socks5Message msg; - - if (addrType == SOCKS_ATYP_DOMAINNAME) - msg = new Socks5Message(command, host, port); - else { - if (ip == null) { - try { - ip = InetAddress.getByName(host); - } - catch (UnknownHostException uh_ex) { - throw new SocksException(Proxy.SOCKS_JUST_ERROR); - } - } - - msg = new Socks5Message(command, ip, port); - } - - data = msg.data; - } - - out.write(data); - } - - /** - Returns IP field of the message as IP, if the message was created - with ATYP of HOSTNAME, it will attempt to resolve the hostname, - which might fail. - @throws UnknownHostException if host can't be resolved. - */ - public InetAddress getInetAddress() throws UnknownHostException { - if (ip != null) return ip; - - return (ip = InetAddress.getByName(host)); - } - - /** - Returns string representation of the message. - */ - public String toString() { - String s = - "Socks5Message:" + "\n" + - "VN " + version + "\n" + - "CMD " + command + "\n" + - "ATYP " + addrType + "\n" + - "ADDR " + host + "\n" + - "PORT " + port + "\n"; - return s; - } - - - /** - *Wether to resolve hostIP returned from SOCKS server - *that is wether to create InetAddress object from the - *hostName string - */ - static public boolean resolveIP() { return doResolveIP;} - - /** - *Wether to resolve hostIP returned from SOCKS server - *that is wether to create InetAddress object from the - *hostName string - *@param doResolve Wether to resolve hostIP from SOCKS server. - *@return Previous value. - */ - static public boolean resolveIP(boolean doResolve) { - boolean old = doResolveIP; - doResolveIP = doResolve; - return old; - } - - /* - private static final void debug(String s){ - if(DEBUG) - System.out.print(s); - } - private static final boolean DEBUG = false; - */ - - //SOCKS5 constants - public static final int SOCKS_VERSION = 5; - - public static final int SOCKS_ATYP_IPV4 = 0x1; //Where is 2?? - public static final int SOCKS_ATYP_DOMAINNAME = 0x3; //!!!!rfc1928 - public static final int SOCKS_ATYP_IPV6 = 0x4; - - public static final int SOCKS_IPV6_LENGTH = 16; - - static boolean doResolveIP = true; - -} +package net.sourceforge.jsocks; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.DataInputStream; +import java.net.InetAddress; +import java.net.UnknownHostException; + +/** + SOCKS5 request/response message. +*/ + +class Socks5Message extends ProxyMessage{ + /** Address type of given message*/ + public int addrType; + + byte[] data; + + /** + Server error response. + @param cmd Error code. + */ + public Socks5Message(int cmd){ + super(cmd,null,0); + data = new byte[3]; + data[0] = SOCKS_VERSION; //Version. + data[1] = (byte)cmd; //Reply code for some kind of failure. + data[2] = 0; //Reserved byte. + } + + /** + Construct client request or server response. + @param cmd - Request/Response code. + @param ip - IP field. + @paarm port - port field. + */ + public Socks5Message(int cmd,InetAddress ip,int port){ + super(cmd,ip,port); + this.host = ip==null?"0.0.0.0":ip.getHostName(); + this.version = SOCKS_VERSION; + + byte[] addr; + + if(ip == null){ + addr = new byte[4]; + addr[0]=addr[1]=addr[2]=addr[3]=0; + }else + addr = ip.getAddress(); + + addrType = addr.length == 4 ? SOCKS_ATYP_IPV4 + : SOCKS_ATYP_IPV6; + + data = new byte[6+addr.length]; + data[0] = (byte) SOCKS_VERSION; //Version + data[1] = (byte) command; //Command + data[2] = (byte) 0; //Reserved byte + data[3] = (byte) addrType; //Address type + + //Put Address + System.arraycopy(addr,0,data,4,addr.length); + //Put port + data[data.length-2] = (byte)(port>>8); + data[data.length-1] = (byte)(port); + } + + + /** + Construct client request or server response. + @param cmd - Request/Response code. + @param hostName - IP field as hostName, uses ADDR_TYPE of HOSTNAME. + @paarm port - port field. + */ + public Socks5Message(int cmd,String hostName,int port){ + super(cmd,null,port); + this.host = hostName; + this.version = SOCKS_VERSION; + + //System.out.println("Doing ATYP_DOMAINNAME"); + + addrType = SOCKS_ATYP_DOMAINNAME; + byte addr[] = hostName.getBytes(); + + data =new byte[7+addr.length]; + data[0] = (byte) SOCKS_VERSION; //Version + data[1] = (byte) command; //Command + data[2] = (byte) 0; //Reserved byte + data[3] = (byte) SOCKS_ATYP_DOMAINNAME; //Address type + data[4] = (byte) addr.length; //Length of the address + + //Put Address + System.arraycopy(addr,0,data,5,addr.length); + //Put port + data[data.length-2] = (byte)(port >>8); + data[data.length-1] = (byte)(port); + } + + /** + Initialises Message from the stream. Reads server response from + given stream. + @param in Input stream to read response from. + @throws SocksException If server response code is not SOCKS_SUCCESS(0), or + if any error with protocol occurs. + @throws IOException If any error happens with I/O. + */ + public Socks5Message(InputStream in) throws SocksException, + IOException{ + this(in,true); + } + + /** + Initialises Message from the stream. Reads server response or client + request from given stream. + + @param in Input stream to read response from. + @param clinetMode If true read server response, else read client request. + @throws SocksException If server response code is not SOCKS_SUCCESS(0) and + reading in client mode, or if any error with protocol occurs. + @throws IOException If any error happens with I/O. + */ + public Socks5Message(InputStream in,boolean clientMode)throws SocksException, + IOException{ + read(in,clientMode); + } + + + /** + Initialises Message from the stream. Reads server response from + given stream. + @param in Input stream to read response from. + @throws SocksException If server response code is not SOCKS_SUCCESS(0), or + if any error with protocol occurs. + @throws IOException If any error happens with I/O. + */ + public void read(InputStream in) throws SocksException, + IOException{ + read(in,true); + } + + + /** + Initialises Message from the stream. Reads server response or client + request from given stream. + + @param in Input stream to read response from. + @param clinetMode If true read server response, else read client request. + @throws SocksException If server response code is not SOCKS_SUCCESS(0) and + reading in client mode, or if any error with protocol occurs. + @throws IOException If any error happens with I/O. + */ + public void read(InputStream in,boolean clientMode) throws SocksException, + IOException{ + data = null; + ip = null; + + DataInputStream di = new DataInputStream(in); + + version = di.readUnsignedByte(); + command = di.readUnsignedByte(); + if(clientMode && command != 0) + throw new SocksException(command); + + int reserved = di.readUnsignedByte(); + addrType = di.readUnsignedByte(); + + byte addr[]; + + switch(addrType){ + case SOCKS_ATYP_IPV4: + addr = new byte[4]; + di.readFully(addr); + host = bytes2IPV4(addr,0); + break; + case SOCKS_ATYP_IPV6: + addr = new byte[SOCKS_IPV6_LENGTH];//I believe it is 16 bytes,huge! + di.readFully(addr); + host = bytes2IPV6(addr,0); + break; + case SOCKS_ATYP_DOMAINNAME: + //System.out.println("Reading ATYP_DOMAINNAME"); + addr = new byte[di.readUnsignedByte()];//Next byte shows the length + di.readFully(addr); + host = new String(addr); + break; + default: + throw(new SocksException(CProxy.SOCKS_JUST_ERROR)); + } + + port = di.readUnsignedShort(); + + if(addrType != SOCKS_ATYP_DOMAINNAME && doResolveIP){ + try{ + ip = InetAddress.getByName(host); + }catch(UnknownHostException uh_ex){ + } + } + } + + /** + Writes the message to the stream. + @param out Output stream to which message should be written. + */ + public void write(OutputStream out)throws SocksException, + IOException{ + if(data == null){ + Socks5Message msg; + + if(addrType == SOCKS_ATYP_DOMAINNAME) + msg = new Socks5Message(command,host,port); + else{ + if(ip == null){ + try{ + ip = InetAddress.getByName(host); + }catch(UnknownHostException uh_ex){ + throw new SocksException(CProxy.SOCKS_JUST_ERROR); + } + } + msg = new Socks5Message(command,ip,port); + } + data = msg.data; + } + out.write(data); + } + + /** + Returns IP field of the message as IP, if the message was created + with ATYP of HOSTNAME, it will attempt to resolve the hostname, + which might fail. + @throws UnknownHostException if host can't be resolved. + */ + public InetAddress getInetAddress() throws UnknownHostException{ + if(ip!=null) return ip; + + return (ip=InetAddress.getByName(host)); + } + + /** + Returns string representation of the message. + */ + public String toString(){ + String s= + "Socks5Message:"+"\n"+ + "VN "+version+"\n"+ + "CMD "+command+"\n"+ + "ATYP "+addrType+"\n"+ + "ADDR "+host+"\n"+ + "PORT "+port+"\n"; + return s; + } + + + /** + *Wether to resolve hostIP returned from SOCKS server + *that is wether to create InetAddress object from the + *hostName string + */ + static public boolean resolveIP(){ return doResolveIP;} + + /** + *Wether to resolve hostIP returned from SOCKS server + *that is wether to create InetAddress object from the + *hostName string + *@param doResolve Wether to resolve hostIP from SOCKS server. + *@return Previous value. + */ + static public boolean resolveIP(boolean doResolve){ + boolean old = doResolveIP; + doResolveIP = doResolve; + return old; + } + + /* + private static final void debug(String s){ + if(DEBUG) + System.out.print(s); + } + private static final boolean DEBUG = false; + */ + + //SOCKS5 constants + public static final int SOCKS_VERSION =5; + + public static final int SOCKS_ATYP_IPV4 =0x1; //Where is 2?? + public static final int SOCKS_ATYP_DOMAINNAME =0x3; //!!!!rfc1928 + public static final int SOCKS_ATYP_IPV6 =0x4; + + public static final int SOCKS_IPV6_LENGTH =16; + + static boolean doResolveIP = true; + +}
--- a/src/net/sourceforge/jsocks/Socks5Proxy.java Fri Aug 01 10:25:44 2014 -0700 +++ b/src/net/sourceforge/jsocks/Socks5Proxy.java Fri Aug 01 11:23:10 2014 -0700 @@ -1,248 +1,248 @@ -package net.sourceforge.jsocks; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.InetAddress; -import java.net.Socket; -import java.net.SocketException; -import java.net.UnknownHostException; -import java.util.Enumeration; -import java.util.Hashtable; - -/** - SOCKS5 Proxy. -*/ - -public class Socks5Proxy extends Proxy implements Cloneable { - -//Data members - private Hashtable<Integer, Authentication> authMethods = new Hashtable<Integer, Authentication>(); - private int selectedMethod; - - boolean resolveAddrLocally = true; - UDPEncapsulation udp_encapsulation = null; - - -//Public Constructors -//==================== - - /** - Creates SOCKS5 proxy. - @param proxyHost Host on which a Proxy server runs. - @param proxyPort Port on which a Proxy server listens for connections. - @throws UnknownHostException If proxyHost can't be resolved. - */ - public Socks5Proxy(String proxyHost, int proxyPort) - throws UnknownHostException { - super(proxyHost, proxyPort); - version = 5; - setAuthenticationMethod(0, new AuthenticationNone()); - } - - - /** - Creates SOCKS5 proxy. - @param proxyIP Host on which a Proxy server runs. - @param proxyPort Port on which a Proxy server listens for connections. - */ - public Socks5Proxy(InetAddress proxyIP, int proxyPort) { - super(proxyIP, proxyPort); - version = 5; - setAuthenticationMethod(0, new AuthenticationNone()); - } - - -//Public instance methods -//======================== - - - /** - * Wether to resolve address locally or to let proxy do so. - <p> - SOCKS5 protocol allows to send host names rather then IPs in the - requests, this option controls wether the hostnames should be send - to the proxy server as names, or should they be resolved locally. - @param doResolve Wether to perform resolution locally. - @return Previous settings. - */ - public boolean resolveAddrLocally(boolean doResolve) { - boolean old = resolveAddrLocally; - resolveAddrLocally = doResolve; - return old; - } - /** - Get current setting on how the addresses should be handled. - @return Current setting for address resolution. - @see Socks5Proxy#resolveAddrLocally(boolean doResolve) - */ - public boolean resolveAddrLocally() { - return resolveAddrLocally; - } - - /** - Adds another authentication method. - @param methodId Authentication method id, see rfc1928 - @param method Implementation of Authentication - @see Authentication - */ - public boolean setAuthenticationMethod(int methodId, - Authentication method) { - if (methodId < 0 || methodId > 255) - return false; - - if (method == null) { - //Want to remove a particular method - return (authMethods.remove(Integer.valueOf(methodId)) != null); - } - else {//Add the method, or rewrite old one - authMethods.put(Integer.valueOf(methodId), method); - } - - return true; - } - - /** - Get authentication method, which corresponds to given method id - @param methodId Authentication method id. - @return Implementation for given method or null, if one was not set. - */ - public Authentication getAuthenticationMethod(int methodId) { - Object method = authMethods.get(Integer.valueOf(methodId)); - - if (method == null) return null; - - return (Authentication)method; - } - - /** - Creates a clone of this Proxy. - */ - @Override - @SuppressWarnings("unchecked") - public Object clone() { - Socks5Proxy newProxy = new Socks5Proxy(proxyIP, proxyPort); - newProxy.authMethods = (Hashtable<Integer, Authentication>) this.authMethods.clone(); - newProxy.resolveAddrLocally = resolveAddrLocally; - newProxy.chainProxy = chainProxy; - return newProxy; - } - -//Public Static(Class) Methods -//============================== - - -//Protected Methods -//================= - - @Override - protected Proxy copy() { - Socks5Proxy copy = new Socks5Proxy(proxyIP, proxyPort); - copy.authMethods = this.authMethods; //same Hash, no copy - copy.chainProxy = this.chainProxy; - copy.resolveAddrLocally = this.resolveAddrLocally; - return copy; - } - /** - * - * - */ - @Override - protected void startSession()throws SocksException { - super.startSession(); - Authentication auth; - Socket ps = proxySocket; //The name is too long - - try { - byte nMethods = (byte) authMethods.size(); //Number of methods - byte[] buf = new byte[2 + nMethods]; //2 is for VER,NMETHODS - buf[0] = (byte) version; - buf[1] = nMethods; //Number of methods - int i = 2; - Enumeration<Integer> ids = authMethods.keys(); - - while (ids.hasMoreElements()) - buf[i++] = (byte)ids.nextElement().intValue(); - - out.write(buf); - out.flush(); - int versionNumber = in.read(); - selectedMethod = in.read(); - - if (versionNumber < 0 || selectedMethod < 0) { - //EOF condition was reached - endSession(); - throw(new SocksException(SOCKS_PROXY_IO_ERROR, - "Connection to proxy lost.")); - } - - if (versionNumber < version) { - //What should we do?? - } - - if (selectedMethod == 0xFF) { //No method selected - ps.close(); - throw(new SocksException(SOCKS_AUTH_NOT_SUPPORTED)); - } - - auth = getAuthenticationMethod(selectedMethod); - - if (auth == null) { - //This shouldn't happen, unless method was removed by other - //thread, or the server stuffed up - throw(new SocksException(SOCKS_JUST_ERROR, - "Speciefied Authentication not found!")); - } - - Object[] in_out = auth.doSocksAuthentication(selectedMethod, ps); - - if (in_out == null) { - //Authentication failed by some reason - throw(new SocksException(SOCKS_AUTH_FAILURE)); - } - - //Most authentication methods are expected to return - //simply the input/output streams associated with - //the socket. However if the auth. method requires - //some kind of encryption/decryption being done on the - //connection it should provide classes to handle I/O. - in = (InputStream) in_out[0]; - out = (OutputStream) in_out[1]; - - if (in_out.length > 2) - udp_encapsulation = (UDPEncapsulation) in_out[2]; - } - catch (SocksException s_ex) { - throw s_ex; - } - catch (UnknownHostException uh_ex) { - throw(new SocksException(SOCKS_PROXY_NO_CONNECT)); - } - catch (SocketException so_ex) { - throw(new SocksException(SOCKS_PROXY_NO_CONNECT)); - } - catch (IOException io_ex) { - //System.err.println(io_ex); - throw(new SocksException(SOCKS_PROXY_IO_ERROR, "" + io_ex)); - } - } - - @Override - protected ProxyMessage formMessage(int cmd, InetAddress ip, int port) { - return new Socks5Message(cmd, ip, port); - } - @Override - protected ProxyMessage formMessage(int cmd, String host, int port) - throws UnknownHostException { - if (resolveAddrLocally) - return formMessage(cmd, InetAddress.getByName(host), port); - else - return new Socks5Message(cmd, host, port); - } - @Override - protected ProxyMessage formMessage(InputStream in) - throws SocksException, - IOException { - return new Socks5Message(in); - } - -} +package net.sourceforge.jsocks; +import java.net.*; +import java.io.*; +import java.util.Hashtable; +import java.util.Enumeration; + +/** + SOCKS5 CProxy. +*/ + +public class Socks5Proxy extends CProxy implements Cloneable{ + +//Data members + private Hashtable authMethods = new Hashtable(); + private int selectedMethod; + + boolean resolveAddrLocally = true; + UDPEncapsulation udp_encapsulation=null; + + +//Public Constructors +//==================== + + /** + Creates SOCKS5 proxy. + @param p CProxy to use to connect to this proxy, allows proxy chaining. + @param proxyHost Host on which a CProxy server runs. + @param proxyPort Port on which a CProxy server listens for connections. + @throws UnknownHostException If proxyHost can't be resolved. + */ + public Socks5Proxy(CProxy p,String proxyHost,int proxyPort) + throws UnknownHostException{ + super(p,proxyHost,proxyPort); + version = 5; + setAuthenticationMethod(0,new AuthenticationNone()); + } + + /** + Creates SOCKS5 proxy. + @param proxyHost Host on which a CProxy server runs. + @param proxyPort Port on which a CProxy server listens for connections. + @throws UnknownHostException If proxyHost can't be resolved. + */ + public Socks5Proxy(String proxyHost,int proxyPort) + throws UnknownHostException{ + this(null,proxyHost,proxyPort); + } + + + /** + Creates SOCKS5 proxy. + @param p CProxy to use to connect to this proxy, allows proxy chaining. + @param proxyIP Host on which a CProxy server runs. + @param proxyPort Port on which a CProxy server listens for connections. + */ + public Socks5Proxy(CProxy p,InetAddress proxyIP,int proxyPort){ + super(p,proxyIP,proxyPort); + version = 5; + setAuthenticationMethod(0,new AuthenticationNone()); + } + + /** + Creates SOCKS5 proxy. + @param proxyIP Host on which a CProxy server runs. + @param proxyPort Port on which a CProxy server listens for connections. + */ + public Socks5Proxy(InetAddress proxyIP,int proxyPort){ + this(null,proxyIP,proxyPort); + } + +//Public instance methods +//======================== + + + /** + * Wether to resolve address locally or to let proxy do so. + <p> + SOCKS5 protocol allows to send host names rather then IPs in the + requests, this option controls wether the hostnames should be send + to the proxy server as names, or should they be resolved locally. + @param doResolve Wether to perform resolution locally. + @return Previous settings. + */ + public boolean resolveAddrLocally(boolean doResolve){ + boolean old = resolveAddrLocally; + resolveAddrLocally = doResolve; + return old; + } + /** + Get current setting on how the addresses should be handled. + @return Current setting for address resolution. + @see Socks5Proxy#resolveAddrLocally(boolean doResolve) + */ + public boolean resolveAddrLocally(){ + return resolveAddrLocally; + } + + /** + Adds another authentication method. + @param methodId Authentication method id, see rfc1928 + @param method Implementation of Authentication + @see Authentication + */ + public boolean setAuthenticationMethod(int methodId, + Authentication method){ + if(methodId<0 || methodId > 255) + return false; + if(method == null){ + //Want to remove a particular method + return (authMethods.remove(new Integer(methodId)) != null); + }else{//Add the method, or rewrite old one + authMethods.put(new Integer(methodId),method); + } + return true; + } + + /** + Get authentication method, which corresponds to given method id + @param methodId Authentication method id. + @return Implementation for given method or null, if one was not set. + */ + public Authentication getAuthenticationMethod(int methodId){ + Object method = authMethods.get(new Integer(methodId)); + if(method == null) return null; + return (Authentication)method; + } + + /** + Creates a clone of this CProxy. + */ + public Object clone(){ + Socks5Proxy newProxy = new Socks5Proxy(proxyIP,proxyPort); + newProxy.authMethods = (Hashtable) this.authMethods.clone(); + newProxy.directHosts = (InetRange)directHosts.clone(); + newProxy.resolveAddrLocally = resolveAddrLocally; + newProxy.chainProxy = chainProxy; + return newProxy; + } + +//Public Static(Class) Methods +//============================== + + +//Protected Methods +//================= + + protected CProxy copy(){ + Socks5Proxy copy = new Socks5Proxy(proxyIP,proxyPort); + copy.authMethods = this.authMethods; //same Hash, no copy + copy.directHosts = this.directHosts; + copy.chainProxy = this.chainProxy; + copy.resolveAddrLocally = this.resolveAddrLocally; + return copy; + } + /** + * + * + */ + protected void startSession()throws SocksException{ + super.startSession(); + Authentication auth; + Socket ps = proxySocket; //The name is too long + + try{ + + byte nMethods = (byte) authMethods.size(); //Number of methods + + byte[] buf = new byte[2+nMethods]; //2 is for VER,NMETHODS + buf[0] = (byte) version; + buf[1] = nMethods; //Number of methods + int i=2; + + Enumeration ids = authMethods.keys(); + while(ids.hasMoreElements()) + buf[i++] = (byte)((Integer)ids.nextElement()).intValue(); + + out.write(buf); + out.flush(); + + int versionNumber = in.read(); + selectedMethod = in.read(); + + if(versionNumber < 0 || selectedMethod < 0){ + //EOF condition was reached + endSession(); + throw(new SocksException(SOCKS_PROXY_IO_ERROR, + "Connection to proxy lost.")); + } + if(versionNumber < version){ + //What should we do?? + } + if(selectedMethod == 0xFF){ //No method selected + ps.close(); + throw ( new SocksException(SOCKS_AUTH_NOT_SUPPORTED)); + } + + auth = getAuthenticationMethod(selectedMethod); + if(auth == null){ + //This shouldn't happen, unless method was removed by other + //thread, or the server stuffed up + throw(new SocksException(SOCKS_JUST_ERROR, + "Speciefied Authentication not found!")); + } + Object[] in_out = auth.doSocksAuthentication(selectedMethod,ps); + if(in_out == null){ + //Authentication failed by some reason + throw(new SocksException(SOCKS_AUTH_FAILURE)); + } + //Most authentication methods are expected to return + //simply the input/output streams associated with + //the socket. However if the auth. method requires + //some kind of encryption/decryption being done on the + //connection it should provide classes to handle I/O. + + in = (InputStream) in_out[0]; + out = (OutputStream) in_out[1]; + if(in_out.length > 2) + udp_encapsulation = (UDPEncapsulation) in_out[2]; + + }catch(SocksException s_ex){ + throw s_ex; + }catch(UnknownHostException uh_ex){ + throw(new SocksException(SOCKS_PROXY_NO_CONNECT)); + }catch(SocketException so_ex){ + throw(new SocksException(SOCKS_PROXY_NO_CONNECT)); + }catch(IOException io_ex){ + //System.err.println(io_ex); + throw(new SocksException(SOCKS_PROXY_IO_ERROR,""+io_ex)); + } + } + + protected ProxyMessage formMessage(int cmd,InetAddress ip,int port){ + return new Socks5Message(cmd,ip,port); + } + protected ProxyMessage formMessage(int cmd,String host,int port) + throws UnknownHostException{ + if(resolveAddrLocally) + return formMessage(cmd,InetAddress.getByName(host),port); + else + return new Socks5Message(cmd,host,port); + } + protected ProxyMessage formMessage(InputStream in) + throws SocksException, + IOException{ + return new Socks5Message(in); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/net/sourceforge/jsocks/SocksDialog.java Fri Aug 01 11:23:10 2014 -0700 @@ -0,0 +1,615 @@ +package net.sourceforge.jsocks; +import java.awt.*; +import java.awt.event.*; + +/** + Socks configuration dialog.<br> + Class which provides GUI means of getting CProxy configuration + from the user. + */ +public class SocksDialog extends Dialog + implements WindowListener, + ItemListener, + ActionListener, + Runnable{ + +//GUI components + TextField host_text, + port_text, + user_text, + password_text, + direct_text; + Button add_button, + remove_button, + cancel_button, + ok_button, + dismiss_button; + List direct_list; + Checkbox socks4radio, + socks5radio, + none_check, + up_check, + gssapi_check; + + Dialog warning_dialog; + Label warning_label; + + String host,user,password; + int port; + Thread net_thread = null; + + //CheckboxGroups + CheckboxGroup socks_group = new CheckboxGroup(); + + CProxy proxy; + InetRange ir; + + final static int COMMAND_MODE = 0; + final static int OK_MODE = 1; + + int mode; + + /**Wether to resolve addresses in separate thread. + <p> + Default value is true, however on some JVMs, namely one from + the Microsoft, it doesn't want to work properly, separate thread + can't close the dialog opened in GUI thread, and everuthing else + is then crashes. + <p> + When setting this variable to false, SocksDialog will block while + trying to look up proxy host, and if this takes considerable amount + of time it might be annoying to user. + + */ + public static boolean useThreads = true; + + +// Constructors +//////////////////////////////////// + /** + Creates SOCKS configuration dialog.<br> + Uses default initialisation:<br> + CProxy host: socks-proxy <br> + CProxy port: 1080 <br> + Version: 5<br> + + */ + public SocksDialog(Frame parent){ + this(parent,null); + } + /** + Creates SOCKS configuration dialog and initialises it + to given proxy. + */ + public SocksDialog(Frame parent,CProxy init_proxy){ + super(parent,"Proxy Configuration",true); + warning_dialog = new Dialog(parent,"Warning",true); + + guiInit(); + setResizable(false); + addWindowListener(this); + Component[] comps = getComponents(); + for(int i=0;i<comps.length;++i){ + if(comps[i] instanceof Button) + ((Button)comps[i]).addActionListener(this); + else if(comps[i] instanceof TextField) + ((TextField) comps[i]).addActionListener(this); + else if(comps[i] instanceof Checkbox){ + ((Checkbox)comps[i]).addItemListener(this); + } + } + proxy = init_proxy; + if(proxy != null) doInit(proxy); + else ir = new InetRange(); + + dismiss_button.addActionListener(this); + warning_dialog.addWindowListener(this); + } + +//Public Methods +//////////////// + + /** + Displays SOCKS configuartion dialog. + <p> + Returns initialised proxy object, or null if user cancels dialog + by either pressing Cancel or closing the dialog window. + */ + public CProxy getProxy(){ + mode = COMMAND_MODE; + pack(); + show(); + return proxy; + } + + /** + Initialises dialog to given proxy and displays SOCKS configuartion dialog. + <p> + Returns initialised proxy object, or null if user cancels dialog + by either pressing Cancel or closing the dialog window. + */ + public CProxy getProxy(CProxy p){ + if(p != null){ + doInit(p); + } + mode = COMMAND_MODE; + pack(); + show(); + return proxy; + } + +// WindowListener Interface +///////////////////////////////// + public void windowActivated(java.awt.event.WindowEvent e){ + } + public void windowDeactivated(java.awt.event.WindowEvent e){ + } + public void windowOpened(java.awt.event.WindowEvent e){ + } + public void windowClosing(java.awt.event.WindowEvent e){ + Window source = e.getWindow(); + if(source == this){ + onCancel(); + }else if(source == warning_dialog){ + onDismiss(); + } + } + public void windowClosed(java.awt.event.WindowEvent e){ + } + public void windowIconified(java.awt.event.WindowEvent e){ + } + public void windowDeiconified(java.awt.event.WindowEvent e){ + } + +//ActionListener interface +/////////////////////////// + public void actionPerformed(ActionEvent ae){ + + Object source = ae.getSource(); + + if(source == cancel_button ) + onCancel(); + else if(source == add_button || source == direct_text) + onAdd(); + else if(source == remove_button) + onRemove(); + else if(source == dismiss_button) + onDismiss(); + else if(source == ok_button || source instanceof TextField) + onOK(); + } +//ItemListener interface +//////////////////////// + public void itemStateChanged(ItemEvent ie){ + Object source = ie.getSource(); + //System.out.println("ItemEvent:"+source); + if(source == socks5radio || source == socks4radio) + onSocksChange(); + else if(source == up_check) + onUPChange(); + + } +//Runnable interface +//////////////////// + /** + Resolves proxy address in other thread, to avoid + annoying blocking in GUI thread. + */ + public void run(){ + + if(!initProxy()){ + //Check if we have been aborted + if(mode != OK_MODE) return; + if(net_thread != Thread.currentThread()) return; + + mode = COMMAND_MODE; + warning_label.setText("Look up failed."); + warning_label.invalidate(); + return; + } + + //System.out.println("Done!"); + while(!warning_dialog.isShowing()) + ; /* do nothing*/; + + warning_dialog.dispose(); + //dispose(); //End Dialog + } + +//Private Methods +/////////////////// + private void onOK(){ + host = host_text.getText().trim(); + user = user_text.getText(); + password = password_text.getText(); + + if(host.length() == 0){ + warn("Proxy host is not set!"); + return; + } + if(socks_group.getSelectedCheckbox() == socks4radio){ + if(user.length() == 0){ + warn("User name is not set"); + return; + } + + }else{ + if(up_check.getState()){ + if(user.length() == 0){ + warn("User name is not set."); + return; + } + if(password.length()==0){ + warn("Password is not set."); + return; + } + }else if(!none_check.getState()){ + warn("Please select at least one Authentication Method."); + return; + } + } + + try{ + port = Integer.parseInt(port_text.getText()); + }catch(NumberFormatException nfe){ + warn("Proxy port is invalid!"); + return; + } + + mode = OK_MODE; + + if(useThreads){ + net_thread = new Thread(this); + net_thread.start(); + + info("Looking up host: "+host); + //System.out.println("Info returned."); + }else if(!initProxy()){ + warn("Proxy host is invalid."); + mode = COMMAND_MODE; + } + + if(mode == OK_MODE) dispose(); + } + + private void onCancel(){ + //System.out.println("Cancel"); + proxy = null; + dispose(); + } + + private void onAdd(){ + String s = direct_text.getText(); + s.trim(); + if(s.length() == 0 ) return; + //Check for Duplicate + String[] direct_hosts = direct_list.getItems(); + for(int i=0;i<direct_hosts.length;++i) + if(direct_hosts[i].equals(s)) return; + + direct_list.add(s); + ir.add(s); + } + private void onRemove(){ + int index = direct_list.getSelectedIndex(); + if(index < 0) return; + ir.remove(direct_list.getItem(index)); + direct_list.remove(index); + direct_list.select(index); + } + + private void onSocksChange(){ + Object selected = socks_group.getSelectedCheckbox(); + if(selected == socks4radio){ + user_text.setEnabled(true); + password_text.setEnabled(false); + none_check.setEnabled(false); + up_check.setEnabled(false); + }else{ + if(up_check.getState()){ + user_text.setEnabled(true); + password_text.setEnabled(true); + }else{ + user_text.setEnabled(false); + password_text.setEnabled(false); + } + none_check.setEnabled(true); + up_check.setEnabled(true); + } + //System.out.println("onSocksChange:"+selected); + } + private void onUPChange(){ + //System.out.println("onUPChange"); + if(up_check.getState()){ + user_text.setEnabled(true); + password_text.setEnabled(true); + }else{ + user_text.setEnabled(false); + password_text.setEnabled(false); + } + } + private void onDismiss(){ + warning_dialog.dispose(); + if(mode == OK_MODE){ + mode = COMMAND_MODE; + if(net_thread!=null) net_thread.interrupt(); + } + } + + private void doInit(CProxy p){ + if(p.version == 5){ + socks_group.setSelectedCheckbox(socks5radio); + onSocksChange(); + if(((Socks5Proxy)p).getAuthenticationMethod(0)!=null) + none_check.setState(true); + UserPasswordAuthentication auth = (UserPasswordAuthentication) + ((Socks5Proxy)p).getAuthenticationMethod(2); + if(auth!=null){ + user_text.setText(auth.getUser()); + password_text.setText(auth.getPassword()); + up_check.setState(true); + onUPChange(); + } + }else{ + socks_group.setSelectedCheckbox(socks4radio); + onSocksChange(); + user_text.setText(((Socks4Proxy)p).user); + } + ir = (InetRange)(p.directHosts.clone()); + String[] direct_hosts = ir.getAll(); + direct_list.removeAll(); + for(int i=0;i<direct_hosts.length;++i) + direct_list.add(direct_hosts[i]); + + host_text.setText(p.proxyIP.getHostName()); + port_text.setText(""+p.proxyPort); + + } + + private boolean initProxy(){ + try{ + if(socks_group.getSelectedCheckbox() == socks5radio){ + proxy = new Socks5Proxy(host,port); + if(up_check.getState()) + ((Socks5Proxy)proxy).setAuthenticationMethod(2, + new UserPasswordAuthentication(user,password)); + if(!none_check.getState()) + ((Socks5Proxy)proxy).setAuthenticationMethod(0,null); + } + else + proxy = new Socks4Proxy(host,port,user); + }catch(java.net.UnknownHostException uhe){ + return false; + } + proxy.directHosts = ir; + return true; + } + private void info(String s){ + msgBox("Info",s); + } + + private void warn(String s){ + msgBox("Warning",s); + } + + private void msgBox(String title, String message){ + warning_label.setText(message); + warning_label.invalidate(); + warning_dialog.setTitle(title); + warning_dialog.pack(); + warning_dialog.show(); + } + +/*====================================================================== + Form: + Table: + +---+-------+---+---+ + | | | | | + +---+-------+---+---+ + | | | + +---+-------+-------+ + | | | | + +---+-------+-------+ + | | | | + +---+-------+-------+ + | | | + +-----------+-------+ + | | | + | +---+---+ + | | | | + +-----------+---+---+ + | | | | + +---+---+---+---+---+ + | | | | | | + +---+---+---+---+---+ +*/ + + void guiInit(){ + //Some default names used + Label label; + Container container; + Font font; + + GridBagConstraints c = new GridBagConstraints(); + + font = new Font("Dialog",Font.PLAIN,12); + + container = this; + //container = new Panel(); + container.setLayout(new GridBagLayout()); + container.setFont(font); + container.setBackground(SystemColor.menu); + c.insets = new Insets(3,3,3,3); + + c.gridx=0; c.gridy=0; + c.gridwidth=1; c.gridheight=1; + c.anchor=GridBagConstraints.NORTHEAST; + label = new Label("Host:"); + container.add(label,c); + + c.gridx=1; c.gridy=0; + c.gridwidth=2; c.gridheight=1; + c.anchor=GridBagConstraints.NORTHWEST; + host_text = new TextField("socks-proxy",15); + container.add(host_text,c); + + c.gridx=3; c.gridy=0; + c.gridwidth=1; c.gridheight=1; + c.anchor=GridBagConstraints.NORTHEAST; + label = new Label("Port:"); + container.add(label,c); + + c.gridx=4; c.gridy=0; + c.gridwidth=1; c.gridheight=1; + c.anchor=GridBagConstraints.NORTHWEST; + port_text = new TextField("1080",5); + container.add(port_text,c); + + c.gridx=0; c.gridy=1; + c.gridwidth=3; c.gridheight=1; + c.anchor=GridBagConstraints.NORTH; + socks4radio = new Checkbox("Socks4",socks_group,false); + //1.0 compatible code + //socks4radio = new Checkbox("Socks4",false); + //socks4radio.setCheckboxGroup(socks_group); + socks4radio.setFont(new Font(font.getName(),Font.BOLD,14)); + container.add(socks4radio,c); + + c.gridx=3; c.gridy=1; + c.gridwidth=2; c.gridheight=1; + c.anchor=GridBagConstraints.NORTH; + socks5radio = new Checkbox("Socks5",socks_group,true); + //1.0 compatible code + //socks5radio = new Checkbox("Socks5",true); + //socks5radio.setCheckboxGroup(socks_group); + socks5radio.setFont(new Font(font.getName(),Font.BOLD,14)); + container.add(socks5radio,c); + + c.gridx=0; c.gridy=2; + c.gridwidth=1; c.gridheight=1; + c.anchor=GridBagConstraints.EAST; + label = new Label("User Id:"); + container.add(label,c); + + c.gridx=1; c.gridy=2; + c.gridwidth=2; c.gridheight=1; + c.anchor=GridBagConstraints.NORTHWEST; + user_text = new TextField("",15); + user_text.setEnabled(false); + container.add(user_text,c); + + c.gridx=3; c.gridy=2; + c.gridwidth=2; c.gridheight=1; + c.anchor=GridBagConstraints.NORTH; + label = new Label("Authentication"); + label.setFont(new Font(font.getName(),Font.BOLD,14)); + container.add(label,c); + + c.gridx=0; c.gridy=3; + c.gridwidth=1; c.gridheight=1; + c.anchor=GridBagConstraints.EAST; + label = new Label("Password:"); + container.add(label,c); + + c.gridx=1; c.gridy=3; + c.gridwidth=2; c.gridheight=1; + c.anchor=GridBagConstraints.NORTHWEST; + password_text = new TextField("",15); + password_text.setEchoChar('*'); + password_text.setEnabled(false); + //password_text.setEchoCharacter('*');//1.0 + container.add(password_text,c); + + c.gridx=3; c.gridy=3; + c.gridwidth=2; c.gridheight=1; + c.anchor=GridBagConstraints.NORTHWEST; + none_check = new Checkbox("None",true); + container.add(none_check,c); + + c.gridx=0; c.gridy=4; + c.gridwidth=3; c.gridheight=1; + c.anchor=GridBagConstraints.NORTH; + label = new Label("Direct Hosts"); + label.setFont(new Font(font.getName(),Font.BOLD,14)); + container.add(label,c); + + c.gridx=3; c.gridy=4; + c.gridwidth=2; c.gridheight=1; + c.anchor=GridBagConstraints.NORTHWEST; + up_check = new Checkbox("User/Password",false); + container.add(up_check,c); + + c.gridx=0; c.gridy=5; + c.gridwidth=3; c.gridheight=2; + c.anchor=GridBagConstraints.NORTHWEST; + c.fill = GridBagConstraints.BOTH; + direct_list = new List(3); + container.add(direct_list,c); + + c.gridx=3; c.gridy=5; + c.gridwidth=2; c.gridheight=1; + c.anchor=GridBagConstraints.NORTHWEST; + gssapi_check = new Checkbox("GSSAPI",false); + gssapi_check.setEnabled(false); + container.add(gssapi_check,c); + + c.gridx=0; c.gridy=7; + c.gridwidth=3; c.gridheight=1; + c.anchor=GridBagConstraints.NORTHWEST; + direct_text = new TextField("",25); + container.add(direct_text,c); + + c.gridx=3; c.gridy=7; + c.gridwidth=1; c.gridheight=1; + c.anchor=GridBagConstraints.NORTH; + add_button = new Button("Add"); + container.add(add_button,c); + + c.gridx=3; c.gridy=6; + c.gridwidth=1; c.gridheight=1; + c.anchor=GridBagConstraints.NORTH; + remove_button = new Button("Remove"); + container.add(remove_button,c); + + c.gridx=1; c.gridy=8; + c.gridwidth=1; c.gridheight=1; + c.anchor=GridBagConstraints.NORTH; + cancel_button = new Button("Cancel"); + container.add(cancel_button,c); + + c.gridx=0; c.gridy=8; + c.gridwidth=1; c.gridheight=1; + c.anchor=GridBagConstraints.NORTHWEST; + ok_button = new Button("OK"); + container.add(ok_button,c); + + //up_check.setEnabled(false); + + //Warning Dialog + dismiss_button = new Button("Dismiss"); + warning_label = new Label("",Label.CENTER); + warning_label.setFont(new Font("Dialog",Font.BOLD,15)); + + Panel p = new Panel(); + p.add(dismiss_button); + warning_dialog.add(p,BorderLayout.SOUTH); + warning_dialog.add(warning_label,BorderLayout.CENTER); + warning_dialog.setResizable(false); + }//end guiInit + +/* +// Main +//////////////////////////////////// + public static void main(String[] args) throws Exception{ + Frame f = new Frame("Test for SocksDialog"); + f.add("Center", new Label("Fill the Dialog")); + SocksDialog socksdialog = new SocksDialog(f); + f.pack(); + f.show(); + f.addWindowListener(socksdialog); + CProxy p = socksdialog.getProxy(); + System.out.println("Selected: "+p); + } +*/ + +}//end class
--- a/src/net/sourceforge/jsocks/SocksException.java Fri Aug 01 10:25:44 2014 -0700 +++ b/src/net/sourceforge/jsocks/SocksException.java Fri Aug 01 11:23:10 2014 -0700 @@ -1,84 +1,78 @@ -package net.sourceforge.jsocks; - -/** - Exception thrown by various socks classes to indicate errors - with protocol or unsuccessful server responses. -*/ -public class SocksException extends java.io.IOException { - private static final long serialVersionUID = 6141184566248512277L; - - /** - Construct a SocksException with given error code. - <p> - Tries to look up message which corresponds to this error code. - @param errCode Error code for this exception. - */ - public SocksException(int errCode) { - this.errCode = errCode; - - if ((errCode >> 16) == 0) { - //Server reply error message - errString = errCode <= serverReplyMessage.length ? - serverReplyMessage[errCode] : - UNASSIGNED_ERROR_MESSAGE; - } - else { - //Local error - errCode = (errCode >> 16) - 1; - errString = errCode <= localErrorMessage.length ? - localErrorMessage[errCode] : - UNASSIGNED_ERROR_MESSAGE; - } - } - /** - Constructs a SocksException with given error code and message. - @param errCode Error code. - @param errString Error Message. - */ - public SocksException(int errCode, String errString) { - this.errCode = errCode; - this.errString = errString; - } - /** - Get the error code associated with this exception. - @return Error code associated with this exception. - */ - public int getErrorCode() { - return errCode; - } - /** - Get human readable representation of this exception. - @return String represntation of this exception. - */ - public String toString() { - return errString; - } - - static final String UNASSIGNED_ERROR_MESSAGE = - "Unknown error message"; - static final String serverReplyMessage[] = { - "Succeeded", - "General SOCKS server failure", - "Connection not allowed by ruleset", - "Network unreachable", - "Host unreachable", - "Connection refused", - "TTL expired", - "Command not supported", - "Address type not supported" - }; - - static final String localErrorMessage[] = { - "SOCKS server not specified", - "Unable to contact SOCKS server", - "IO error", - "None of Authentication methods are supported", - "Authentication failed", - "General SOCKS fault" - }; - - String errString; - public int errCode; - -}//End of SocksException class - +package net.sourceforge.jsocks; + +/** + Exception thrown by various socks classes to indicate errors + with protocol or unsuccessfull server responses. +*/ +public class SocksException extends java.io.IOException{ + /** + Construct a SocksException with given errorcode. + <p> + Tries to look up message which corresponds to this error code. + @param errCode Error code for this exception. + */ + public SocksException(int errCode){ + this.errCode = errCode; + if((errCode >> 16) == 0){ + //Server reply error message + errString = errCode <= serverReplyMessage.length ? + serverReplyMessage[errCode] : + UNASSIGNED_ERROR_MESSAGE; + }else{ + //Local error + errCode = (errCode >> 16) -1; + errString = errCode <= localErrorMessage.length ? + localErrorMessage[errCode] : + UNASSIGNED_ERROR_MESSAGE; + } + } + /** + Constructs a SocksException with given error code and message. + @param errCode Error code. + @param errString Error Message. + */ + public SocksException(int errCode,String errString){ + this.errCode = errCode; + this.errString = errString; + } + /** + Get the error code associated with this exception. + @return Error code associated with this exception. + */ + public int getErrorCode(){ + return errCode; + } + /** + Get human readable representation of this exception. + @return String represntation of this exception. + */ + public String toString(){ + return errString; + } + + static final String UNASSIGNED_ERROR_MESSAGE = + "Unknown error message"; + static final String serverReplyMessage[] = { + "Succeeded", + "General SOCKS server failure", + "Connection not allowed by ruleset", + "Network unreachable", + "Host unreachable", + "Connection refused", + "TTL expired", + "Command not supported", + "Address type not supported" }; + + static final String localErrorMessage[] ={ + "SOCKS server not specified", + "Unable to contact SOCKS server", + "IO error", + "None of Authentication methods are supported", + "Authentication failed", + "General SOCKS fault" }; + + String errString; + int errCode; + +}//End of SocksException class +
--- a/src/net/sourceforge/jsocks/SocksServerSocket.java Fri Aug 01 10:25:44 2014 -0700 +++ b/src/net/sourceforge/jsocks/SocksServerSocket.java Fri Aug 01 11:23:10 2014 -0700 @@ -1,170 +1,207 @@ -package net.sourceforge.jsocks; - -import java.net.*; -import java.io.*; - -/** - SocksServerSocket allows to accept connections from one particular - host through the SOCKS4 or SOCKS5 proxy. -*/ -public class SocksServerSocket extends ServerSocket { - //Data members - protected Proxy proxy; - protected String localHost; - protected InetAddress localIP; - protected int localPort; - - boolean doing_direct = false; - InetAddress remoteAddr; - - /** - *Creates ServerSocket capable of accepting one connection - *through the firewall, uses given proxy. - *@param host Host from which the connection should be recieved. - *@param port Port number of the primary connection. - */ - public SocksServerSocket(String host, int port) throws SocksException, - UnknownHostException, IOException { - super(0); - remoteAddr = InetAddress.getByName(host); - doDirect(); - } - - /** - * Creates ServerSocket capable of accepting one connection - * through the firewall, uses default Proxy. - *@param ip Host from which the connection should be recieved. - *@param port Port number of the primary connection. - */ - public SocksServerSocket(InetAddress ip, int port) throws SocksException, - IOException { - this(Proxy.defaultProxy, ip, port); - } - - /** - *Creates ServerSocket capable of accepting one connection - *through the firewall, uses given proxy. - *@param ip Host from which the connection should be recieved. - *@param port Port number of the primary connection. - */ - public SocksServerSocket(Proxy p, InetAddress ip, int port) - throws SocksException, IOException { - super(0); - remoteAddr = ip; - doDirect(); - } - - - /** - * Accepts the incoming connection. - */ - public Socket accept() throws IOException { - Socket s; - - if (!doing_direct) { - if (proxy == null) return null; - - ProxyMessage msg = proxy.accept(); - s = msg.ip == null ? new SocksSocket(msg.host, msg.port, proxy) - : new SocksSocket(msg.ip, msg.port, proxy); - //Set timeout back to 0 - proxy.proxySocket.setSoTimeout(0); - } - else { //Direct Connection - - //Mimic the proxy behaviour, - //only accept connections from the speciefed host. - while (true) { - s = super.accept(); - - if (s.getInetAddress().equals(remoteAddr)) { - //got the connection from the right host - //Close listenning socket. - break; - } - else - s.close(); //Drop all connections from other hosts - } - } - - proxy = null; - //Return accepted socket - return s; - } - - /** - * Closes the connection to proxy if socket have not been accepted, if - * the direct connection is used, closes direct ServerSocket. If the - * client socket have been allready accepted, does nothing. - */ - public void close() throws IOException { - super.close(); - - if (proxy != null) proxy.endSession(); - - proxy = null; - } - - /** - Get the name of the host proxy is using to listen for incoming - connection. - <P> - Usefull when address is returned by proxy as the hostname. - @return the hostname of the address proxy is using to listen - for incoming connection. - */ - public String getHost() { - return localHost; - } - - /** - * Get address assigned by proxy to listen for incomming - * connections, or the local machine address if doing direct - * connection. - */ - public InetAddress getInetAddress() { - if (localIP == null) { - try { - localIP = InetAddress.getByName(localHost); - } - catch (UnknownHostException e) { - return null; - } - } - - return localIP; - } - - /** - * Get port assigned by proxy to listen for incoming connections, or - the port chosen by local system, if accepting directly. - */ - public int getLocalPort() { - return localPort; - } - - /** - Set Timeout. - - @param timeout Amount of time in milliseconds, accept should wait for - incoming connection before failing with exception. - Zero timeout implies infinity. - */ - public void setSoTimeout(int timeout) throws SocketException { - super.setSoTimeout(timeout); - - if (!doing_direct) proxy.proxySocket.setSoTimeout(timeout); - } - - -//Private Methods -////////////////// - - private void doDirect() { - doing_direct = true; - localPort = super.getLocalPort(); - localIP = super.getInetAddress(); - localHost = localIP.getHostName(); - } - -} +package net.sourceforge.jsocks; + +import java.net.*; +import java.io.*; + +/** + SocksServerSocket allows to accept connections from one particular + host through the SOCKS4 or SOCKS5 proxy. +*/ +public class SocksServerSocket extends ServerSocket{ + //Data members + protected CProxy proxy; + protected String localHost; + protected InetAddress localIP; + protected int localPort; + + boolean doing_direct = false; + InetAddress remoteAddr; + + /** + * Creates ServerSocket capable of accepting one connection + * through the firewall, uses default CProxy. + *@param host Host from which the connection should be recieved. + *@param port Port number of the primary connection. + */ + public SocksServerSocket(String host,int port) + throws SocksException,UnknownHostException,IOException{ + this(CProxy.defaultProxy,host,port); + } + /** + *Creates ServerSocket capable of accepting one connection + *through the firewall, uses given proxy. + *@param p CProxy object to use. + *@param host Host from which the connection should be recieved. + *@param port Port number of the primary connection. + */ + public SocksServerSocket(CProxy p,String host,int port) + throws SocksException,UnknownHostException,IOException{ + + + super(0); + if(p == null) throw new SocksException(CProxy.SOCKS_NO_PROXY); + //proxy=p; + proxy = p.copy(); + if(proxy.isDirect(host)){ + remoteAddr = InetAddress.getByName(host); + proxy = null; + doDirect(); + }else{ + processReply(proxy.bind(host,port)); + } + } + + /** + * Creates ServerSocket capable of accepting one connection + * through the firewall, uses default CProxy. + *@param ip Host from which the connection should be recieved. + *@param port Port number of the primary connection. + */ + public SocksServerSocket(InetAddress ip, int port) throws SocksException, + IOException{ + this(CProxy.defaultProxy,ip,port); + } + + /** + *Creates ServerSocket capable of accepting one connection + *through the firewall, uses given proxy. + *@param p CProxy object to use. + *@param ip Host from which the connection should be recieved. + *@param port Port number of the primary connection. + */ + public SocksServerSocket(CProxy p,InetAddress ip, int port) + throws SocksException,IOException{ + super(0); + + if(p == null) throw new SocksException(CProxy.SOCKS_NO_PROXY); + this.proxy = p.copy(); + + if(proxy.isDirect(ip)){ + remoteAddr = ip; + doDirect(); + }else{ + processReply(proxy.bind(ip,port)); + } + } + + + /** + * Accepts the incoming connection. + */ + public Socket accept() throws IOException{ + Socket s; + + if(!doing_direct){ + if(proxy == null) return null; + + ProxyMessage msg = proxy.accept(); + s = msg.ip == null? new SocksSocket(msg.host,msg.port,proxy) + : new SocksSocket(msg.ip,msg.port,proxy); + //Set timeout back to 0 + proxy.proxySocket.setSoTimeout(0); + }else{ //Direct Connection + + //Mimic the proxy behaviour, + //only accept connections from the speciefed host. + while(true){ + s = super.accept(); + if(s.getInetAddress().equals(remoteAddr)){ + //got the connection from the right host + //Close listenning socket. + break; + }else + s.close(); //Drop all connections from other hosts + } + + } + proxy = null; + //Return accepted socket + return s; + } + + /** + * Closes the connection to proxy if socket have not been accepted, if + * the direct connection is used, closes direct ServerSocket. If the + * client socket have been allready accepted, does nothing. + */ + public void close() throws IOException{ + super.close(); + if(proxy != null) proxy.endSession(); + proxy = null; + } + + /** + Get the name of the host proxy is using to listen for incoming + connection. + <P> + Usefull when address is returned by proxy as the hostname. + @return the hostname of the address proxy is using to listen + for incoming connection. + */ + public String getHost(){ + return localHost; + } + + /** + * Get address assigned by proxy to listen for incomming + * connections, or the local machine address if doing direct + * connection. + */ + public InetAddress getInetAddress(){ + if(localIP == null){ + try{ + localIP = InetAddress.getByName(localHost); + }catch(UnknownHostException e){ + return null; + } + } + return localIP; + } + + /** + * Get port assigned by proxy to listen for incoming connections, or + the port chosen by local system, if accepting directly. + */ + public int getLocalPort(){ + return localPort; + } + + /** + Set Timeout. + + @param timeout Amount of time in milliseconds, accept should wait for + incoming connection before failing with exception. + Zero timeout implies infinity. + */ + public void setSoTimeout(int timeout) throws SocketException{ + super.setSoTimeout(timeout); + if(!doing_direct) proxy.proxySocket.setSoTimeout(timeout); + } + + +//Private Methods +////////////////// + + private void processReply(ProxyMessage reply)throws SocksException{ + localPort = reply.port; + /* + * If the server have assigned same host as it was contacted on + * it might return an address of all zeros + */ + if(reply.host.equals("0.0.0.0")){ + localIP = proxy.proxyIP; + localHost = localIP.getHostName(); + }else{ + localHost = reply.host; + localIP = reply.ip; + } + } + + private void doDirect(){ + doing_direct = true; + localPort = super.getLocalPort(); + localIP = super.getInetAddress(); + localHost = localIP.getHostName(); + } + +}
--- a/src/net/sourceforge/jsocks/SocksSocket.java Fri Aug 01 10:25:44 2014 -0700 +++ b/src/net/sourceforge/jsocks/SocksSocket.java Fri Aug 01 11:23:10 2014 -0700 @@ -1,297 +1,332 @@ -package net.sourceforge.jsocks; - -import java.net.*; -import java.io.*; - -/** - * SocksSocket tryies to look very similar to normal Socket, - * while allowing connections through the SOCKS4 or 5 proxy. - * To use this class you will have to identify proxy you need - * to use, Proxy class allows you to set default proxy, which - * will be used by all Socks aware sockets. You can also create - * either Socks4Proxy or Socks5Proxy, and use them by passing to the - * appropriate constructors. - * <P> - * Using Socks package can be as easy as that: - * - * <pre><tt> - * - * import Socks.*; - * .... - * - * try{ - * //Specify SOCKS5 proxy - * Proxy.setDefaultProxy("socks-proxy",1080); - * - * //OR you still use SOCKS4 - * //Code below uses SOCKS4 proxy - * //Proxy.setDefaultProxy("socks-proxy",1080,userName); - * - * Socket s = SocksSocket("some.host.of.mine",13); - * readTimeFromSock(s); - * }catch(SocksException sock_ex){ - * //Usually it will turn in more or less meaningfull message - * System.err.println("SocksException:"+sock_ex); - * } - * - * </tt></pre> - *<P> - * However if the need exist for more control, like resolving addresses - * remotely, or using some non-trivial authentication schemes, it can be done. - */ - -public class SocksSocket extends Socket { - //Data members - protected Proxy proxy; - protected String localHost, remoteHost; - protected InetAddress localIP, remoteIP; - protected int localPort, remotePort; - - private Socket directSock = null; - - /** - * Tryies to connect to given host and port - * using default proxy. If no default proxy speciefied - * it throws SocksException with error code SOCKS_NO_PROXY. - @param host Machine to connect to. - @param port Port to which to connect. - * @see SocksSocket#SocksSocket(Proxy,String,int) - * @see Socks5Proxy#resolveAddrLocally - */ - public SocksSocket(String host, int port) - throws SocksException, UnknownHostException { - this(Proxy.defaultProxy, host, port); - } - /** - * Connects to host port using given proxy server. - @param p Proxy to use. - @param host Machine to connect to. - @param port Port to which to connect. - @throws UnknownHostException - If one of the following happens: - <ol> - - <li> Proxy settings say that address should be resolved locally, but - this fails. - <li> Proxy settings say that the host should be contacted directly but - host name can't be resolved. - </ol> - @throws SocksException - If one of the following happens: - <ul> - <li> Proxy is is null. - <li> Proxy settings say that the host should be contacted directly but - this fails. - <li> Socks Server can't be contacted. - <li> Authentication fails. - <li> Connection is not allowed by the SOCKS proxy. - <li> SOCKS proxy can't establish the connection. - <li> Any IO error occured. - <li> Any protocol error occured. - </ul> - @throws IOexception if anything is wrong with I/O. - @see Socks5Proxy#resolveAddrLocally - */ - public SocksSocket(Proxy p, String host, int port) throws SocksException, - UnknownHostException { - remoteHost = host; - remotePort = port; - remoteIP = InetAddress.getByName(host); - doDirect(); - } - - /** - Connects to given ip and port using given Proxy server. - @param p Proxy to use. - @param ip Machine to connect to. - @param port Port to which to connect. - - */ - public SocksSocket(InetAddress ip, int port) throws SocksException { - this.remoteIP = ip; - this.remotePort = port; - this.remoteHost = ip.getHostName(); - doDirect(); - } - - - /** - * These 2 constructors are used by the SocksServerSocket. - * This socket simply overrides remoteHost, remotePort - */ - protected SocksSocket(String host, int port, Proxy proxy) { - this.remotePort = port; - this.proxy = proxy; - this.localIP = proxy.proxySocket.getLocalAddress(); - this.localPort = proxy.proxySocket.getLocalPort(); - this.remoteHost = host; - } - protected SocksSocket(InetAddress ip, int port, Proxy proxy) { - remoteIP = ip; - remotePort = port; - this.proxy = proxy; - this.localIP = proxy.proxySocket.getLocalAddress(); - this.localPort = proxy.proxySocket.getLocalPort(); - remoteHost = remoteIP.getHostName(); - } - - /** - * Same as Socket - */ - public void close() throws IOException { - if (proxy != null)proxy.endSession(); - - proxy = null; - } - /** - * Same as Socket - */ - public InputStream getInputStream() { - return proxy.in; - } - /** - * Same as Socket - */ - public OutputStream getOutputStream() { - return proxy.out; - } - /** - * Same as Socket - */ - public int getPort() { - return remotePort; - } - /** - * Returns remote host name, it is usefull in cases when addresses - * are resolved by proxy, and we can't create InetAddress object. - @return The name of the host this socket is connected to. - */ - public String getHost() { - return remoteHost; - } - /** - * Get remote host as InetAddress object, might return null if - * addresses are resolved by proxy, and it is not possible to resolve - * it locally - @return Ip address of the host this socket is connected to, or null - if address was returned by the proxy as DOMAINNAME and can't be - resolved locally. - */ - public InetAddress getInetAddress() { - if (remoteIP == null) { - try { - remoteIP = InetAddress.getByName(remoteHost); - } - catch (UnknownHostException e) { - return null; - } - } - - return remoteIP; - } - - /** - * Get the port assigned by the proxy for the socket, not - * the port on locall machine as in Socket. - @return Port of the socket used on the proxy server. - */ - public int getLocalPort() { - return localPort; - } - - /** - * Get address assigned by proxy to make a remote connection, - * it might be different from the host specified for the proxy. - * Can return null if socks server returned this address as hostname - * and it can't be resolved locally, use getLocalHost() then. - @return Address proxy is using to make a connection. - */ - public InetAddress getLocalAddress() { - if (localIP == null) { - try { - localIP = InetAddress.getByName(localHost); - } - catch (UnknownHostException e) { - return null; - } - } - - return localIP; - } - /** - Get name of the host, proxy has assigned to make a remote connection - for this socket. This method is usefull when proxy have returned - address as hostname, and we can't resolve it on this machine. - @return The name of the host proxy is using to make a connection. - */ - public String getLocalHost() { - return localHost; - } - - /** - Same as socket. - */ - public void setSoLinger(boolean on, int val) throws SocketException { - proxy.proxySocket.setSoLinger(on, val); - } - /** - Same as socket. - */ - public int getSoLinger(int timeout) throws SocketException { - return proxy.proxySocket.getSoLinger(); - } - /** - Same as socket. - */ - public void setSoTimeout(int timeout) throws SocketException { - proxy.proxySocket.setSoTimeout(timeout); - } - /** - Same as socket. - */ - public int getSoTimeout(int timeout) throws SocketException { - return proxy.proxySocket.getSoTimeout(); - } - /** - Same as socket. - */ - public void setTcpNoDelay(boolean on) throws SocketException { - proxy.proxySocket.setTcpNoDelay(on); - } - /** - Same as socket. - */ - public boolean getTcpNoDelay() throws SocketException { - return proxy.proxySocket.getTcpNoDelay(); - } - - /** - Get string representation of the socket. - */ - public String toString() { - if (directSock != null) return "Direct connection:" + directSock; - - return ("Proxy:" + proxy + ";" + "addr:" + remoteHost + ",port:" + remotePort - + ",localport:" + localPort); - } - -//Private Methods -////////////////// - - private void doDirect()throws SocksException { - try { - //System.out.println("IP:"+remoteIP+":"+remotePort); - directSock = new Socket(remoteIP, remotePort); - proxy.out = directSock.getOutputStream(); - proxy.in = directSock.getInputStream(); - proxy.proxySocket = directSock; - localIP = directSock.getLocalAddress(); - localPort = directSock.getLocalPort(); - } - catch (IOException io_ex) { - throw new SocksException(Proxy.SOCKS_DIRECT_FAILED, - "Direct connect failed:" + io_ex); - } - } - -} +package net.sourceforge.jsocks; + +import java.net.*; +import java.io.*; + +/** + * SocksSocket tryies to look very similar to normal Socket, + * while allowing connections through the SOCKS4 or 5 proxy. + * To use this class you will have to identify proxy you need + * to use, CProxy class allows you to set default proxy, which + * will be used by all Socks aware sockets. You can also create + * either Socks4Proxy or Socks5Proxy, and use them by passing to the + * appropriate constructors. + * <P> + * Using Socks package can be as easy as that: + * + * <pre><tt> + * + * import Socks.*; + * .... + * + * try{ + * //Specify SOCKS5 proxy + * CProxy.setDefaultProxy("socks-proxy",1080); + * + * //OR you still use SOCKS4 + * //Code below uses SOCKS4 proxy + * //CProxy.setDefaultProxy("socks-proxy",1080,userName); + * + * Socket s = SocksSocket("some.host.of.mine",13); + * readTimeFromSock(s); + * }catch(SocksException sock_ex){ + * //Usually it will turn in more or less meaningfull message + * System.err.println("SocksException:"+sock_ex); + * } + * + * </tt></pre> + *<P> + * However if the need exist for more control, like resolving addresses + * remotely, or using some non-trivial authentication schemes, it can be done. + */ + +public class SocksSocket extends Socket{ + //Data members + protected CProxy proxy; + protected String localHost, remoteHost; + protected InetAddress localIP, remoteIP; + protected int localPort,remotePort; + + private Socket directSock = null; + + /** + * Tryies to connect to given host and port + * using default proxy. If no default proxy speciefied + * it throws SocksException with error code SOCKS_NO_PROXY. + @param host Machine to connect to. + @param port Port to which to connect. + * @see SocksSocket#SocksSocket(CProxy,String,int) + * @see Socks5Proxy#resolveAddrLocally + */ + public SocksSocket(String host,int port) + throws SocksException,UnknownHostException{ + this(CProxy.defaultProxy,host,port); + } + /** + * Connects to host port using given proxy server. + @param p CProxy to use. + @param host Machine to connect to. + @param port Port to which to connect. + @throws UnknownHostException + If one of the following happens: + <ol> + + <li> CProxy settings say that address should be resolved locally, but + this fails. + <li> CProxy settings say that the host should be contacted directly but + host name can't be resolved. + </ol> + @throws SocksException + If one of the following happens: + <ul> + <li> CProxy is is null. + <li> CProxy settings say that the host should be contacted directly but + this fails. + <li> Socks Server can't be contacted. + <li> Authentication fails. + <li> Connection is not allowed by the SOCKS proxy. + <li> SOCKS proxy can't establish the connection. + <li> Any IO error occured. + <li> Any protocol error occured. + </ul> + @throws IOexception if anything is wrong with I/O. + @see Socks5Proxy#resolveAddrLocally + */ + public SocksSocket(CProxy p,String host,int port) + throws SocksException,UnknownHostException{ + + + if(p == null) throw new SocksException(CProxy.SOCKS_NO_PROXY); + //proxy=p; + proxy = p.copy(); + remoteHost = host; + remotePort = port; + if(proxy.isDirect(host)){ + remoteIP = InetAddress.getByName(host); + doDirect(); + } + else + processReply(proxy.connect(host,port)); + } + + + /** + * Tryies to connect to given ip and port + * using default proxy. If no default proxy speciefied + * it throws SocksException with error code SOCKS_NO_PROXY. + @param ip Machine to connect to. + @param port Port to which to connect. + * @see SocksSocket#SocksSocket(CProxy,String,int) + */ + public SocksSocket(InetAddress ip, int port) throws SocksException{ + this(CProxy.defaultProxy,ip,port); + } + + /** + Connects to given ip and port using given CProxy server. + @param p CProxy to use. + @param ip Machine to connect to. + @param port Port to which to connect. + + */ + public SocksSocket(CProxy p,InetAddress ip, int port) throws SocksException{ + if(p == null) throw new SocksException(CProxy.SOCKS_NO_PROXY); + this.proxy = p.copy(); + this.remoteIP = ip; + this.remotePort = port; + this.remoteHost = ip.getHostName(); + if(proxy.isDirect(remoteIP)) + doDirect(); + else + processReply(proxy.connect(ip,port)); + } + + + /** + * These 2 constructors are used by the SocksServerSocket. + * This socket simply overrides remoteHost, remotePort + */ + protected SocksSocket(String host,int port,CProxy proxy){ + this.remotePort = port; + this.proxy = proxy; + this.localIP = proxy.proxySocket.getLocalAddress(); + this.localPort = proxy.proxySocket.getLocalPort(); + this.remoteHost = host; + } + protected SocksSocket(InetAddress ip,int port,CProxy proxy){ + remoteIP = ip; + remotePort = port; + this.proxy = proxy; + this.localIP = proxy.proxySocket.getLocalAddress(); + this.localPort = proxy.proxySocket.getLocalPort(); + remoteHost = remoteIP.getHostName(); + } + + /** + * Same as Socket + */ + public void close() throws IOException{ + if(proxy!= null)proxy.endSession(); + proxy = null; + } + /** + * Same as Socket + */ + public InputStream getInputStream(){ + return proxy.in; + } + /** + * Same as Socket + */ + public OutputStream getOutputStream(){ + return proxy.out; + } + /** + * Same as Socket + */ + public int getPort(){ + return remotePort; + } + /** + * Returns remote host name, it is usefull in cases when addresses + * are resolved by proxy, and we can't create InetAddress object. + @return The name of the host this socket is connected to. + */ + public String getHost(){ + return remoteHost; + } + /** + * Get remote host as InetAddress object, might return null if + * addresses are resolved by proxy, and it is not possible to resolve + * it locally + @return Ip address of the host this socket is connected to, or null + if address was returned by the proxy as DOMAINNAME and can't be + resolved locally. + */ + public InetAddress getInetAddress(){ + if(remoteIP == null){ + try{ + remoteIP = InetAddress.getByName(remoteHost); + }catch(UnknownHostException e){ + return null; + } + } + return remoteIP; + } + + /** + * Get the port assigned by the proxy for the socket, not + * the port on locall machine as in Socket. + @return Port of the socket used on the proxy server. + */ + public int getLocalPort(){ + return localPort; + } + + /** + * Get address assigned by proxy to make a remote connection, + * it might be different from the host specified for the proxy. + * Can return null if socks server returned this address as hostname + * and it can't be resolved locally, use getLocalHost() then. + @return Address proxy is using to make a connection. + */ + public InetAddress getLocalAddress(){ + if(localIP == null){ + try{ + localIP = InetAddress.getByName(localHost); + }catch(UnknownHostException e){ + return null; + } + } + return localIP; + } + /** + Get name of the host, proxy has assigned to make a remote connection + for this socket. This method is usefull when proxy have returned + address as hostname, and we can't resolve it on this machine. + @return The name of the host proxy is using to make a connection. + */ + public String getLocalHost(){ + return localHost; + } + + /** + Same as socket. + */ + public void setSoLinger(boolean on,int val) throws SocketException{ + proxy.proxySocket.setSoLinger(on,val); + } + /** + Same as socket. + */ + public int getSoLinger(int timeout) throws SocketException{ + return proxy.proxySocket.getSoLinger(); + } + /** + Same as socket. + */ + public void setSoTimeout(int timeout) throws SocketException{ + proxy.proxySocket.setSoTimeout(timeout); + } + /** + Same as socket. + */ + public int getSoTimeout(int timeout) throws SocketException{ + return proxy.proxySocket.getSoTimeout(); + } + /** + Same as socket. + */ + public void setTcpNoDelay(boolean on) throws SocketException{ + proxy.proxySocket.setTcpNoDelay(on); + } + /** + Same as socket. + */ + public boolean getTcpNoDelay() throws SocketException{ + return proxy.proxySocket.getTcpNoDelay(); + } + + /** + Get string representation of the socket. + */ + public String toString(){ + if(directSock!=null) return "Direct connection:"+directSock; + return ("Proxy:"+proxy+";"+"addr:"+remoteHost+",port:"+remotePort + +",localport:"+localPort); + + } + +//Private Methods +////////////////// + + private void processReply(ProxyMessage reply)throws SocksException{ + localPort = reply.port; + /* + * If the server have assigned same host as it was contacted on + * it might return an address of all zeros + */ + if(reply.host.equals("0.0.0.0")){ + localIP = proxy.proxyIP; + localHost = localIP.getHostName(); + }else{ + localHost = reply.host; + localIP = reply.ip; + } + } + private void doDirect()throws SocksException{ + try{ + //System.out.println("IP:"+remoteIP+":"+remotePort); + directSock = new Socket(remoteIP,remotePort); + proxy.out = directSock.getOutputStream(); + proxy.in = directSock.getInputStream(); + proxy.proxySocket = directSock; + localIP = directSock.getLocalAddress(); + localPort = directSock.getLocalPort(); + }catch(IOException io_ex){ + throw new SocksException(CProxy.SOCKS_DIRECT_FAILED, + "Direct connect failed:"+io_ex); + } + } + +}
--- a/src/net/sourceforge/jsocks/UDPEncapsulation.java Fri Aug 01 10:25:44 2014 -0700 +++ b/src/net/sourceforge/jsocks/UDPEncapsulation.java Fri Aug 01 11:23:10 2014 -0700 @@ -1,29 +1,29 @@ -package net.sourceforge.jsocks; -/** - This interface provides for datagram encapsulation for SOCKSv5 protocol. - <p> - SOCKSv5 allows for datagrams to be encapsulated for purposes of integrity - and/or authenticity. How it should be done is aggreed during the - authentication stage, and is authentication dependent. This interface is - provided to allow this encapsulation. - @see Authentication -*/ -public interface UDPEncapsulation { - - /** - This method should provide any authentication depended transformation - on datagrams being send from/to the client. - - @param data Datagram data (including any SOCKS related bytes), to be - encapsulated/decapsulated. - @param out Wether the data is being send out. If true method should - encapsulate/encrypt data, otherwise it should decapsulate/ - decrypt data. - @throw IOException if for some reason data can be transformed correctly. - @return Should return byte array containing data after transformation. - It is possible to return same array as input, if transformation - only involves bit mangling, and no additional data is being - added or removed. - */ - byte[] udpEncapsulate(byte[] data, boolean out) throws java.io.IOException; -} +package net.sourceforge.jsocks; +/** + This interface provides for datagram encapsulation for SOCKSv5 protocol. + <p> + SOCKSv5 allows for datagrams to be encapsulated for purposes of integrity + and/or authenticity. How it should be done is aggreed during the + authentication stage, and is authentication dependent. This interface is + provided to allow this encapsulation. + @see Authentication +*/ +public interface UDPEncapsulation{ + + /** + This method should provide any authentication depended transformation + on datagrams being send from/to the client. + + @param data Datagram data (including any SOCKS related bytes), to be + encapsulated/decapsulated. + @param out Wether the data is being send out. If true method should + encapsulate/encrypt data, otherwise it should decapsulate/ + decrypt data. + @throw IOException if for some reason data can be transformed correctly. + @return Should return byte array containing data after transformation. + It is possible to return same array as input, if transformation + only involves bit mangling, and no additional data is being + added or removed. + */ + byte[] udpEncapsulate(byte[] data, boolean out) throws java.io.IOException; +}
--- a/src/net/sourceforge/jsocks/UDPRelayServer.java Fri Aug 01 10:25:44 2014 -0700 +++ b/src/net/sourceforge/jsocks/UDPRelayServer.java Fri Aug 01 11:23:10 2014 -0700 @@ -1,212 +1,212 @@ -package net.sourceforge.jsocks; -import net.sourceforge.jsocks.server.*; -import java.net.*; -import java.io.*; - -/** - UDP Relay server, used by ProxyServer to perform udp forwarding. -*/ -class UDPRelayServer implements Runnable { - - - DatagramSocket client_sock; - DatagramSocket remote_sock; - - Socket controlConnection; - - int relayPort; - InetAddress relayIP; - - Thread pipe_thread1, pipe_thread2; - Thread master_thread; - - ServerAuthenticator auth; - - long lastReadTime; - - static PrintStream log = null; - static Proxy proxy = null; - static int datagramSize = 0xFFFF;//64K, a bit more than max udp size - static int iddleTimeout = 180000;//3 minutes - - - /** - Constructs UDP relay server to communicate with client - on given ip and port. - @param clientIP Address of the client from whom datagrams - will be recieved and to whom they will be forwarded. - @param clientPort Clients port. - @param master_thread Thread which will be interrupted, when - UDP relay server stoppes for some reason. - @param controlConnection Socket which will be closed, before - interrupting the master thread, it is introduced due to a bug - in windows JVM which does not throw InterruptedIOException in - threads which block in I/O operation. - */ - public UDPRelayServer(InetAddress clientIP, int clientPort, - Thread master_thread, - Socket controlConnection, - ServerAuthenticator auth) - throws IOException { - this.master_thread = master_thread; - this.controlConnection = controlConnection; - this.auth = auth; - client_sock = new Socks5DatagramSocket(true, auth.getUdpEncapsulation(), - clientIP, clientPort); - relayPort = client_sock.getLocalPort(); - relayIP = client_sock.getLocalAddress(); - - if (relayIP.getHostAddress().equals("0.0.0.0")) - relayIP = InetAddress.getLocalHost(); - - if (proxy == null) - remote_sock = new DatagramSocket(); - else - remote_sock = new Socks5DatagramSocket(proxy, 0, null); - } - - -//Public methods -///////////////// - - - /** - Sets the timeout for UDPRelay server.<br> - Zero timeout implies infinity.<br> - Default timeout is 3 minutes. - */ - - static public void setTimeout(int timeout) { - iddleTimeout = timeout; - } - - - /** - Sets the size of the datagrams used in the UDPRelayServer.<br> - Default size is 64K, a bit more than maximum possible size of the - datagram. - */ - static public void setDatagramSize(int size) { - datagramSize = size; - } - - /** - Port to which client should send datagram for association. - */ - public int getRelayPort() { - return relayPort; - } - /** - IP address to which client should send datagrams for association. - */ - public InetAddress getRelayIP() { - return relayIP; - } - - /** - Starts udp relay server. - Spawns two threads of execution and returns. - */ - public void start() throws IOException { - remote_sock.setSoTimeout(iddleTimeout); - client_sock.setSoTimeout(iddleTimeout); - log("Starting UDP relay server on " + relayIP + ":" + relayPort); - log("Remote socket " + remote_sock.getLocalAddress() + ":" + - remote_sock.getLocalPort()); - pipe_thread1 = new Thread(this, "pipe1"); - pipe_thread2 = new Thread(this, "pipe2"); - lastReadTime = System.currentTimeMillis(); - pipe_thread1.start(); - pipe_thread2.start(); - } - - /** - Stops Relay server. - <p> - Does not close control connection, does not interrupt master_thread. - */ - - public synchronized void stop() { - master_thread = null; - controlConnection = null; - abort(); - } - -//Runnable interface -//////////////////// - public void run() { - try { - if (Thread.currentThread().getName().equals("pipe1")) - pipe(remote_sock, client_sock, false); - else - pipe(client_sock, remote_sock, true); - } - catch (IOException ioe) { - } - finally { - abort(); - log("UDP Pipe thread " + Thread.currentThread().getName() + " stopped."); - } - } - -//Private methods -///////////////// - - private synchronized void abort() { - if (pipe_thread1 == null) return; - - log("Aborting UDP Relay Server"); - remote_sock.close(); - client_sock.close(); - - if (controlConnection != null) - try { controlConnection.close();} - catch (IOException ioe) {} - - if (master_thread != null) master_thread.interrupt(); - - pipe_thread1.interrupt(); - pipe_thread2.interrupt(); - pipe_thread1 = null; - } - - - static private void log(String s) { - if (log != null) { - log.println(s); - log.flush(); - } - } - - private void pipe(DatagramSocket from, DatagramSocket to, boolean out) - throws IOException { - byte[] data = new byte[datagramSize]; - DatagramPacket dp = new DatagramPacket(data, data.length); - - while (true) { - try { - from.receive(dp); - lastReadTime = System.currentTimeMillis(); - - if (auth.checkRequest(dp, out)) - to.send(dp); - } - catch (UnknownHostException uhe) { - log("Dropping datagram for unknown host"); - } - catch (InterruptedIOException iioe) { - //log("Interrupted: "+iioe); - //If we were interrupted by other thread. - if (iddleTimeout == 0) return; - - //If last datagram was received, long time ago, return. - long timeSinceRead = System.currentTimeMillis() - lastReadTime; - - if (timeSinceRead >= iddleTimeout - 100) //-100 for adjustment - return; - } - - dp.setLength(data.length); - } - } -} +package net.sourceforge.jsocks; +import net.sourceforge.jsocks.server.*; +import java.net.*; +import java.io.*; + +/** + UDP Relay server, used by ProxyServer to perform udp forwarding. +*/ +class UDPRelayServer implements Runnable{ + + + DatagramSocket client_sock; + DatagramSocket remote_sock; + + Socket controlConnection; + + int relayPort; + InetAddress relayIP; + + Thread pipe_thread1,pipe_thread2; + Thread master_thread; + + ServerAuthenticator auth; + + long lastReadTime; + + static PrintStream log = null; + static CProxy proxy = null; + static int datagramSize = 0xFFFF;//64K, a bit more than max udp size + static int iddleTimeout = 180000;//3 minutes + + + /** + Constructs UDP relay server to communicate with client + on given ip and port. + @param clientIP Address of the client from whom datagrams + will be recieved and to whom they will be forwarded. + @param clientPort Clients port. + @param master_thread Thread which will be interrupted, when + UDP relay server stoppes for some reason. + @param controlConnection Socket which will be closed, before + interrupting the master thread, it is introduced due to a bug + in windows JVM which does not throw InterruptedIOException in + threads which block in I/O operation. + */ + public UDPRelayServer(InetAddress clientIP,int clientPort, + Thread master_thread, + Socket controlConnection, + ServerAuthenticator auth) + throws IOException{ + this.master_thread = master_thread; + this.controlConnection = controlConnection; + this.auth = auth; + + client_sock = new Socks5DatagramSocket(true,auth.getUdpEncapsulation(), + clientIP,clientPort); + relayPort = client_sock.getLocalPort(); + relayIP = client_sock.getLocalAddress(); + + if(relayIP.getHostAddress().equals("0.0.0.0")) + relayIP = InetAddress.getLocalHost(); + + if(proxy == null) + remote_sock = new DatagramSocket(); + else + remote_sock = new Socks5DatagramSocket(proxy,0,null); + } + + +//Public methods +///////////////// + + + /** + Sets the timeout for UDPRelay server.<br> + Zero timeout implies infinity.<br> + Default timeout is 3 minutes. + */ + + static public void setTimeout(int timeout){ + iddleTimeout = timeout; + } + + + /** + Sets the size of the datagrams used in the UDPRelayServer.<br> + Default size is 64K, a bit more than maximum possible size of the + datagram. + */ + static public void setDatagramSize(int size){ + datagramSize = size; + } + + /** + Port to which client should send datagram for association. + */ + public int getRelayPort(){ + return relayPort; + } + /** + IP address to which client should send datagrams for association. + */ + public InetAddress getRelayIP(){ + return relayIP; + } + + /** + Starts udp relay server. + Spawns two threads of execution and returns. + */ + public void start() throws IOException{ + remote_sock.setSoTimeout(iddleTimeout); + client_sock.setSoTimeout(iddleTimeout); + + log("Starting UDP relay server on "+relayIP+":"+relayPort); + log("Remote socket "+remote_sock.getLocalAddress()+":"+ + remote_sock.getLocalPort()); + + pipe_thread1 = new Thread(this,"pipe1"); + pipe_thread2 = new Thread(this,"pipe2"); + + lastReadTime = System.currentTimeMillis(); + + pipe_thread1.start(); + pipe_thread2.start(); + } + + /** + Stops Relay server. + <p> + Does not close control connection, does not interrupt master_thread. + */ + public synchronized void stop(){ + master_thread = null; + controlConnection = null; + abort(); + } + +//Runnable interface +//////////////////// + public void run(){ + try{ + if(Thread.currentThread().getName().equals("pipe1")) + pipe(remote_sock,client_sock,false); + else + pipe(client_sock,remote_sock,true); + }catch(IOException ioe){ + }finally{ + abort(); + log("UDP Pipe thread "+Thread.currentThread().getName()+" stopped."); + } + + } + +//Private methods +///////////////// + private synchronized void abort(){ + if(pipe_thread1 == null) return; + + log("Aborting UDP Relay Server"); + + remote_sock.close(); + client_sock.close(); + + if(controlConnection != null) + try{ controlConnection.close();} catch(IOException ioe){} + + if(master_thread!=null) master_thread.interrupt(); + + pipe_thread1.interrupt(); + pipe_thread2.interrupt(); + + pipe_thread1 = null; + } + + + static private void log(String s){ + if(log != null){ + log.println(s); + log.flush(); + } + } + + private void pipe(DatagramSocket from,DatagramSocket to,boolean out) + throws IOException{ + byte[] data = new byte[datagramSize]; + DatagramPacket dp = new DatagramPacket(data,data.length); + + while(true){ + try{ + from.receive(dp); + lastReadTime = System.currentTimeMillis(); + + if(auth.checkRequest(dp,out)) + to.send(dp); + + }catch(UnknownHostException uhe){ + log("Dropping datagram for unknown host"); + }catch(InterruptedIOException iioe){ + //log("Interrupted: "+iioe); + //If we were interrupted by other thread. + if(iddleTimeout == 0) return; + + //If last datagram was received, long time ago, return. + long timeSinceRead = System.currentTimeMillis() - lastReadTime; + if(timeSinceRead >= iddleTimeout -100) //-100 for adjustment + return; + } + dp.setLength(data.length); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/net/sourceforge/jsocks/UserPasswordAuthentication.java Fri Aug 01 11:23:10 2014 -0700 @@ -0,0 +1,75 @@ +package net.sourceforge.jsocks; + +/** + SOCKS5 User Password authentication scheme. +*/ +public class UserPasswordAuthentication implements Authentication{ + + /**SOCKS ID for User/Password authentication method*/ + public final static int METHOD_ID = 2; + + String userName, password; + byte[] request; + + /** + Create an instance of UserPasswordAuthentication. + @param userName User Name to send to SOCKS server. + @param password Password to send to SOCKS server. + */ + public UserPasswordAuthentication(String userName,String password){ + this.userName = userName; + this.password = password; + formRequest(); + } + /** Get the user name. + @return User name. + */ + public String getUser(){ + return userName; + } + /** Get password + @return Password + */ + public String getPassword(){ + return password; + } + /** + Does User/Password authentication as defined in rfc1929. + @return An array containnig in, out streams, or null if authentication + fails. + */ + public Object[] doSocksAuthentication(int methodId, + java.net.Socket proxySocket) + throws java.io.IOException{ + + if(methodId != METHOD_ID) return null; + + java.io.InputStream in = proxySocket.getInputStream(); + java.io.OutputStream out = proxySocket.getOutputStream(); + + out.write(request); + int version = in.read(); + if(version < 0) return null; //Server closed connection + int status = in.read(); + if(status != 0) return null; //Server closed connection, or auth failed. + + return new Object[] {in,out}; + } + +//Private methods +////////////////// + +/** Convert UserName password in to binary form, ready to be send to server*/ + private void formRequest(){ + byte[] user_bytes = userName.getBytes(); + byte[] password_bytes = password.getBytes(); + + request = new byte[3+user_bytes.length+password_bytes.length]; + request[0] = (byte) 1; + request[1] = (byte) user_bytes.length; + System.arraycopy(user_bytes,0,request,2,user_bytes.length); + request[2+user_bytes.length] = (byte) password_bytes.length; + System.arraycopy(password_bytes,0, + request,3+user_bytes.length,password_bytes.length); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/net/sourceforge/jsocks/server/Ident.java Fri Aug 01 11:23:10 2014 -0700 @@ -0,0 +1,158 @@ +package socks.server; +import net.sourceforge.jsocks.*; +import java.net.*; +import java.io.*; +import java.util.StringTokenizer; + +/** + Class Ident provides means to obtain user name of the owner of the socket + on remote machine, providing remote machine runs identd daemon. + <p> + To use it: + <tt><pre> + Socket s = ss.accept(); + Ident id = new Ident(s); + if(id.successful) goUseUser(id.userName); + else handleIdentError(id.errorCode,id.errorMessage) + </pre></tt> +*/ +public class Ident{ + + /** Error Message can be null.*/ + public String errorMessage; + /** Host type as returned by daemon, can be null, if error happened*/ + public String hostType; + /** User name as returned by the identd daemon, or null, if it failed*/ + public String userName; + + /** If this is true then userName and hostType contain valid values. + Else errorCode contain the error code, and errorMessage contains + the corresponding message. + */ + public boolean successful; + /** Error code*/ + public int errorCode; + /** Identd on port 113 can't be contacted*/ + public static final int ERR_NO_CONNECT = 1; + /** Connection timed out*/ + public static final int ERR_TIMEOUT = 2; + /** Identd daemon responded with ERROR, in this case errorMessage + contains the string explanation, as send by the daemon. + */ + public static final int ERR_PROTOCOL = 3; + /** + When parsing server response protocol error happened. + */ + public static final int ERR_PROTOCOL_INCORRECT = 4; + + + /** Maximum amount of time we should wait before dropping the + connection to identd server.Setting it to 0 implies infinit + timeout. + */ + public static final int connectionTimeout = 10000; + + + /** + Constructor tries to connect to Identd daemon on the host of the + given socket, and retrieve user name of the owner of given socket + connection on remote machine. After constructor returns public + fields are initialised to whatever the server returned. + <p> + If user name was successfully retrieved successful is set to true, + and userName and hostType are set to whatever server returned. If + however for some reason user name was not obtained, successful is set + to false and errorCode contains the code explaining the reason of + failure, and errorMessage contains human readable explanation. + <p> + Constructor may block, for a while. + @param s Socket whose ownership on remote end should be obtained. + */ + public Ident(Socket s ){ + Socket sock = null; + successful = false; //We are pessimistic + + try{ + sock = new Socket(s.getInetAddress(),113); + sock.setSoTimeout(connectionTimeout); + byte[] request = (""+s.getPort()+" , "+ + s.getLocalPort()+"\r\n").getBytes(); + + sock.getOutputStream().write(request); + + BufferedReader in = new BufferedReader( + new InputStreamReader(sock.getInputStream())); + + parseResponse(in.readLine()); + + }catch(InterruptedIOException iioe){ + errorCode = ERR_TIMEOUT; + errorMessage = "Connection to identd timed out."; + }catch(ConnectException ce){ + errorCode = ERR_NO_CONNECT; + errorMessage = "Connection to identd server failed."; + + }catch(IOException ioe){ + errorCode = ERR_NO_CONNECT; + errorMessage = ""+ioe; + }finally{ + try{ if(sock!=null) sock.close();}catch(IOException ioe){}; + } + } + + private void parseResponse(String response){ + if(response == null){ + errorCode = ERR_PROTOCOL_INCORRECT; + errorMessage = "Identd server closed connection."; + return; + } + + StringTokenizer st = new StringTokenizer(response,":"); + if(st.countTokens() < 3){ + errorCode = ERR_PROTOCOL_INCORRECT; + errorMessage = "Can't parse server response."; + return; + } + + st.nextToken(); //Discard first token, it's basically what we have send + String command = st.nextToken().trim().toUpperCase(); + + if(command.equals("USERID") && st.countTokens() >= 2){ + successful = true; + hostType = st.nextToken().trim(); + userName = st.nextToken("").substring(1);//Get all that is left + }else if(command.equals("ERROR")){ + errorCode = ERR_PROTOCOL; + errorMessage = st.nextToken(); + }else{ + errorCode = ERR_PROTOCOL_INCORRECT; + System.out.println("Opa!"); + errorMessage = "Can't parse server response."; + } + + + } + +/////////////////////////////////////////////// +//USED for Testing +/* + public static void main(String[] args) throws IOException{ + + Socket s = null; + s = new Socket("gp101-16", 1391); + + Ident id = new Ident(s); + if(id.successful){ + System.out.println("User: "+id.userName); + System.out.println("HostType: "+id.hostType); + }else{ + System.out.println("ErrorCode: "+id.errorCode); + System.out.println("ErrorMessage: "+id.errorMessage); + + } + + if(s!= null) s.close(); + } +//*/ + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/net/sourceforge/jsocks/server/IdentAuthenticator.java Fri Aug 01 11:23:10 2014 -0700 @@ -0,0 +1,150 @@ +package socks.server; +import net.sourceforge.jsocks.InetRange; +import net.sourceforge.jsocks.ProxyMessage; +import java.util.Hashtable; +import java.util.Vector; +import java.util.Enumeration; +import java.net.*; +import java.io.*; + +/** + An implementation of socks.ServerAuthentication which provides + simple authentication based on the host from which the connection + is made and the name of the user on the remote machine, as reported + by identd daemon on the remote machine. + <p> + It can also be used to provide authentication based only on the contacting + host address. +*/ + +public class IdentAuthenticator extends ServerAuthenticatorNone{ + /** Vector of InetRanges */ + Vector hosts; + + /** Vector of user hashes*/ + Vector users; + + String user; + + + /** + Constructs empty IdentAuthenticator. + */ + public IdentAuthenticator(){ + hosts = new Vector(); + users = new Vector(); + } + /** + Used to create instances returned from startSession. + @param in Input stream. + @param out OutputStream. + @param user Username associated with this connection,could be + null if name was not required. + */ + IdentAuthenticator(InputStream in,OutputStream out, String user){ + super(in,out); + this.user = user; + } + + /** + Adds range of addresses from which connection is allowed. Hashtable + users should contain user names as keys and anything as values + (value is not used and will be ignored). + @param hostRange Range of ip addresses from which connection is allowed. + @param users Hashtable of users for whom connection is allowed, or null + to indicate that anybody is allowed to connect from the hosts within given + range. + */ + public synchronized void add(InetRange hostRange,Hashtable users){ + this.hosts.addElement(hostRange); + this.users.addElement(users); + } + + /** + Grants permission only to those users, who connect from one of the + hosts registered with add(InetRange,Hashtable) and whose names, as + reported by identd daemon, are listed for the host the connection + came from. + */ + public ServerAuthenticator startSession(Socket s) + throws IOException{ + + int ind = getRangeIndex(s.getInetAddress()); + String user = null; + + //System.out.println("getRangeReturned:"+ind); + + if(ind < 0) return null; //Host is not on the list. + + ServerAuthenticatorNone auth = (ServerAuthenticatorNone) + super.startSession(s); + + //System.out.println("super.startSession() returned:"+auth); + if(auth == null) return null; + + //do the authentication + + Hashtable user_names = (Hashtable) users.elementAt(ind); + + if(user_names != null){ //If need to do authentication + Ident ident; + ident = new Ident(s); + //If can't obtain user name, fail + if(!ident.successful) return null; + //If user name is not listed for this address, fail + if(!user_names.containsKey(ident.userName)) return null; + user = ident.userName; + } + return new IdentAuthenticator(auth.in,auth.out,user); + + } + /** + For SOCKS5 requests allways returns true. For SOCKS4 requests + checks wether the user name supplied in the request corresponds + to the name obtained from the ident daemon. + */ + public boolean checkRequest(ProxyMessage msg,java.net.Socket s){ + //If it's version 5 request, or if anybody is permitted, return true; + if(msg.version == 5 || user == null) + return true; + + if(msg.version != 4) return false; //Who knows? + + return user.equals(msg.user); + } + + /** Get String representaion of the IdentAuthenticator.*/ + public String toString(){ + String s = ""; + + for(int i=0;i<hosts.size();++i) + s += "Range:"+hosts.elementAt(i)+"\nUsers:"+userNames(i)+"\n"; + return s; + } + +//Private Methods +////////////////// + private int getRangeIndex(InetAddress ip){ + int index = 0; + Enumeration eEnum = hosts.elements(); + while(eEnum.hasMoreElements()){ + InetRange ir = (InetRange) eEnum.nextElement(); + if(ir.contains(ip)) return index; + index++; + } + return -1; //Not found + } + + private String userNames(int i){ + if(users.elementAt(i) == null) return "Everybody is permitted."; + + Enumeration eEnum = ((Hashtable)users.elementAt(i)).keys(); + if(!eEnum.hasMoreElements()) return ""; + String s = eEnum.nextElement().toString(); + while(eEnum.hasMoreElements()) + s += "; "+eEnum.nextElement(); + + return s; + } + +}
--- a/src/net/sourceforge/jsocks/server/ServerAuthenticator.java Fri Aug 01 10:25:44 2014 -0700 +++ b/src/net/sourceforge/jsocks/server/ServerAuthenticator.java Fri Aug 01 11:23:10 2014 -0700 @@ -1,120 +1,119 @@ -package net.sourceforge.jsocks.server; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.DatagramPacket; -import java.net.Socket; - -import net.sourceforge.jsocks.ProxyMessage; -import net.sourceforge.jsocks.UDPEncapsulation; - -/** - Classes implementing this interface should provide socks server with - authentication and authorization of users. -**/ -public interface ServerAuthenticator { - - /** - This method is called when a new connection accepted by the server. - <p> - At this point no data have been extracted from the connection. It is - responsibility of this method to ensure that the next byte in the - stream after this method have been called is the first byte of the - socks request message. For SOCKSv4 there is no authentication data and - the first byte in the stream is part of the request. With SOCKSv5 however - there is an authentication data first. It is expected that implementaions - will process this authentication data. - <p> - If authentication was successful an instance of ServerAuthentication - should be returned, it later will be used by the server to perform - authorization and some other things. If authentication fails null should - be returned, or an exception may be thrown. - - @param s Accepted Socket. - @return An instance of ServerAuthenticator to be used for this connection - or null - */ - ServerAuthenticator startSession(Socket s) throws IOException; - - /** - This method should return input stream which should be used on the - accepted socket. - <p> - SOCKSv5 allows to have multiple authentication methods, and these methods - might require some kind of transformations being made on the data. - <p> - This method is called on the object returned from the startSession - function. - */ - InputStream getInputStream(); - /** - This method should return output stream to use to write to the accepted - socket. - <p> - SOCKSv5 allows to have multiple authentication methods, and these methods - might require some kind of transformations being made on the data. - <p> - This method is called on the object returned from the startSession - function. - */ - OutputStream getOutputStream(); - - /** - This method should return UDPEncapsulation, which should be used - on the datagrams being send in/out. - <p> - If no transformation should be done on the datagrams, this method - should return null. - <p> - This method is called on the object returned from the startSession - function. - */ - - UDPEncapsulation getUdpEncapsulation(); - - /** - This method is called when a request have been read. - <p> - Implementation should decide wether to grant request or not. Returning - true implies granting the request, false means request should be rejected. - <p> - This method is called on the object returned from the startSession - function. - @param msg Request message. - @return true to grant request, false to reject it. - */ - boolean checkRequest(ProxyMessage msg); - - /** - This method is called when datagram is received by the server. - <p> - Implementaions should decide wether it should be forwarded or dropped. - It is expecteed that implementation will use datagram address and port - information to make a decision, as well as anything else. Address and - port of the datagram are always correspond to remote machine. It is - either destination or source address. If out is true address is destination - address, else it is a source address, address of the machine from which - datagram have been received for the client. - <p> - Implementaions should return true if the datagram is to be forwarded, and - false if the datagram should be dropped. - <p> - This method is called on the object returned from the startSession - function. - - @param out If true the datagram is being send out(from the client), - otherwise it is an incoming datagram. - @return True to forward datagram false drop it silently. - */ - boolean checkRequest(DatagramPacket dp, boolean out); - - /** - This method is called when session is completed. Either due to normal - termination or due to any error condition. - <p> - This method is called on the object returned from the startSession - function. - */ - void endSession(); -} +package socks.server; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.Socket; +import java.net.DatagramPacket; +import net.sourceforge.jsocks.ProxyMessage; +import net.sourceforge.jsocks.UDPEncapsulation; + +/** + Classes implementing this interface should provide socks server with + authentication and authorization of users. +**/ +public interface ServerAuthenticator{ + + /** + This method is called when a new connection accepted by the server. + <p> + At this point no data have been extracted from the connection. It is + responsibility of this method to ensure that the next byte in the + stream after this method have been called is the first byte of the + socks request message. For SOCKSv4 there is no authentication data and + the first byte in the stream is part of the request. With SOCKSv5 however + there is an authentication data first. It is expected that implementaions + will process this authentication data. + <p> + If authentication was successful an instance of ServerAuthentication + should be returned, it later will be used by the server to perform + authorization and some other things. If authentication fails null should + be returned, or an exception may be thrown. + + @param s Accepted Socket. + @return An instance of ServerAuthenticator to be used for this connection + or null + */ + ServerAuthenticator startSession(Socket s) throws IOException; + + /** + This method should return input stream which should be used on the + accepted socket. + <p> + SOCKSv5 allows to have multiple authentication methods, and these methods + might require some kind of transformations being made on the data. + <p> + This method is called on the object returned from the startSession + function. + */ + InputStream getInputStream(); + /** + This method should return output stream to use to write to the accepted + socket. + <p> + SOCKSv5 allows to have multiple authentication methods, and these methods + might require some kind of transformations being made on the data. + <p> + This method is called on the object returned from the startSession + function. + */ + OutputStream getOutputStream(); + + /** + This method should return UDPEncapsulation, which should be used + on the datagrams being send in/out. + <p> + If no transformation should be done on the datagrams, this method + should return null. + <p> + This method is called on the object returned from the startSession + function. + */ + + UDPEncapsulation getUdpEncapsulation(); + + /** + This method is called when a request have been read. + <p> + Implementation should decide wether to grant request or not. Returning + true implies granting the request, false means request should be rejected. + <p> + This method is called on the object returned from the startSession + function. + @param msg Request message. + @return true to grant request, false to reject it. + */ + boolean checkRequest(ProxyMessage msg); + + /** + This method is called when datagram is received by the server. + <p> + Implementaions should decide wether it should be forwarded or dropped. + It is expecteed that implementation will use datagram address and port + information to make a decision, as well as anything else. Address and + port of the datagram are always correspond to remote machine. It is + either destination or source address. If out is true address is destination + address, else it is a source address, address of the machine from which + datagram have been received for the client. + <p> + Implementaions should return true if the datagram is to be forwarded, and + false if the datagram should be dropped. + <p> + This method is called on the object returned from the startSession + function. + + @param out If true the datagram is being send out(from the client), + otherwise it is an incoming datagram. + @return True to forward datagram false drop it silently. + */ + boolean checkRequest(DatagramPacket dp, boolean out); + + /** + This method is called when session is completed. Either due to normal + termination or due to any error condition. + <p> + This method is called on the object returned from the startSession + function. + */ + void endSession(); +}
--- a/src/net/sourceforge/jsocks/server/ServerAuthenticatorNone.java Fri Aug 01 10:25:44 2014 -0700 +++ b/src/net/sourceforge/jsocks/server/ServerAuthenticatorNone.java Fri Aug 01 11:23:10 2014 -0700 @@ -1,169 +1,170 @@ -package net.sourceforge.jsocks.server; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.PushbackInputStream; -import java.net.Socket; - -import net.sourceforge.jsocks.ProxyMessage; -import net.sourceforge.jsocks.UDPEncapsulation; - -/** - An implementation of ServerAuthenticator, which does <b>not</b> do - any authentication. -<P> -<FONT size="+3" color ="FF0000"> Warning!!</font><br> Should not be -used on machines which are not behind the firewall. -<p> -It is only provided to make implementing other authentication schemes -easier.<br> -For Example: <tt><pre> - class MyAuth extends socks.server.ServerAuthenticator{ - ... - public ServerAuthenticator startSession(java.net.Socket s){ - if(!checkHost(s.getInetAddress()) return null; - return super.startSession(s); - } - - boolean checkHost(java.net.Inetaddress addr){ - boolean allow; - //Do it somehow - return allow; - } - } -</pre></tt> -*/ -public class ServerAuthenticatorNone implements ServerAuthenticator { - - static final byte[] socks5response = {5, 0}; - - InputStream in; - OutputStream out; - - /** - Creates new instance of the ServerAuthenticatorNone. - */ - public ServerAuthenticatorNone() { - this.in = null; - this.out = null; - } - /** - Constructs new ServerAuthenticatorNone object suitable for returning - from the startSession function. - @param in Input stream to return from getInputStream method. - @param out Output stream to return from getOutputStream method. - */ - public ServerAuthenticatorNone(InputStream in, OutputStream out) { - this.in = in; - this.out = out; - } - /** - Grants access to everyone.Removes authentication related bytes from - the stream, when a SOCKS5 connection is being made, selects an - authentication NONE. - */ - public ServerAuthenticator startSession(Socket s) - throws IOException { - PushbackInputStream in = new PushbackInputStream(s.getInputStream()); - OutputStream out = s.getOutputStream(); - int version = in.read(); - - if (version == 5) { - if (!selectSocks5Authentication(in, out, 0)) - return null; - } - else if (version == 4) { - //Else it is the request message allready, version 4 - in.unread(version); - } - else - return null; - - return new ServerAuthenticatorNone(in, out); - } - - /** - Get input stream. - @return Input stream speciefied in the constructor. - */ - public InputStream getInputStream() { - return in; - } - /** - Get output stream. - @return Output stream speciefied in the constructor. - */ - public OutputStream getOutputStream() { - return out; - } - /** - Allways returns null. - @return null - */ - public UDPEncapsulation getUdpEncapsulation() { - return null; - } - - /** - Allways returns true. - */ - public boolean checkRequest(ProxyMessage msg) { - return true; - } - - /** - Allways returns true. - */ - public boolean checkRequest(java.net.DatagramPacket dp, boolean out) { - return true; - } - - /** - Does nothing. - */ - public void endSession() { - } - - /** - Convinience routine for selecting SOCKSv5 authentication. - <p> - This method reads in authentication methods that client supports, - checks wether it supports given method. If it does, the notification - method is written back to client, that this method have been chosen - for authentication. If given method was not found, authentication - failure message is send to client ([5,FF]). - @param in Input stream, version byte should be removed from the stream - before calling this method. - @param out Output stream. - @param methodId Method which should be selected. - @return true if methodId was found, false otherwise. - */ - static public boolean selectSocks5Authentication(InputStream in, - OutputStream out, - int methodId) - throws IOException { - int num_methods = in.read(); - - if (num_methods <= 0) return false; - - byte method_ids[] = new byte[num_methods]; - byte response[] = new byte[2]; - boolean found = false; - response[0] = (byte) 5; //SOCKS version - response[1] = (byte) 0xFF; //Not found, we are pessimistic - int bread = 0; //bytes read so far - - while (bread < num_methods) - bread += in.read(method_ids, bread, num_methods - bread); - - for (int i = 0; i < num_methods; ++i) - if (method_ids[i] == methodId) { - found = true; - response[1] = (byte) methodId; - break; - } - - out.write(response); - return found; - } -} +package socks.server; +import net.sourceforge.jsocks.ProxyMessage; +import net.sourceforge.jsocks.UDPEncapsulation; + +import java.io.IOException; +import java.io.InputStream; +import java.io.DataInputStream; +import java.io.OutputStream; +import java.io.PushbackInputStream; +import java.net.Socket; + +/** + An implementation of ServerAuthenticator, which does <b>not</b> do + any authentication. +<P> +<FONT size="+3" color ="FF0000"> Warning!!</font><br> Should not be +used on machines which are not behind the firewall. +<p> +It is only provided to make implementing other authentication schemes +easier.<br> +For Example: <tt><pre> + class MyAuth extends socks.server.ServerAuthenticator{ + ... + public ServerAuthenticator startSession(java.net.Socket s){ + if(!checkHost(s.getInetAddress()) return null; + return super.startSession(s); + } + + boolean checkHost(java.net.Inetaddress addr){ + boolean allow; + //Do it somehow + return allow; + } + } +</pre></tt> +*/ +public class ServerAuthenticatorNone implements ServerAuthenticator{ + + static final byte[] socks5response = {5,0}; + + InputStream in; + OutputStream out; + + /** + Creates new instance of the ServerAuthenticatorNone. + */ + public ServerAuthenticatorNone(){ + this.in = null; + this.out = null; + } + /** + Constructs new ServerAuthenticatorNone object suitable for returning + from the startSession function. + @param in Input stream to return from getInputStream method. + @param out Output stream to return from getOutputStream method. + */ + public ServerAuthenticatorNone(InputStream in, OutputStream out){ + this.in = in; + this.out = out; + } + /** + Grants access to everyone.Removes authentication related bytes from + the stream, when a SOCKS5 connection is being made, selects an + authentication NONE. + */ + public ServerAuthenticator startSession(Socket s) + throws IOException{ + + PushbackInputStream in = new PushbackInputStream(s.getInputStream()); + OutputStream out = s.getOutputStream(); + + int version = in.read(); + if(version == 5){ + if(!selectSocks5Authentication(in,out,0)) + return null; + }else if(version == 4){ + //Else it is the request message allready, version 4 + in.unread(version); + }else + return null; + + + return new ServerAuthenticatorNone(in,out); + } + + /** + Get input stream. + @return Input stream speciefied in the constructor. + */ + public InputStream getInputStream(){ + return in; + } + /** + Get output stream. + @return Output stream speciefied in the constructor. + */ + public OutputStream getOutputStream(){ + return out; + } + /** + Allways returns null. + @return null + */ + public UDPEncapsulation getUdpEncapsulation(){ + return null; + } + + /** + Allways returns true. + */ + public boolean checkRequest(ProxyMessage msg){ + return true; + } + + /** + Allways returns true. + */ + public boolean checkRequest(java.net.DatagramPacket dp, boolean out){ + return true; + } + + /** + Does nothing. + */ + public void endSession(){ + } + + /** + Convinience routine for selecting SOCKSv5 authentication. + <p> + This method reads in authentication methods that client supports, + checks wether it supports given method. If it does, the notification + method is written back to client, that this method have been chosen + for authentication. If given method was not found, authentication + failure message is send to client ([5,FF]). + @param in Input stream, version byte should be removed from the stream + before calling this method. + @param out Output stream. + @param methodId Method which should be selected. + @return true if methodId was found, false otherwise. + */ + static public boolean selectSocks5Authentication(InputStream in, + OutputStream out, + int methodId) + throws IOException{ + + int num_methods = in.read(); + if (num_methods <= 0) return false; + byte method_ids[] = new byte[num_methods]; + byte response[] = new byte[2]; + boolean found = false; + + response[0] = (byte) 5; //SOCKS version + response[1] = (byte) 0xFF; //Not found, we are pessimistic + + int bread = 0; //bytes read so far + while(bread < num_methods) + bread += in.read(method_ids,bread,num_methods-bread); + + for(int i=0;i<num_methods;++i) + if(method_ids[i] == methodId){ + found = true; + response[1] = (byte) methodId; + break; + } + + out.write(response); + return found; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/net/sourceforge/jsocks/server/UserPasswordAuthenticator.java Fri Aug 01 11:23:10 2014 -0700 @@ -0,0 +1,73 @@ +package socks.server; + +import net.sourceforge.jsocks.ProxyMessage; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.Socket; + +/** + This class implements SOCKS5 User/Password authentication scheme as + defined in rfc1929,the server side of it. +*/ +public class UserPasswordAuthenticator extends ServerAuthenticatorNone{ + + static final int METHOD_ID = 2; + + UserValidation validator; + + /** + Construct a new UserPasswordAuthentication object, with given + UserVlaidation scheme. + + @param v UserValidation to use for validating users. + */ + public UserPasswordAuthenticator(UserValidation validator){ + this.validator = validator; + } + + public ServerAuthenticator startSession(Socket s) throws IOException{ + InputStream in = s.getInputStream(); + OutputStream out = s.getOutputStream(); + + if(in.read() != 5) return null; //Drop non version 5 messages. + + if(!selectSocks5Authentication(in,out,METHOD_ID)) + return null; + if(!doUserPasswordAuthentication(s,in,out)) + return null; + + return new ServerAuthenticatorNone(in,out); + } + + +//Private Methods +////////////////// + + private boolean doUserPasswordAuthentication(Socket s, + InputStream in, + OutputStream out) + throws IOException{ + int version = in.read(); + if(version != 1) return false; + int ulen = in.read(); + if(ulen < 0) return false; + byte[] user = new byte[ulen]; + in.read(user); + int plen = in.read(); + if(plen < 0) return false; + byte[] password = new byte[plen]; + in.read(password); + + if(validator.isUserValid(new String(user), new String(password),s)){ + //System.out.println("user valid"); + out.write(new byte[]{1,0}); + }else{ + //System.out.println("user invalid"); + out.write(new byte[]{1,1}); + return false; + } + + return true; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/net/sourceforge/jsocks/server/UserValidation.java Fri Aug 01 11:23:10 2014 -0700 @@ -0,0 +1,21 @@ +package socks.server; + +/** + Interface which provides for user validation, based on user name + password and where it connects from. +*/ +public interface UserValidation{ + /** + Implementations of this interface are expected to use some or all + of the information provided plus any information they can extract + from other sources to decide wether given user should be allowed + access to SOCKS server, or whatever you use it for. + + @return true to indicate user is valid, false otherwise. + @param username User whom implementation should validate. + @param password Password this user provided. + @param connection Socket which user used to connect to the server. + */ + boolean isUserValid(String username,String password, + java.net.Socket connection); +}