diff options
Diffstat (limited to 'src/net')
17 files changed, 3481 insertions, 3481 deletions
diff --git a/src/net/sourceforge/jsocks/Authentication.java b/src/net/sourceforge/jsocks/Authentication.java index 4e9eae1..18cc48b 100644 --- a/src/net/sourceforge/jsocks/Authentication.java +++ b/src/net/sourceforge/jsocks/Authentication.java @@ -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; +} diff --git a/src/net/sourceforge/jsocks/AuthenticationNone.java b/src/net/sourceforge/jsocks/AuthenticationNone.java index 676b2da..f28193a 100644 --- a/src/net/sourceforge/jsocks/AuthenticationNone.java +++ b/src/net/sourceforge/jsocks/AuthenticationNone.java @@ -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()}; + } +} diff --git a/src/net/sourceforge/jsocks/Proxy.java b/src/net/sourceforge/jsocks/Proxy.java index ed91516..381c0a0 100644 --- a/src/net/sourceforge/jsocks/Proxy.java +++ b/src/net/sourceforge/jsocks/Proxy.java @@ -1,404 +1,404 @@ -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;
-
-}
+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; + +} diff --git a/src/net/sourceforge/jsocks/ProxyMessage.java b/src/net/sourceforge/jsocks/ProxyMessage.java index 6ea8b4b..442c380 100644 --- a/src/net/sourceforge/jsocks/ProxyMessage.java +++ b/src/net/sourceforge/jsocks/ProxyMessage.java @@ -1,109 +1,109 @@ -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.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; + } + +} diff --git a/src/net/sourceforge/jsocks/ProxyServer.java b/src/net/sourceforge/jsocks/ProxyServer.java index 39f6383..225149d 100644 --- a/src/net/sourceforge/jsocks/ProxyServer.java +++ b/src/net/sourceforge/jsocks/ProxyServer.java @@ -1,591 +1,591 @@ -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 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; + } +} diff --git a/src/net/sourceforge/jsocks/Socks4Message.java b/src/net/sourceforge/jsocks/Socks4Message.java index 1d68cb7..99fb211 100644 --- a/src/net/sourceforge/jsocks/Socks4Message.java +++ b/src/net/sourceforge/jsocks/Socks4Message.java @@ -1,171 +1,171 @@ -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.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; + +} diff --git a/src/net/sourceforge/jsocks/Socks4Proxy.java b/src/net/sourceforge/jsocks/Socks4Proxy.java index f920b75..9a17fc2 100644 --- a/src/net/sourceforge/jsocks/Socks4Proxy.java +++ b/src/net/sourceforge/jsocks/Socks4Proxy.java @@ -1,107 +1,107 @@ -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.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); + } + +} diff --git a/src/net/sourceforge/jsocks/Socks5DatagramSocket.java b/src/net/sourceforge/jsocks/Socks5DatagramSocket.java index bb73ccd..b847400 100644 --- a/src/net/sourceforge/jsocks/Socks5DatagramSocket.java +++ b/src/net/sourceforge/jsocks/Socks5DatagramSocket.java @@ -1,460 +1,460 @@ -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 + 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(); + } + } +*/ + +} diff --git a/src/net/sourceforge/jsocks/Socks5Message.java b/src/net/sourceforge/jsocks/Socks5Message.java index 49539c4..ea2a321 100644 --- a/src/net/sourceforge/jsocks/Socks5Message.java +++ b/src/net/sourceforge/jsocks/Socks5Message.java @@ -1,292 +1,292 @@ -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.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; + +} diff --git a/src/net/sourceforge/jsocks/Socks5Proxy.java b/src/net/sourceforge/jsocks/Socks5Proxy.java index 8b1d946..aa9c643 100644 --- a/src/net/sourceforge/jsocks/Socks5Proxy.java +++ b/src/net/sourceforge/jsocks/Socks5Proxy.java @@ -1,231 +1,231 @@ -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(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 Proxy.
- */
- @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
-//=================
-
- 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;
- }
- /**
- *
- *
- */
- 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)((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);
- }
-
-}
+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(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 Proxy. + */ + @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 +//================= + + 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; + } + /** + * + * + */ + 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)((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); + } + +} diff --git a/src/net/sourceforge/jsocks/SocksException.java b/src/net/sourceforge/jsocks/SocksException.java index 867eff6..764587f 100644 --- a/src/net/sourceforge/jsocks/SocksException.java +++ b/src/net/sourceforge/jsocks/SocksException.java @@ -1,80 +1,80 @@ -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 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 + diff --git a/src/net/sourceforge/jsocks/SocksServerSocket.java b/src/net/sourceforge/jsocks/SocksServerSocket.java index 739251d..179e9c4 100644 --- a/src/net/sourceforge/jsocks/SocksServerSocket.java +++ b/src/net/sourceforge/jsocks/SocksServerSocket.java @@ -1,164 +1,164 @@ -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 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(); + } + +} diff --git a/src/net/sourceforge/jsocks/SocksSocket.java b/src/net/sourceforge/jsocks/SocksSocket.java index 95a7e42..cf9ff65 100644 --- a/src/net/sourceforge/jsocks/SocksSocket.java +++ b/src/net/sourceforge/jsocks/SocksSocket.java @@ -1,291 +1,291 @@ -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, 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); + } + } + +} diff --git a/src/net/sourceforge/jsocks/UDPEncapsulation.java b/src/net/sourceforge/jsocks/UDPEncapsulation.java index efeb0ed..e965942 100644 --- a/src/net/sourceforge/jsocks/UDPEncapsulation.java +++ b/src/net/sourceforge/jsocks/UDPEncapsulation.java @@ -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; +} diff --git a/src/net/sourceforge/jsocks/UDPRelayServer.java b/src/net/sourceforge/jsocks/UDPRelayServer.java index 682ab17..dfa6016 100644 --- a/src/net/sourceforge/jsocks/UDPRelayServer.java +++ b/src/net/sourceforge/jsocks/UDPRelayServer.java @@ -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 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); + } + } +} diff --git a/src/net/sourceforge/jsocks/server/ServerAuthenticator.java b/src/net/sourceforge/jsocks/server/ServerAuthenticator.java index 6fb99e0..cb7f0af 100644 --- a/src/net/sourceforge/jsocks/server/ServerAuthenticator.java +++ b/src/net/sourceforge/jsocks/server/ServerAuthenticator.java @@ -1,120 +1,120 @@ -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 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(); +} diff --git a/src/net/sourceforge/jsocks/server/ServerAuthenticatorNone.java b/src/net/sourceforge/jsocks/server/ServerAuthenticatorNone.java index 30eb265..e4edbe7 100644 --- a/src/net/sourceforge/jsocks/server/ServerAuthenticatorNone.java +++ b/src/net/sourceforge/jsocks/server/ServerAuthenticatorNone.java @@ -1,169 +1,169 @@ -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 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; + } +} |