first commit of new OrbotVPN integration into Orbot
This commit is contained in:
		
							parent
							
								
									dbbd8292c2
								
							
						
					
					
						commit
						e45991899a
					
				| 
						 | 
					@ -29,3 +29,6 @@
 | 
				
			||||||
[submodule "external/polipo"]
 | 
					[submodule "external/polipo"]
 | 
				
			||||||
	path = external/polipo
 | 
						path = external/polipo
 | 
				
			||||||
	url = https://github.com/jech/polipo.git
 | 
						url = https://github.com/jech/polipo.git
 | 
				
			||||||
 | 
					[submodule "external/badvpn"]
 | 
				
			||||||
 | 
						path = external/badvpn
 | 
				
			||||||
 | 
						url = https://github.com/ambrop72/badvpn.git
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -101,6 +101,14 @@
 | 
				
			||||||
				<action	android:name="android.intent.action.BOOT_COMPLETED" />
 | 
									<action	android:name="android.intent.action.BOOT_COMPLETED" />
 | 
				
			||||||
			</intent-filter>
 | 
								</intent-filter>
 | 
				
			||||||
		</receiver>
 | 
							</receiver>
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
					    	
 | 
				
			||||||
 | 
					        <service android:name="org.torproject.android.vpn.OrbotVpnService"
 | 
				
			||||||
 | 
					                android:permission="android.permission.BIND_VPN_SERVICE">
 | 
				
			||||||
 | 
					            <intent-filter>
 | 
				
			||||||
 | 
					                <action android:name="android.net.VpnService"/>
 | 
				
			||||||
 | 
					            </intent-filter>
 | 
				
			||||||
 | 
					        </service>
 | 
				
			||||||
    	
 | 
					    	
 | 
				
			||||||
    </application>
 | 
					    </application>
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1 @@
 | 
				
			||||||
 | 
					Subproject commit 5153894f4375d7a0e43d0b60c1b759543e6b383a
 | 
				
			||||||
| 
						 | 
					@ -1 +1 @@
 | 
				
			||||||
Subproject commit 40233cadbbbf77214913db818a1458c6ddd14a9f
 | 
					Subproject commit a64f3ab3ee5c433cc1f046a7e26df7a49e308e4c
 | 
				
			||||||
| 
						 | 
					@ -73,6 +73,9 @@
 | 
				
			||||||
         
 | 
					         
 | 
				
			||||||
         />
 | 
					         />
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
 | 
					  <item android:id="@+id/menu_vpn"
 | 
				
			||||||
 | 
					      android:title="start VPN"
 | 
				
			||||||
 | 
					      yourapp:showAsAction="never"/>
 | 
				
			||||||
   <!-- 
 | 
					   <!-- 
 | 
				
			||||||
  <item android:id="@+id/menu_diag"
 | 
					  <item android:id="@+id/menu_diag"
 | 
				
			||||||
        android:title="Test Mode"
 | 
					        android:title="Test Mode"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,269 @@
 | 
				
			||||||
 | 
					package com.runjva.sourceforge.jsocks.main;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.FileInputStream;
 | 
				
			||||||
 | 
					import java.io.IOException;
 | 
				
			||||||
 | 
					import java.io.InputStream;
 | 
				
			||||||
 | 
					import java.net.InetAddress;
 | 
				
			||||||
 | 
					import java.net.UnknownHostException;
 | 
				
			||||||
 | 
					import java.util.Hashtable;
 | 
				
			||||||
 | 
					import java.util.Properties;
 | 
				
			||||||
 | 
					import java.util.StringTokenizer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.slf4j.Logger;
 | 
				
			||||||
 | 
					import org.slf4j.LoggerFactory;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.runjva.sourceforge.jsocks.protocol.InetRange;
 | 
				
			||||||
 | 
					import com.runjva.sourceforge.jsocks.protocol.ProxyServer;
 | 
				
			||||||
 | 
					import com.runjva.sourceforge.jsocks.protocol.SocksProxyBase;
 | 
				
			||||||
 | 
					import com.runjva.sourceforge.jsocks.server.IdentAuthenticator;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class SOCKS {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private static final int DEFAULT_LISTENING_PORT = 1080;
 | 
				
			||||||
 | 
						final private static Logger log = LoggerFactory.getLogger(SOCKS.class);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static public void usage() {
 | 
				
			||||||
 | 
							System.out.println("Usage: java SOCKS [inifile1 inifile2 ...]\n"
 | 
				
			||||||
 | 
									+ "If none inifile is given, uses socks.properties.\n");
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static public void main(String[] args) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							String[] file_names;
 | 
				
			||||||
 | 
							int port = DEFAULT_LISTENING_PORT;
 | 
				
			||||||
 | 
							String logFile = null;
 | 
				
			||||||
 | 
							String host = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							final IdentAuthenticator auth = new IdentAuthenticator();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							InetAddress localIP = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (args.length == 0) {
 | 
				
			||||||
 | 
								file_names = new String[] { "socks.properties" };
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								file_names = args;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							inform("Loading properties");
 | 
				
			||||||
 | 
							for (int i = 0; i < file_names.length; ++i) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								inform("Reading file " + file_names[i]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								final Properties pr = loadProperties(file_names[i]);
 | 
				
			||||||
 | 
								if (pr == null) {
 | 
				
			||||||
 | 
									System.err.println("Loading of properties from "
 | 
				
			||||||
 | 
											+ file_names[i] + "failed.");
 | 
				
			||||||
 | 
									usage();
 | 
				
			||||||
 | 
									return;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if (!addAuth(auth, pr)) {
 | 
				
			||||||
 | 
									System.err.println("Error in file " + file_names[i] + ".");
 | 
				
			||||||
 | 
									usage();
 | 
				
			||||||
 | 
									return;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								// First file should contain all global settings,
 | 
				
			||||||
 | 
								// like port and host and log.
 | 
				
			||||||
 | 
								if (i == 0) {
 | 
				
			||||||
 | 
									final String port_s = (String) pr.get("port");
 | 
				
			||||||
 | 
									if (port_s != null) {
 | 
				
			||||||
 | 
										try {
 | 
				
			||||||
 | 
											port = Integer.parseInt(port_s);
 | 
				
			||||||
 | 
										} catch (final NumberFormatException nfe) {
 | 
				
			||||||
 | 
											System.err.println("Can't parse port: " + port_s);
 | 
				
			||||||
 | 
											return;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									serverInit(pr);
 | 
				
			||||||
 | 
									logFile = (String) pr.get("log");
 | 
				
			||||||
 | 
									host = (String) pr.get("host");
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// inform("Props:"+pr);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (logFile != null) {
 | 
				
			||||||
 | 
								System.err.println("log property not supported anymore.");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (host != null) {
 | 
				
			||||||
 | 
								try {
 | 
				
			||||||
 | 
									localIP = InetAddress.getByName(host);
 | 
				
			||||||
 | 
								} catch (final UnknownHostException uhe) {
 | 
				
			||||||
 | 
									System.err.println("Can't resolve local ip: " + host);
 | 
				
			||||||
 | 
									return;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							inform("Using Ident Authentication scheme: " + auth);
 | 
				
			||||||
 | 
							final ProxyServer server = new ProxyServer(auth);
 | 
				
			||||||
 | 
							server.start(port, 5, localIP);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static Properties loadProperties(String file_name) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							final Properties pr = new Properties();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							try {
 | 
				
			||||||
 | 
								final InputStream fin = new FileInputStream(file_name);
 | 
				
			||||||
 | 
								pr.load(fin);
 | 
				
			||||||
 | 
								fin.close();
 | 
				
			||||||
 | 
							} catch (final IOException ioe) {
 | 
				
			||||||
 | 
								return null;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return pr;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static boolean addAuth(IdentAuthenticator ident, Properties pr) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							InetRange irange;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							final String range = (String) pr.get("range");
 | 
				
			||||||
 | 
							if (range == null) {
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							irange = parseInetRange(range);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							final String users = (String) pr.get("users");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (users == null) {
 | 
				
			||||||
 | 
								ident.add(irange, null);
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							final Hashtable<String, String> uhash = new Hashtable<String, String>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							final StringTokenizer st = new StringTokenizer(users, ";");
 | 
				
			||||||
 | 
							while (st.hasMoreTokens()) {
 | 
				
			||||||
 | 
								uhash.put(st.nextToken(), "");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ident.add(irange, uhash);
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Does server initialisation.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						static void serverInit(Properties props) {
 | 
				
			||||||
 | 
							int val;
 | 
				
			||||||
 | 
							val = readInt(props, "iddleTimeout");
 | 
				
			||||||
 | 
							if (val >= 0) {
 | 
				
			||||||
 | 
								ProxyServer.setIddleTimeout(val);
 | 
				
			||||||
 | 
								inform("Setting iddle timeout to " + val + " ms.");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							val = readInt(props, "acceptTimeout");
 | 
				
			||||||
 | 
							if (val >= 0) {
 | 
				
			||||||
 | 
								ProxyServer.setAcceptTimeout(val);
 | 
				
			||||||
 | 
								inform("Setting accept timeout to " + val + " ms.");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							val = readInt(props, "udpTimeout");
 | 
				
			||||||
 | 
							if (val >= 0) {
 | 
				
			||||||
 | 
								ProxyServer.setUDPTimeout(val);
 | 
				
			||||||
 | 
								inform("Setting udp timeout to " + val + " ms.");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							val = readInt(props, "datagramSize");
 | 
				
			||||||
 | 
							if (val >= 0) {
 | 
				
			||||||
 | 
								ProxyServer.setDatagramSize(val);
 | 
				
			||||||
 | 
								inform("Setting datagram size to " + val + " bytes.");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							proxyInit(props);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Initialises proxy, if any specified.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						static void proxyInit(Properties props) {
 | 
				
			||||||
 | 
							String proxy_list;
 | 
				
			||||||
 | 
							SocksProxyBase proxy = null;
 | 
				
			||||||
 | 
							StringTokenizer st;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							proxy_list = (String) props.get("proxy");
 | 
				
			||||||
 | 
							if (proxy_list == null) {
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							st = new StringTokenizer(proxy_list, ";");
 | 
				
			||||||
 | 
							while (st.hasMoreTokens()) {
 | 
				
			||||||
 | 
								final String proxy_entry = st.nextToken();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								final SocksProxyBase p = SocksProxyBase.parseProxy(proxy_entry);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (p == null) {
 | 
				
			||||||
 | 
									exit("Can't parse proxy entry:" + proxy_entry);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								inform("Adding Proxy:" + p);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (proxy != null) {
 | 
				
			||||||
 | 
									p.setChainProxy(proxy);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								proxy = p;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (proxy == null) {
 | 
				
			||||||
 | 
								return; // Empty list
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							final String direct_hosts = (String) props.get("directHosts");
 | 
				
			||||||
 | 
							if (direct_hosts != null) {
 | 
				
			||||||
 | 
								final InetRange ir = parseInetRange(direct_hosts);
 | 
				
			||||||
 | 
								inform("Setting direct hosts:" + ir);
 | 
				
			||||||
 | 
								proxy.setDirect(ir);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ProxyServer.setProxy(proxy);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Inits range from the string of semicolon separated ranges.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						static InetRange parseInetRange(String source) {
 | 
				
			||||||
 | 
							final InetRange irange = new InetRange();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							final StringTokenizer st = new StringTokenizer(source, ";");
 | 
				
			||||||
 | 
							while (st.hasMoreTokens()) {
 | 
				
			||||||
 | 
								irange.add(st.nextToken());
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return irange;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Integer representaion of the property named name, or -1 if one is not
 | 
				
			||||||
 | 
						 * found.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						static int readInt(Properties props, String name) {
 | 
				
			||||||
 | 
							int result = -1;
 | 
				
			||||||
 | 
							final String val = (String) props.get(name);
 | 
				
			||||||
 | 
							if (val == null) {
 | 
				
			||||||
 | 
								return -1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							final StringTokenizer st = new StringTokenizer(val);
 | 
				
			||||||
 | 
							if (!st.hasMoreElements()) {
 | 
				
			||||||
 | 
								return -1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							try {
 | 
				
			||||||
 | 
								result = Integer.parseInt(st.nextToken());
 | 
				
			||||||
 | 
							} catch (final NumberFormatException nfe) {
 | 
				
			||||||
 | 
								inform("Bad value for " + name + ":" + val);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return result;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Display functions
 | 
				
			||||||
 | 
						// /////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static void inform(String s) {
 | 
				
			||||||
 | 
							log.info(s);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static void exit(String msg) {
 | 
				
			||||||
 | 
							System.err.println("Error:" + msg);
 | 
				
			||||||
 | 
							System.err.println("Aborting operation");
 | 
				
			||||||
 | 
							System.exit(0);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 926 B  | 
| 
						 | 
					@ -0,0 +1,35 @@
 | 
				
			||||||
 | 
					package com.runjva.sourceforge.jsocks.protocol;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,22 @@
 | 
				
			||||||
 | 
					package com.runjva.sourceforge.jsocks.protocol;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.InputStream;
 | 
				
			||||||
 | 
					import java.io.OutputStream;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * SOCKS5 none authentication. Dummy class does almost nothing.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class AuthenticationNone implements Authentication {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public Object[] doSocksAuthentication(final int methodId,
 | 
				
			||||||
 | 
								final java.net.Socket proxySocket) throws java.io.IOException {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (methodId != 0) {
 | 
				
			||||||
 | 
								return null;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							InputStream in = proxySocket.getInputStream();
 | 
				
			||||||
 | 
							OutputStream out = proxySocket.getOutputStream();
 | 
				
			||||||
 | 
							return new Object[] { in, out };
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,492 @@
 | 
				
			||||||
 | 
					package com.runjva.sourceforge.jsocks.protocol;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.net.InetAddress;
 | 
				
			||||||
 | 
					import java.net.UnknownHostException;
 | 
				
			||||||
 | 
					import java.util.Enumeration;
 | 
				
			||||||
 | 
					import java.util.Hashtable;
 | 
				
			||||||
 | 
					import java.util.StringTokenizer;
 | 
				
			||||||
 | 
					import java.util.Vector;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Class InetRange provides the means of defining the range of inetaddresses.
 | 
				
			||||||
 | 
					 * It's used by Proxy class to store and look up addresses of machines, that
 | 
				
			||||||
 | 
					 * should be contacted directly rather then through the proxy.
 | 
				
			||||||
 | 
					 * <P>
 | 
				
			||||||
 | 
					 * InetRange provides several methods to add either standalone addresses, or
 | 
				
			||||||
 | 
					 * ranges (e.g. 100.200.300.0:100.200.300.255, which covers all addresses on on
 | 
				
			||||||
 | 
					 * someones local network). It also provides methods for checking wether given
 | 
				
			||||||
 | 
					 * address is in this range. Any number of ranges and standalone addresses can
 | 
				
			||||||
 | 
					 * be added to the range.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class InetRange implements Cloneable {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Hashtable<String, Object[]> host_names;
 | 
				
			||||||
 | 
						Vector<Object[]> all;
 | 
				
			||||||
 | 
						Vector<String> end_names;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						boolean useSeparateThread = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Creates the empty range.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public InetRange() {
 | 
				
			||||||
 | 
							all = new Vector<Object[]>();
 | 
				
			||||||
 | 
							host_names = new Hashtable<String, Object[]>();
 | 
				
			||||||
 | 
							end_names = new Vector<String>();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Adds another host or range to this range. The String can be one of those:
 | 
				
			||||||
 | 
						 * <UL>
 | 
				
			||||||
 | 
						 * <li>Host name. eg.(Athena.myhost.com or 45.54.56.65)
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * <li>Range in the form .myhost.net.au <BR>
 | 
				
			||||||
 | 
						 * In which case anything that ends with .myhost.net.au will be considered
 | 
				
			||||||
 | 
						 * in the range.
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * <li>Range in the form ddd.ddd.ddd. <BR>
 | 
				
			||||||
 | 
						 * This will be treated as range ddd.ddd.ddd.0 to ddd.ddd.ddd.255. It is not
 | 
				
			||||||
 | 
						 * necessary to specify 3 first bytes you can use just one or two. For
 | 
				
			||||||
 | 
						 * example 130. will cover address between 130.0.0.0 and 13.255.255.255.
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * <li>Range in the form host_from[: \t\n\r\f]host_to. <br>
 | 
				
			||||||
 | 
						 * That is two hostnames or ips separated by either whitespace or colon.
 | 
				
			||||||
 | 
						 * </UL>
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public synchronized boolean add(final String s0) {
 | 
				
			||||||
 | 
							if (s0 == null) {
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							String s = s0.trim();
 | 
				
			||||||
 | 
							if (s.length() == 0) {
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Object[] entry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (s.endsWith(".")) {
 | 
				
			||||||
 | 
								// thing like: 111.222.33.
 | 
				
			||||||
 | 
								// it is being treated as range 111.222.33.000 - 111.222.33.255
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								final int[] addr = ip2intarray(s);
 | 
				
			||||||
 | 
								long from, to;
 | 
				
			||||||
 | 
								from = to = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (addr == null) {
 | 
				
			||||||
 | 
									return false;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								for (int i = 0; i < 4; i++) {
 | 
				
			||||||
 | 
									if (addr[i] >= 0) {
 | 
				
			||||||
 | 
										from += (((long) addr[i]) << 8 * (3 - i));
 | 
				
			||||||
 | 
									} else {
 | 
				
			||||||
 | 
										to = from;
 | 
				
			||||||
 | 
										while (i < 4) {
 | 
				
			||||||
 | 
											to += 255l << 8 * (3 - i++);
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								entry = new Object[] { s, null, new Long(from), new Long(to) };
 | 
				
			||||||
 | 
								all.addElement(entry);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							} else if (s.startsWith(".")) {
 | 
				
			||||||
 | 
								// Thing like: .myhost.com
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								end_names.addElement(s);
 | 
				
			||||||
 | 
								all.addElement(new Object[] { s, null, null, null });
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								final StringTokenizer tokens = new StringTokenizer(s, " \t\r\n\f:");
 | 
				
			||||||
 | 
								if (tokens.countTokens() > 1) {
 | 
				
			||||||
 | 
									entry = new Object[] { s, null, null, null };
 | 
				
			||||||
 | 
									resolve(entry, tokens.nextToken(), tokens.nextToken());
 | 
				
			||||||
 | 
									all.addElement(entry);
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									entry = new Object[] { s, null, null, null };
 | 
				
			||||||
 | 
									all.addElement(entry);
 | 
				
			||||||
 | 
									host_names.put(s, entry);
 | 
				
			||||||
 | 
									resolve(entry);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Adds another ip for this range.
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * @param ip
 | 
				
			||||||
 | 
						 *            IP os the host which should be added to this range.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public synchronized void add(final InetAddress ip) {
 | 
				
			||||||
 | 
							long from, to;
 | 
				
			||||||
 | 
							from = to = ip2long(ip);
 | 
				
			||||||
 | 
							all.addElement(new Object[] { ip.getHostName(), ip, new Long(from),
 | 
				
			||||||
 | 
									new Long(to) });
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Adds another range of ips for this range.Any host with ip address greater
 | 
				
			||||||
 | 
						 * than or equal to the address of from and smaller than or equal to the
 | 
				
			||||||
 | 
						 * address of to will be included in the range.
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * @param from
 | 
				
			||||||
 | 
						 *            IP from where range starts(including).
 | 
				
			||||||
 | 
						 * @param to
 | 
				
			||||||
 | 
						 *            IP where range ends(including).
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public synchronized void add(final InetAddress from, final InetAddress to) {
 | 
				
			||||||
 | 
							all.addElement(new Object[] {
 | 
				
			||||||
 | 
									from.getHostAddress() + ":" + to.getHostAddress(), null,
 | 
				
			||||||
 | 
									new Long(ip2long(from)), new Long(ip2long(to)) });
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Checks wether the givan host is in the range. Attempts to resolve host
 | 
				
			||||||
 | 
						 * name if required.
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * @param host
 | 
				
			||||||
 | 
						 *            Host name to check.
 | 
				
			||||||
 | 
						 * @return true If host is in the range, false otherwise.
 | 
				
			||||||
 | 
						 * @see InetRange#contains(String,boolean)
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public synchronized boolean contains(final String host) {
 | 
				
			||||||
 | 
							return contains(host, true);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Checks wether the given host is in the range.
 | 
				
			||||||
 | 
						 * <P>
 | 
				
			||||||
 | 
						 * Algorithm: <BR>
 | 
				
			||||||
 | 
						 * <ol>
 | 
				
			||||||
 | 
						 * <li>Look up if the hostname is in the range (in the Hashtable).
 | 
				
			||||||
 | 
						 * <li>Check if it ends with one of the speciefied endings.
 | 
				
			||||||
 | 
						 * <li>Check if it is ip(eg.130.220.35.98). If it is check if it is in the
 | 
				
			||||||
 | 
						 * range.
 | 
				
			||||||
 | 
						 * <li>If attemptResolve is true, host is name, rather than ip, and all
 | 
				
			||||||
 | 
						 * previous attempts failed, try to resolve the hostname, and check wether
 | 
				
			||||||
 | 
						 * the ip associated with the host is in the range.It also repeats all
 | 
				
			||||||
 | 
						 * previos steps with the hostname obtained from InetAddress, but the name
 | 
				
			||||||
 | 
						 * is not allways the full name,it is quite likely to be the same. Well it
 | 
				
			||||||
 | 
						 * was on my machine.
 | 
				
			||||||
 | 
						 * </ol>
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * @param host
 | 
				
			||||||
 | 
						 *            Host name to check.
 | 
				
			||||||
 | 
						 * @param attemptResolve
 | 
				
			||||||
 | 
						 *            Wether to lookup ip address which corresponds to the host,if
 | 
				
			||||||
 | 
						 *            required.
 | 
				
			||||||
 | 
						 * @return true If host is in the range, false otherwise.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public synchronized boolean contains(final String host0,
 | 
				
			||||||
 | 
								final boolean attemptResolve) {
 | 
				
			||||||
 | 
							if (all.size() == 0) {
 | 
				
			||||||
 | 
								return false; // Empty range
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							String host = host0.trim();
 | 
				
			||||||
 | 
							if (host.length() == 0) {
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (checkHost(host)) {
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (checkHostEnding(host)) {
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							final long l = host2long(host);
 | 
				
			||||||
 | 
							if (l >= 0) {
 | 
				
			||||||
 | 
								return contains(l);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!attemptResolve) {
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							try {
 | 
				
			||||||
 | 
								final InetAddress ip = InetAddress.getByName(host);
 | 
				
			||||||
 | 
								return contains(ip);
 | 
				
			||||||
 | 
							} catch (final UnknownHostException uhe) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Checks wether the given ip is in the range.
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * @param ip
 | 
				
			||||||
 | 
						 *            Address of the host to check.
 | 
				
			||||||
 | 
						 * @return true If host is in the range, false otherwise.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public synchronized boolean contains(final InetAddress ip) {
 | 
				
			||||||
 | 
							if (checkHostEnding(ip.getHostName())) {
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (checkHost(ip.getHostName())) {
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return contains(ip2long(ip));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Get all entries in the range as strings. <BR>
 | 
				
			||||||
 | 
						 * These strings can be used to delete entries from the range with remove
 | 
				
			||||||
 | 
						 * function.
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * @return Array of entries as strings.
 | 
				
			||||||
 | 
						 * @see InetRange#remove(String)
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public synchronized String[] getAll() {
 | 
				
			||||||
 | 
							final int size = all.size();
 | 
				
			||||||
 | 
							Object entry[];
 | 
				
			||||||
 | 
							final String all_names[] = new String[size];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (int i = 0; i < size; ++i) {
 | 
				
			||||||
 | 
								entry = all.elementAt(i);
 | 
				
			||||||
 | 
								all_names[i] = (String) entry[0];
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return all_names;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Removes an entry from this range.<BR>
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * @param s
 | 
				
			||||||
 | 
						 *            Entry to remove.
 | 
				
			||||||
 | 
						 * @return true if successfull.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public synchronized boolean remove(final String s) {
 | 
				
			||||||
 | 
							final Enumeration<Object[]> enumx = all.elements();
 | 
				
			||||||
 | 
							while (enumx.hasMoreElements()) {
 | 
				
			||||||
 | 
								final Object[] entry = enumx.nextElement();
 | 
				
			||||||
 | 
								if (s.equals(entry[0])) {
 | 
				
			||||||
 | 
									all.removeElement(entry);
 | 
				
			||||||
 | 
									end_names.removeElement(s);
 | 
				
			||||||
 | 
									host_names.remove(s);
 | 
				
			||||||
 | 
									return true;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Get string representaion of this Range. */
 | 
				
			||||||
 | 
						public String toString() {
 | 
				
			||||||
 | 
							final String all[] = getAll();
 | 
				
			||||||
 | 
							if (all.length == 0) {
 | 
				
			||||||
 | 
								return "";
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							String s = all[0];
 | 
				
			||||||
 | 
							for (int i = 1; i < all.length; ++i) {
 | 
				
			||||||
 | 
								s += "; " + all[i];
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return s;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Creates a clone of this Object */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						@SuppressWarnings("unchecked")
 | 
				
			||||||
 | 
						public Object clone() {
 | 
				
			||||||
 | 
							final InetRange new_range = new InetRange();
 | 
				
			||||||
 | 
							new_range.all = (Vector<Object[]>) all.clone();
 | 
				
			||||||
 | 
							new_range.end_names = (Vector<String>) end_names.clone();
 | 
				
			||||||
 | 
							new_range.host_names = (Hashtable<String, Object[]>) host_names.clone();
 | 
				
			||||||
 | 
							return new_range;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Private methods
 | 
				
			||||||
 | 
						// ///////////////
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Same as previous but used internally, to avoid unnecessary convertion of
 | 
				
			||||||
 | 
						 * IPs, when checking subranges
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						private synchronized boolean contains(final long ip) {
 | 
				
			||||||
 | 
							final Enumeration<Object[]> enumx = all.elements();
 | 
				
			||||||
 | 
							while (enumx.hasMoreElements()) {
 | 
				
			||||||
 | 
								final Object[] obj = enumx.nextElement();
 | 
				
			||||||
 | 
								final Long from = obj[2] == null ? null : (Long) obj[2];
 | 
				
			||||||
 | 
								final Long to = obj[3] == null ? null : (Long) obj[3];
 | 
				
			||||||
 | 
								if ((from != null) && (from.longValue() <= ip)
 | 
				
			||||||
 | 
										&& (to.longValue() >= ip)) {
 | 
				
			||||||
 | 
									return true;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private boolean checkHost(final String host) {
 | 
				
			||||||
 | 
							return host_names.containsKey(host);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private boolean checkHostEnding(final String host) {
 | 
				
			||||||
 | 
							final Enumeration<String> enumx = end_names.elements();
 | 
				
			||||||
 | 
							while (enumx.hasMoreElements()) {
 | 
				
			||||||
 | 
								if (host.endsWith(enumx.nextElement())) {
 | 
				
			||||||
 | 
									return true;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private void resolve(final Object[] entry) {
 | 
				
			||||||
 | 
							// First check if it's in the form ddd.ddd.ddd.ddd.
 | 
				
			||||||
 | 
							final long ip = host2long((String) entry[0]);
 | 
				
			||||||
 | 
							if (ip >= 0) {
 | 
				
			||||||
 | 
								entry[2] = entry[3] = new Long(ip);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								final InetRangeResolver res = new InetRangeResolver(entry);
 | 
				
			||||||
 | 
								res.resolve(useSeparateThread);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private void resolve(final Object[] entry, final String from,
 | 
				
			||||||
 | 
								final String to) {
 | 
				
			||||||
 | 
							long f, t;
 | 
				
			||||||
 | 
							if (((f = host2long(from)) >= 0) && ((t = host2long(to)) >= 0)) {
 | 
				
			||||||
 | 
								entry[2] = new Long(f);
 | 
				
			||||||
 | 
								entry[3] = new Long(t);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								final InetRangeResolver res = new InetRangeResolver(entry, from, to);
 | 
				
			||||||
 | 
								res.resolve(useSeparateThread);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Class methods
 | 
				
			||||||
 | 
						// /////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Converts ipv4 to long value(unsigned int)
 | 
				
			||||||
 | 
						// /////////////////////////////////////////
 | 
				
			||||||
 | 
						static long ip2long(final InetAddress ip) {
 | 
				
			||||||
 | 
							long l = 0;
 | 
				
			||||||
 | 
							final byte[] addr = ip.getAddress();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (addr.length == 4) { // IPV4
 | 
				
			||||||
 | 
								for (int i = 0; i < 4; ++i) {
 | 
				
			||||||
 | 
									l += (((long) addr[i] & 0xFF) << 8 * (3 - i));
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else { // IPV6
 | 
				
			||||||
 | 
								return 0; // Have no idea how to deal with those
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return l;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						long host2long(final String host) {
 | 
				
			||||||
 | 
							long ip = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// check if it's ddd.ddd.ddd.ddd
 | 
				
			||||||
 | 
							if (!Character.isDigit(host.charAt(0))) {
 | 
				
			||||||
 | 
								return -1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							final int[] addr = ip2intarray(host);
 | 
				
			||||||
 | 
							if (addr == null) {
 | 
				
			||||||
 | 
								return -1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (int i = 0; i < addr.length; ++i) {
 | 
				
			||||||
 | 
								ip += ((long) (addr[i] >= 0 ? addr[i] : 0)) << 8 * (3 - i);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return ip;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static int[] ip2intarray(final String host) {
 | 
				
			||||||
 | 
							final int[] address = { -1, -1, -1, -1 };
 | 
				
			||||||
 | 
							int i = 0;
 | 
				
			||||||
 | 
							final StringTokenizer tokens = new StringTokenizer(host, ".");
 | 
				
			||||||
 | 
							if (tokens.countTokens() > 4) {
 | 
				
			||||||
 | 
								return null;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							while (tokens.hasMoreTokens()) {
 | 
				
			||||||
 | 
								try {
 | 
				
			||||||
 | 
									address[i++] = Integer.parseInt(tokens.nextToken()) & 0xFF;
 | 
				
			||||||
 | 
								} catch (final NumberFormatException nfe) {
 | 
				
			||||||
 | 
									return null;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return address;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * //* This was the test main function //**********************************
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * public static void main(String args[])throws UnknownHostException{ int i;
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * InetRange ir = new InetRange();
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * for(i=0;i<args.length;++i){ System.out.println("Adding:" + args[i]);
 | 
				
			||||||
 | 
						 * ir.add(args[i]); }
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * String host; java.io.DataInputStream din = new
 | 
				
			||||||
 | 
						 * java.io.DataInputStream(System.in); try{ host = din.readLine();
 | 
				
			||||||
 | 
						 * while(host!=null){ if(ir.contains(host)){
 | 
				
			||||||
 | 
						 * System.out.println("Range contains ip:"+host); }else{
 | 
				
			||||||
 | 
						 * System.out.println(host+" is not in the range"); } host = din.readLine();
 | 
				
			||||||
 | 
						 * } }catch(java.io.IOException io_ex){ io_ex.printStackTrace(); } }
 | 
				
			||||||
 | 
						 * ******************
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class InetRangeResolver implements Runnable {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Object[] entry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						String from;
 | 
				
			||||||
 | 
						String to;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						InetRangeResolver(final Object[] entry) {
 | 
				
			||||||
 | 
							this.entry = entry;
 | 
				
			||||||
 | 
							from = null;
 | 
				
			||||||
 | 
							to = null;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						InetRangeResolver(final Object[] entry, final String from, final String to) {
 | 
				
			||||||
 | 
							this.entry = entry;
 | 
				
			||||||
 | 
							this.from = from;
 | 
				
			||||||
 | 
							this.to = to;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public final void resolve() {
 | 
				
			||||||
 | 
							resolve(true);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public final void resolve(final boolean inSeparateThread) {
 | 
				
			||||||
 | 
							if (inSeparateThread) {
 | 
				
			||||||
 | 
								final Thread t = new Thread(this);
 | 
				
			||||||
 | 
								t.start();
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								run();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public void run() {
 | 
				
			||||||
 | 
							try {
 | 
				
			||||||
 | 
								if (from == null) {
 | 
				
			||||||
 | 
									final InetAddress ip = InetAddress.getByName((String) entry[0]);
 | 
				
			||||||
 | 
									entry[1] = ip;
 | 
				
			||||||
 | 
									final Long l = new Long(InetRange.ip2long(ip));
 | 
				
			||||||
 | 
									entry[2] = l;
 | 
				
			||||||
 | 
									entry[3] = l;
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									final InetAddress f = InetAddress.getByName(from);
 | 
				
			||||||
 | 
									final InetAddress t = InetAddress.getByName(to);
 | 
				
			||||||
 | 
									entry[2] = new Long(InetRange.ip2long(f));
 | 
				
			||||||
 | 
									entry[3] = new Long(InetRange.ip2long(t));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} catch (final UnknownHostException uhe) {
 | 
				
			||||||
 | 
								// System.err.println("Resolve failed for "+from+','+to+','+entry[0]);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,118 @@
 | 
				
			||||||
 | 
					package com.runjva.sourceforge.jsocks.protocol;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,669 @@
 | 
				
			||||||
 | 
					package com.runjva.sourceforge.jsocks.protocol;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.EOFException;
 | 
				
			||||||
 | 
					import java.io.IOException;
 | 
				
			||||||
 | 
					import java.io.InputStream;
 | 
				
			||||||
 | 
					import java.io.InterruptedIOException;
 | 
				
			||||||
 | 
					import java.io.OutputStream;
 | 
				
			||||||
 | 
					import java.io.PushbackInputStream;
 | 
				
			||||||
 | 
					import java.net.ConnectException;
 | 
				
			||||||
 | 
					import java.net.InetAddress;
 | 
				
			||||||
 | 
					import java.net.InetSocketAddress;
 | 
				
			||||||
 | 
					import java.net.NoRouteToHostException;
 | 
				
			||||||
 | 
					import java.net.ServerSocket;
 | 
				
			||||||
 | 
					import java.net.Socket;
 | 
				
			||||||
 | 
					import java.net.SocketAddress;
 | 
				
			||||||
 | 
					import java.nio.channels.SocketChannel;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.slf4j.Logger;
 | 
				
			||||||
 | 
					import org.slf4j.LoggerFactory;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import android.net.VpnService;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.runjva.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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static int iddleTimeout = 180000; // 3 minutes
 | 
				
			||||||
 | 
						static int acceptTimeout = 180000; // 3 minutes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static Logger log = LoggerFactory.getLogger(ProxyServer.class);
 | 
				
			||||||
 | 
						static SocksProxyBase proxy;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static VpnService vpnService;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						// Public Constructors
 | 
				
			||||||
 | 
						// ///////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Creates a proxy server with given Authentication scheme.
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * @param auth
 | 
				
			||||||
 | 
						 *            Authentication scheme to be used.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public ProxyServer(final ServerAuthenticator auth) {
 | 
				
			||||||
 | 
							this.auth = auth;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Other constructors
 | 
				
			||||||
 | 
						// //////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ProxyServer(final ServerAuthenticator auth, final Socket s) {
 | 
				
			||||||
 | 
							this.auth = auth;
 | 
				
			||||||
 | 
							this.sock = s;
 | 
				
			||||||
 | 
							this.mode = START_MODE;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Public methods
 | 
				
			||||||
 | 
						// ///////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * 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(final SocksProxyBase p) {
 | 
				
			||||||
 | 
							proxy = p;
 | 
				
			||||||
 | 
							// FIXME: Side effect.
 | 
				
			||||||
 | 
							UDPRelayServer.proxy = proxy;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static void setVpnService (final VpnService v)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							vpnService = v;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Get proxy.
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * @return Proxy wich is used to handle user requests.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public static SocksProxyBase 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(final 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(final 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(final 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(final int size) {
 | 
				
			||||||
 | 
							UDPRelayServer.setDatagramSize(size);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Start the Proxy server at given port.<br>
 | 
				
			||||||
 | 
						 * This methods blocks.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public void start(final 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(final int port, final int backlog,
 | 
				
			||||||
 | 
								final InetAddress localIP) {
 | 
				
			||||||
 | 
							try {
 | 
				
			||||||
 | 
								ss = new ServerSocket(port, backlog, localIP);
 | 
				
			||||||
 | 
								final String address = ss.getInetAddress().getHostAddress();
 | 
				
			||||||
 | 
								final int localPort = ss.getLocalPort();
 | 
				
			||||||
 | 
								log.info("Starting SOCKS Proxy on: {}:{}", address, localPort);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								while (true) {
 | 
				
			||||||
 | 
									final Socket s = ss.accept();
 | 
				
			||||||
 | 
									final String hostName = s.getInetAddress().getHostName();
 | 
				
			||||||
 | 
									final int port2 = s.getPort();
 | 
				
			||||||
 | 
									log.info("Accepted from:{}:{}", hostName, port2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									final ProxyServer ps = new ProxyServer(auth, s);
 | 
				
			||||||
 | 
									(new Thread(ps)).start();
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} catch (final 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 (final IOException ioe) {
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Runnable interface
 | 
				
			||||||
 | 
						// //////////////////
 | 
				
			||||||
 | 
						public void run() {
 | 
				
			||||||
 | 
							switch (mode) {
 | 
				
			||||||
 | 
							case START_MODE:
 | 
				
			||||||
 | 
								try {
 | 
				
			||||||
 | 
									startSession();
 | 
				
			||||||
 | 
								} catch (final IOException ioe) {
 | 
				
			||||||
 | 
									handleException(ioe);
 | 
				
			||||||
 | 
									// ioe.printStackTrace();
 | 
				
			||||||
 | 
								} finally {
 | 
				
			||||||
 | 
									abort();
 | 
				
			||||||
 | 
									if (auth != null) {
 | 
				
			||||||
 | 
										auth.endSession();
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									log.info("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 (final IOException ioe) {
 | 
				
			||||||
 | 
									// log("Accept exception:"+ioe);
 | 
				
			||||||
 | 
									handleException(ioe);
 | 
				
			||||||
 | 
								} finally {
 | 
				
			||||||
 | 
									abort();
 | 
				
			||||||
 | 
									log.info("Accept thread(remote->client) stopped");
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case PIPE_MODE:
 | 
				
			||||||
 | 
								try {
 | 
				
			||||||
 | 
									pipe(remote_in, out);
 | 
				
			||||||
 | 
								} catch (final IOException ioe) {
 | 
				
			||||||
 | 
								} finally {
 | 
				
			||||||
 | 
									abort();
 | 
				
			||||||
 | 
									log.info("Support thread(remote->client) stopped");
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case ABORT_MODE:
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								log.warn("Unexpected MODE " + mode);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Private methods
 | 
				
			||||||
 | 
						// ///////////////
 | 
				
			||||||
 | 
						private void startSession() throws IOException {
 | 
				
			||||||
 | 
							sock.setSoTimeout(iddleTimeout);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							try {
 | 
				
			||||||
 | 
								auth = auth.startSession(sock);
 | 
				
			||||||
 | 
							} catch (final IOException ioe) {
 | 
				
			||||||
 | 
								log.warn("Auth throwed exception:", ioe);
 | 
				
			||||||
 | 
								auth = null;
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (auth == null) { // Authentication failed
 | 
				
			||||||
 | 
								log.info("Authentication failed");
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							in = auth.getInputStream();
 | 
				
			||||||
 | 
							out = auth.getOutputStream();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							msg = readMsg(in);
 | 
				
			||||||
 | 
							handleRequest(msg);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private void handleRequest(final ProxyMessage msg) throws IOException {
 | 
				
			||||||
 | 
							if (!auth.checkRequest(msg)) {
 | 
				
			||||||
 | 
								throw new SocksException(SocksProxyBase.SOCKS_FAILURE);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (msg.ip == null) {
 | 
				
			||||||
 | 
								if (msg instanceof Socks5Message) {
 | 
				
			||||||
 | 
									msg.ip = InetAddress.getByName(msg.host);
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									throw new SocksException(SocksProxyBase.SOCKS_FAILURE);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							log(msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							switch (msg.command) {
 | 
				
			||||||
 | 
							case SocksProxyBase.SOCKS_CMD_CONNECT:
 | 
				
			||||||
 | 
								onConnect(msg);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case SocksProxyBase.SOCKS_CMD_BIND:
 | 
				
			||||||
 | 
								onBind(msg);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case SocksProxyBase.SOCKS_CMD_UDP_ASSOCIATE:
 | 
				
			||||||
 | 
								onUDP(msg);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								throw new SocksException(SocksProxyBase.SOCKS_CMD_NOT_SUPPORTED);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private void handleException(final 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 = SocksProxyBase.SOCKS_FAILURE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (ioe instanceof SocksException) {
 | 
				
			||||||
 | 
								error_code = ((SocksException) ioe).errCode;
 | 
				
			||||||
 | 
							} else if (ioe instanceof NoRouteToHostException) {
 | 
				
			||||||
 | 
								error_code = SocksProxyBase.SOCKS_HOST_UNREACHABLE;
 | 
				
			||||||
 | 
							} else if (ioe instanceof ConnectException) {
 | 
				
			||||||
 | 
								error_code = SocksProxyBase.SOCKS_CONNECTION_REFUSED;
 | 
				
			||||||
 | 
							} else if (ioe instanceof InterruptedIOException) {
 | 
				
			||||||
 | 
								error_code = SocksProxyBase.SOCKS_TTL_EXPIRE;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if ((error_code > SocksProxyBase.SOCKS_ADDR_NOT_SUPPORTED)
 | 
				
			||||||
 | 
									|| (error_code < 0)) {
 | 
				
			||||||
 | 
								error_code = SocksProxyBase.SOCKS_FAILURE;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							sendErrorMessage(error_code);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private void onConnect(final ProxyMessage msg) throws IOException {
 | 
				
			||||||
 | 
							Socket s;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (proxy == null) {
 | 
				
			||||||
 | 
								//s = new Socket(msg.ip, msg.port);
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								s= SocketChannel.open().socket();
 | 
				
			||||||
 | 
								if ((null != s) && (null != vpnService)) {
 | 
				
			||||||
 | 
								    vpnService.protect(s);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								s.connect(new InetSocketAddress(msg.ip,msg.port));
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								s = new SocksSocket(proxy, msg.ip, msg.port);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (vpnService != null)
 | 
				
			||||||
 | 
								vpnService.protect(s);
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
							log.info("Connected to " + s.getInetAddress() + ":" + s.getPort());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ProxyMessage response = null;
 | 
				
			||||||
 | 
							final InetAddress localAddress = s.getLocalAddress();
 | 
				
			||||||
 | 
							final int localPort = s.getLocalPort();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (msg instanceof Socks5Message) {
 | 
				
			||||||
 | 
								final int cmd = SocksProxyBase.SOCKS_SUCCESS;
 | 
				
			||||||
 | 
								response = new Socks5Message(cmd, localAddress, localPort);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								final int cmd = Socks4Message.REPLY_OK;
 | 
				
			||||||
 | 
								response = new Socks4Message(cmd, localAddress, localPort);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							response.write(out);
 | 
				
			||||||
 | 
							startPipe(s);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private void onBind(final 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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							final InetAddress inetAddress = ss.getInetAddress();
 | 
				
			||||||
 | 
							final int localPort = ss.getLocalPort();
 | 
				
			||||||
 | 
							log.info("Trying accept on {}:{}", inetAddress, localPort);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (msg.version == 5) {
 | 
				
			||||||
 | 
								final int cmd = SocksProxyBase.SOCKS_SUCCESS;
 | 
				
			||||||
 | 
								response = new Socks5Message(cmd, inetAddress, localPort);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								final int cmd = Socks4Message.REPLY_OK;
 | 
				
			||||||
 | 
								response = new Socks4Message(cmd, inetAddress, localPort);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							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 (final EOFException e) {
 | 
				
			||||||
 | 
								log.debug("Connection closed while we were trying to accept", e);
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							} catch (final InterruptedIOException e) {
 | 
				
			||||||
 | 
								log.debug("Interrupted by unsucessful accept thread", e);
 | 
				
			||||||
 | 
								if (mode != PIPE_MODE) {
 | 
				
			||||||
 | 
									return;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} finally {
 | 
				
			||||||
 | 
								// System.out.println("Finnaly!");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (eof < 0) {
 | 
				
			||||||
 | 
								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(final ProxyMessage msg) throws IOException {
 | 
				
			||||||
 | 
							if (msg.ip.getHostAddress().equals("0.0.0.0")) {
 | 
				
			||||||
 | 
								msg.ip = sock.getInetAddress();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							log.info("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(SocksProxyBase.SOCKS_SUCCESS,
 | 
				
			||||||
 | 
									relayServer.relayIP, relayServer.relayPort);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							response.write(out);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							relayServer.start();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Make timeout infinit.
 | 
				
			||||||
 | 
							sock.setSoTimeout(0);
 | 
				
			||||||
 | 
							try {
 | 
				
			||||||
 | 
								while (in.read() >= 0) {
 | 
				
			||||||
 | 
									/* do nothing */;
 | 
				
			||||||
 | 
									// FIXME: Consider a slight delay here?
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} catch (final EOFException eofe) {
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Private methods
 | 
				
			||||||
 | 
						// ////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private void doAccept() throws IOException {
 | 
				
			||||||
 | 
							Socket s = null;
 | 
				
			||||||
 | 
							final 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(SocksProxyBase.SOCKS_FAILURE);
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									if (acceptTimeout != 0) { // If timeout is not infinit
 | 
				
			||||||
 | 
										final long passed = System.currentTimeMillis() - startTime;
 | 
				
			||||||
 | 
										final int newTimeout = acceptTimeout - (int) passed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										if (newTimeout <= 0) {
 | 
				
			||||||
 | 
											throw new InterruptedIOException("newTimeout <= 0");
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							final InetAddress inetAddress = s.getInetAddress();
 | 
				
			||||||
 | 
							final int port = s.getPort();
 | 
				
			||||||
 | 
							log.info("Accepted from {}:{}", s.getInetAddress(), port);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ProxyMessage response;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (msg.version == 5) {
 | 
				
			||||||
 | 
								final int cmd = SocksProxyBase.SOCKS_SUCCESS;
 | 
				
			||||||
 | 
								response = new Socks5Message(cmd, inetAddress, port);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								final int cmd = Socks4Message.REPLY_OK;
 | 
				
			||||||
 | 
								response = new Socks4Message(cmd, inetAddress, port);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							response.write(out);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private ProxyMessage readMsg(final InputStream in) throws IOException {
 | 
				
			||||||
 | 
							PushbackInputStream push_in;
 | 
				
			||||||
 | 
							if (in instanceof PushbackInputStream) {
 | 
				
			||||||
 | 
								push_in = (PushbackInputStream) in;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								push_in = new PushbackInputStream(in);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							final 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(SocksProxyBase.SOCKS_FAILURE);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return msg;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private void startPipe(final 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 (final IOException ioe) {
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private void sendErrorMessage(final 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 (final IOException ioe) {
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private synchronized void abort() {
 | 
				
			||||||
 | 
							if (mode == ABORT_MODE) {
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							mode = ABORT_MODE;
 | 
				
			||||||
 | 
							try {
 | 
				
			||||||
 | 
								log.info("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 (final IOException ioe) {
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static final void log(final ProxyMessage msg) {
 | 
				
			||||||
 | 
							log.debug("Request version: {}, Command: ", msg.version,
 | 
				
			||||||
 | 
									command2String(msg.command));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							final String user = msg.version == 4 ? ", User:" + msg.user : "";
 | 
				
			||||||
 | 
							log.debug("IP:" + msg.ip + ", Port:" + msg.port + user);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private void pipe(final InputStream in, final OutputStream out)
 | 
				
			||||||
 | 
								throws IOException {
 | 
				
			||||||
 | 
							lastReadTime = System.currentTimeMillis();
 | 
				
			||||||
 | 
							final 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 (final InterruptedIOException iioe) {
 | 
				
			||||||
 | 
									if (iddleTimeout == 0) {
 | 
				
			||||||
 | 
										return;// Other thread interrupted us.
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									final long timeSinceRead = System.currentTimeMillis()
 | 
				
			||||||
 | 
											- lastReadTime;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (timeSinceRead >= iddleTimeout - 1000) {
 | 
				
			||||||
 | 
										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;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,167 @@
 | 
				
			||||||
 | 
					package com.runjva.sourceforge.jsocks.protocol;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Socks4Message extends ProxyMessage {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private byte[] msgBytes;
 | 
				
			||||||
 | 
						private int msgLength;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Server failed reply, cmd command for failed request
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public Socks4Message(final 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(final int cmd, final InetAddress ip, final int port) {
 | 
				
			||||||
 | 
							this(0, cmd, ip, port, null);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Client request
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public Socks4Message(final int cmd, final InetAddress ip, final int port,
 | 
				
			||||||
 | 
								final String user) {
 | 
				
			||||||
 | 
							this(SOCKS_VERSION, cmd, ip, port, user);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Most general constructor
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public Socks4Message(final int version, final int cmd,
 | 
				
			||||||
 | 
								final InetAddress ip, final int port, final 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) {
 | 
				
			||||||
 | 
								final 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(final InputStream in, final boolean clientMode)
 | 
				
			||||||
 | 
								throws IOException {
 | 
				
			||||||
 | 
							msgBytes = null;
 | 
				
			||||||
 | 
							read(in, clientMode);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public void read(final InputStream in) throws IOException {
 | 
				
			||||||
 | 
							read(in, true);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public void read(final InputStream in, final boolean clientMode)
 | 
				
			||||||
 | 
								throws IOException {
 | 
				
			||||||
 | 
							final DataInputStream d_in = new DataInputStream(in);
 | 
				
			||||||
 | 
							version = d_in.readUnsignedByte();
 | 
				
			||||||
 | 
							command = d_in.readUnsignedByte();
 | 
				
			||||||
 | 
							if (clientMode && (command != REPLY_OK)) {
 | 
				
			||||||
 | 
								String errMsg;
 | 
				
			||||||
 | 
								// FIXME: Range should be replaced with cases.
 | 
				
			||||||
 | 
								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();
 | 
				
			||||||
 | 
							final byte[] addr = new byte[4];
 | 
				
			||||||
 | 
							d_in.readFully(addr);
 | 
				
			||||||
 | 
							ip = bytes2IP(addr);
 | 
				
			||||||
 | 
							host = ip.getHostName();
 | 
				
			||||||
 | 
							if (!clientMode) {
 | 
				
			||||||
 | 
								int b = in.read();
 | 
				
			||||||
 | 
								// FIXME: Hope there are no idiots with user name bigger than this
 | 
				
			||||||
 | 
								final byte[] userBytes = new byte[256];
 | 
				
			||||||
 | 
								int i = 0;
 | 
				
			||||||
 | 
								for (i = 0; (i < userBytes.length) && (b > 0); ++i) {
 | 
				
			||||||
 | 
									userBytes[i] = (byte) b;
 | 
				
			||||||
 | 
									b = in.read();
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								user = new String(userBytes, 0, i);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public void write(final OutputStream out) throws IOException {
 | 
				
			||||||
 | 
							if (msgBytes == null) {
 | 
				
			||||||
 | 
								final Socks4Message msg;
 | 
				
			||||||
 | 
								msg = new Socks4Message(version, command, ip, port, user);
 | 
				
			||||||
 | 
								msgBytes = msg.msgBytes;
 | 
				
			||||||
 | 
								msgLength = msg.msgLength;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							out.write(msgBytes);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Class methods
 | 
				
			||||||
 | 
						static InetAddress bytes2IP(final byte[] addr) {
 | 
				
			||||||
 | 
							final String s = bytes2IPV4(addr, 0);
 | 
				
			||||||
 | 
							try {
 | 
				
			||||||
 | 
								return InetAddress.getByName(s);
 | 
				
			||||||
 | 
							} catch (final 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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,144 @@
 | 
				
			||||||
 | 
					package com.runjva.sourceforge.jsocks.protocol;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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 SocksProxyBase 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(SocksProxyBase p, String proxyHost, int proxyPort,
 | 
				
			||||||
 | 
								String user) throws UnknownHostException {
 | 
				
			||||||
 | 
							super(p, proxyHost, proxyPort);
 | 
				
			||||||
 | 
							this.user = new String(user);
 | 
				
			||||||
 | 
							version = 4;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Creates the SOCKS4 proxy
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * @param proxyHost
 | 
				
			||||||
 | 
						 *            Address of the proxy server.
 | 
				
			||||||
 | 
						 * @param proxyPort
 | 
				
			||||||
 | 
						 *            Port of the proxy server
 | 
				
			||||||
 | 
						 * @param user
 | 
				
			||||||
 | 
						 *            User name to use for identification purposes.
 | 
				
			||||||
 | 
						 * @throws UnknownHostException
 | 
				
			||||||
 | 
						 *             If proxyHost can't be resolved.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public Socks4Proxy(String proxyHost, int proxyPort, String user)
 | 
				
			||||||
 | 
								throws UnknownHostException {
 | 
				
			||||||
 | 
							this(null, proxyHost, proxyPort, user);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Creates the SOCKS4 proxy
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * @param p
 | 
				
			||||||
 | 
						 *            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(SocksProxyBase 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() {
 | 
				
			||||||
 | 
							final Socks4Proxy newProxy = new Socks4Proxy(proxyIP, proxyPort, user);
 | 
				
			||||||
 | 
							newProxy.directHosts = (InetRange) directHosts.clone();
 | 
				
			||||||
 | 
							newProxy.chainProxy = chainProxy;
 | 
				
			||||||
 | 
							return newProxy;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Public Static(Class) Methods
 | 
				
			||||||
 | 
						// ==============================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Protected Methods
 | 
				
			||||||
 | 
						// =================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						protected SocksProxyBase copy() {
 | 
				
			||||||
 | 
							final Socks4Proxy copy = new Socks4Proxy(proxyIP, proxyPort, user);
 | 
				
			||||||
 | 
							copy.directHosts = this.directHosts;
 | 
				
			||||||
 | 
							copy.chainProxy = chainProxy;
 | 
				
			||||||
 | 
							return copy;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						protected ProxyMessage formMessage(int cmd, InetAddress ip, int port) {
 | 
				
			||||||
 | 
							switch (cmd) {
 | 
				
			||||||
 | 
							case SOCKS_CMD_CONNECT:
 | 
				
			||||||
 | 
								cmd = Socks4Message.REQUEST_CONNECT;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case SOCKS_CMD_BIND:
 | 
				
			||||||
 | 
								cmd = Socks4Message.REQUEST_BIND;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								return null;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return new Socks4Message(cmd, ip, port, user);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						protected ProxyMessage formMessage(int cmd, String host, int port)
 | 
				
			||||||
 | 
								throws UnknownHostException {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return formMessage(cmd, InetAddress.getByName(host), port);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						protected ProxyMessage formMessage(InputStream in) throws SocksException,
 | 
				
			||||||
 | 
								IOException {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return new Socks4Message(in, true);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,485 @@
 | 
				
			||||||
 | 
					package com.runjva.sourceforge.jsocks.protocol;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.ByteArrayInputStream;
 | 
				
			||||||
 | 
					import java.io.IOException;
 | 
				
			||||||
 | 
					import java.io.InterruptedIOException;
 | 
				
			||||||
 | 
					import java.net.DatagramPacket;
 | 
				
			||||||
 | 
					import java.net.DatagramSocket;
 | 
				
			||||||
 | 
					import java.net.InetAddress;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.slf4j.Logger;
 | 
				
			||||||
 | 
					import org.slf4j.LoggerFactory;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private Logger log = LoggerFactory.getLogger(Socks5DatagramSocket.class);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * 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(SocksProxyBase.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(SocksProxyBase.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(SocksProxyBase.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 datagram socket to given address/port
 | 
				
			||||||
 | 
						 * fails. See java.net.DatagramSocket for more details.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public Socks5DatagramSocket(SocksProxyBase p, int port, InetAddress ip)
 | 
				
			||||||
 | 
								throws SocksException, IOException {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							super(port, ip);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (p == null) {
 | 
				
			||||||
 | 
								throw new SocksException(SocksProxyBase.SOCKS_NO_PROXY);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!(p instanceof Socks5Proxy)) {
 | 
				
			||||||
 | 
								final String s = "Datagram Socket needs Proxy version 5";
 | 
				
			||||||
 | 
								throw new SocksException(-1, s);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (p.chainProxy != null) {
 | 
				
			||||||
 | 
								final String s = "Datagram Sockets do not support proxy chaining.";
 | 
				
			||||||
 | 
								throw new SocksException(SocksProxyBase.SOCKS_JUST_ERROR, s);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							proxy = (Socks5Proxy) p.copy();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							final ProxyMessage msg = proxy.udpAssociate(super.getLocalAddress(),
 | 
				
			||||||
 | 
									super.getLocalPort());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							relayIP = msg.ip;
 | 
				
			||||||
 | 
							if (relayIP.getHostAddress().equals("0.0.0.0")) {
 | 
				
			||||||
 | 
								// FIXME: What happens here?
 | 
				
			||||||
 | 
								relayIP = proxy.proxyIP;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							relayPort = msg.port;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							encapsulation = proxy.udp_encapsulation;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							log.debug("Datagram Socket:{}:{}", getLocalAddress(), getLocalPort());
 | 
				
			||||||
 | 
							log.debug("Socks5Datagram: {}:{}", relayIP, relayPort);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Used by UDPRelayServer.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						Socks5DatagramSocket(boolean server_mode, UDPEncapsulation encapsulation,
 | 
				
			||||||
 | 
								InetAddress relayIP, int relayPort) throws IOException {
 | 
				
			||||||
 | 
							super();
 | 
				
			||||||
 | 
							this.server_mode = server_mode;
 | 
				
			||||||
 | 
							this.relayIP = relayIP;
 | 
				
			||||||
 | 
							this.relayPort = relayPort;
 | 
				
			||||||
 | 
							this.encapsulation = encapsulation;
 | 
				
			||||||
 | 
							this.proxy = null;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Sends the Datagram either through the proxy or directly depending on
 | 
				
			||||||
 | 
						 * current proxy settings and destination address. <BR>
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * <B> NOTE: </B> DatagramPacket size should be at least 10 bytes less than
 | 
				
			||||||
 | 
						 * the systems limit.
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * <P>
 | 
				
			||||||
 | 
						 * See documentation on java.net.DatagramSocket for full details on how to
 | 
				
			||||||
 | 
						 * use this method.
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * @param dp
 | 
				
			||||||
 | 
						 *            Datagram to send.
 | 
				
			||||||
 | 
						 * @throws IOException
 | 
				
			||||||
 | 
						 *             If error happens with I/O.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public void send(DatagramPacket dp) throws IOException {
 | 
				
			||||||
 | 
							// If the host should be accessed directly, send it as is.
 | 
				
			||||||
 | 
							if (!server_mode && proxy.isDirect(dp.getAddress())) {
 | 
				
			||||||
 | 
								super.send(dp);
 | 
				
			||||||
 | 
								log.debug("Sending datagram packet directly:");
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							final byte[] head = formHeader(dp.getAddress(), dp.getPort());
 | 
				
			||||||
 | 
							byte[] buf = new byte[head.length + dp.getLength()];
 | 
				
			||||||
 | 
							final byte[] data = dp.getData();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Merge head and data
 | 
				
			||||||
 | 
							System.arraycopy(head, 0, buf, 0, head.length);
 | 
				
			||||||
 | 
							// System.arraycopy(data,dp.getOffset(),buf,head.length,dp.getLength());
 | 
				
			||||||
 | 
							System.arraycopy(data, 0, buf, head.length, dp.getLength());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (encapsulation != null) {
 | 
				
			||||||
 | 
								buf = encapsulation.udpEncapsulate(buf, true);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							super.send(new DatagramPacket(buf, buf.length, relayIP, relayPort));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * This method allows to send datagram packets with address type DOMAINNAME.
 | 
				
			||||||
 | 
						 * SOCKS5 allows to specify host as names rather than ip addresses.Using
 | 
				
			||||||
 | 
						 * this method one can send udp datagrams through the proxy, without having
 | 
				
			||||||
 | 
						 * to know the ip address of the destination host.
 | 
				
			||||||
 | 
						 * <p>
 | 
				
			||||||
 | 
						 * If proxy specified for that socket has an option resolveAddrLocally set
 | 
				
			||||||
 | 
						 * to true host will be resolved, and the datagram will be send with address
 | 
				
			||||||
 | 
						 * type IPV4, if resolve fails, UnknownHostException is thrown.
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * @param dp
 | 
				
			||||||
 | 
						 *            Datagram to send, it should contain valid port and data
 | 
				
			||||||
 | 
						 * @param host
 | 
				
			||||||
 | 
						 *            Host name to which datagram should be send.
 | 
				
			||||||
 | 
						 * @throws IOException
 | 
				
			||||||
 | 
						 *             If error happens with I/O, or the host can't be resolved when
 | 
				
			||||||
 | 
						 *             proxy settings say that hosts should be resolved locally.
 | 
				
			||||||
 | 
						 * @see Socks5Proxy#resolveAddrLocally(boolean)
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public void send(DatagramPacket dp, String host) throws IOException {
 | 
				
			||||||
 | 
							if (proxy.isDirect(host)) {
 | 
				
			||||||
 | 
								dp.setAddress(InetAddress.getByName(host));
 | 
				
			||||||
 | 
								super.send(dp);
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if ((proxy).resolveAddrLocally) {
 | 
				
			||||||
 | 
								dp.setAddress(InetAddress.getByName(host));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							final byte[] head = formHeader(host, dp.getPort());
 | 
				
			||||||
 | 
							byte[] buf = new byte[head.length + dp.getLength()];
 | 
				
			||||||
 | 
							final byte[] data = dp.getData();
 | 
				
			||||||
 | 
							// Merge head and data
 | 
				
			||||||
 | 
							System.arraycopy(head, 0, buf, 0, head.length);
 | 
				
			||||||
 | 
							// System.arraycopy(data,dp.getOffset(),buf,head.length,dp.getLength());
 | 
				
			||||||
 | 
							System.arraycopy(data, 0, buf, head.length, dp.getLength());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (encapsulation != null) {
 | 
				
			||||||
 | 
								buf = encapsulation.udpEncapsulate(buf, true);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							super.send(new DatagramPacket(buf, buf.length, relayIP, relayPort));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Receives udp packet. If packet have arrived from the proxy relay server,
 | 
				
			||||||
 | 
						 * it is processed and address and port of the packet are set to the address
 | 
				
			||||||
 | 
						 * and port of sending host.<BR>
 | 
				
			||||||
 | 
						 * If the packet arrived from anywhere else it is not changed.<br>
 | 
				
			||||||
 | 
						 * <B> NOTE: </B> DatagramPacket size should be at least 10 bytes bigger
 | 
				
			||||||
 | 
						 * than the largest packet you expect (this is for IPV4 addresses). For
 | 
				
			||||||
 | 
						 * hostnames and IPV6 it is even more.
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * @param dp
 | 
				
			||||||
 | 
						 *            Datagram in which all relevent information will be copied.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public void receive(DatagramPacket dp) throws IOException {
 | 
				
			||||||
 | 
							super.receive(dp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (server_mode) {
 | 
				
			||||||
 | 
								// Drop all datagrams not from relayIP/relayPort
 | 
				
			||||||
 | 
								final int init_length = dp.getLength();
 | 
				
			||||||
 | 
								final int initTimeout = getSoTimeout();
 | 
				
			||||||
 | 
								final 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) {
 | 
				
			||||||
 | 
										final long passed = System.currentTimeMillis() - startTime;
 | 
				
			||||||
 | 
										final int newTimeout = initTimeout - (int) passed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										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);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// FIXME: What is this?
 | 
				
			||||||
 | 
							final int offset = 0; // Java 1.1
 | 
				
			||||||
 | 
							// int offset = dp.getOffset(); //Java 1.2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							final ByteArrayInputStream bIn = new ByteArrayInputStream(data, offset,
 | 
				
			||||||
 | 
									dp.getLength());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							final ProxyMessage msg = new Socks5Message(bIn);
 | 
				
			||||||
 | 
							dp.setPort(msg.port);
 | 
				
			||||||
 | 
							dp.setAddress(msg.getInetAddress());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// what wasn't read by the Message is the data
 | 
				
			||||||
 | 
							final 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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									final int eof = proxy.in.read();
 | 
				
			||||||
 | 
									if (eof < 0) {
 | 
				
			||||||
 | 
										return false; // EOF encountered.
 | 
				
			||||||
 | 
									} else {
 | 
				
			||||||
 | 
										log.warn("This really should not happen");
 | 
				
			||||||
 | 
										return true; // This really should not happen
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								} catch (final InterruptedIOException iioe) {
 | 
				
			||||||
 | 
									return true; // read timed out.
 | 
				
			||||||
 | 
								} catch (final IOException ioe) {
 | 
				
			||||||
 | 
									return false;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// PRIVATE METHODS
 | 
				
			||||||
 | 
						// ////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private byte[] formHeader(InetAddress ip, int port) {
 | 
				
			||||||
 | 
							final Socks5Message request = new Socks5Message(0, ip, port);
 | 
				
			||||||
 | 
							request.data[0] = 0;
 | 
				
			||||||
 | 
							return request.data;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private byte[] formHeader(String host, int port) {
 | 
				
			||||||
 | 
							final Socks5Message request = new Socks5Message(0, host, port);
 | 
				
			||||||
 | 
							request.data[0] = 0;
 | 
				
			||||||
 | 
							return request.data;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * ======================================================================
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * //Mainly Test functions //////////////////////
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * private String bytes2String(byte[] b){ String s=""; char[] hex_digit = {
 | 
				
			||||||
 | 
						 * '0','1','2','3','4','5','6','7','8','9', 'A','B','C','D','E','F'};
 | 
				
			||||||
 | 
						 * for(int i=0;i<b.length;++i){ int i1 = (b[i] & 0xF0) >> 4; int i2 = b[i] &
 | 
				
			||||||
 | 
						 * 0xF; s+=hex_digit[i1]; s+=hex_digit[i2]; s+=" "; } return s; } private
 | 
				
			||||||
 | 
						 * static final void debug(String s){ if(DEBUG) System.out.print(s); }
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * private static final boolean DEBUG = true;
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * public static void usage(){ System.err.print(
 | 
				
			||||||
 | 
						 * "Usage: java Socks.SocksDatagramSocket host port [socksHost socksPort]\n"
 | 
				
			||||||
 | 
						 * ); }
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * static final int defaultProxyPort = 1080; //Default Port static final
 | 
				
			||||||
 | 
						 * String defaultProxyHost = "www-proxy"; //Default proxy
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * public static void main(String args[]){ int port; String host; int
 | 
				
			||||||
 | 
						 * proxyPort; String proxyHost; InetAddress ip;
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * if(args.length > 1 && args.length < 5){ try{
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * host = args[0]; port = Integer.parseInt(args[1]);
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * proxyPort =(args.length > 3)? Integer.parseInt(args[3]) :
 | 
				
			||||||
 | 
						 * defaultProxyPort;
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * host = args[0]; ip = InetAddress.getByName(host);
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * proxyHost =(args.length > 2)? args[2] : defaultProxyHost;
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * 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(); } }
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,330 @@
 | 
				
			||||||
 | 
					package com.runjva.sourceforge.jsocks.protocol;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.DataInputStream;
 | 
				
			||||||
 | 
					import java.io.IOException;
 | 
				
			||||||
 | 
					import java.io.InputStream;
 | 
				
			||||||
 | 
					import java.io.OutputStream;
 | 
				
			||||||
 | 
					import java.net.InetAddress;
 | 
				
			||||||
 | 
					import java.net.UnknownHostException;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.slf4j.Logger;
 | 
				
			||||||
 | 
					import org.slf4j.LoggerFactory;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * SOCKS5 request/response message.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Socks5Message extends ProxyMessage {
 | 
				
			||||||
 | 
						/** Address type of given message */
 | 
				
			||||||
 | 
						public int addrType;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						byte[] data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private Logger log = LoggerFactory.getLogger(Socks5Message.class);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * 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);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (ip == null) {
 | 
				
			||||||
 | 
								this.host = "0.0.0.0";
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								this.host = 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();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (addr.length == 4) {
 | 
				
			||||||
 | 
								addrType = SOCKS_ATYP_IPV4;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								addrType = 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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							log.debug("Doing ATYP_DOMAINNAME");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							addrType = SOCKS_ATYP_DOMAINNAME;
 | 
				
			||||||
 | 
							final 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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							final DataInputStream di = new DataInputStream(in);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							version = di.readUnsignedByte();
 | 
				
			||||||
 | 
							command = di.readUnsignedByte();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (clientMode && (command != 0)) {
 | 
				
			||||||
 | 
								throw new SocksException(command);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							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:
 | 
				
			||||||
 | 
								log.debug("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(SocksProxyBase.SOCKS_JUST_ERROR));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							port = di.readUnsignedShort();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if ((addrType != SOCKS_ATYP_DOMAINNAME) && doResolveIP) {
 | 
				
			||||||
 | 
								try {
 | 
				
			||||||
 | 
									ip = InetAddress.getByName(host);
 | 
				
			||||||
 | 
								} catch (final 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 (final UnknownHostException uh_ex) {
 | 
				
			||||||
 | 
											throw new SocksException(
 | 
				
			||||||
 | 
													SocksProxyBase.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() {
 | 
				
			||||||
 | 
							// FIXME: Single line version, please.
 | 
				
			||||||
 | 
							final 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) {
 | 
				
			||||||
 | 
							final 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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,295 @@
 | 
				
			||||||
 | 
					package com.runjva.sourceforge.jsocks.protocol;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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 SocksProxyBase 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 p
 | 
				
			||||||
 | 
						 *            Proxy to use to connect to this proxy, allows proxy chaining.
 | 
				
			||||||
 | 
						 * @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(SocksProxyBase p, String proxyHost, int proxyPort)
 | 
				
			||||||
 | 
								throws UnknownHostException {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							super(p, proxyHost, proxyPort);
 | 
				
			||||||
 | 
							version = 5;
 | 
				
			||||||
 | 
							setAuthenticationMethod(0, new AuthenticationNone());
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Creates SOCKS5 proxy.
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * @param proxyHost
 | 
				
			||||||
 | 
						 *            Host on which a 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 {
 | 
				
			||||||
 | 
							this(null, proxyHost, proxyPort);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Creates SOCKS5 proxy.
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * @param p
 | 
				
			||||||
 | 
						 *            Proxy to use to connect to this proxy, allows proxy chaining.
 | 
				
			||||||
 | 
						 * @param proxyIP
 | 
				
			||||||
 | 
						 *            Host on which a Proxy server runs.
 | 
				
			||||||
 | 
						 * @param proxyPort
 | 
				
			||||||
 | 
						 *            Port on which a Proxy server listens for connections.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public Socks5Proxy(SocksProxyBase p, InetAddress proxyIP, int proxyPort) {
 | 
				
			||||||
 | 
							super(p, proxyIP, 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) {
 | 
				
			||||||
 | 
							this(null, proxyIP, proxyPort);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Public instance methods
 | 
				
			||||||
 | 
						// ========================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Wether to resolve address locally or to let proxy do so.
 | 
				
			||||||
 | 
						 * <p>
 | 
				
			||||||
 | 
						 * SOCKS5 protocol allows to send host names rather then IPs in the
 | 
				
			||||||
 | 
						 * requests, this option controls wether the hostnames should be send to the
 | 
				
			||||||
 | 
						 * proxy server as names, or should they be resolved locally.
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * @param doResolve
 | 
				
			||||||
 | 
						 *            Wether to perform resolution locally.
 | 
				
			||||||
 | 
						 * @return Previous settings.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public boolean resolveAddrLocally(boolean doResolve) {
 | 
				
			||||||
 | 
							final 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) {
 | 
				
			||||||
 | 
							final Object method = authMethods.get(new Integer(methodId));
 | 
				
			||||||
 | 
							if (method == null) {
 | 
				
			||||||
 | 
								return null;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return (Authentication) method;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Creates a clone of this Proxy. clone() returns an
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						@SuppressWarnings("unchecked")
 | 
				
			||||||
 | 
						public Object clone() {
 | 
				
			||||||
 | 
							final Socks5Proxy newProxy = new Socks5Proxy(proxyIP, proxyPort);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							final Object o = this.authMethods.clone();
 | 
				
			||||||
 | 
							newProxy.authMethods = (Hashtable<Integer, Authentication>) o;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							newProxy.directHosts = (InetRange) directHosts.clone();
 | 
				
			||||||
 | 
							newProxy.resolveAddrLocally = resolveAddrLocally;
 | 
				
			||||||
 | 
							newProxy.chainProxy = chainProxy;
 | 
				
			||||||
 | 
							return newProxy;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Public Static(Class) Methods
 | 
				
			||||||
 | 
						// ==============================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Protected Methods
 | 
				
			||||||
 | 
						// =================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						protected SocksProxyBase copy() {
 | 
				
			||||||
 | 
							final Socks5Proxy copy = new Socks5Proxy(proxyIP, proxyPort);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							copy.authMethods = this.authMethods; // same Hash, no copy
 | 
				
			||||||
 | 
							copy.directHosts = this.directHosts;
 | 
				
			||||||
 | 
							copy.chainProxy = this.chainProxy;
 | 
				
			||||||
 | 
							copy.resolveAddrLocally = this.resolveAddrLocally;
 | 
				
			||||||
 | 
							return copy;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
					    *
 | 
				
			||||||
 | 
					    *
 | 
				
			||||||
 | 
					    */
 | 
				
			||||||
 | 
						protected void startSession() throws SocksException {
 | 
				
			||||||
 | 
							super.startSession();
 | 
				
			||||||
 | 
							Authentication auth;
 | 
				
			||||||
 | 
							final Socket ps = proxySocket; // The name is too long
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							try {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								final byte nMethods = (byte) authMethods.size(); // Number of
 | 
				
			||||||
 | 
								// methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								final byte[] buf = new byte[2 + nMethods]; // 2 is for VER,NMETHODS
 | 
				
			||||||
 | 
								buf[0] = (byte) version;
 | 
				
			||||||
 | 
								buf[1] = nMethods; // Number of methods
 | 
				
			||||||
 | 
								int i = 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								final Enumeration<Integer> ids = authMethods.keys();
 | 
				
			||||||
 | 
								while (ids.hasMoreElements()) {
 | 
				
			||||||
 | 
									buf[i++] = (byte) ids.nextElement().intValue();
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								out.write(buf);
 | 
				
			||||||
 | 
								out.flush();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								final int versionNumber = in.read();
 | 
				
			||||||
 | 
								selectedMethod = in.read();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if ((versionNumber < 0) || (selectedMethod < 0)) {
 | 
				
			||||||
 | 
									// EOF condition was reached
 | 
				
			||||||
 | 
									endSession();
 | 
				
			||||||
 | 
									final String s = "Connection to proxy lost.";
 | 
				
			||||||
 | 
									throw new SocksException(SOCKS_PROXY_IO_ERROR, s);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								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
 | 
				
			||||||
 | 
									final String s = "Specified Authentication not found!";
 | 
				
			||||||
 | 
									throw new SocksException(SOCKS_JUST_ERROR, s);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								final Object[] in_out;
 | 
				
			||||||
 | 
								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 (final SocksException s_ex) {
 | 
				
			||||||
 | 
								throw s_ex;
 | 
				
			||||||
 | 
							} catch (final UnknownHostException uh_ex) {
 | 
				
			||||||
 | 
								throw new SocksException(SOCKS_PROXY_NO_CONNECT, uh_ex);
 | 
				
			||||||
 | 
							} catch (final SocketException so_ex) {
 | 
				
			||||||
 | 
								throw new SocksException(SOCKS_PROXY_NO_CONNECT, so_ex);
 | 
				
			||||||
 | 
							} catch (final IOException 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);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,111 @@
 | 
				
			||||||
 | 
					package com.runjva.sourceforge.jsocks.protocol;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Exception thrown by various socks classes to indicate errors with protocol or
 | 
				
			||||||
 | 
					 * unsuccessfull server responses.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class SocksException extends java.io.IOException {
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						private static final long serialVersionUID = 1L;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Construct a SocksException with given errorcode.
 | 
				
			||||||
 | 
						 * <p>
 | 
				
			||||||
 | 
						 * Tries to look up message which corresponds to this error code.
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * @param errCode
 | 
				
			||||||
 | 
						 *            Error code for this exception.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public SocksException(int errCode) {
 | 
				
			||||||
 | 
							this.errCode = errCode;
 | 
				
			||||||
 | 
							lookupErrorString(errCode);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private void lookupErrorString(int errCode) {
 | 
				
			||||||
 | 
							if ((errCode >> 16) == 0) {
 | 
				
			||||||
 | 
								if (errCode <= serverReplyMessage.length) {
 | 
				
			||||||
 | 
									errString = serverReplyMessage[errCode];
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									errString = UNASSIGNED_ERROR_MESSAGE;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								// Local error
 | 
				
			||||||
 | 
								errCode = (errCode >> 16) - 1;
 | 
				
			||||||
 | 
								if (errCode <= localErrorMessage.length) {
 | 
				
			||||||
 | 
									errString = localErrorMessage[errCode];
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									errString = UNASSIGNED_ERROR_MESSAGE;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Construct a SocksException with given error code, and a Throwable cause
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * @param errCode
 | 
				
			||||||
 | 
						 * @param t
 | 
				
			||||||
 | 
						 *            Nested exception for debugging purposes.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public SocksException(int errCode, Throwable t) {
 | 
				
			||||||
 | 
							super(t);  // Java 1.6+
 | 
				
			||||||
 | 
							this.errCode = errCode;
 | 
				
			||||||
 | 
							lookupErrorString(errCode);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * 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;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public SocksException(int errCode, String string, Throwable t) {
 | 
				
			||||||
 | 
							super(string, t);  // Java 1.6+
 | 
				
			||||||
 | 
							this.errCode = errCode;
 | 
				
			||||||
 | 
							this.errString = string;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Get the error code associated with this exception.
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * @return Error code associated with this exception.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public int getErrorCode() {
 | 
				
			||||||
 | 
							return errCode;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Get human readable representation of this exception.
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * @return String represntation of this exception.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public String toString() {
 | 
				
			||||||
 | 
							return errString;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static final String UNASSIGNED_ERROR_MESSAGE = "Unknown error message";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static final String serverReplyMessage[] = { "Succeeded",
 | 
				
			||||||
 | 
								"General SOCKS server failure",
 | 
				
			||||||
 | 
								"Connection not allowed by ruleset", "Network unreachable",
 | 
				
			||||||
 | 
								"Host unreachable", "Connection refused", "TTL expired",
 | 
				
			||||||
 | 
								"Command not supported", "Address type not supported" };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static final String localErrorMessage[] = { "SOCKS server not specified",
 | 
				
			||||||
 | 
								"Unable to contact SOCKS server", "IO error",
 | 
				
			||||||
 | 
								"None of Authentication methods are supported",
 | 
				
			||||||
 | 
								"Authentication failed", "General SOCKS fault" };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						String errString;
 | 
				
			||||||
 | 
						int errCode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}// End of SocksException class
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,543 @@
 | 
				
			||||||
 | 
					package com.runjva.sourceforge.jsocks.protocol;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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 SocksProxyBase {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 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 SocksProxyBase chainProxy = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Protected static/class variables
 | 
				
			||||||
 | 
						protected static SocksProxyBase defaultProxy = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Constructors
 | 
				
			||||||
 | 
						// ====================
 | 
				
			||||||
 | 
						SocksProxyBase(SocksProxyBase chainProxy, String proxyHost, int proxyPort)
 | 
				
			||||||
 | 
								throws UnknownHostException {
 | 
				
			||||||
 | 
							this.chainProxy = chainProxy;
 | 
				
			||||||
 | 
							this.proxyHost = proxyHost;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (chainProxy == null) {
 | 
				
			||||||
 | 
								this.proxyIP = InetAddress.getByName(proxyHost);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							this.proxyPort = proxyPort;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						SocksProxyBase(String proxyHost, int proxyPort) throws UnknownHostException {
 | 
				
			||||||
 | 
							this(null, proxyHost, proxyPort);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						SocksProxyBase(SocksProxyBase chainProxy, InetAddress proxyIP, int proxyPort) {
 | 
				
			||||||
 | 
							this.chainProxy = chainProxy;
 | 
				
			||||||
 | 
							this.proxyIP = proxyIP;
 | 
				
			||||||
 | 
							this.proxyPort = proxyPort;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						SocksProxyBase(InetAddress proxyIP, int proxyPort) {
 | 
				
			||||||
 | 
							this(null, proxyIP, proxyPort);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						SocksProxyBase(SocksProxyBase p) {
 | 
				
			||||||
 | 
							this.proxyIP = p.proxyIP;
 | 
				
			||||||
 | 
							this.proxyPort = p.proxyPort;
 | 
				
			||||||
 | 
							this.version = p.version;
 | 
				
			||||||
 | 
							this.directHosts = p.directHosts;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Public instance methods
 | 
				
			||||||
 | 
						// ========================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Get the port on which proxy server is running.
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * @return Proxy port.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public int getPort() {
 | 
				
			||||||
 | 
							return proxyPort;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Get the ip address of the proxy server host.
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * @return Proxy InetAddress.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public InetAddress getInetAddress() {
 | 
				
			||||||
 | 
							return proxyIP;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Adds given ip to the list of direct addresses. This machine will be
 | 
				
			||||||
 | 
						 * accessed without using proxy.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public void addDirect(InetAddress ip) {
 | 
				
			||||||
 | 
							directHosts.add(ip);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Adds host to the list of direct addresses. This machine will be accessed
 | 
				
			||||||
 | 
						 * without using proxy.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public boolean addDirect(String host) {
 | 
				
			||||||
 | 
							return directHosts.add(host);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Adds given range of addresses to the lsit of direct addresses, machines
 | 
				
			||||||
 | 
						 * within this range will be accessed without using proxy.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public void addDirect(InetAddress from, InetAddress to) {
 | 
				
			||||||
 | 
							directHosts.add(from, to);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Sets given InetRange as the list of direct address, previous list will be
 | 
				
			||||||
 | 
						 * discarded, any changes done previously with addDirect(Inetaddress) will
 | 
				
			||||||
 | 
						 * be lost. The machines in this range will be accessed without using proxy.
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * @param ir
 | 
				
			||||||
 | 
						 *            InetRange which should be used to look up direct addresses.
 | 
				
			||||||
 | 
						 * @see InetRange
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public void setDirect(InetRange ir) {
 | 
				
			||||||
 | 
							directHosts = ir;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Get the list of direct hosts.
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * @return Current range of direct address as InetRange object.
 | 
				
			||||||
 | 
						 * @see InetRange
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public InetRange getDirect() {
 | 
				
			||||||
 | 
							return directHosts;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Check wether the given host is on the list of direct address.
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * @param host
 | 
				
			||||||
 | 
						 *            Host name to check.
 | 
				
			||||||
 | 
						 * @return true if the given host is specified as the direct addresses.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public boolean isDirect(String host) {
 | 
				
			||||||
 | 
							return directHosts.contains(host);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Check wether the given host is on the list of direct addresses.
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * @param host
 | 
				
			||||||
 | 
						 *            Host address to check.
 | 
				
			||||||
 | 
						 * @return true if the given host is specified as the direct address.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public boolean isDirect(InetAddress host) {
 | 
				
			||||||
 | 
							return directHosts.contains(host);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Set the proxy which should be used to connect to given proxy.
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * @param chainProxy
 | 
				
			||||||
 | 
						 *            Proxy to use to connect to this proxy.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public void setChainProxy(SocksProxyBase chainProxy) {
 | 
				
			||||||
 | 
							this.chainProxy = chainProxy;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Get proxy which is used to connect to this proxy.
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * @return Proxy which is used to connect to this proxy, or null if proxy is
 | 
				
			||||||
 | 
						 *         to be contacted directly.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public SocksProxyBase getChainProxy() {
 | 
				
			||||||
 | 
							return chainProxy;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Get string representation of this proxy.
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * @returns string in the form:proxyHost:proxyPort \t Version versionNumber
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public String toString() {
 | 
				
			||||||
 | 
							return ("" + proxyIP.getHostName() + ":" + proxyPort + "\tVersion " + version);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Public Static(Class) Methods
 | 
				
			||||||
 | 
						// ==============================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Sets SOCKS4 proxy as default.
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * @param hostName
 | 
				
			||||||
 | 
						 *            Host name on which SOCKS4 server is running.
 | 
				
			||||||
 | 
						 * @param port
 | 
				
			||||||
 | 
						 *            Port on which SOCKS4 server is running.
 | 
				
			||||||
 | 
						 * @param user
 | 
				
			||||||
 | 
						 *            Username to use for communications with proxy.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public static void setDefaultProxy(String hostName, int port, String user)
 | 
				
			||||||
 | 
								throws UnknownHostException {
 | 
				
			||||||
 | 
							defaultProxy = new Socks4Proxy(hostName, port, user);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Sets SOCKS4 proxy as default.
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * @param ipAddress
 | 
				
			||||||
 | 
						 *            Host address on which SOCKS4 server is running.
 | 
				
			||||||
 | 
						 * @param port
 | 
				
			||||||
 | 
						 *            Port on which SOCKS4 server is running.
 | 
				
			||||||
 | 
						 * @param user
 | 
				
			||||||
 | 
						 *            Username to use for communications with proxy.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public static void setDefaultProxy(InetAddress ipAddress, int port,
 | 
				
			||||||
 | 
								String user) {
 | 
				
			||||||
 | 
							defaultProxy = new Socks4Proxy(ipAddress, port, user);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Sets SOCKS5 proxy as default. Default proxy only supports
 | 
				
			||||||
 | 
						 * no-authentication.
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * @param hostName
 | 
				
			||||||
 | 
						 *            Host name on which SOCKS5 server is running.
 | 
				
			||||||
 | 
						 * @param port
 | 
				
			||||||
 | 
						 *            Port on which SOCKS5 server is running.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public static void setDefaultProxy(String hostName, int port)
 | 
				
			||||||
 | 
								throws UnknownHostException {
 | 
				
			||||||
 | 
							defaultProxy = new Socks5Proxy(hostName, port);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Sets SOCKS5 proxy as default. Default proxy only supports
 | 
				
			||||||
 | 
						 * no-authentication.
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * @param ipAddress
 | 
				
			||||||
 | 
						 *            Host address on which SOCKS5 server is running.
 | 
				
			||||||
 | 
						 * @param port
 | 
				
			||||||
 | 
						 *            Port on which SOCKS5 server is running.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public static void setDefaultProxy(InetAddress ipAddress, int port) {
 | 
				
			||||||
 | 
							defaultProxy = new Socks5Proxy(ipAddress, port);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Sets default proxy.
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * @param p
 | 
				
			||||||
 | 
						 *            Proxy to use as default proxy.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public static void setDefaultProxy(SocksProxyBase p) {
 | 
				
			||||||
 | 
							defaultProxy = p;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Get current default proxy.
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * @return Current default proxy, or null if none is set.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public static SocksProxyBase 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 SocksProxyBase parseProxy(String proxy_entry) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							String proxy_host;
 | 
				
			||||||
 | 
							int proxy_port = 1080;
 | 
				
			||||||
 | 
							String proxy_user = null;
 | 
				
			||||||
 | 
							String proxy_password = null;
 | 
				
			||||||
 | 
							SocksProxyBase proxy;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							final 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 (final 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);
 | 
				
			||||||
 | 
									final UserPasswordAuthentication upa = new UserPasswordAuthentication(
 | 
				
			||||||
 | 
											proxy_user, proxy_password);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									((Socks5Proxy) proxy).setAuthenticationMethod(
 | 
				
			||||||
 | 
											UserPasswordAuthentication.METHOD_ID, upa);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} catch (final UnknownHostException uhe) {
 | 
				
			||||||
 | 
								return null;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return proxy;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Protected Methods
 | 
				
			||||||
 | 
						// =================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						protected void startSession() throws SocksException {
 | 
				
			||||||
 | 
							try {
 | 
				
			||||||
 | 
								if (chainProxy == null) {
 | 
				
			||||||
 | 
									proxySocket = new Socket(proxyIP, proxyPort);
 | 
				
			||||||
 | 
								} else if (proxyIP != null) {
 | 
				
			||||||
 | 
									proxySocket = new SocksSocket(chainProxy, proxyIP, proxyPort);
 | 
				
			||||||
 | 
								} else {
 | 
				
			||||||
 | 
									proxySocket = new SocksSocket(chainProxy, proxyHost, proxyPort);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								in = proxySocket.getInputStream();
 | 
				
			||||||
 | 
								out = proxySocket.getOutputStream();
 | 
				
			||||||
 | 
							} catch (final SocksException se) {
 | 
				
			||||||
 | 
								throw se;
 | 
				
			||||||
 | 
							} catch (final IOException io_ex) {
 | 
				
			||||||
 | 
								throw new SocksException(SOCKS_PROXY_IO_ERROR, "" + io_ex);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Create a copy of this proxy for use by individual threads.
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * @return proxy
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						protected abstract SocksProxyBase 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();
 | 
				
			||||||
 | 
								final ProxyMessage request = formMessage(SOCKS_CMD_CONNECT, ip,
 | 
				
			||||||
 | 
										port);
 | 
				
			||||||
 | 
								return exchange(request);
 | 
				
			||||||
 | 
							} catch (final SocksException se) {
 | 
				
			||||||
 | 
								endSession();
 | 
				
			||||||
 | 
								throw se;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						protected ProxyMessage connect(String host, int port)
 | 
				
			||||||
 | 
								throws UnknownHostException, SocksException {
 | 
				
			||||||
 | 
							try {
 | 
				
			||||||
 | 
								startSession();
 | 
				
			||||||
 | 
								final ProxyMessage request = formMessage(SOCKS_CMD_CONNECT, host,
 | 
				
			||||||
 | 
										port);
 | 
				
			||||||
 | 
								return exchange(request);
 | 
				
			||||||
 | 
							} catch (final SocksException se) {
 | 
				
			||||||
 | 
								endSession();
 | 
				
			||||||
 | 
								throw se;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						protected ProxyMessage bind(InetAddress ip, int port) throws SocksException {
 | 
				
			||||||
 | 
							try {
 | 
				
			||||||
 | 
								startSession();
 | 
				
			||||||
 | 
								final ProxyMessage request = formMessage(SOCKS_CMD_BIND, ip, port);
 | 
				
			||||||
 | 
								return exchange(request);
 | 
				
			||||||
 | 
							} catch (final SocksException se) {
 | 
				
			||||||
 | 
								endSession();
 | 
				
			||||||
 | 
								throw se;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						protected ProxyMessage bind(String host, int port)
 | 
				
			||||||
 | 
								throws UnknownHostException, SocksException {
 | 
				
			||||||
 | 
							try {
 | 
				
			||||||
 | 
								startSession();
 | 
				
			||||||
 | 
								final ProxyMessage request = formMessage(SOCKS_CMD_BIND, host, port);
 | 
				
			||||||
 | 
								return exchange(request);
 | 
				
			||||||
 | 
							} catch (final SocksException se) {
 | 
				
			||||||
 | 
								endSession();
 | 
				
			||||||
 | 
								throw se;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						protected ProxyMessage accept() throws IOException, SocksException {
 | 
				
			||||||
 | 
							ProxyMessage msg;
 | 
				
			||||||
 | 
							try {
 | 
				
			||||||
 | 
								msg = formMessage(in);
 | 
				
			||||||
 | 
							} catch (final InterruptedIOException iioe) {
 | 
				
			||||||
 | 
								throw iioe;
 | 
				
			||||||
 | 
							} catch (final 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();
 | 
				
			||||||
 | 
								final ProxyMessage request = formMessage(SOCKS_CMD_UDP_ASSOCIATE,
 | 
				
			||||||
 | 
										ip, port);
 | 
				
			||||||
 | 
								if (request != null) {
 | 
				
			||||||
 | 
									return exchange(request);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} catch (final 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();
 | 
				
			||||||
 | 
								final ProxyMessage request = formMessage(SOCKS_CMD_UDP_ASSOCIATE,
 | 
				
			||||||
 | 
										host, port);
 | 
				
			||||||
 | 
								if (request != null) {
 | 
				
			||||||
 | 
									return exchange(request);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} catch (final 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 (final 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 (final SocksException s_ex) {
 | 
				
			||||||
 | 
								throw s_ex;
 | 
				
			||||||
 | 
							} catch (final IOException ioe) {
 | 
				
			||||||
 | 
								throw (new SocksException(SOCKS_PROXY_IO_ERROR, "" + ioe));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return reply;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Private methods
 | 
				
			||||||
 | 
						// ===============
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Constants
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static final int SOCKS_SUCCESS = 0;
 | 
				
			||||||
 | 
						public static final int SOCKS_FAILURE = 1;
 | 
				
			||||||
 | 
						public static final int SOCKS_BADCONNECT = 2;
 | 
				
			||||||
 | 
						public static final int SOCKS_BADNETWORK = 3;
 | 
				
			||||||
 | 
						public static final int SOCKS_HOST_UNREACHABLE = 4;
 | 
				
			||||||
 | 
						public static final int SOCKS_CONNECTION_REFUSED = 5;
 | 
				
			||||||
 | 
						public static final int SOCKS_TTL_EXPIRE = 6;
 | 
				
			||||||
 | 
						public static final int SOCKS_CMD_NOT_SUPPORTED = 7;
 | 
				
			||||||
 | 
						public static final int SOCKS_ADDR_NOT_SUPPORTED = 8;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static final int SOCKS_NO_PROXY = 1 << 16;
 | 
				
			||||||
 | 
						public static final int SOCKS_PROXY_NO_CONNECT = 2 << 16;
 | 
				
			||||||
 | 
						public static final int SOCKS_PROXY_IO_ERROR = 3 << 16;
 | 
				
			||||||
 | 
						public static final int SOCKS_AUTH_NOT_SUPPORTED = 4 << 16;
 | 
				
			||||||
 | 
						public static final int SOCKS_AUTH_FAILURE = 5 << 16;
 | 
				
			||||||
 | 
						public static final int SOCKS_JUST_ERROR = 6 << 16;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public static final int SOCKS_DIRECT_FAILED = 7 << 16;
 | 
				
			||||||
 | 
						public static final int SOCKS_METHOD_NOTSUPPORTED = 8 << 16;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static final int SOCKS_CMD_CONNECT = 0x1;
 | 
				
			||||||
 | 
						static final int SOCKS_CMD_BIND = 0x2;
 | 
				
			||||||
 | 
						static final int SOCKS_CMD_UDP_ASSOCIATE = 0x3;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,238 @@
 | 
				
			||||||
 | 
					package com.runjva.sourceforge.jsocks.protocol;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.IOException;
 | 
				
			||||||
 | 
					import java.net.InetAddress;
 | 
				
			||||||
 | 
					import java.net.ServerSocket;
 | 
				
			||||||
 | 
					import java.net.Socket;
 | 
				
			||||||
 | 
					import java.net.SocketException;
 | 
				
			||||||
 | 
					import java.net.UnknownHostException;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * SocksServerSocket allows to accept connections from one particular host
 | 
				
			||||||
 | 
					 * through the SOCKS4 or SOCKS5 proxy.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class SocksServerSocket extends ServerSocket {
 | 
				
			||||||
 | 
						// Data members
 | 
				
			||||||
 | 
						protected SocksProxyBase proxy;
 | 
				
			||||||
 | 
						protected String localHost;
 | 
				
			||||||
 | 
						protected InetAddress localIP;
 | 
				
			||||||
 | 
						protected int localPort;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						boolean doing_direct = false;
 | 
				
			||||||
 | 
						InetAddress remoteAddr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Creates ServerSocket capable of accepting one connection through the
 | 
				
			||||||
 | 
						 * firewall, uses default 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 {
 | 
				
			||||||
 | 
							this(SocksProxyBase.defaultProxy, host, port);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 *Creates ServerSocket capable of accepting one connection through the
 | 
				
			||||||
 | 
						 * firewall, uses given proxy.
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * @param p
 | 
				
			||||||
 | 
						 *            Proxy object to use.
 | 
				
			||||||
 | 
						 *@param host
 | 
				
			||||||
 | 
						 *            Host from which the connection should be recieved.
 | 
				
			||||||
 | 
						 *@param port
 | 
				
			||||||
 | 
						 *            Port number of the primary connection.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public SocksServerSocket(SocksProxyBase p, String host, int port)
 | 
				
			||||||
 | 
								throws SocksException, UnknownHostException, IOException {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							super(0);
 | 
				
			||||||
 | 
							if (p == null) {
 | 
				
			||||||
 | 
								throw new SocksException(SocksProxyBase.SOCKS_NO_PROXY);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							// proxy=p;
 | 
				
			||||||
 | 
							proxy = p.copy();
 | 
				
			||||||
 | 
							if (proxy.isDirect(host)) {
 | 
				
			||||||
 | 
								remoteAddr = InetAddress.getByName(host);
 | 
				
			||||||
 | 
								proxy = null;
 | 
				
			||||||
 | 
								doDirect();
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								processReply(proxy.bind(host, port));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Creates ServerSocket capable of accepting one connection through the
 | 
				
			||||||
 | 
						 * firewall, uses default 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(SocksProxyBase.defaultProxy, ip, port);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 *Creates ServerSocket capable of accepting one connection through the
 | 
				
			||||||
 | 
						 * firewall, uses given proxy.
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * @param p
 | 
				
			||||||
 | 
						 *            Proxy object to use.
 | 
				
			||||||
 | 
						 *@param ip
 | 
				
			||||||
 | 
						 *            Host from which the connection should be recieved.
 | 
				
			||||||
 | 
						 *@param port
 | 
				
			||||||
 | 
						 *            Port number of the primary connection.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public SocksServerSocket(SocksProxyBase p, InetAddress ip, int port)
 | 
				
			||||||
 | 
								throws SocksException, IOException {
 | 
				
			||||||
 | 
							super(0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (p == null) {
 | 
				
			||||||
 | 
								throw new SocksException(SocksProxyBase.SOCKS_NO_PROXY);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							this.proxy = p.copy();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (proxy.isDirect(ip)) {
 | 
				
			||||||
 | 
								remoteAddr = ip;
 | 
				
			||||||
 | 
								doDirect();
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								processReply(proxy.bind(ip, port));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Accepts the incoming connection.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public Socket accept() throws IOException {
 | 
				
			||||||
 | 
							Socket s;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!doing_direct) {
 | 
				
			||||||
 | 
								if (proxy == null) {
 | 
				
			||||||
 | 
									return null;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								final 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);
 | 
				
			||||||
 | 
								if (ProxyServer.vpnService != null)
 | 
				
			||||||
 | 
									ProxyServer.vpnService.protect(proxy.proxySocket);
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
							} 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 (final UnknownHostException e) {
 | 
				
			||||||
 | 
									return null;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return localIP;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Get port assigned by proxy to listen for incoming connections, or the
 | 
				
			||||||
 | 
						 * port chosen by local system, if accepting directly.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public int getLocalPort() {
 | 
				
			||||||
 | 
							return localPort;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Set Timeout.
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * @param timeout
 | 
				
			||||||
 | 
						 *            Amount of time in milliseconds, accept should wait for
 | 
				
			||||||
 | 
						 *            incoming connection before failing with exception. Zero
 | 
				
			||||||
 | 
						 *            timeout implies infinity.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public void setSoTimeout(int timeout) throws SocketException {
 | 
				
			||||||
 | 
							super.setSoTimeout(timeout);
 | 
				
			||||||
 | 
							if (!doing_direct) {
 | 
				
			||||||
 | 
								proxy.proxySocket.setSoTimeout(timeout);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Private Methods
 | 
				
			||||||
 | 
						// ////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private void processReply(ProxyMessage reply) throws SocksException {
 | 
				
			||||||
 | 
							localPort = reply.port;
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * If the server have assigned same host as it was contacted on it might
 | 
				
			||||||
 | 
							 * return an address of all zeros
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							if (reply.host.equals("0.0.0.0")) {
 | 
				
			||||||
 | 
								localIP = proxy.proxyIP;
 | 
				
			||||||
 | 
								localHost = localIP.getHostName();
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								localHost = reply.host;
 | 
				
			||||||
 | 
								localIP = reply.ip;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private void doDirect() {
 | 
				
			||||||
 | 
							doing_direct = true;
 | 
				
			||||||
 | 
							localPort = super.getLocalPort();
 | 
				
			||||||
 | 
							localIP = super.getInetAddress();
 | 
				
			||||||
 | 
							localHost = localIP.getHostName();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,389 @@
 | 
				
			||||||
 | 
					package com.runjva.sourceforge.jsocks.protocol;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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 org.slf4j.Logger;
 | 
				
			||||||
 | 
					import org.slf4j.LoggerFactory;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 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 SocksProxyBase proxy;
 | 
				
			||||||
 | 
						protected String localHost, remoteHost;
 | 
				
			||||||
 | 
						protected InetAddress localIP, remoteIP;
 | 
				
			||||||
 | 
						protected int localPort, remotePort;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private Socket directSock = null;
 | 
				
			||||||
 | 
						private Logger log = LoggerFactory.getLogger(SocksSocket.class);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * 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(SocksProxyBase,String,int)
 | 
				
			||||||
 | 
						 * @see Socks5Proxy#resolveAddrLocally
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public SocksSocket(String host, int port) throws SocksException,
 | 
				
			||||||
 | 
								UnknownHostException {
 | 
				
			||||||
 | 
							this(SocksProxyBase.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(SocksProxyBase p, String host, int port)
 | 
				
			||||||
 | 
								throws SocksException, UnknownHostException {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (p == null) {
 | 
				
			||||||
 | 
								throw new SocksException(SocksProxyBase.SOCKS_NO_PROXY);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							// proxy=p;
 | 
				
			||||||
 | 
							proxy = p.copy();
 | 
				
			||||||
 | 
							remoteHost = host;
 | 
				
			||||||
 | 
							remotePort = port;
 | 
				
			||||||
 | 
							if (proxy.isDirect(host)) {
 | 
				
			||||||
 | 
								remoteIP = InetAddress.getByName(host);
 | 
				
			||||||
 | 
								doDirect();
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								processReply(proxy.connect(host, port));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Tryies to connect to given ip and port using default proxy. If no default
 | 
				
			||||||
 | 
						 * proxy speciefied it throws SocksException with error code SOCKS_NO_PROXY.
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * @param ip
 | 
				
			||||||
 | 
						 *            Machine to connect to.
 | 
				
			||||||
 | 
						 * @param port
 | 
				
			||||||
 | 
						 *            Port to which to connect.
 | 
				
			||||||
 | 
						 * @see SocksSocket#SocksSocket(SocksProxyBase,String,int)
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public SocksSocket(InetAddress ip, int port) throws SocksException {
 | 
				
			||||||
 | 
							this(SocksProxyBase.defaultProxy, ip, port);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * 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(SocksProxyBase p, InetAddress ip, int port)
 | 
				
			||||||
 | 
								throws SocksException {
 | 
				
			||||||
 | 
							if (p == null) {
 | 
				
			||||||
 | 
								throw new SocksException(SocksProxyBase.SOCKS_NO_PROXY);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							this.proxy = p.copy();
 | 
				
			||||||
 | 
							this.remoteIP = ip;
 | 
				
			||||||
 | 
							this.remotePort = port;
 | 
				
			||||||
 | 
							this.remoteHost = ip.getHostName();
 | 
				
			||||||
 | 
							if (proxy.isDirect(remoteIP)) {
 | 
				
			||||||
 | 
								doDirect();
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								processReply(proxy.connect(ip, port));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * These 2 constructors are used by the SocksServerSocket. This socket
 | 
				
			||||||
 | 
						 * simply overrides remoteHost, remotePort
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						protected SocksSocket(String host, int port, SocksProxyBase 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, SocksProxyBase 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 (final 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 (final 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;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							StringBuffer sb = new StringBuffer();
 | 
				
			||||||
 | 
							sb.append("Proxy:");
 | 
				
			||||||
 | 
							sb.append(proxy);
 | 
				
			||||||
 | 
							sb.append(";");
 | 
				
			||||||
 | 
							sb.append("addr:");
 | 
				
			||||||
 | 
							sb.append(remoteHost);
 | 
				
			||||||
 | 
							sb.append(",port:");
 | 
				
			||||||
 | 
							sb.append(remotePort);
 | 
				
			||||||
 | 
							sb.append(",localport:");
 | 
				
			||||||
 | 
							sb.append(localPort);
 | 
				
			||||||
 | 
							return sb.toString();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Private Methods
 | 
				
			||||||
 | 
						// ////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private void processReply(ProxyMessage reply) throws SocksException {
 | 
				
			||||||
 | 
							localPort = reply.port;
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * If the server have assigned same host as it was contacted on it might
 | 
				
			||||||
 | 
							 * return an address of all zeros
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							if (reply.host.equals("0.0.0.0")) {
 | 
				
			||||||
 | 
								localIP = proxy.proxyIP;
 | 
				
			||||||
 | 
								localHost = localIP.getHostName();
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								localHost = reply.host;
 | 
				
			||||||
 | 
								localIP = reply.ip;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private void doDirect() throws SocksException {
 | 
				
			||||||
 | 
							try {
 | 
				
			||||||
 | 
								log.debug("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 (final IOException io_ex) {
 | 
				
			||||||
 | 
								final int errCode = SocksProxyBase.SOCKS_DIRECT_FAILED;
 | 
				
			||||||
 | 
								throw new SocksException(errCode, "Direct connect failed:", io_ex);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,33 @@
 | 
				
			||||||
 | 
					package com.runjva.sourceforge.jsocks.protocol;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,231 @@
 | 
				
			||||||
 | 
					package com.runjva.sourceforge.jsocks.protocol;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.IOException;
 | 
				
			||||||
 | 
					import java.io.InterruptedIOException;
 | 
				
			||||||
 | 
					import java.net.DatagramPacket;
 | 
				
			||||||
 | 
					import java.net.DatagramSocket;
 | 
				
			||||||
 | 
					import java.net.InetAddress;
 | 
				
			||||||
 | 
					import java.net.Socket;
 | 
				
			||||||
 | 
					import java.net.UnknownHostException;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.slf4j.Logger;
 | 
				
			||||||
 | 
					import org.slf4j.LoggerFactory;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.runjva.sourceforge.jsocks.server.ServerAuthenticator;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * 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 Logger log = LoggerFactory.getLogger(UDPRelayServer.class);
 | 
				
			||||||
 | 
						static SocksProxyBase 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.info("Starting UDP relay server on {}:{}", relayIP, relayPort);
 | 
				
			||||||
 | 
							log.info("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 (final IOException ioe) {
 | 
				
			||||||
 | 
							} finally {
 | 
				
			||||||
 | 
								abort();
 | 
				
			||||||
 | 
								log.info("UDP Pipe thread " + Thread.currentThread().getName()
 | 
				
			||||||
 | 
										+ " stopped.");
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Private methods
 | 
				
			||||||
 | 
						// ///////////////
 | 
				
			||||||
 | 
						private synchronized void abort() {
 | 
				
			||||||
 | 
							if (pipe_thread1 == null) {
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							log.info("Aborting UDP Relay Server");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							remote_sock.close();
 | 
				
			||||||
 | 
							client_sock.close();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (controlConnection != null) {
 | 
				
			||||||
 | 
								try {
 | 
				
			||||||
 | 
									controlConnection.close();
 | 
				
			||||||
 | 
								} catch (final IOException ioe) {
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (master_thread != null) {
 | 
				
			||||||
 | 
								master_thread.interrupt();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							pipe_thread1.interrupt();
 | 
				
			||||||
 | 
							pipe_thread2.interrupt();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							pipe_thread1 = null;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private void pipe(DatagramSocket from, DatagramSocket to, boolean out)
 | 
				
			||||||
 | 
								throws IOException {
 | 
				
			||||||
 | 
							final byte[] data = new byte[datagramSize];
 | 
				
			||||||
 | 
							final 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 (final UnknownHostException uhe) {
 | 
				
			||||||
 | 
									log.info("Dropping datagram for unknown host");
 | 
				
			||||||
 | 
								} catch (final 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.
 | 
				
			||||||
 | 
									final long timeSinceRead = System.currentTimeMillis()
 | 
				
			||||||
 | 
											- lastReadTime;
 | 
				
			||||||
 | 
									if (timeSinceRead >= iddleTimeout - 100) {
 | 
				
			||||||
 | 
										return;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								dp.setLength(data.length);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,91 @@
 | 
				
			||||||
 | 
					package com.runjva.sourceforge.jsocks.protocol;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * SOCKS5 User Password authentication scheme.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class UserPasswordAuthentication implements Authentication {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** SOCKS ID for User/Password authentication method */
 | 
				
			||||||
 | 
						public final static int METHOD_ID = 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						String userName, password;
 | 
				
			||||||
 | 
						byte[] request;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Create an instance of UserPasswordAuthentication.
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * @param userName
 | 
				
			||||||
 | 
						 *            User Name to send to SOCKS server.
 | 
				
			||||||
 | 
						 * @param password
 | 
				
			||||||
 | 
						 *            Password to send to SOCKS server.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public UserPasswordAuthentication(String userName, String password) {
 | 
				
			||||||
 | 
							this.userName = userName;
 | 
				
			||||||
 | 
							this.password = password;
 | 
				
			||||||
 | 
							formRequest();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Get the user name.
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * @return User name.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public String getUser() {
 | 
				
			||||||
 | 
							return userName;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Get password
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * @return Password
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public String getPassword() {
 | 
				
			||||||
 | 
							return password;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Does User/Password authentication as defined in rfc1929.
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * @return An array containnig in, out streams, or null if authentication
 | 
				
			||||||
 | 
						 *         fails.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public Object[] doSocksAuthentication(int methodId,
 | 
				
			||||||
 | 
								java.net.Socket proxySocket) throws java.io.IOException {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (methodId != METHOD_ID) {
 | 
				
			||||||
 | 
								return null;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							final java.io.InputStream in = proxySocket.getInputStream();
 | 
				
			||||||
 | 
							final java.io.OutputStream out = proxySocket.getOutputStream();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							out.write(request);
 | 
				
			||||||
 | 
							final int version = in.read();
 | 
				
			||||||
 | 
							if (version < 0) {
 | 
				
			||||||
 | 
								return null; // Server closed connection
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							final int status = in.read();
 | 
				
			||||||
 | 
							if (status != 0) {
 | 
				
			||||||
 | 
								return null; // Server closed connection, or auth failed.
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return new Object[] { in, out };
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Private methods
 | 
				
			||||||
 | 
						// ////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Convert UserName password in to binary form, ready to be send to server */
 | 
				
			||||||
 | 
						private void formRequest() {
 | 
				
			||||||
 | 
							final byte[] user_bytes = userName.getBytes();
 | 
				
			||||||
 | 
							final byte[] password_bytes = password.getBytes();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							request = new byte[3 + user_bytes.length + password_bytes.length];
 | 
				
			||||||
 | 
							request[0] = (byte) 1;
 | 
				
			||||||
 | 
							request[1] = (byte) user_bytes.length;
 | 
				
			||||||
 | 
							System.arraycopy(user_bytes, 0, request, 2, user_bytes.length);
 | 
				
			||||||
 | 
							request[2 + user_bytes.length] = (byte) password_bytes.length;
 | 
				
			||||||
 | 
							System.arraycopy(password_bytes, 0, request, 3 + user_bytes.length,
 | 
				
			||||||
 | 
									password_bytes.length);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,176 @@
 | 
				
			||||||
 | 
					package com.runjva.sourceforge.jsocks.server;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.BufferedReader;
 | 
				
			||||||
 | 
					import java.io.IOException;
 | 
				
			||||||
 | 
					import java.io.InputStreamReader;
 | 
				
			||||||
 | 
					import java.io.InterruptedIOException;
 | 
				
			||||||
 | 
					import java.net.ConnectException;
 | 
				
			||||||
 | 
					import java.net.Socket;
 | 
				
			||||||
 | 
					import java.util.StringTokenizer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.slf4j.Logger;
 | 
				
			||||||
 | 
					import org.slf4j.LoggerFactory;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Class Ident provides means to obtain user name of the owner of the socket on
 | 
				
			||||||
 | 
					 * remote machine, providing remote machine runs identd daemon.
 | 
				
			||||||
 | 
					 * <p>
 | 
				
			||||||
 | 
					 * To use it: <tt><pre>
 | 
				
			||||||
 | 
					   Socket s = ss.accept();
 | 
				
			||||||
 | 
					   Ident id = new Ident(s);
 | 
				
			||||||
 | 
					   if(id.successful) goUseUser(id.userName);
 | 
				
			||||||
 | 
					   else handleIdentError(id.errorCode,id.errorMessage)
 | 
				
			||||||
 | 
					   </pre></tt>
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class Ident {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Logger log = LoggerFactory.getLogger(Ident.class);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Error Message can be null. */
 | 
				
			||||||
 | 
						public String errorMessage;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Host type as returned by daemon, can be null, if error happened */
 | 
				
			||||||
 | 
						public String hostType;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** User name as returned by the identd daemon, or null, if it failed */
 | 
				
			||||||
 | 
						public String userName;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * If this is true then userName and hostType contain valid values. Else
 | 
				
			||||||
 | 
						 * errorCode contain the error code, and errorMessage contains the
 | 
				
			||||||
 | 
						 * corresponding message.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public boolean successful;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Error code */
 | 
				
			||||||
 | 
						public int errorCode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Identd on port 113 can't be contacted */
 | 
				
			||||||
 | 
						public static final int ERR_NO_CONNECT = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Connection timed out */
 | 
				
			||||||
 | 
						public static final int ERR_TIMEOUT = 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Identd daemon responded with ERROR, in this case errorMessage contains
 | 
				
			||||||
 | 
						 * the string explanation, as send by the daemon.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public static final int ERR_PROTOCOL = 3;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * When parsing server response protocol error happened.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public static final int ERR_PROTOCOL_INCORRECT = 4;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Maximum amount of time we should wait before dropping the connection to
 | 
				
			||||||
 | 
						 * identd server.Setting it to 0 implies infinit timeout.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public static final int connectionTimeout = 10000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Constructor tries to connect to Identd daemon on the host of the given
 | 
				
			||||||
 | 
						 * socket, and retrieve user name of the owner of given socket connection on
 | 
				
			||||||
 | 
						 * remote machine. After constructor returns public fields are initialised
 | 
				
			||||||
 | 
						 * to whatever the server returned.
 | 
				
			||||||
 | 
						 * <p>
 | 
				
			||||||
 | 
						 * If user name was successfully retrieved successful is set to true, and
 | 
				
			||||||
 | 
						 * userName and hostType are set to whatever server returned. If however for
 | 
				
			||||||
 | 
						 * some reason user name was not obtained, successful is set to false and
 | 
				
			||||||
 | 
						 * errorCode contains the code explaining the reason of failure, and
 | 
				
			||||||
 | 
						 * errorMessage contains human readable explanation.
 | 
				
			||||||
 | 
						 * <p>
 | 
				
			||||||
 | 
						 * Constructor may block, for a while.
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * @param s
 | 
				
			||||||
 | 
						 *            Socket whose ownership on remote end should be obtained.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public Ident(Socket s) {
 | 
				
			||||||
 | 
							Socket sock = null;
 | 
				
			||||||
 | 
							successful = false; // We are pessimistic
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							try {
 | 
				
			||||||
 | 
								sock = new Socket(s.getInetAddress(), 113);
 | 
				
			||||||
 | 
								sock.setSoTimeout(connectionTimeout);
 | 
				
			||||||
 | 
								final byte[] request = ("" + s.getPort() + " , " + s.getLocalPort() + "\r\n")
 | 
				
			||||||
 | 
										.getBytes();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								sock.getOutputStream().write(request);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								final BufferedReader in = new BufferedReader(new InputStreamReader(
 | 
				
			||||||
 | 
										sock.getInputStream()));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								parseResponse(in.readLine());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							} catch (final InterruptedIOException iioe) {
 | 
				
			||||||
 | 
								errorCode = ERR_TIMEOUT;
 | 
				
			||||||
 | 
								errorMessage = "Connection to identd timed out.";
 | 
				
			||||||
 | 
							} catch (final ConnectException ce) {
 | 
				
			||||||
 | 
								errorCode = ERR_NO_CONNECT;
 | 
				
			||||||
 | 
								errorMessage = "Connection to identd server failed.";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							} catch (final IOException ioe) {
 | 
				
			||||||
 | 
								errorCode = ERR_NO_CONNECT;
 | 
				
			||||||
 | 
								errorMessage = "" + ioe;
 | 
				
			||||||
 | 
							} finally {
 | 
				
			||||||
 | 
								try {
 | 
				
			||||||
 | 
									if (sock != null) {
 | 
				
			||||||
 | 
										sock.close();
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								} catch (final IOException ioe) {
 | 
				
			||||||
 | 
									log.warn("Could not close socket", ioe);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private void parseResponse(String response) {
 | 
				
			||||||
 | 
							if (response == null) {
 | 
				
			||||||
 | 
								errorCode = ERR_PROTOCOL_INCORRECT;
 | 
				
			||||||
 | 
								errorMessage = "Identd server closed connection.";
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							final StringTokenizer st = new StringTokenizer(response, ":");
 | 
				
			||||||
 | 
							if (st.countTokens() < 3) {
 | 
				
			||||||
 | 
								errorCode = ERR_PROTOCOL_INCORRECT;
 | 
				
			||||||
 | 
								errorMessage = "Can't parse server response.";
 | 
				
			||||||
 | 
								return;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							st.nextToken(); // Discard first token, it's basically what we have send
 | 
				
			||||||
 | 
							final String command = st.nextToken().trim().toUpperCase();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (command.equals("USERID") && (st.countTokens() >= 2)) {
 | 
				
			||||||
 | 
								successful = true;
 | 
				
			||||||
 | 
								hostType = st.nextToken().trim();
 | 
				
			||||||
 | 
								userName = st.nextToken("").substring(1);// Get all that is left
 | 
				
			||||||
 | 
							} else if (command.equals("ERROR")) {
 | 
				
			||||||
 | 
								errorCode = ERR_PROTOCOL;
 | 
				
			||||||
 | 
								errorMessage = st.nextToken();
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								errorCode = ERR_PROTOCOL_INCORRECT;
 | 
				
			||||||
 | 
								System.out.println("Opa!");
 | 
				
			||||||
 | 
								errorMessage = "Can't parse server response.";
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// /////////////////////////////////////////////
 | 
				
			||||||
 | 
						// USED for Testing
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * public static void main(String[] args) throws IOException{
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * Socket s = null; s = new Socket("gp101-16", 1391);
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * Ident id = new Ident(s); if(id.successful){
 | 
				
			||||||
 | 
						 * System.out.println("User: "+id.userName);
 | 
				
			||||||
 | 
						 * System.out.println("HostType: "+id.hostType); }else{
 | 
				
			||||||
 | 
						 * System.out.println("ErrorCode: "+id.errorCode);
 | 
				
			||||||
 | 
						 * System.out.println("ErrorMessage: "+id.errorMessage);
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * }
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * if(s!= null) s.close(); } //
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,182 @@
 | 
				
			||||||
 | 
					package com.runjva.sourceforge.jsocks.server;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.IOException;
 | 
				
			||||||
 | 
					import java.io.InputStream;
 | 
				
			||||||
 | 
					import java.io.OutputStream;
 | 
				
			||||||
 | 
					import java.net.InetAddress;
 | 
				
			||||||
 | 
					import java.net.Socket;
 | 
				
			||||||
 | 
					import java.util.Enumeration;
 | 
				
			||||||
 | 
					import java.util.Hashtable;
 | 
				
			||||||
 | 
					import java.util.Vector;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.runjva.sourceforge.jsocks.protocol.InetRange;
 | 
				
			||||||
 | 
					import com.runjva.sourceforge.jsocks.protocol.ProxyMessage;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * An implementation of socks.ServerAuthentication which provides simple
 | 
				
			||||||
 | 
					 * authentication based on the host from which the connection is made and the
 | 
				
			||||||
 | 
					 * name of the user on the remote machine, as reported by identd daemon on the
 | 
				
			||||||
 | 
					 * remote machine.
 | 
				
			||||||
 | 
					 * <p>
 | 
				
			||||||
 | 
					 * It can also be used to provide authentication based only on the contacting
 | 
				
			||||||
 | 
					 * host address.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class IdentAuthenticator extends ServerAuthenticatorBase {
 | 
				
			||||||
 | 
						/** Vector of InetRanges */
 | 
				
			||||||
 | 
						Vector<InetRange> hosts;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Vector of user hashes */
 | 
				
			||||||
 | 
						Vector<Hashtable<?, ?>> users;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						String user;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Constructs empty IdentAuthenticator.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public IdentAuthenticator() {
 | 
				
			||||||
 | 
							hosts = new Vector<InetRange>();
 | 
				
			||||||
 | 
							users = new Vector<Hashtable<?, ?>>();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Used to create instances returned from startSession.
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * @param in
 | 
				
			||||||
 | 
						 *            Input stream.
 | 
				
			||||||
 | 
						 * @param out
 | 
				
			||||||
 | 
						 *            OutputStream.
 | 
				
			||||||
 | 
						 * @param user
 | 
				
			||||||
 | 
						 *            Username associated with this connection,could be null if name
 | 
				
			||||||
 | 
						 *            was not required.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						IdentAuthenticator(InputStream in, OutputStream out, String user) {
 | 
				
			||||||
 | 
							super(in, out);
 | 
				
			||||||
 | 
							this.user = user;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Adds range of addresses from which connection is allowed. Hashtable users
 | 
				
			||||||
 | 
						 * should contain user names as keys and anything as values (value is not
 | 
				
			||||||
 | 
						 * used and will be ignored).
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * @param hostRange
 | 
				
			||||||
 | 
						 *            Range of ip addresses from which connection is allowed.
 | 
				
			||||||
 | 
						 * @param users
 | 
				
			||||||
 | 
						 *            Hashtable of users for whom connection is allowed, or null to
 | 
				
			||||||
 | 
						 *            indicate that anybody is allowed to connect from the hosts
 | 
				
			||||||
 | 
						 *            within given range.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public synchronized void add(InetRange hostRange, Hashtable<?, ?> users) {
 | 
				
			||||||
 | 
							this.hosts.addElement(hostRange);
 | 
				
			||||||
 | 
							this.users.addElement(users);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Grants permission only to those users, who connect from one of the hosts
 | 
				
			||||||
 | 
						 * registered with add(InetRange,Hashtable) and whose names, as reported by
 | 
				
			||||||
 | 
						 * identd daemon, are listed for the host the connection came from.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public ServerAuthenticator startSession(Socket s) throws IOException {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							final int ind = getRangeIndex(s.getInetAddress());
 | 
				
			||||||
 | 
							String user = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// System.out.println("getRangeReturned:"+ind);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (ind < 0) {
 | 
				
			||||||
 | 
								return null; // Host is not on the list.
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							final ServerAuthenticator serverAuthenticator = super.startSession(s);
 | 
				
			||||||
 | 
							final ServerAuthenticatorBase auth = (ServerAuthenticatorBase) serverAuthenticator;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// System.out.println("super.startSession() returned:"+auth);
 | 
				
			||||||
 | 
							if (auth == null) {
 | 
				
			||||||
 | 
								return null;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// do the authentication
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							final Hashtable<?, ?> user_names = users.elementAt(ind);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (user_names != null) { // If need to do authentication
 | 
				
			||||||
 | 
								Ident ident;
 | 
				
			||||||
 | 
								ident = new Ident(s);
 | 
				
			||||||
 | 
								// If can't obtain user name, fail
 | 
				
			||||||
 | 
								if (!ident.successful) {
 | 
				
			||||||
 | 
									return null;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								// If user name is not listed for this address, fail
 | 
				
			||||||
 | 
								if (!user_names.containsKey(ident.userName)) {
 | 
				
			||||||
 | 
									return null;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								user = ident.userName;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return new IdentAuthenticator(auth.in, auth.out, user);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * For SOCKS5 requests allways returns true. For SOCKS4 requests checks
 | 
				
			||||||
 | 
						 * wether the user name supplied in the request corresponds to the name
 | 
				
			||||||
 | 
						 * obtained from the ident daemon.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public boolean checkRequest(ProxyMessage msg, java.net.Socket s) {
 | 
				
			||||||
 | 
							// If it's version 5 request, or if anybody is permitted, return true;
 | 
				
			||||||
 | 
							if ((msg.version == 5) || (user == null)) {
 | 
				
			||||||
 | 
								return true;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (msg.version != 4) {
 | 
				
			||||||
 | 
								return false; // Who knows?
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return user.equals(msg.user);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** Get String representaion of the IdentAuthenticator. */
 | 
				
			||||||
 | 
						public String toString() {
 | 
				
			||||||
 | 
							String s = "";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (int i = 0; i < hosts.size(); ++i) {
 | 
				
			||||||
 | 
								s += "(Range:" + hosts.elementAt(i) + "," + //
 | 
				
			||||||
 | 
										" Users:" + userNames(i) + ") ";
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return s;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Private Methods
 | 
				
			||||||
 | 
						// ////////////////
 | 
				
			||||||
 | 
						private int getRangeIndex(InetAddress ip) {
 | 
				
			||||||
 | 
							int index = 0;
 | 
				
			||||||
 | 
							final Enumeration<InetRange> enumx = hosts.elements();
 | 
				
			||||||
 | 
							while (enumx.hasMoreElements()) {
 | 
				
			||||||
 | 
								final InetRange ir = enumx.nextElement();
 | 
				
			||||||
 | 
								if (ir.contains(ip)) {
 | 
				
			||||||
 | 
									return index;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								index++;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return -1; // Not found
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private String userNames(int i) {
 | 
				
			||||||
 | 
							if (users.elementAt(i) == null) {
 | 
				
			||||||
 | 
								return "Everybody is permitted.";
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							final Enumeration<?> enumx = ((Hashtable<?, ?>) users.elementAt(i))
 | 
				
			||||||
 | 
									.keys();
 | 
				
			||||||
 | 
							if (!enumx.hasMoreElements()) {
 | 
				
			||||||
 | 
								return "";
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							String s = enumx.nextElement().toString();
 | 
				
			||||||
 | 
							while (enumx.hasMoreElements()) {
 | 
				
			||||||
 | 
								s += "; " + enumx.nextElement();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return s;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,126 @@
 | 
				
			||||||
 | 
					package com.runjva.sourceforge.jsocks.server;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.IOException;
 | 
				
			||||||
 | 
					import java.io.InputStream;
 | 
				
			||||||
 | 
					import java.io.OutputStream;
 | 
				
			||||||
 | 
					import java.net.DatagramPacket;
 | 
				
			||||||
 | 
					import java.net.Socket;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.runjva.sourceforge.jsocks.protocol.ProxyMessage;
 | 
				
			||||||
 | 
					import com.runjva.sourceforge.jsocks.protocol.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();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,187 @@
 | 
				
			||||||
 | 
					package com.runjva.sourceforge.jsocks.server;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.IOException;
 | 
				
			||||||
 | 
					import java.io.InputStream;
 | 
				
			||||||
 | 
					import java.io.OutputStream;
 | 
				
			||||||
 | 
					import java.io.PushbackInputStream;
 | 
				
			||||||
 | 
					import java.net.Socket;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.runjva.sourceforge.jsocks.protocol.ProxyMessage;
 | 
				
			||||||
 | 
					import com.runjva.sourceforge.jsocks.protocol.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 abstract class ServerAuthenticatorBase implements ServerAuthenticator {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static final byte[] socks5response = { 5, 0 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						InputStream in;
 | 
				
			||||||
 | 
						OutputStream out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Creates new instance of the ServerAuthenticatorNone.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public ServerAuthenticatorBase() {
 | 
				
			||||||
 | 
							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 ServerAuthenticatorBase(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 {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							final PushbackInputStream in = new PushbackInputStream(s
 | 
				
			||||||
 | 
									.getInputStream());
 | 
				
			||||||
 | 
							final OutputStream out = s.getOutputStream();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							final int version = in.read();
 | 
				
			||||||
 | 
							if (version == 5) {
 | 
				
			||||||
 | 
								if (!selectSocks5Authentication(in, out, 0)) {
 | 
				
			||||||
 | 
									return null;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							} else if (version == 4) {
 | 
				
			||||||
 | 
								// Else it is the request message already, 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 {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							final int num_methods = in.read();
 | 
				
			||||||
 | 
							if (num_methods <= 0) {
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							final byte method_ids[] = new byte[num_methods];
 | 
				
			||||||
 | 
							final 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;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,16 @@
 | 
				
			||||||
 | 
					package com.runjva.sourceforge.jsocks.server;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.InputStream;
 | 
				
			||||||
 | 
					import java.io.OutputStream;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Simplest possible ServerAuthenticator implementation. Extends common base.
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class ServerAuthenticatorNone extends ServerAuthenticatorBase {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public ServerAuthenticatorNone(InputStream in, OutputStream out) {
 | 
				
			||||||
 | 
							super(in, out);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,82 @@
 | 
				
			||||||
 | 
					package com.runjva.sourceforge.jsocks.server;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.IOException;
 | 
				
			||||||
 | 
					import java.io.InputStream;
 | 
				
			||||||
 | 
					import java.io.OutputStream;
 | 
				
			||||||
 | 
					import java.net.Socket;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * This class implements SOCKS5 User/Password authentication scheme as defined
 | 
				
			||||||
 | 
					 * in rfc1929,the server side of it. (see docs/rfc1929.txt)
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class UserPasswordAuthenticator extends ServerAuthenticatorBase {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static final int METHOD_ID = 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						UserValidation validator;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Construct a new UserPasswordAuthentication object, with given
 | 
				
			||||||
 | 
						 * UserVlaidation scheme.
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * @param v
 | 
				
			||||||
 | 
						 *            UserValidation to use for validating users.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						public UserPasswordAuthenticator(UserValidation validator) {
 | 
				
			||||||
 | 
							this.validator = validator;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public ServerAuthenticator startSession(Socket s) throws IOException {
 | 
				
			||||||
 | 
							final InputStream in = s.getInputStream();
 | 
				
			||||||
 | 
							final OutputStream out = s.getOutputStream();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (in.read() != 5) {
 | 
				
			||||||
 | 
								return null; // Drop non version 5 messages.
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!selectSocks5Authentication(in, out, METHOD_ID)) {
 | 
				
			||||||
 | 
								return null;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (!doUserPasswordAuthentication(s, in, out)) {
 | 
				
			||||||
 | 
								return null;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return new ServerAuthenticatorNone(in, out);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Private Methods
 | 
				
			||||||
 | 
						// ////////////////
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private boolean doUserPasswordAuthentication(Socket s, InputStream in,
 | 
				
			||||||
 | 
								OutputStream out) throws IOException {
 | 
				
			||||||
 | 
							final int version = in.read();
 | 
				
			||||||
 | 
							if (version != 1) {
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							final int ulen = in.read();
 | 
				
			||||||
 | 
							if (ulen < 0) {
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							final byte[] user = new byte[ulen];
 | 
				
			||||||
 | 
							in.read(user);
 | 
				
			||||||
 | 
							final int plen = in.read();
 | 
				
			||||||
 | 
							if (plen < 0) {
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							final byte[] password = new byte[plen];
 | 
				
			||||||
 | 
							in.read(password);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (validator.isUserValid(new String(user), new String(password), s)) {
 | 
				
			||||||
 | 
								// System.out.println("user valid");
 | 
				
			||||||
 | 
								out.write(new byte[] { 1, 0 });
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								// System.out.println("user invalid");
 | 
				
			||||||
 | 
								out.write(new byte[] { 1, 1 });
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return true;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,24 @@
 | 
				
			||||||
 | 
					package com.runjva.sourceforge.jsocks.server;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Interface which provides for user validation, based on user name password and
 | 
				
			||||||
 | 
					 * where it connects from.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public interface UserValidation {
 | 
				
			||||||
 | 
						/**
 | 
				
			||||||
 | 
						 * Implementations of this interface are expected to use some or all of the
 | 
				
			||||||
 | 
						 * information provided plus any information they can extract from other
 | 
				
			||||||
 | 
						 * sources to decide wether given user should be allowed access to SOCKS
 | 
				
			||||||
 | 
						 * server, or whatever you use it for.
 | 
				
			||||||
 | 
						 * 
 | 
				
			||||||
 | 
						 * @return true to indicate user is valid, false otherwise.
 | 
				
			||||||
 | 
						 * @param username
 | 
				
			||||||
 | 
						 *            User whom implementation should validate.
 | 
				
			||||||
 | 
						 * @param password
 | 
				
			||||||
 | 
						 *            Password this user provided.
 | 
				
			||||||
 | 
						 * @param connection
 | 
				
			||||||
 | 
						 *            Socket which user used to connect to the server.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						boolean isUserValid(String username, String password,
 | 
				
			||||||
 | 
								java.net.Socket connection);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -13,9 +13,11 @@ import org.torproject.android.service.TorService;
 | 
				
			||||||
import org.torproject.android.service.TorServiceConstants;
 | 
					import org.torproject.android.service.TorServiceConstants;
 | 
				
			||||||
import org.torproject.android.service.TorServiceUtils;
 | 
					import org.torproject.android.service.TorServiceUtils;
 | 
				
			||||||
import org.torproject.android.settings.SettingsPreferences;
 | 
					import org.torproject.android.settings.SettingsPreferences;
 | 
				
			||||||
 | 
					import org.torproject.android.vpn.OrbotVpnService;
 | 
				
			||||||
import org.torproject.android.wizard.ChooseLocaleWizardActivity;
 | 
					import org.torproject.android.wizard.ChooseLocaleWizardActivity;
 | 
				
			||||||
import org.torproject.android.wizard.TipsAndTricks;
 | 
					import org.torproject.android.wizard.TipsAndTricks;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import android.annotation.TargetApi;
 | 
				
			||||||
import android.app.AlertDialog;
 | 
					import android.app.AlertDialog;
 | 
				
			||||||
import android.app.ProgressDialog;
 | 
					import android.app.ProgressDialog;
 | 
				
			||||||
import android.content.ComponentName;
 | 
					import android.content.ComponentName;
 | 
				
			||||||
| 
						 | 
					@ -32,6 +34,8 @@ import android.content.pm.PackageManager;
 | 
				
			||||||
import android.content.pm.PackageManager.NameNotFoundException;
 | 
					import android.content.pm.PackageManager.NameNotFoundException;
 | 
				
			||||||
import android.content.res.Configuration;
 | 
					import android.content.res.Configuration;
 | 
				
			||||||
import android.net.Uri;
 | 
					import android.net.Uri;
 | 
				
			||||||
 | 
					import android.net.VpnService;
 | 
				
			||||||
 | 
					import android.os.Build;
 | 
				
			||||||
import android.os.Bundle;
 | 
					import android.os.Bundle;
 | 
				
			||||||
import android.os.Handler;
 | 
					import android.os.Handler;
 | 
				
			||||||
import android.os.IBinder;
 | 
					import android.os.IBinder;
 | 
				
			||||||
| 
						 | 
					@ -412,6 +416,10 @@ public class Orbot extends ActionBarActivity implements TorConstants, OnLongClic
 | 
				
			||||||
                        
 | 
					                        
 | 
				
			||||||
                        
 | 
					                        
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					                else if (item.getItemId() == R.id.menu_vpn)
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                	this.startVpnService();
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
                
 | 
					                
 | 
				
			||||||
        return true;
 | 
					        return true;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					@ -782,9 +790,18 @@ public class Orbot extends ActionBarActivity implements TorConstants, OnLongClic
 | 
				
			||||||
            startActivityForResult(new Intent(this, SettingsPreferences.class), 1);
 | 
					            startActivityForResult(new Intent(this, SettingsPreferences.class), 1);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
 | 
					    private final static int REQUEST_VPN = 8888;
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    
 | 
					    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
 | 
				
			||||||
    
 | 
						public void startVpnService () {
 | 
				
			||||||
 | 
					        Intent intent = VpnService.prepare(this);
 | 
				
			||||||
 | 
					        if (intent != null) {
 | 
				
			||||||
 | 
					            startActivityForResult(intent, REQUEST_VPN);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            onActivityResult(REQUEST_VPN, RESULT_OK, null);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
	protected void onActivityResult(int request, int response, Intent data) {
 | 
						protected void onActivityResult(int request, int response, Intent data) {
 | 
				
			||||||
| 
						 | 
					@ -827,6 +844,11 @@ public class Orbot extends ActionBarActivity implements TorConstants, OnLongClic
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							else if (request == REQUEST_VPN && response == RESULT_OK)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								Intent intent = new Intent(this, OrbotVpnService.class);
 | 
				
			||||||
 | 
					            startService(intent);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1207,7 +1229,6 @@ public class Orbot extends ActionBarActivity implements TorConstants, OnLongClic
 | 
				
			||||||
     
 | 
					     
 | 
				
			||||||
    private final ServiceConnection mConnection = new ServiceConnection() {
 | 
					    private final ServiceConnection mConnection = new ServiceConnection() {
 | 
				
			||||||
    	
 | 
					    	
 | 
				
			||||||
    	
 | 
					 | 
				
			||||||
        public void onServiceConnected(ComponentName className,
 | 
					        public void onServiceConnected(ComponentName className,
 | 
				
			||||||
                IBinder service) {
 | 
					                IBinder service) {
 | 
				
			||||||
        	
 | 
					        	
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,239 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2011 The Android Open Source Project
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
 | 
					 * you may not use this file except in compliance with the License.
 | 
				
			||||||
 | 
					 * You may obtain a copy of the License at
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *      http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Unless required by applicable law or agreed to in writing, software
 | 
				
			||||||
 | 
					 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
				
			||||||
 | 
					 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
				
			||||||
 | 
					 * See the License for the specific language governing permissions and
 | 
				
			||||||
 | 
					 * limitations under the License.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package org.torproject.android.vpn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.net.DatagramSocket;
 | 
				
			||||||
 | 
					import java.net.InetAddress;
 | 
				
			||||||
 | 
					import java.net.InetSocketAddress;
 | 
				
			||||||
 | 
					import java.net.UnknownHostException;
 | 
				
			||||||
 | 
					import java.nio.ByteBuffer;
 | 
				
			||||||
 | 
					import java.nio.channels.DatagramChannel;
 | 
				
			||||||
 | 
					import java.util.Locale;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.torproject.android.service.TorServiceConstants;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import android.annotation.TargetApi;
 | 
				
			||||||
 | 
					import android.app.PendingIntent;
 | 
				
			||||||
 | 
					import android.content.Intent;
 | 
				
			||||||
 | 
					import android.net.VpnService;
 | 
				
			||||||
 | 
					import android.os.Build;
 | 
				
			||||||
 | 
					import android.os.Handler;
 | 
				
			||||||
 | 
					import android.os.Message;
 | 
				
			||||||
 | 
					import android.os.ParcelFileDescriptor;
 | 
				
			||||||
 | 
					import android.util.Log;
 | 
				
			||||||
 | 
					import android.widget.Toast;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.runjva.sourceforge.jsocks.protocol.ProxyServer;
 | 
				
			||||||
 | 
					import com.runjva.sourceforge.jsocks.server.ServerAuthenticatorNone;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
 | 
				
			||||||
 | 
					public class OrbotVpnService extends VpnService implements Handler.Callback {
 | 
				
			||||||
 | 
					    private static final String TAG = "OrbotVpnService";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private PendingIntent mConfigureIntent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private Handler mHandler;
 | 
				
			||||||
 | 
					    private Thread mThread;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private String mSessionName = "OrbotVPN";
 | 
				
			||||||
 | 
					    private ParcelFileDescriptor mInterface;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private int mSocksProxyPort = 9999;
 | 
				
			||||||
 | 
					    private ProxyServer mProxyServer;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    private boolean mKeepRunning = true;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public int onStartCommand(Intent intent, int flags, int startId) {
 | 
				
			||||||
 | 
					        // The handler is only used to show messages.
 | 
				
			||||||
 | 
					        if (mHandler == null) {
 | 
				
			||||||
 | 
					            mHandler = new Handler(this);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Stop the previous session by interrupting the thread.
 | 
				
			||||||
 | 
					        if (mThread != null) {
 | 
				
			||||||
 | 
					            mThread.interrupt();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					     
 | 
				
			||||||
 | 
					        startSocksBypass ();
 | 
				
			||||||
 | 
					        setupTun2Socks();
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        return START_STICKY;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    private void startSocksBypass ()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
						    Thread thread = new Thread ()
 | 
				
			||||||
 | 
						    {
 | 
				
			||||||
 | 
						    	public void run ()
 | 
				
			||||||
 | 
						    	{
 | 
				
			||||||
 | 
						    
 | 
				
			||||||
 | 
							        try {
 | 
				
			||||||
 | 
							        	mProxyServer = new ProxyServer(new ServerAuthenticatorNone(null, null));
 | 
				
			||||||
 | 
							        	mProxyServer.setVpnService(OrbotVpnService.this);
 | 
				
			||||||
 | 
							        	mProxyServer.start(mSocksProxyPort, 5, InetAddress.getLocalHost());
 | 
				
			||||||
 | 
									} catch (Exception e) {
 | 
				
			||||||
 | 
										e.printStackTrace();
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
						    	}
 | 
				
			||||||
 | 
						    };
 | 
				
			||||||
 | 
						    
 | 
				
			||||||
 | 
						    thread.start();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void onDestroy() {
 | 
				
			||||||
 | 
					        if (mThread != null) {
 | 
				
			||||||
 | 
					        	mKeepRunning = false;
 | 
				
			||||||
 | 
					            mThread.interrupt();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        if (mProxyServer != null)
 | 
				
			||||||
 | 
					        	mProxyServer.stop();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public boolean handleMessage(Message message) {
 | 
				
			||||||
 | 
					        if (message != null) {
 | 
				
			||||||
 | 
					            Toast.makeText(this, message.what, Toast.LENGTH_SHORT).show();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					    private void setupTun2Socks()  {
 | 
				
			||||||
 | 
					       
 | 
				
			||||||
 | 
					    	if (mInterface == null)
 | 
				
			||||||
 | 
					    	{
 | 
				
			||||||
 | 
					    		// Set the locale to English (or probably any other language that^M
 | 
				
			||||||
 | 
					            // uses Hindu-Arabic (aka Latin) numerals).^M
 | 
				
			||||||
 | 
					            // We have found that VpnService.Builder does something locale-dependent^M
 | 
				
			||||||
 | 
					            // internally that causes errors when the locale uses its own numerals^M
 | 
				
			||||||
 | 
					            // (i.e., Farsi and Arabic).^M
 | 
				
			||||||
 | 
					    		Locale.setDefault(new Locale("en"));
 | 
				
			||||||
 | 
					    		
 | 
				
			||||||
 | 
						        Builder builder = new Builder();
 | 
				
			||||||
 | 
						        
 | 
				
			||||||
 | 
						        builder.setMtu(3000);
 | 
				
			||||||
 | 
						        builder.addAddress("10.0.0.1",8);
 | 
				
			||||||
 | 
						        builder.setSession("OrbotVPN");	        	
 | 
				
			||||||
 | 
						        builder.addRoute("0.0.0.0",0);	        
 | 
				
			||||||
 | 
						        builder.addRoute("10.0.0.0",8);
 | 
				
			||||||
 | 
						        //builder.addDnsServer("10.0.0.2");
 | 
				
			||||||
 | 
						        builder.addDnsServer("127.0.0.1");
 | 
				
			||||||
 | 
						        // Close the old interface since the parameters have been changed.
 | 
				
			||||||
 | 
						        try {
 | 
				
			||||||
 | 
						            mInterface.close();
 | 
				
			||||||
 | 
						        } catch (Exception e) {  
 | 
				
			||||||
 | 
						            // ignore
 | 
				
			||||||
 | 
						        }
 | 
				
			||||||
 | 
						        
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						        // Create a new interface using the builder and save the parameters.
 | 
				
			||||||
 | 
						        mInterface = builder.setSession(mSessionName)
 | 
				
			||||||
 | 
						                .setConfigureIntent(mConfigureIntent)
 | 
				
			||||||
 | 
						                .establish();
 | 
				
			||||||
 | 
						        	    
 | 
				
			||||||
 | 
						        Tun2Socks.Start(mInterface, 3000, "10.0.0.2", "255.255.255.0", "localhost:" + TorServiceConstants.PORT_SOCKS_DEFAULT, null, true);
 | 
				
			||||||
 | 
					    	}
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    private void debugPacket(ByteBuffer packet)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    	int buffer = packet.get();
 | 
				
			||||||
 | 
					        int version;
 | 
				
			||||||
 | 
					        int headerlength;
 | 
				
			||||||
 | 
					        version = buffer >> 4;
 | 
				
			||||||
 | 
					        headerlength = buffer & 0x0F;
 | 
				
			||||||
 | 
					        headerlength *= 4;
 | 
				
			||||||
 | 
					        Log.d(TAG, "IP Version:"+version);
 | 
				
			||||||
 | 
					        Log.d(TAG, "Header Length:"+headerlength);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        String status = "";
 | 
				
			||||||
 | 
					        status += "Header Length:"+headerlength;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        buffer = packet.get();      //DSCP + EN
 | 
				
			||||||
 | 
					        buffer = packet.getChar();  //Total Length
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Log.d(TAG, "Total Length:"+buffer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        buffer = packet.getChar();  //Identification
 | 
				
			||||||
 | 
					        Log.d(TAG, "Identification:"+buffer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        buffer = packet.getChar();  //Flags + Fragment Offset
 | 
				
			||||||
 | 
					        buffer = packet.get();      //Time to Live
 | 
				
			||||||
 | 
					        buffer = packet.get();      //Protocol
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Log.d(TAG, "Protocol:"+buffer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        status += "  Protocol:"+buffer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        buffer = packet.getChar();  //Header checksum
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        String sourceIP  = "";
 | 
				
			||||||
 | 
					        buffer = packet.get();  //Source IP 1st Octet
 | 
				
			||||||
 | 
					        sourceIP += buffer;
 | 
				
			||||||
 | 
					        sourceIP += ".";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        buffer = packet.get();  //Source IP 2nd Octet
 | 
				
			||||||
 | 
					        sourceIP += buffer;
 | 
				
			||||||
 | 
					        sourceIP += ".";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        buffer = packet.get();  //Source IP 3rd Octet
 | 
				
			||||||
 | 
					        sourceIP += buffer;
 | 
				
			||||||
 | 
					        sourceIP += ".";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        buffer = packet.get();  //Source IP 4th Octet
 | 
				
			||||||
 | 
					        sourceIP += buffer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Log.d(TAG, "Source IP:"+sourceIP);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        status += "   Source IP:"+sourceIP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        String destIP  = "";
 | 
				
			||||||
 | 
					        buffer = packet.get();  //Destination IP 1st Octet
 | 
				
			||||||
 | 
					        destIP += buffer;
 | 
				
			||||||
 | 
					        destIP += ".";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        buffer = packet.get();  //Destination IP 2nd Octet
 | 
				
			||||||
 | 
					        destIP += buffer;
 | 
				
			||||||
 | 
					        destIP += ".";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        buffer = packet.get();  //Destination IP 3rd Octet
 | 
				
			||||||
 | 
					        destIP += buffer;
 | 
				
			||||||
 | 
					        destIP += ".";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        buffer = packet.get();  //Destination IP 4th Octet
 | 
				
			||||||
 | 
					        destIP += buffer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Log.d(TAG, "Destination IP:"+destIP);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        status += "   Destination IP:"+destIP;
 | 
				
			||||||
 | 
					        /*
 | 
				
			||||||
 | 
					        msgObj = mHandler.obtainMessage();
 | 
				
			||||||
 | 
					        msgObj.obj = status;
 | 
				
			||||||
 | 
					        mHandler.sendMessage(msgObj);
 | 
				
			||||||
 | 
					        */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        //Log.d(TAG, "version:"+packet.getInt());
 | 
				
			||||||
 | 
					        //Log.d(TAG, "version:"+packet.getInt());
 | 
				
			||||||
 | 
					        //Log.d(TAG, "version:"+packet.getInt());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,124 @@
 | 
				
			||||||
 | 
					package org.torproject.android.vpn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (c) 2013, Psiphon Inc.
 | 
				
			||||||
 | 
					 * All rights reserved.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 * it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					 * the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
					 * (at your option) any later version.
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * This program is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					 * GNU General Public License for more details.
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
					 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.net.DatagramSocket;
 | 
				
			||||||
 | 
					import java.net.Socket;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import android.annotation.TargetApi;
 | 
				
			||||||
 | 
					import android.os.Build;
 | 
				
			||||||
 | 
					import android.os.ParcelFileDescriptor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1)
 | 
				
			||||||
 | 
					public class Tun2Socks
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    public static interface IProtectSocket
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        boolean doVpnProtect(Socket socket);
 | 
				
			||||||
 | 
					        boolean doVpnProtect(DatagramSocket socket);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static Thread mThread;
 | 
				
			||||||
 | 
					    private static ParcelFileDescriptor mVpnInterfaceFileDescriptor;
 | 
				
			||||||
 | 
					    private static int mVpnInterfaceMTU;
 | 
				
			||||||
 | 
					    private static String mVpnIpAddress;
 | 
				
			||||||
 | 
					    private static String mVpnNetMask;
 | 
				
			||||||
 | 
					    private static String mSocksServerAddress;
 | 
				
			||||||
 | 
					    private static String mUdpgwServerAddress;
 | 
				
			||||||
 | 
					    private static boolean mUdpgwTransparentDNS;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    // Note: this class isn't a singleton, but you can't run more
 | 
				
			||||||
 | 
					    // than one instance due to the use of global state (the lwip
 | 
				
			||||||
 | 
					    // module, etc.) in the native code.
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    public static synchronized void Start(
 | 
				
			||||||
 | 
					            ParcelFileDescriptor vpnInterfaceFileDescriptor,
 | 
				
			||||||
 | 
					            int vpnInterfaceMTU,
 | 
				
			||||||
 | 
					            String vpnIpAddress,
 | 
				
			||||||
 | 
					            String vpnNetMask,
 | 
				
			||||||
 | 
					            String socksServerAddress,
 | 
				
			||||||
 | 
					            String udpgwServerAddress,
 | 
				
			||||||
 | 
					            boolean udpgwTransparentDNS)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        Stop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        mVpnInterfaceFileDescriptor = vpnInterfaceFileDescriptor;
 | 
				
			||||||
 | 
					        mVpnInterfaceMTU = vpnInterfaceMTU;
 | 
				
			||||||
 | 
					        mVpnIpAddress = vpnIpAddress;
 | 
				
			||||||
 | 
					        mVpnNetMask = vpnNetMask;
 | 
				
			||||||
 | 
					        mSocksServerAddress = socksServerAddress;
 | 
				
			||||||
 | 
					        mUdpgwServerAddress = udpgwServerAddress;
 | 
				
			||||||
 | 
					        mUdpgwTransparentDNS = udpgwTransparentDNS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        mThread = new Thread(new Runnable()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            @Override
 | 
				
			||||||
 | 
					            public void run()
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                runTun2Socks(
 | 
				
			||||||
 | 
					                        mVpnInterfaceFileDescriptor.detachFd(),
 | 
				
			||||||
 | 
					                        mVpnInterfaceMTU,
 | 
				
			||||||
 | 
					                        mVpnIpAddress,
 | 
				
			||||||
 | 
					                        mVpnNetMask,
 | 
				
			||||||
 | 
					                        mSocksServerAddress,
 | 
				
			||||||
 | 
					                        mUdpgwServerAddress,
 | 
				
			||||||
 | 
					                        mUdpgwTransparentDNS ? 1 : 0);
 | 
				
			||||||
 | 
					            	
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        mThread.start();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    public static synchronized void Stop()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (mThread != null)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            terminateTun2Socks();
 | 
				
			||||||
 | 
					            try
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                mThread.join();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            catch (InterruptedException e)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                Thread.currentThread().interrupt();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            mThread = null;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					    private native static int runTun2Socks(
 | 
				
			||||||
 | 
					            int vpnInterfaceFileDescriptor,
 | 
				
			||||||
 | 
					            int vpnInterfaceMTU,
 | 
				
			||||||
 | 
					            String vpnIpAddress,
 | 
				
			||||||
 | 
					            String vpnNetMask,
 | 
				
			||||||
 | 
					            String socksServerAddress,
 | 
				
			||||||
 | 
					            String udpgwServerAddress,
 | 
				
			||||||
 | 
					            int udpgwTransparentDNS);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private native static void terminateTun2Socks();
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    static
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        System.loadLibrary("tun2socks");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
		Reference in New Issue