parent
							
								
									cfab5663bb
								
							
						
					
					
						commit
						ac867a662f
					
				|  | @ -1,6 +1,6 @@ | ||||||
| <?xml version="1.0" encoding="utf-8"?> | <?xml version="1.0" encoding="utf-8"?> | ||||||
| <manifest xmlns:android="http://schemas.android.com/apk/res/android" | <manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||||||
|       package="org.torproject.android" android:versionName="1.0.4" android:versionCode="11"> |       package="org.torproject.android" android:versionName="1.0.5" android:versionCode="11"> | ||||||
|         |         | ||||||
|        <uses-permission android:name="android.permission.INTERNET" /> |        <uses-permission android:name="android.permission.INTERNET" /> | ||||||
|        <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> |        <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> | ||||||
|  | @ -33,8 +33,7 @@ | ||||||
|         <activity android:name=".AppManager"  android:label="@string/app_name"/> |         <activity android:name=".AppManager"  android:label="@string/app_name"/> | ||||||
|         <activity android:name=".WizardActivity"  android:label="@string/app_name"/> |         <activity android:name=".WizardActivity"  android:label="@string/app_name"/> | ||||||
|        |        | ||||||
|     	<!-- <service android:name=".service.TorService" android:process=":remote"> --> |     	<service android:name=".service.TorService" android:process=":remote"> | ||||||
|     	<service android:name=".service.TorService"> |  | ||||||
| 	            <intent-filter> | 	            <intent-filter> | ||||||
| 	                <action android:name="org.torproject.android.service.ITorService" /> | 	                <action android:name="org.torproject.android.service.ITorService" /> | ||||||
| 	              	<action android:name="org.torproject.android.service.TOR_SERVICE" /> | 	              	<action android:name="org.torproject.android.service.TOR_SERVICE" /> | ||||||
|  |  | ||||||
|  | @ -1,5 +1,7 @@ | ||||||
| NOTE: Specific #s below correspond to Trac tickets logged and maintained at https://trac.torproject.org/projects/tor/ | NOTE: Specific #s below correspond to Trac tickets logged and maintained at https://trac.torproject.org/projects/tor/ | ||||||
| 
 | 
 | ||||||
|  | 1.0.5 | ||||||
|  | - Removed unused Socks client code from android.net package | ||||||
| 
 | 
 | ||||||
| 1.0.4 | 1.0.4 | ||||||
| - Added Russian, Persian, Arabic and other .po translations (see res/values-* folders) | - Added Russian, Persian, Arabic and other .po translations (see res/values-* folders) | ||||||
|  |  | ||||||
|  | @ -1,6 +1,6 @@ | ||||||
| SocksPort 9050 | SocksPort 9050 | ||||||
| SocksListenAddress 127.0.0.1 | TestSocks 1 | ||||||
| SafeSocks 1 | WarnUnsafeSocks 1 | ||||||
| Log notice stdout | Log notice stdout | ||||||
| DataDirectory /data/data/org.torproject.android/data | DataDirectory /data/data/org.torproject.android/data | ||||||
| ControlPort 9051 | ControlPort 9051 | ||||||
|  |  | ||||||
|  | @ -10,5 +10,5 @@ | ||||||
| # Indicates whether an apk should be generated for each density. | # Indicates whether an apk should be generated for each density. | ||||||
| split.density=false | split.density=false | ||||||
| # Project target. | # Project target. | ||||||
| target=android-4 | target=android-8 | ||||||
| apk-configurations= | apk-configurations= | ||||||
|  |  | ||||||
|  | @ -50,6 +50,13 @@ | ||||||
| <string name="pref_transparent_all_title">Tor Everything</string> | <string name="pref_transparent_all_title">Tor Everything</string> | ||||||
| <string name="pref_transparent_all_summary">Proxy traffic for all apps through Tor</string> | <string name="pref_transparent_all_summary">Proxy traffic for all apps through Tor</string> | ||||||
| 
 | 
 | ||||||
|  | <string name="pref_transparent_port_fallback_title">Port Proxy Fallback</string> | ||||||
|  | <string name="pref_transparent_port_fallback_summary">WARNING: Circumvents common ports (80, 443, etc). *USE ONLY* if \'All\' or \'App\' mode doesn\'t work.</string> | ||||||
|  | 
 | ||||||
|  | <string name="pref_transparent_port_title">Port List</string> | ||||||
|  | <string name="pref_transparent_port_summary">List of ports to proxy. *USE ONLY* if \'All\' or \'App\' mode doesn\'t work</string> | ||||||
|  | <string name="pref_transparent_port_dialog">Enter ports to proxy</string> | ||||||
|  | 
 | ||||||
| <string name="status_install_success">Tor binaries successfully installed!</string> | <string name="status_install_success">Tor binaries successfully installed!</string> | ||||||
| <string name="status_install_fail">The Tor binary files were unable to be installed. Please check the log and notify tor-assistants@torproject.org</string> | <string name="status_install_fail">The Tor binary files were unable to be installed. Please check the log and notify tor-assistants@torproject.org</string> | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -33,7 +33,19 @@ android:summary="Choose Apps to Route Through Tor" | ||||||
| android:enabled="true"/> | android:enabled="true"/> | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | <CheckBoxPreference | ||||||
|  | android:defaultValue="false"  | ||||||
|  | android:key="pref_transparent_port_fallback" | ||||||
|  | android:summary="@string/pref_transparent_port_fallback_summary" | ||||||
|  | android:enabled="true"  | ||||||
|  | android:title="@string/pref_transparent_port_fallback_title"/> | ||||||
| 
 | 
 | ||||||
|  | <EditTextPreference android:key="pref_port_list" | ||||||
|  | android:defaultValue="80,443,8080,8888,8443" | ||||||
|  | android:title="@string/pref_transparent_port_title" | ||||||
|  | android:summary="@string/pref_transparent_port_summary" | ||||||
|  | android:dialogTitle="@string/pref_transparent_port_dialog" | ||||||
|  | /> | ||||||
| </PreferenceCategory> | </PreferenceCategory> | ||||||
| 
 | 
 | ||||||
|   |   | ||||||
|  |  | ||||||
|  | @ -825,7 +825,7 @@ public class Orbot extends Activity implements OnClickListener, TorConstants | ||||||
|     	 |     	 | ||||||
|     	//unbindService(); |     	//unbindService(); | ||||||
| 		 | 		 | ||||||
|         //stopService(new Intent(ITorService.class.getName())); |         stopService(new Intent(ITorService.class.getName())); | ||||||
| 	 | 	 | ||||||
|     	 |     	 | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -1,442 +0,0 @@ | ||||||
| /* |  | ||||||
|  * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/conn/ssl/SSLSocketFactory.java $ |  | ||||||
|  * $Revision: 659194 $ |  | ||||||
|  * $Date: 2008-05-22 11:33:47 -0700 (Thu, 22 May 2008) $ |  | ||||||
|  * |  | ||||||
|  * ==================================================================== |  | ||||||
|  * Licensed to the Apache Software Foundation (ASF) under one |  | ||||||
|  * or more contributor license agreements.  See the NOTICE file |  | ||||||
|  * distributed with this work for additional information |  | ||||||
|  * regarding copyright ownership.  The ASF licenses this file |  | ||||||
|  * to you 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. |  | ||||||
|  * ==================================================================== |  | ||||||
|  * |  | ||||||
|  * This software consists of voluntary contributions made by many |  | ||||||
|  * individuals on behalf of the Apache Software Foundation.  For more |  | ||||||
|  * information on the Apache Software Foundation, please see |  | ||||||
|  * <http://www.apache.org/>. |  | ||||||
|  * |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| package org.torproject.android.net; |  | ||||||
| 
 |  | ||||||
| import java.io.IOException; |  | ||||||
| import java.net.InetAddress; |  | ||||||
| import java.net.InetSocketAddress; |  | ||||||
| import java.net.Socket; |  | ||||||
| import java.net.UnknownHostException; |  | ||||||
| import java.security.KeyManagementException; |  | ||||||
| import java.security.KeyStore; |  | ||||||
| import java.security.KeyStoreException; |  | ||||||
| import java.security.NoSuchAlgorithmException; |  | ||||||
| import java.security.SecureRandom; |  | ||||||
| import java.security.UnrecoverableKeyException; |  | ||||||
| 
 |  | ||||||
| import javax.net.ssl.KeyManager; |  | ||||||
| import javax.net.ssl.KeyManagerFactory; |  | ||||||
| import javax.net.ssl.SSLContext; |  | ||||||
| import javax.net.ssl.SSLSocket; |  | ||||||
| import javax.net.ssl.TrustManager; |  | ||||||
| import javax.net.ssl.TrustManagerFactory; |  | ||||||
| 
 |  | ||||||
| import org.apache.http.conn.scheme.HostNameResolver; |  | ||||||
| import org.apache.http.conn.scheme.LayeredSocketFactory; |  | ||||||
| import org.apache.http.conn.ssl.AllowAllHostnameVerifier; |  | ||||||
| import org.apache.http.conn.ssl.BrowserCompatHostnameVerifier; |  | ||||||
| import org.apache.http.conn.ssl.SSLSocketFactory; |  | ||||||
| import org.apache.http.conn.ssl.StrictHostnameVerifier; |  | ||||||
| import org.apache.http.conn.ssl.X509HostnameVerifier; |  | ||||||
| import org.apache.http.params.HttpConnectionParams; |  | ||||||
| import org.apache.http.params.HttpParams; |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * Layered socket factory for TLS/SSL connections, based on JSSE. |  | ||||||
|  *. |  | ||||||
|  * <p> |  | ||||||
|  * SSLSocketFactory can be used to validate the identity of the HTTPS  |  | ||||||
|  * server against a list of trusted certificates and to authenticate to |  | ||||||
|  * the HTTPS server using a private key.  |  | ||||||
|  * </p> |  | ||||||
|  *  |  | ||||||
|  * <p> |  | ||||||
|  * SSLSocketFactory will enable server authentication when supplied with |  | ||||||
|  * a {@link KeyStore truststore} file containg one or several trusted |  | ||||||
|  * certificates. The client secure socket will reject the connection during |  | ||||||
|  * the SSL session handshake if the target HTTPS server attempts to |  | ||||||
|  * authenticate itself with a non-trusted certificate. |  | ||||||
|  * </p> |  | ||||||
|  *  |  | ||||||
|  * <p> |  | ||||||
|  * Use JDK keytool utility to import a trusted certificate and generate a truststore file:     |  | ||||||
|  *    <pre> |  | ||||||
|  *     keytool -import -alias "my server cert" -file server.crt -keystore my.truststore |  | ||||||
|  *    </pre> |  | ||||||
|  * </p> |  | ||||||
|  *  |  | ||||||
|  * <p> |  | ||||||
|  * SSLSocketFactory will enable client authentication when supplied with |  | ||||||
|  * a {@link KeyStore keystore} file containg a private key/public certificate |  | ||||||
|  * pair. The client secure socket will use the private key to authenticate |  | ||||||
|  * itself to the target HTTPS server during the SSL session handshake if |  | ||||||
|  * requested to do so by the server. |  | ||||||
|  * The target HTTPS server will in its turn verify the certificate presented |  | ||||||
|  * by the client in order to establish client's authenticity |  | ||||||
|  * </p> |  | ||||||
|  *  |  | ||||||
|  * <p> |  | ||||||
|  * Use the following sequence of actions to generate a keystore file |  | ||||||
|  * </p> |  | ||||||
|  *   <ul> |  | ||||||
|  *     <li> |  | ||||||
|  *      <p> |  | ||||||
|  *      Use JDK keytool utility to generate a new key |  | ||||||
|  *      <pre>keytool -genkey -v -alias "my client key" -validity 365 -keystore my.keystore</pre> |  | ||||||
|  *      For simplicity use the same password for the key as that of the keystore |  | ||||||
|  *      </p> |  | ||||||
|  *     </li> |  | ||||||
|  *     <li> |  | ||||||
|  *      <p> |  | ||||||
|  *      Issue a certificate signing request (CSR) |  | ||||||
|  *      <pre>keytool -certreq -alias "my client key" -file mycertreq.csr -keystore my.keystore</pre> |  | ||||||
|  *     </p> |  | ||||||
|  *     </li> |  | ||||||
|  *     <li> |  | ||||||
|  *      <p> |  | ||||||
|  *      Send the certificate request to the trusted Certificate Authority for signature.  |  | ||||||
|  *      One may choose to act as her own CA and sign the certificate request using a PKI  |  | ||||||
|  *      tool, such as OpenSSL. |  | ||||||
|  *      </p> |  | ||||||
|  *     </li> |  | ||||||
|  *     <li> |  | ||||||
|  *      <p> |  | ||||||
|  *       Import the trusted CA root certificate |  | ||||||
|  *       <pre>keytool -import -alias "my trusted ca" -file caroot.crt -keystore my.keystore</pre>  |  | ||||||
|  *      </p> |  | ||||||
|  *     </li> |  | ||||||
|  *     <li> |  | ||||||
|  *      <p> |  | ||||||
|  *       Import the PKCS#7 file containg the complete certificate chain |  | ||||||
|  *       <pre>keytool -import -alias "my client key" -file mycert.p7 -keystore my.keystore</pre>  |  | ||||||
|  *      </p> |  | ||||||
|  *     </li> |  | ||||||
|  *     <li> |  | ||||||
|  *      <p> |  | ||||||
|  *       Verify the content the resultant keystore file |  | ||||||
|  *       <pre>keytool -list -v -keystore my.keystore</pre>  |  | ||||||
|  *      </p> |  | ||||||
|  *     </li> |  | ||||||
|  *   </ul> |  | ||||||
|  * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a> |  | ||||||
|  * @author Julius Davies |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| public class ModSSLSocketFactory implements LayeredSocketFactory { |  | ||||||
| 
 |  | ||||||
|     public static final String TLS   = "TLS"; |  | ||||||
|     public static final String SSL   = "SSL"; |  | ||||||
|     public static final String SSLV2 = "SSLv2"; |  | ||||||
|      |  | ||||||
|     public static final X509HostnameVerifier ALLOW_ALL_HOSTNAME_VERIFIER  |  | ||||||
|         = new AllowAllHostnameVerifier(); |  | ||||||
|      |  | ||||||
|     public static final X509HostnameVerifier BROWSER_COMPATIBLE_HOSTNAME_VERIFIER  |  | ||||||
|         = new BrowserCompatHostnameVerifier(); |  | ||||||
|      |  | ||||||
|     public static final X509HostnameVerifier STRICT_HOSTNAME_VERIFIER  |  | ||||||
|         = new StrictHostnameVerifier(); |  | ||||||
|     /** |  | ||||||
|      * The factory using the default JVM settings for secure connections. |  | ||||||
|      */ |  | ||||||
|     private static ModSSLSocketFactory DEFAULT_FACTORY = null; |  | ||||||
|      |  | ||||||
|     /** |  | ||||||
|      * Gets an singleton instance of the SSLProtocolSocketFactory. |  | ||||||
|      * @return a SSLProtocolSocketFactory |  | ||||||
|      */ |  | ||||||
|     public static ModSSLSocketFactory getSocketFactory() { |  | ||||||
|     	if (DEFAULT_FACTORY == null) { |  | ||||||
|     		DEFAULT_FACTORY = new ModSSLSocketFactory(); |  | ||||||
|     	} |  | ||||||
| 		return DEFAULT_FACTORY; |  | ||||||
|     } |  | ||||||
|      |  | ||||||
|     private final SSLContext sslcontext; |  | ||||||
|     private final SSLSocketFactory socketfactory; |  | ||||||
|     //private final HostNameResolver nameResolver; |  | ||||||
|     private X509HostnameVerifier hostnameVerifier = BROWSER_COMPATIBLE_HOSTNAME_VERIFIER; |  | ||||||
|     private SocksSocketFactory mSocksSocketFactory = null; |  | ||||||
| 
 |  | ||||||
|     public ModSSLSocketFactory( |  | ||||||
|         String algorithm,  |  | ||||||
|         final KeyStore keystore,  |  | ||||||
|         final String keystorePassword,  |  | ||||||
|         final KeyStore truststore, |  | ||||||
|         final SecureRandom random, |  | ||||||
|         final HostNameResolver nameResolver)  |  | ||||||
|         throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException |  | ||||||
|     { |  | ||||||
|         super(); |  | ||||||
|         if (algorithm == null) { |  | ||||||
|             algorithm = SSL; |  | ||||||
|         } |  | ||||||
|         KeyManager[] keymanagers = null; |  | ||||||
|         if (keystore != null) { |  | ||||||
|             keymanagers = createKeyManagers(keystore, keystorePassword); |  | ||||||
|         } |  | ||||||
|         TrustManager[] trustmanagers = null; |  | ||||||
|         if (truststore != null) { |  | ||||||
|             trustmanagers = createTrustManagers(truststore); |  | ||||||
|         } |  | ||||||
|         this.sslcontext = SSLContext.getInstance(algorithm); |  | ||||||
|         this.sslcontext.init(keymanagers, trustmanagers, random); |  | ||||||
|         this.socketfactory = SSLSocketFactory.getSocketFactory(); |  | ||||||
|         //this.nameResolver = nameResolver; |  | ||||||
|          |  | ||||||
|           |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public ModSSLSocketFactory( |  | ||||||
|             final KeyStore keystore,  |  | ||||||
|             final String keystorePassword,  |  | ||||||
|             final KeyStore truststore)  |  | ||||||
|             throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException |  | ||||||
|     { |  | ||||||
|         this(SSL, keystore, keystorePassword, truststore, null, null); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public ModSSLSocketFactory(final KeyStore keystore, final String keystorePassword)  |  | ||||||
|             throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException |  | ||||||
|     { |  | ||||||
|         this(SSL, keystore, keystorePassword, null, null, null); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public ModSSLSocketFactory(final KeyStore truststore)  |  | ||||||
|             throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException |  | ||||||
|     { |  | ||||||
|         this(SSL, null, null, truststore, null, null); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * Constructs an HttpClient SSLSocketFactory backed by the given JSSE |  | ||||||
|      * SSLSocketFactory. |  | ||||||
|      * |  | ||||||
|      * @hide |  | ||||||
|      */ |  | ||||||
|     public ModSSLSocketFactory(SSLSocketFactory socketfactory) { |  | ||||||
|         super(); |  | ||||||
|         this.sslcontext = null; |  | ||||||
|         this.socketfactory = socketfactory; |  | ||||||
|         //this.nameResolver = null; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * Creates the default SSL socket factory. |  | ||||||
|      * This constructor is used exclusively to instantiate the factory for |  | ||||||
|      * {@link #getSocketFactory getSocketFactory}. |  | ||||||
|      */ |  | ||||||
|     private ModSSLSocketFactory() { |  | ||||||
|         super(); |  | ||||||
|         this.sslcontext = null; |  | ||||||
|         this.socketfactory = SSLSocketFactory.getSocketFactory(); |  | ||||||
|         //this.nameResolver = null; |  | ||||||
|          |  | ||||||
|         this.mSocksSocketFactory = new SocksSocketFactory("127.0.0.1",9050); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     private static KeyManager[] createKeyManagers(final KeyStore keystore, final String password) |  | ||||||
|         throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException { |  | ||||||
|         if (keystore == null) { |  | ||||||
|             throw new IllegalArgumentException("Keystore may not be null"); |  | ||||||
|         } |  | ||||||
|         KeyManagerFactory kmfactory = KeyManagerFactory.getInstance( |  | ||||||
|             KeyManagerFactory.getDefaultAlgorithm()); |  | ||||||
|         kmfactory.init(keystore, password != null ? password.toCharArray(): null); |  | ||||||
|         return kmfactory.getKeyManagers();  |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     private static TrustManager[] createTrustManagers(final KeyStore keystore) |  | ||||||
|         throws KeyStoreException, NoSuchAlgorithmException {  |  | ||||||
|         if (keystore == null) { |  | ||||||
|             throw new IllegalArgumentException("Keystore may not be null"); |  | ||||||
|         } |  | ||||||
|         TrustManagerFactory tmfactory = TrustManagerFactory.getInstance( |  | ||||||
|             TrustManagerFactory.getDefaultAlgorithm()); |  | ||||||
|         tmfactory.init(keystore); |  | ||||||
|         return tmfactory.getTrustManagers(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|     // non-javadoc, see interface org.apache.http.conn.SocketFactory |  | ||||||
|     public Socket createSocket() |  | ||||||
|         throws IOException { |  | ||||||
| 
 |  | ||||||
|     	// SSL Sockets don't work at the moment. |  | ||||||
|     	//throw new SSLException("SSL socket functionality broken"); |  | ||||||
|         // the cast makes sure that the factory is working as expected |  | ||||||
|         return (SSLSocket) this.socketfactory.createSocket(); |  | ||||||
|     	//return new Socket(); |  | ||||||
|     	//return null; |  | ||||||
|          |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|     // non-javadoc, see interface org.apache.http.conn.SocketFactory |  | ||||||
|     public Socket connectSocket( |  | ||||||
|         final Socket sock, |  | ||||||
|         final String host, |  | ||||||
|         final int port, |  | ||||||
|         final InetAddress localAddress, |  | ||||||
|         int localPort, |  | ||||||
|         final HttpParams params |  | ||||||
|     ) throws IOException { |  | ||||||
| 
 |  | ||||||
|         if (host == null) { |  | ||||||
|             throw new IllegalArgumentException("Target host may not be null."); |  | ||||||
|         } |  | ||||||
|         if (params == null) { |  | ||||||
|             throw new IllegalArgumentException("Parameters may not be null."); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         //Socket underlying = (Socket) |  | ||||||
|         //    ((sock != null) ? sock : createSocket()); |  | ||||||
|         Socket underlying =  null; |  | ||||||
|          |  | ||||||
|         /*sock; |  | ||||||
|         if (underlying == null)// underlying = new Socket();  |  | ||||||
|         { |  | ||||||
|         	underlying = mSocksSocketFactory.createSocket(); |  | ||||||
|            |  | ||||||
|         }*/ |  | ||||||
|          |  | ||||||
|         Socket sSocket = mSocksSocketFactory.connectSocket(underlying, host, port, localAddress, localPort, params); |  | ||||||
|          |  | ||||||
|        // SSLSocket sslsock =  (SSLSocket) socketfactory.connectSocket(sSocket, host, port, localAddress, localPort, params); |  | ||||||
|         SSLSocket sslsock = (SSLSocket)socketfactory.createSocket(sSocket, host, port, true); |  | ||||||
|          |  | ||||||
|         if ((localAddress != null) || (localPort > 0)) { |  | ||||||
| 
 |  | ||||||
|             // we need to bind explicitly |  | ||||||
|             if (localPort < 0) |  | ||||||
|                 localPort = 0; // indicates "any" |  | ||||||
| 
 |  | ||||||
|             InetSocketAddress isa = |  | ||||||
|                 new InetSocketAddress(localAddress, localPort); |  | ||||||
| 
 |  | ||||||
|             sslsock.bind(isa); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         int connTimeout = HttpConnectionParams.getConnectionTimeout(params); |  | ||||||
|         int soTimeout = HttpConnectionParams.getSoTimeout(params); |  | ||||||
| 
 |  | ||||||
|         InetSocketAddress remoteAddress; |  | ||||||
| //        if (this.nameResolver != null) { |  | ||||||
| //            remoteAddress = new InetSocketAddress(this.nameResolver.resolve(host), port);  |  | ||||||
| //        } else { |  | ||||||
|          remoteAddress = new InetSocketAddress(host, port);             |  | ||||||
| //        } |  | ||||||
| //         |  | ||||||
| 
 |  | ||||||
|          sslsock.connect(remoteAddress, connTimeout); |  | ||||||
| 
 |  | ||||||
|        // sslsock.setSoTimeout(0); |  | ||||||
|         try { |  | ||||||
|             hostnameVerifier.verify(host, sslsock); |  | ||||||
|             // verifyHostName() didn't blowup - good! |  | ||||||
|         } catch (IOException iox) { |  | ||||||
|             // close the socket before re-throwing the exception |  | ||||||
|             try { sslsock.close(); } catch (Exception x) {  } |  | ||||||
|             throw iox; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         return sslsock; |  | ||||||
|         |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|     /** |  | ||||||
|      * Checks whether a socket connection is secure. |  | ||||||
|      * This factory creates TLS/SSL socket connections |  | ||||||
|      * which, by default, are considered secure. |  | ||||||
|      * <br/> |  | ||||||
|      * Derived classes may override this method to perform |  | ||||||
|      * runtime checks, for example based on the cypher suite. |  | ||||||
|      * |  | ||||||
|      * @param sock      the connected socket |  | ||||||
|      * |  | ||||||
|      * @return  <code>true</code> |  | ||||||
|      * |  | ||||||
|      * @throws IllegalArgumentException if the argument is invalid |  | ||||||
|      */ |  | ||||||
|     public boolean isSecure(Socket sock) |  | ||||||
|         throws IllegalArgumentException { |  | ||||||
| 
 |  | ||||||
|         if (sock == null) { |  | ||||||
|             throw new IllegalArgumentException("Socket may not be null."); |  | ||||||
|         } |  | ||||||
|         // This instanceof check is in line with createSocket() above. |  | ||||||
|         if (!(sock instanceof SSLSocket)) { |  | ||||||
|             throw new IllegalArgumentException |  | ||||||
|                 ("Socket not created by this factory."); |  | ||||||
|         } |  | ||||||
|         // This check is performed last since it calls the argument object. |  | ||||||
|         if (sock.isClosed()) { |  | ||||||
|             throw new IllegalArgumentException("Socket is closed."); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         return true; |  | ||||||
| 
 |  | ||||||
|     } // isSecure |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|     // non-javadoc, see interface LayeredSocketFactory |  | ||||||
|     public Socket createSocket( |  | ||||||
|         final Socket socket, |  | ||||||
|         final String host, |  | ||||||
|         final int port, |  | ||||||
|         final boolean autoClose |  | ||||||
|     ) throws IOException, UnknownHostException { |  | ||||||
|         SSLSocket sslSocket = (SSLSocket) this.socketfactory.createSocket( |  | ||||||
|               socket, |  | ||||||
|               host, |  | ||||||
|               port, |  | ||||||
|               autoClose |  | ||||||
|         ); |  | ||||||
|         hostnameVerifier.verify(host, sslSocket); |  | ||||||
|         // verifyHostName() didn't blowup - good! |  | ||||||
|         return sslSocket; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public void setHostnameVerifier(X509HostnameVerifier hostnameVerifier) { |  | ||||||
|         if ( hostnameVerifier == null ) { |  | ||||||
|             throw new IllegalArgumentException("Hostname verifier may not be null"); |  | ||||||
|         } |  | ||||||
|         this.hostnameVerifier = hostnameVerifier; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public X509HostnameVerifier getHostnameVerifier() { |  | ||||||
|         return hostnameVerifier; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     public class SSLException extends IOException { |  | ||||||
| 		private static final long serialVersionUID = 1L; |  | ||||||
| 
 |  | ||||||
| 		public SSLException(String msg) { |  | ||||||
| 			super(msg); |  | ||||||
| 		} |  | ||||||
|     }; |  | ||||||
|      |  | ||||||
|      |  | ||||||
| } |  | ||||||
|  | @ -1,70 +0,0 @@ | ||||||
| package org.torproject.android.net; |  | ||||||
| 
 |  | ||||||
| import java.io.IOException; |  | ||||||
| import java.net.ConnectException; |  | ||||||
| import java.net.InetAddress; |  | ||||||
| import java.net.Socket; |  | ||||||
| 
 |  | ||||||
| import org.apache.http.HttpHost; |  | ||||||
| import org.apache.http.conn.HttpHostConnectException; |  | ||||||
| import org.apache.http.conn.OperatedClientConnection; |  | ||||||
| import org.apache.http.conn.scheme.Scheme; |  | ||||||
| import org.apache.http.conn.scheme.SchemeRegistry; |  | ||||||
| import org.apache.http.conn.scheme.SocketFactory; |  | ||||||
| import org.apache.http.impl.conn.DefaultClientConnectionOperator; |  | ||||||
| import org.apache.http.params.HttpParams; |  | ||||||
| import org.apache.http.protocol.HttpContext; |  | ||||||
| 
 |  | ||||||
| public class MyDefaultClientConnectionOperator extends |  | ||||||
| 		DefaultClientConnectionOperator { |  | ||||||
| 
 |  | ||||||
| 	public MyDefaultClientConnectionOperator(SchemeRegistry schemes) { |  | ||||||
| 		super(schemes); |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	@Override |  | ||||||
| 	public void openConnection(OperatedClientConnection conn, HttpHost target, |  | ||||||
| 			InetAddress local, HttpContext context, HttpParams params) |  | ||||||
| 			throws IOException { |  | ||||||
| 		if (conn == null) { |  | ||||||
|             throw new IllegalArgumentException |  | ||||||
|                 ("Connection must not be null."); |  | ||||||
|         } |  | ||||||
|         if (target == null) { |  | ||||||
|             throw new IllegalArgumentException |  | ||||||
|                 ("Target host must not be null."); |  | ||||||
|         } |  | ||||||
|         // local address may be null |  | ||||||
|         //@@@ is context allowed to be null? |  | ||||||
|         if (params == null) { |  | ||||||
|             throw new IllegalArgumentException |  | ||||||
|                 ("Parameters must not be null."); |  | ||||||
|         } |  | ||||||
|         if (conn.isOpen()) { |  | ||||||
|             throw new IllegalArgumentException |  | ||||||
|                 ("Connection must not be open."); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         final Scheme schm = schemeRegistry.getScheme(target.getSchemeName()); |  | ||||||
|         final SocketFactory sf = schm.getSocketFactory(); |  | ||||||
| 
 |  | ||||||
|         Socket sock = sf.createSocket(); |  | ||||||
|         conn.opening(sock, target); |  | ||||||
| 	 |  | ||||||
|         try { |  | ||||||
|         	Socket connsock = sf.connectSocket(sock, target.getHostName(), |  | ||||||
|                     schm.resolvePort(target.getPort()), |  | ||||||
|                     local, 0, params); |  | ||||||
|         	 |  | ||||||
|         			if (sock != connsock) { |  | ||||||
| 		                sock = connsock; |  | ||||||
| 		                conn.opening(sock, target); |  | ||||||
| 		            } |  | ||||||
|         } catch (ConnectException ex) { |  | ||||||
|             throw new HttpHostConnectException(target, ex); |  | ||||||
|         } |  | ||||||
|         prepareSocket(sock, context, params); |  | ||||||
|         conn.openCompleted(sf.isSecure(sock), params); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
|  | @ -1,21 +0,0 @@ | ||||||
| package org.torproject.android.net; |  | ||||||
| 
 |  | ||||||
| import org.apache.http.conn.ClientConnectionOperator; |  | ||||||
| import org.apache.http.conn.scheme.SchemeRegistry; |  | ||||||
| import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager; |  | ||||||
| import org.apache.http.params.HttpParams; |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| public class MyThreadSafeClientConnManager extends ThreadSafeClientConnManager { |  | ||||||
| 
 |  | ||||||
| 	public MyThreadSafeClientConnManager(HttpParams params, SchemeRegistry schreg) { |  | ||||||
| 		super(params, schreg); |  | ||||||
| 		 |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	@Override |  | ||||||
| 	protected ClientConnectionOperator createConnectionOperator( |  | ||||||
| 			SchemeRegistry schreg) { |  | ||||||
| 		return new MyDefaultClientConnectionOperator(schreg); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  | @ -1,71 +0,0 @@ | ||||||
| package org.torproject.android.net; |  | ||||||
| 
 |  | ||||||
| import org.apache.http.HttpVersion; |  | ||||||
| import org.apache.http.conn.ClientConnectionManager; |  | ||||||
| import org.apache.http.conn.scheme.PlainSocketFactory; |  | ||||||
| import org.apache.http.conn.scheme.Scheme; |  | ||||||
| import org.apache.http.conn.scheme.SchemeRegistry; |  | ||||||
| import org.apache.http.conn.ssl.SSLSocketFactory; |  | ||||||
| import org.apache.http.impl.client.DefaultHttpClient; |  | ||||||
| import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager; |  | ||||||
| import org.apache.http.params.BasicHttpParams; |  | ||||||
| import org.apache.http.params.HttpParams; |  | ||||||
| import org.apache.http.params.HttpProtocolParams; |  | ||||||
| 
 |  | ||||||
| public class SOCKSHttpClient extends DefaultHttpClient { |  | ||||||
| 
 |  | ||||||
| 	private final static String DEFAULT_HOST = "127.0.0.1"; |  | ||||||
| 	private final static int DEFAULT_PORT = 9050; |  | ||||||
| 	 |  | ||||||
| 	private static ClientConnectionManager ccm = null; |  | ||||||
| 	private static HttpParams params = null; |  | ||||||
| 	 |  | ||||||
| 	public SOCKSHttpClient () |  | ||||||
| 	{ |  | ||||||
| 		 |  | ||||||
|        super(initConnectionManager(), initParams()); |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	private void setSystemProperties () |  | ||||||
| 	{ |  | ||||||
| //       System.getProperties().put("socks.proxySet","true"); |  | ||||||
|   //     System.getProperties().put("socks.proxyHost",DEFAULT_HOST); |  | ||||||
| 	//	System.getProperties().put("socks.proxyPort", DEFAULT_PORT+""); |  | ||||||
| 
 |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	private static ClientConnectionManager initConnectionManager () |  | ||||||
| 	{ |  | ||||||
| 		if (ccm == null) |  | ||||||
| 		{ |  | ||||||
| 		SchemeRegistry supportedSchemes = new SchemeRegistry(); |  | ||||||
| 		 |  | ||||||
| 		 |  | ||||||
| 		 supportedSchemes.register(new Scheme("http",  |  | ||||||
| 	                SocksSocketFactory.getSocketFactory(), 80)); |  | ||||||
| 	     |  | ||||||
| 		 supportedSchemes.register(new Scheme("https",  |  | ||||||
| 	                ModSSLSocketFactory.getSocketFactory(), 443)); |  | ||||||
| 	 |  | ||||||
| 			ccm = new MyThreadSafeClientConnManager(initParams(), supportedSchemes); |  | ||||||
| 		} |  | ||||||
| 		 |  | ||||||
|       return ccm; |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	private static HttpParams initParams () |  | ||||||
| 	{ |  | ||||||
| 	    if (params == null) |  | ||||||
| 	    { |  | ||||||
| 	      // prepare parameters |  | ||||||
| 	      params = new BasicHttpParams(); |  | ||||||
| 	      HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); |  | ||||||
| 	      HttpProtocolParams.setContentCharset(params, "UTF-8"); |  | ||||||
| 	      HttpProtocolParams.setUseExpectContinue(params, true); |  | ||||||
| 	    } |  | ||||||
| 	     |  | ||||||
| 	    return params; |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  | @ -1,146 +0,0 @@ | ||||||
| /* Copyright (c) 2009, Nathan Freitas, Orbot / The Guardian Project - http://openideals.com/guardian */ |  | ||||||
| /* See LICENSE for licensing information */ |  | ||||||
| 
 |  | ||||||
| /** SOCKS aware echo client*/ |  | ||||||
| 
 |  | ||||||
| package org.torproject.android.net; |  | ||||||
| 
 |  | ||||||
| import java.io.BufferedReader; |  | ||||||
| import java.io.IOException; |  | ||||||
| import java.io.InputStream; |  | ||||||
| import java.io.InputStreamReader; |  | ||||||
| import java.io.OutputStream; |  | ||||||
| import java.net.InetAddress; |  | ||||||
| import java.net.Socket; |  | ||||||
| import java.net.UnknownHostException; |  | ||||||
| 
 |  | ||||||
| import net.sourceforge.jsocks.socks.InetRange; |  | ||||||
| import net.sourceforge.jsocks.socks.Proxy; |  | ||||||
| import net.sourceforge.jsocks.socks.SocksException; |  | ||||||
| import net.sourceforge.jsocks.socks.SocksSocket; |  | ||||||
| 
 |  | ||||||
| import org.torproject.android.TorConstants; |  | ||||||
| 
 |  | ||||||
| import android.util.Log; |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| public class SocksClient implements Runnable { |  | ||||||
|    |  | ||||||
| 	   @SuppressWarnings("unused") |  | ||||||
|    private int port; |  | ||||||
| 	    |  | ||||||
| 	   @SuppressWarnings("unused") |  | ||||||
|    private InetAddress hostIP; |  | ||||||
| 
 |  | ||||||
|    private Socket ss; |  | ||||||
|    private InputStream in; |  | ||||||
|    private OutputStream out; |  | ||||||
| 
 |  | ||||||
|    @SuppressWarnings("unused") |  | ||||||
| private static final int BUF_SIZE = 1024; |  | ||||||
|    private static final String IP_LOCALHOST = "127.0.0.1"; |  | ||||||
|     |  | ||||||
|    public SocksClient(String host,int port)  |  | ||||||
| 	  throws IOException,UnknownHostException,SocksException{ |  | ||||||
|       this.port = port; |  | ||||||
| 
 |  | ||||||
|       ss = new SocksSocket(host, port); |  | ||||||
|       out = ss.getOutputStream(); |  | ||||||
|       in  = ss.getInputStream(); |  | ||||||
|       Log.d(getClass().getName(),"Connected..."); |  | ||||||
|       Log.d(getClass().getName(),"TO: "+host+":"+port); |  | ||||||
|       Log.d(getClass().getName(),"ViaProxy: "+ss.getLocalAddress().getHostAddress() |  | ||||||
|                                  +":"+ss.getLocalPort()); |  | ||||||
| 
 |  | ||||||
|    } |  | ||||||
| 
 |  | ||||||
|    public void close()throws IOException{ |  | ||||||
|      ss.close(); |  | ||||||
|    } |  | ||||||
|    public void send(String s) throws IOException{ |  | ||||||
|       out.write(s.getBytes()); |  | ||||||
|    } |  | ||||||
| 
 |  | ||||||
|    public void run(){ |  | ||||||
|       byte[] buf = new byte[1024]; |  | ||||||
|       int bytes_read; |  | ||||||
|       try{ |  | ||||||
| 	  while((bytes_read = in.read(buf)) > 0){ |  | ||||||
| 	     System.out.write(buf,0,bytes_read); |  | ||||||
| 	  } |  | ||||||
|       }catch(IOException io_ex){ |  | ||||||
| 	 io_ex.printStackTrace(); |  | ||||||
|       } |  | ||||||
|    } |  | ||||||
| 
 |  | ||||||
|    public static void usage(){ |  | ||||||
|       System.err.print( |  | ||||||
|       "Usage: java SocksTest host port [socksHost socksPort]\n"); |  | ||||||
|    } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
|    public static void main(String args[]){ |  | ||||||
|       int port; |  | ||||||
|       String host; |  | ||||||
|       int proxyPort; |  | ||||||
|       String proxyHost; |  | ||||||
| 
 |  | ||||||
|       if(args.length > 1 && args.length < 5){ |  | ||||||
| 	 try{ |  | ||||||
| 
 |  | ||||||
| 	     host = args[0]; |  | ||||||
| 	     port = Integer.parseInt(args[1]); |  | ||||||
| 
 |  | ||||||
| 	     proxyPort =(args.length > 3)? Integer.parseInt(args[3])	      |  | ||||||
| 	                                 : 9050; |  | ||||||
| 
 |  | ||||||
| 	     host = args[0]; |  | ||||||
| 	     proxyHost =(args.length > 2)? args[2] |  | ||||||
| 	                                 : IP_LOCALHOST; |  | ||||||
| 
 |  | ||||||
| 	     Proxy.setDefaultProxy(proxyHost,proxyPort,"KOUKY001"); |  | ||||||
| 	     //Proxy.setDefaultProxy(proxyHost,proxyPort); |  | ||||||
| 	     InetRange inetRange = new InetRange(); |  | ||||||
| 	     inetRange.add(InetAddress.getByName("localhost")); |  | ||||||
| 	     Proxy.getDefaultProxy().setDirect(inetRange); |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 	     SocksClient st = new SocksClient(host,port); |  | ||||||
| 	     Thread thread = new Thread(st); |  | ||||||
| 	     thread.start(); |  | ||||||
| 
 |  | ||||||
| 	     BufferedReader in = new BufferedReader( |  | ||||||
| 				 new InputStreamReader(System.in)); |  | ||||||
|              String s; |  | ||||||
| 
 |  | ||||||
|              s = in.readLine(); |  | ||||||
| 	     while(s != null){ |  | ||||||
|                 st.send(s+"\r\n"); |  | ||||||
| 		//try{ |  | ||||||
| 		   //Thread.currentThread().sleep(10); |  | ||||||
| 		//}catch(InterruptedException i_ex){ |  | ||||||
| 		//} |  | ||||||
|                 s = in.readLine(); |  | ||||||
| 	     } |  | ||||||
| 	     st.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(); |  | ||||||
|       } |  | ||||||
|    } |  | ||||||
| 
 |  | ||||||
| }//End of class |  | ||||||
|  | @ -1,141 +0,0 @@ | ||||||
| /** |  | ||||||
|  * Shadow - Anonymous web browser for Android devices |  | ||||||
|  * Copyright (C) 2009 Connell Gauld |  | ||||||
|  *  |  | ||||||
|  * Thanks to University of Cambridge, |  | ||||||
|  * 		Alastair Beresford and Andrew Rice |  | ||||||
|  *  |  | ||||||
|  * This program is free software; you can redistribute it and/or |  | ||||||
|  * modify it under the terms of the GNU General Public License |  | ||||||
|  * version 2 as published by the Free Software Foundation. |  | ||||||
|  *  |  | ||||||
|  * 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, write to the Free Software |  | ||||||
|  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA |  | ||||||
|  */ |  | ||||||
| 
 |  | ||||||
| package org.torproject.android.net; |  | ||||||
| 
 |  | ||||||
| import java.io.IOException; |  | ||||||
| import java.net.InetAddress; |  | ||||||
| import java.net.InetSocketAddress; |  | ||||||
| import java.net.Socket; |  | ||||||
| import java.net.UnknownHostException; |  | ||||||
| 
 |  | ||||||
| import net.sourceforge.jsocks.socks.Socks5Proxy; |  | ||||||
| import net.sourceforge.jsocks.socks.SocksException; |  | ||||||
| import net.sourceforge.jsocks.socks.SocksSocket; |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| import org.apache.http.conn.ConnectTimeoutException; |  | ||||||
| import org.apache.http.conn.scheme.SocketFactory; |  | ||||||
| import org.apache.http.params.HttpConnectionParams; |  | ||||||
| import org.apache.http.params.HttpParams; |  | ||||||
| 
 |  | ||||||
| import android.util.Log; |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * Provides sockets for an HttpClient connection. |  | ||||||
|  * @author cmg47 |  | ||||||
|  * |  | ||||||
|  */ |  | ||||||
| public class SocksSocketFactory implements SocketFactory { |  | ||||||
| 
 |  | ||||||
| 	SocksSocket server = null; |  | ||||||
| 	private static Socks5Proxy sProxy = null; |  | ||||||
| 
 |  | ||||||
| 	private final static String DEFAULT_HOST = "127.0.0.1"; |  | ||||||
| 	private final static int DEFAULT_PORT = 9050; |  | ||||||
| 	 |  | ||||||
| 	/** |  | ||||||
| 	 * Construct a SocksSocketFactory that uses the provided SOCKS proxy. |  | ||||||
| 	 * @param proxyaddress the IP address of the SOCKS proxy |  | ||||||
| 	 * @param proxyport the port of the SOCKS proxy |  | ||||||
| 	 */ |  | ||||||
| 	public SocksSocketFactory(String proxyaddress, int proxyport) { |  | ||||||
| 		 |  | ||||||
| 
 |  | ||||||
| 		try { |  | ||||||
| 			sProxy = new Socks5Proxy(proxyaddress, proxyport); |  | ||||||
| 		} catch (UnknownHostException e) { |  | ||||||
| 			// TODO Auto-generated catch block |  | ||||||
| 			Log.d("TOR_SERVICE","SocksSF couldn't connect",e); |  | ||||||
| 		} |  | ||||||
| 		 |  | ||||||
| 		sProxy.resolveAddrLocally(false); |  | ||||||
| 	 |  | ||||||
| 
 |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	public Socket connectSocket(Socket sock, String host, int port, |  | ||||||
| 			InetAddress localAddress, int localPort, HttpParams params) throws IOException, |  | ||||||
| 			UnknownHostException, ConnectTimeoutException { |  | ||||||
| 		 |  | ||||||
| 		Log.d("TOR_SERVICE","SocksSocketFactory: connectSocket: " + host + ":" + port); |  | ||||||
| 		 |  | ||||||
| 		if (host == null) { |  | ||||||
|             throw new IllegalArgumentException("Target host may not be null."); |  | ||||||
|         } |  | ||||||
|         if (params == null) { |  | ||||||
|             throw new IllegalArgumentException("Parameters may not be null."); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|      //   int timeout = HttpConnectionParams.getConnectionTimeout(params); |  | ||||||
|          |  | ||||||
|         // Pipe this socket over the proxy |  | ||||||
|       //  sock = mSocksProxy.connectSocksProxy(sock, host, port, timeout); |  | ||||||
|          |  | ||||||
|          |  | ||||||
|      |  | ||||||
| 		try { |  | ||||||
| 			sock =  new SocksSocket(sProxy,host, port); |  | ||||||
| 			 |  | ||||||
| 
 |  | ||||||
| 			 |  | ||||||
| 			sock.setSoTimeout(0); //indef |  | ||||||
| 			 |  | ||||||
| 			 |  | ||||||
| 			 if ((localAddress != null) || (localPort > 0)) { |  | ||||||
| 
 |  | ||||||
| 		            // we need to bind explicitly |  | ||||||
| 		            if (localPort < 0) |  | ||||||
| 		                localPort = 0; // indicates "any" |  | ||||||
| 
 |  | ||||||
| 		            InetSocketAddress isa = |  | ||||||
| 		                new InetSocketAddress(localAddress, localPort); |  | ||||||
| 		            sock.bind(isa); |  | ||||||
| 		        } |  | ||||||
| 
 |  | ||||||
| 			 |  | ||||||
| 		} catch (SocksException e) { |  | ||||||
| 			Log.e("TOR_SERVICE","error connecting socks to" + host + ":" + port,e); |  | ||||||
| 		} catch (UnknownHostException e) { |  | ||||||
| 			Log.e("TOR_SERVICE","error connecting socks to" + host + ":" + port,e); |  | ||||||
| 		} |  | ||||||
| 		 |  | ||||||
|         return sock; |  | ||||||
| 		 |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
|      |  | ||||||
|      |  | ||||||
| 	public Socket createSocket() throws IOException { |  | ||||||
| 		return new Socket(); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	public boolean isSecure(Socket sock) throws IllegalArgumentException { |  | ||||||
| 		return false; |  | ||||||
| 	} |  | ||||||
| 	 |  | ||||||
| 	public static SocketFactory getSocketFactory () |  | ||||||
| 	{ |  | ||||||
| 		return new SocksSocketFactory (DEFAULT_HOST, DEFAULT_PORT); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| } |  | ||||||
|  | @ -294,6 +294,8 @@ public class TorService extends Service implements TorServiceConstants, Runnable | ||||||
|      |      | ||||||
|     private void killTorProcess () throws Exception |     private void killTorProcess () throws Exception | ||||||
|     { |     { | ||||||
|  | 		//android.os.Debug.waitForDebugger(); | ||||||
|  |     	 | ||||||
|     	StringBuilder log = new StringBuilder(); |     	StringBuilder log = new StringBuilder(); | ||||||
|     	int procId = -1; |     	int procId = -1; | ||||||
|     	 |     	 | ||||||
|  | @ -301,9 +303,9 @@ public class TorService extends Service implements TorServiceConstants, Runnable | ||||||
| 		{ | 		{ | ||||||
|     		logNotice("Using control port to shutdown Tor"); |     		logNotice("Using control port to shutdown Tor"); | ||||||
|     		 |     		 | ||||||
|  |     		 | ||||||
| 			try { | 			try { | ||||||
| 				logNotice("sending SHUTDOWN signal to Tor process"); | 				logNotice("sending SHUTDOWN signal to Tor process"); | ||||||
| 				 |  | ||||||
| 				conn.shutdownTor("SHUTDOWN"); | 				conn.shutdownTor("SHUTDOWN"); | ||||||
| 				 | 				 | ||||||
| 				 | 				 | ||||||
|  | @ -313,30 +315,18 @@ public class TorService extends Service implements TorServiceConstants, Runnable | ||||||
| 			 | 			 | ||||||
| 			conn = null; | 			conn = null; | ||||||
| 		} | 		} | ||||||
|     	else |  | ||||||
|     	{ |  | ||||||
|     	 |     	 | ||||||
| 	    	 | 		while ((procId = TorServiceUtils.findProcessId(torBinaryPath)) != -1) | ||||||
| 	    	logNotice("Checking for existing Tor process via path: " + torBinaryPath); | 		{ | ||||||
| 			procId = TorServiceUtils.findProcessId(torBinaryPath); | 			 | ||||||
| 	 | 			logNotice("Found Tor PID=" + procId + " - killing now..."); | ||||||
| 			while (procId != -1) | 			 | ||||||
| 			{ | 			String[] cmd = { SHELL_CMD_KILL + ' ' + procId + "" }; | ||||||
| 				 | 			TorServiceUtils.doShellCommand(cmd,log, false, false); | ||||||
| 				logNotice("Found Tor PID=" + procId + " - killing now..."); |  | ||||||
| 				 |  | ||||||
| 				String[] cmd = { SHELL_CMD_KILL + ' ' + procId + "" }; |  | ||||||
| 				TorServiceUtils.doShellCommand(cmd,log, false, false); |  | ||||||
| 	 |  | ||||||
| 				procId = TorServiceUtils.findProcessId(torBinaryPath); |  | ||||||
| 			} |  | ||||||
|     	 |  | ||||||
|     	} |  | ||||||
| 		 |  | ||||||
|     	logNotice("Checking for existing Privoxy process via path: " + privoxyPath); |  | ||||||
| 		procId = TorServiceUtils.findProcessId(privoxyPath); |  | ||||||
| 
 | 
 | ||||||
| 		while (procId != -1) | 		} | ||||||
|  | 
 | ||||||
|  | 		while ((procId = TorServiceUtils.findProcessId(privoxyPath)) != -1) | ||||||
| 		{ | 		{ | ||||||
| 			 | 			 | ||||||
| 			logNotice("Found Privoxy PID=" + procId + " - killing now..."); | 			logNotice("Found Privoxy PID=" + procId + " - killing now..."); | ||||||
|  | @ -344,7 +334,6 @@ public class TorService extends Service implements TorServiceConstants, Runnable | ||||||
| 
 | 
 | ||||||
| 			TorServiceUtils.doShellCommand(cmd,log, false, false); | 			TorServiceUtils.doShellCommand(cmd,log, false, false); | ||||||
| 
 | 
 | ||||||
| 			procId = TorServiceUtils.findProcessId(privoxyPath); |  | ||||||
| 		} | 		} | ||||||
| 		 | 		 | ||||||
|     } |     } | ||||||
|  | @ -444,7 +433,6 @@ public class TorService extends Service implements TorServiceConstants, Runnable | ||||||
|     private boolean checkTorBinaries () throws Exception |     private boolean checkTorBinaries () throws Exception | ||||||
|     { |     { | ||||||
|     	 |     	 | ||||||
|     	 |  | ||||||
| 		appHome = "/data/data/" + TOR_APP_USERNAME + "/"; | 		appHome = "/data/data/" + TOR_APP_USERNAME + "/"; | ||||||
| 		//appHome = getApplicationContext().getFilesDir().getAbsolutePath(); | 		//appHome = getApplicationContext().getFilesDir().getAbsolutePath(); | ||||||
|     	 |     	 | ||||||
|  | @ -1353,8 +1341,11 @@ public class TorService extends Service implements TorServiceConstants, Runnable | ||||||
| 		boolean enableTransparentProxy = prefs.getBoolean("pref_transparent", false); | 		boolean enableTransparentProxy = prefs.getBoolean("pref_transparent", false); | ||||||
| 		boolean transProxyAll = prefs.getBoolean("pref_transparent_all", false); | 		boolean transProxyAll = prefs.getBoolean("pref_transparent_all", false); | ||||||
| 	 | 	 | ||||||
|  | 		boolean transProxyPortFallback = prefs.getBoolean("pref_transparent_port_fallback", false); | ||||||
|  | 		 | ||||||
|     	logNotice ("Transparent Proxying: " + enableTransparentProxy); |     	logNotice ("Transparent Proxying: " + enableTransparentProxy); | ||||||
|     	 |     	 | ||||||
|  |     	String portProxyList = prefs.getString("pref_port_list", ""); | ||||||
| 
 | 
 | ||||||
| 		if (enabled) | 		if (enabled) | ||||||
| 		{ | 		{ | ||||||
|  | @ -1371,6 +1362,16 @@ public class TorService extends Service implements TorServiceConstants, Runnable | ||||||
| 				 | 				 | ||||||
| 					logNotice ("TorTransProxy resp code: " + code); | 					logNotice ("TorTransProxy resp code: " + code); | ||||||
| 					 | 					 | ||||||
|  | 					//this is for Androids w/o owner module support as a circumvention only fallback | ||||||
|  | 					if (transProxyPortFallback) | ||||||
|  | 					{ | ||||||
|  | 						StringTokenizer st = new StringTokenizer(portProxyList, ","); | ||||||
|  | 						 | ||||||
|  | 						while (st.hasMoreTokens()) | ||||||
|  | 							TorTransProxy.setTransparentProxyingByPort(this, Integer.parseInt(st.nextToken())); | ||||||
|  | 						 | ||||||
|  | 					} | ||||||
|  | 					 | ||||||
| 					return true; | 					return true; | ||||||
| 				 | 				 | ||||||
| 				 | 				 | ||||||
|  |  | ||||||
|  | @ -6,7 +6,7 @@ public interface TorServiceConstants { | ||||||
| 
 | 
 | ||||||
| 	public final static String TAG = "ORBOT"; | 	public final static String TAG = "ORBOT"; | ||||||
| 
 | 
 | ||||||
| 	public static boolean LOG_OUTPUT_TO_DEBUG = false; | 	public static boolean LOG_OUTPUT_TO_DEBUG = true; | ||||||
| 
 | 
 | ||||||
| 	public final static String TOR_APP_USERNAME = "org.torproject.android"; | 	public final static String TOR_APP_USERNAME = "org.torproject.android"; | ||||||
| 	 | 	 | ||||||
|  | @ -31,7 +31,7 @@ public interface TorServiceConstants { | ||||||
| 		 | 		 | ||||||
| 	//various console cmds | 	//various console cmds | ||||||
| 	public final static String SHELL_CMD_CHMOD = "chmod"; | 	public final static String SHELL_CMD_CHMOD = "chmod"; | ||||||
| 	public final static String SHELL_CMD_KILL = "kill"; | 	public final static String SHELL_CMD_KILL = "kill -9"; | ||||||
| 	public final static String SHELL_CMD_RM = "rm"; | 	public final static String SHELL_CMD_RM = "rm"; | ||||||
| 	public final static String SHELL_CMD_PS = "ps"; | 	public final static String SHELL_CMD_PS = "ps"; | ||||||
| 	public final static String SHELL_CMD_PIDOF = "pidof"; | 	public final static String SHELL_CMD_PIDOF = "pidof"; | ||||||
|  |  | ||||||
|  | @ -3,6 +3,7 @@ | ||||||
| package org.torproject.android.service; | package org.torproject.android.service; | ||||||
| 
 | 
 | ||||||
| import java.io.BufferedReader; | import java.io.BufferedReader; | ||||||
|  | import java.io.File; | ||||||
| import java.io.IOException; | import java.io.IOException; | ||||||
| import java.io.InputStreamReader; | import java.io.InputStreamReader; | ||||||
| import java.io.OutputStreamWriter; | import java.io.OutputStreamWriter; | ||||||
|  | @ -66,7 +67,6 @@ public class TorServiceUtils implements TorServiceConstants { | ||||||
| 			try | 			try | ||||||
| 			{ | 			{ | ||||||
| 				procId = findProcessIdWithPS(command); | 				procId = findProcessIdWithPS(command); | ||||||
| 
 |  | ||||||
| 			} | 			} | ||||||
| 			catch (Exception e2) | 			catch (Exception e2) | ||||||
| 			{ | 			{ | ||||||
|  | @ -87,23 +87,27 @@ public class TorServiceUtils implements TorServiceConstants { | ||||||
| 		    	 | 		    	 | ||||||
| 		Process procPs = null; | 		Process procPs = null; | ||||||
| 		 | 		 | ||||||
|         procPs = r.exec(SHELL_CMD_PIDOF); | 		String baseName = new File(command).getName(); | ||||||
|  | 		//fix contributed my mikos on 2010.12.10 | ||||||
|  | 		procPs = r.exec(new String[] {SHELL_CMD_PIDOF, baseName}); | ||||||
|  |         //procPs = r.exec(SHELL_CMD_PIDOF); | ||||||
|              |              | ||||||
|         BufferedReader reader = new BufferedReader(new InputStreamReader(procPs.getInputStream())); |         BufferedReader reader = new BufferedReader(new InputStreamReader(procPs.getInputStream())); | ||||||
|         String line = null; |         String line = null; | ||||||
|          |  | ||||||
| 
 | 
 | ||||||
|         while ((line = reader.readLine())!=null) |         while ((line = reader.readLine())!=null) | ||||||
|         { |         { | ||||||
|         	if (line.indexOf(command)!=-1) |          | ||||||
|  |         	try | ||||||
|         	{ |         	{ | ||||||
| 
 |  | ||||||
|         		//this line should just be the process id |         		//this line should just be the process id | ||||||
|         		procId = Integer.parseInt(line.trim()); |         		procId = Integer.parseInt(line.trim()); | ||||||
| 
 |  | ||||||
|         		 |  | ||||||
|         		break; |         		break; | ||||||
|         	} |         	} | ||||||
|  |         	catch (NumberFormatException e) | ||||||
|  |         	{ | ||||||
|  |         		logNotice("unable to parse process pid: " + line); | ||||||
|  |         	} | ||||||
|         } |         } | ||||||
|              |              | ||||||
|         |         | ||||||
|  | @ -128,7 +132,7 @@ public class TorServiceUtils implements TorServiceConstants { | ||||||
|          |          | ||||||
|         while ((line = reader.readLine())!=null) |         while ((line = reader.readLine())!=null) | ||||||
|         { |         { | ||||||
|         	if (line.indexOf(command)!=-1) |         	if (line.indexOf(' ' + command)!=-1) | ||||||
|         	{ |         	{ | ||||||
|         		 |         		 | ||||||
|         		StringTokenizer st = new StringTokenizer(line," "); |         		StringTokenizer st = new StringTokenizer(line," "); | ||||||
|  |  | ||||||
|  | @ -42,7 +42,7 @@ public class TorTransProxy implements TorServiceConstants { | ||||||
| 				out = out.substring(out.indexOf(" v")+2); | 				out = out.substring(out.indexOf(" v")+2); | ||||||
| 				out = out.substring(0,out.indexOf(":")); | 				out = out.substring(0,out.indexOf(":")); | ||||||
| 				 | 				 | ||||||
| 				return out; | 				return out.trim(); | ||||||
| 			} | 			} | ||||||
| 			 | 			 | ||||||
| 			 | 			 | ||||||
|  | @ -221,6 +221,15 @@ public class TorTransProxy implements TorServiceConstants { | ||||||
| 				 | 				 | ||||||
| 				logNotice("enabling transproxy for app: " + apps[i].getUsername() + "(" + apps[i].getUid() + ")"); | 				logNotice("enabling transproxy for app: " + apps[i].getUsername() + "(" + apps[i].getUid() + ")"); | ||||||
| 			  | 			  | ||||||
|  | 				/* | ||||||
|  | 				 * iptables -t nat -A OUTPUT -p tcp -m owner --uid-owner anonymous -m tcp --syn -j REDIRECT --to-ports 9040  | ||||||
|  | iptables -t nat -A OUTPUT -p udp -m owner --uid-owner anonymous -m udp --dport 53 -j REDIRECT --to-ports 53  | ||||||
|  | iptables -t nat -A OUTPUT -m owner --uid-owner anonymous -j DROP | ||||||
|  | 				 */ | ||||||
|  | 				 | ||||||
|  | 				 | ||||||
|  | 				//iptables -t nat -A output -p tcp -m owner --uid-owner 100 -m tcp --sync -j REDIRECT --to-ports 9040 | ||||||
|  | 				 | ||||||
| 				//TCP | 				//TCP | ||||||
| 				script.append(baseDir); | 				script.append(baseDir); | ||||||
| 				script.append("iptables -t nat"); | 				script.append("iptables -t nat"); | ||||||
|  | @ -243,7 +252,7 @@ public class TorTransProxy implements TorServiceConstants { | ||||||
| 				script.append("iptables -t nat"); | 				script.append("iptables -t nat"); | ||||||
| 				script.append(" -A OUTPUT -p udp -m owner --uid-owner "); | 				script.append(" -A OUTPUT -p udp -m owner --uid-owner "); | ||||||
| 				script.append(apps[i].getUid()); | 				script.append(apps[i].getUid()); | ||||||
| 				script.append(" --dport ");  | 				script.append(" -m udp --dport ");  | ||||||
| 				script.append(STANDARD_DNS_PORT); | 				script.append(STANDARD_DNS_PORT); | ||||||
| 				 | 				 | ||||||
| 				if (ipTablesOld) | 				if (ipTablesOld) | ||||||
|  | @ -256,15 +265,14 @@ public class TorTransProxy implements TorServiceConstants { | ||||||
| 				script.append(" || exit\n"); | 				script.append(" || exit\n"); | ||||||
| 				 | 				 | ||||||
| 				 | 				 | ||||||
| 				//EVERYTHING ELSE UDP - DROP! | 				//EVERYTHING ELSE - DROP! | ||||||
| 				if (ipTablesOld) //for some reason this doesn't work on iptables 1.3.7 | 				if (ipTablesOld) //for some reason this doesn't work on iptables 1.3.7 | ||||||
| 				{ | 				{ | ||||||
| 					 | 					 | ||||||
| 					script.append(baseDir); | 					script.append("iptables -t nat"); | ||||||
| 					script.append("iptables"); | 					script.append(" -A OUTPUT -m owner --uid-owner "); | ||||||
| 					script.append(" -t nat -A OUTPUT -m owner --uid-owner "); |  | ||||||
| 					script.append(apps[i].getUid()); | 					script.append(apps[i].getUid()); | ||||||
| 					script.append(" -j DROP"); //drop all other packets as Tor won't handle them | 					script.append(" -j DROP");  | ||||||
| 					script.append(" || exit\n"); | 					script.append(" || exit\n"); | ||||||
| 				}	 | 				}	 | ||||||
| 				else | 				else | ||||||
|  | @ -310,5 +318,92 @@ public class TorTransProxy implements TorServiceConstants { | ||||||
| 		return code; | 		return code; | ||||||
|     }	 |     }	 | ||||||
| 	 | 	 | ||||||
|  | 	public static int setTransparentProxyingByPort(Context context, int port) throws Exception | ||||||
|  | 	{ | ||||||
|  | 
 | ||||||
|  | 		//android.os.Debug.waitForDebugger(); | ||||||
|  | 		 | ||||||
|  | 		//redirectDNSResolvConf(); //not working yet | ||||||
|  | 		 | ||||||
|  | 		String baseDir = findBaseDir(); | ||||||
|  | 
 | ||||||
|  | 		String iptablesVersion = getIPTablesVersion(); | ||||||
|  | 		logNotice( "iptables version: " + iptablesVersion); | ||||||
|  | 		 | ||||||
|  | 		boolean ipTablesOld = false; | ||||||
|  | 		if (iptablesVersion != null && iptablesVersion.startsWith("1.3")){ | ||||||
|  | 			ipTablesOld = true; | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  |     	StringBuilder script = new StringBuilder(); | ||||||
|  |     	 | ||||||
|  |     	StringBuilder res = new StringBuilder(); | ||||||
|  |     	int code = -1; | ||||||
|  |     	 | ||||||
|  |     	String[] cmdFlush = {script.toString()}; | ||||||
|  | 		code = TorServiceUtils.doShellCommand(cmdFlush, res, true, true); | ||||||
|  | 		//String msg = res.toString(); //get stdout from command | ||||||
|  | 		 | ||||||
|  | 		script = new StringBuilder(); | ||||||
|  | 		 | ||||||
|  | 		//TCP | ||||||
|  | 		//iptables -t nat -A PREROUTING -i eth0 -p tcp --dport $srcPortNumber -j REDIRECT --to-port $dstPortNumbe | ||||||
|  | 
 | ||||||
|  | 		script.append(baseDir); | ||||||
|  | 		script.append("iptables -t nat"); | ||||||
|  | 		script.append(" -A OUTPUT -p tcp"); | ||||||
|  | 		script.append(" --dport "); | ||||||
|  | 		script.append(port); | ||||||
|  | 		//script.append(" -m tcp --syn"); | ||||||
|  | 		 | ||||||
|  | 		if (ipTablesOld) | ||||||
|  | 			script.append(" -j DNAT --to 127.0.0.1:"); | ||||||
|  | 		else | ||||||
|  | 			script.append(" -j REDIRECT --to-ports "); | ||||||
|  | 		 | ||||||
|  | 		script.append(TOR_TRANSPROXY_PORT); | ||||||
|  | 		 | ||||||
|  | 		script.append(" || exit\n"); | ||||||
|  | 		 | ||||||
|  | 		script.append(baseDir); | ||||||
|  | 		script.append("iptables -t nat"); | ||||||
|  | 		script.append(" -A OUTPUT -p udp"); | ||||||
|  | 		script.append(" --dport "); | ||||||
|  | 		script.append(port); | ||||||
|  | 		 | ||||||
|  | 		if (ipTablesOld) | ||||||
|  | 			script.append(" -j DNAT --to 127.0.0.1:"); | ||||||
|  | 		else | ||||||
|  | 			script.append(" -j REDIRECT --to-ports "); | ||||||
|  | 		 | ||||||
|  | 		script.append(TOR_TRANSPROXY_PORT); | ||||||
|  | 		 | ||||||
|  | 		script.append(" || exit\n"); | ||||||
|  | 		 | ||||||
|  | 		//DNS | ||||||
|  | 		script.append(baseDir); | ||||||
|  | 		script.append("iptables -t nat"); | ||||||
|  | 		script.append(" -A OUTPUT -p udp "); | ||||||
|  | 		script.append(" -m udp --dport ");  | ||||||
|  | 		script.append(STANDARD_DNS_PORT); | ||||||
|  | 		 | ||||||
|  | 		if (ipTablesOld) | ||||||
|  | 			script.append(" -j DNAT --to 127.0.0.1:"); | ||||||
|  | 		else | ||||||
|  | 			script.append(" -j REDIRECT --to-ports "); | ||||||
|  | 		 | ||||||
|  | 		script.append(TOR_DNS_PORT); | ||||||
|  | 		 | ||||||
|  | 		script.append(" || exit\n"); | ||||||
|  | 		 | ||||||
|  |     	 | ||||||
|  |     	String[] cmdAdd = {script.toString()};    	 | ||||||
|  | 		code = TorServiceUtils.doShellCommand(cmdAdd, res, true, true); | ||||||
|  | 		String msg = res.toString(); | ||||||
|  | 		logNotice(cmdAdd[0] + ";errCode=" + code + ";resp=" + msg); | ||||||
|  | 		 | ||||||
|  | 		return code; | ||||||
|  |     }	 | ||||||
|  | 	 | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue