implementing http server for meek-client VPN bypass
This commit is contained in:
parent
bff6d0f567
commit
096eae705b
|
@ -2120,9 +2120,9 @@ public class TorService extends Service implements TorServiceConstants, TorConst
|
||||||
{
|
{
|
||||||
if (mUseVPN) //set the proxy here if we aren't using a bridge
|
if (mUseVPN) //set the proxy here if we aren't using a bridge
|
||||||
{
|
{
|
||||||
String proxyType = "socks5";
|
String proxyType = "http";//"socks5";
|
||||||
String proxyHost = "127.0.0.1";
|
String proxyHost = "10.0.0.1";
|
||||||
int proxyPort = 9999;
|
int proxyPort = 8888;//9999;
|
||||||
updateConfiguration(proxyType + "Proxy", proxyHost + ':' + proxyPort, false);
|
updateConfiguration(proxyType + "Proxy", proxyHost + ':' + proxyPort, false);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2244,11 +2244,11 @@ public class TorService extends Service implements TorServiceConstants, TorConst
|
||||||
|
|
||||||
if (mUseVPN)
|
if (mUseVPN)
|
||||||
{
|
{
|
||||||
proxyType = "socks5";
|
proxyType = "http"; //"socks5";
|
||||||
String proxyHost = "127.0.0.1";
|
String proxyHost = "10.0.0.1";
|
||||||
int proxyPort = 9999;
|
int proxyPort = 8888; //9999;
|
||||||
|
|
||||||
proxyBridge = " proxyurl=" + proxyType + "://" + proxyHost + ':' + proxyPort;
|
proxyBridge = " proxy=" + proxyType + "://" + proxyHost + ':' + proxyPort;
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (proxyType != null && proxyType.length() > 0)
|
else if (proxyType != null && proxyType.length() > 0)
|
||||||
|
|
|
@ -0,0 +1,606 @@
|
||||||
|
package org.torproject.android.vpn;
|
||||||
|
/* <!-- in case someone opens this in a browser... --> <pre> */
|
||||||
|
/*
|
||||||
|
* This is a simple multi-threaded Java proxy server
|
||||||
|
* for HTTP requests (HTTPS doesn't seem to work, because
|
||||||
|
* the CONNECT requests aren't always handled properly).
|
||||||
|
* I implemented the class as a thread so you can call it
|
||||||
|
* from other programs and kill it, if necessary (by using
|
||||||
|
* the closeSocket() method).
|
||||||
|
*
|
||||||
|
* We'll call this the 1.1 version of this class. All I
|
||||||
|
* changed was to separate the HTTP header elements with
|
||||||
|
* \r\n instead of just \n, to comply with the official
|
||||||
|
* HTTP specification.
|
||||||
|
*
|
||||||
|
* This can be used either as a direct proxy to other
|
||||||
|
* servers, or as a forwarding proxy to another proxy
|
||||||
|
* server. This makes it useful if you want to monitor
|
||||||
|
* traffic going to and from a proxy server (for example,
|
||||||
|
* you can run this on your local machine and set the
|
||||||
|
* fwdServer and fwdPort to a real proxy server, and then
|
||||||
|
* tell your browser to use "localhost" as the proxy, and
|
||||||
|
* you can watch the browser traffic going in and out).
|
||||||
|
*
|
||||||
|
* One limitation of this implementation is that it doesn't
|
||||||
|
* close the ProxyThread socket if the client disconnects
|
||||||
|
* or the server never responds, so you could end up with
|
||||||
|
* a bunch of loose threads running amuck and waiting for
|
||||||
|
* connections. As a band-aid, you can set the server socket
|
||||||
|
* to timeout after a certain amount of time (use the
|
||||||
|
* setTimeout() method in the ProxyThread class), although
|
||||||
|
* this can cause false timeouts if a remote server is simply
|
||||||
|
* slow to respond.
|
||||||
|
*
|
||||||
|
* Another thing is that it doesn't limit the number of
|
||||||
|
* socket threads it will create, so if you use this on a
|
||||||
|
* really busy machine that processed a bunch of requests,
|
||||||
|
* you may have problems. You should use thread pools if
|
||||||
|
* you're going to try something like this in a "real"
|
||||||
|
* application.
|
||||||
|
*
|
||||||
|
* Note that if you're using the "main" method to run this
|
||||||
|
* by itself and you don't need the debug output, it will
|
||||||
|
* run a bit faster if you pipe the std output to 'nul'.
|
||||||
|
*
|
||||||
|
* You may use this code as you wish, just don't pretend
|
||||||
|
* that you wrote it yourself, and don't hold me liable for
|
||||||
|
* anything that it does or doesn't do. If you're feeling
|
||||||
|
* especially honest, please include a link to nsftools.com
|
||||||
|
* along with the code. Thanks, and good luck.
|
||||||
|
*
|
||||||
|
* Julian Robichaux -- http://www.nsftools.com
|
||||||
|
*/
|
||||||
|
import java.io.*;
|
||||||
|
import java.net.*;
|
||||||
|
import java.nio.channels.SocketChannel;
|
||||||
|
import java.lang.reflect.Array;
|
||||||
|
|
||||||
|
import android.net.VpnService;
|
||||||
|
|
||||||
|
public class HttpProxy extends Thread
|
||||||
|
{
|
||||||
|
public static final int DEFAULT_PORT = 8080;
|
||||||
|
|
||||||
|
private ServerSocket server = null;
|
||||||
|
private int thisPort = DEFAULT_PORT;
|
||||||
|
private String fwdServer = "";
|
||||||
|
private int fwdPort = 0;
|
||||||
|
private int ptTimeout = ProxyThread.DEFAULT_TIMEOUT;
|
||||||
|
private int debugLevel = 0;
|
||||||
|
private PrintStream debugOut = System.out;
|
||||||
|
|
||||||
|
public static VpnService vpnService;
|
||||||
|
|
||||||
|
/* here's a main method, in case you want to run this by itself */
|
||||||
|
public static void main (String args[])
|
||||||
|
{
|
||||||
|
int port = 0;
|
||||||
|
String fwdProxyServer = "";
|
||||||
|
int fwdProxyPort = 0;
|
||||||
|
|
||||||
|
if (args.length == 0)
|
||||||
|
{
|
||||||
|
System.err.println("USAGE: java HttpProxy <port number> [<fwd proxy> <fwd port>]");
|
||||||
|
System.err.println(" <port number> the port this service listens on");
|
||||||
|
System.err.println(" <fwd proxy> optional proxy server to forward requests to");
|
||||||
|
System.err.println(" <fwd port> the port that the optional proxy server is on");
|
||||||
|
System.err.println("\nHINT: if you don't want to see all the debug information flying by,");
|
||||||
|
System.err.println("you can pipe the output to a file or to 'nul' using \">\". For example:");
|
||||||
|
System.err.println(" to send output to the file prox.txt: java HttpProxy 8080 > prox.txt");
|
||||||
|
System.err.println(" to make the output go away: java HttpProxy 8080 > nul");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the command-line parameters
|
||||||
|
port = Integer.parseInt(args[0]);
|
||||||
|
if (args.length > 2)
|
||||||
|
{
|
||||||
|
fwdProxyServer = args[1];
|
||||||
|
fwdProxyPort = Integer.parseInt(args[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// create and start the HttpProxy thread, using a 20 second timeout
|
||||||
|
// value to keep the threads from piling up too much
|
||||||
|
System.err.println(" ** Starting HttpProxy on port " + port + ". Press CTRL-C to end. **\n");
|
||||||
|
HttpProxy jp = new HttpProxy(port, fwdProxyServer, fwdProxyPort, 20);
|
||||||
|
jp.setDebug(1, System.out); // or set the debug level to 2 for tons of output
|
||||||
|
jp.start();
|
||||||
|
|
||||||
|
// run forever; if you were calling this class from another
|
||||||
|
// program and you wanted to stop the HttpProxy thread at some
|
||||||
|
// point, you could write a loop that waits for a certain
|
||||||
|
// condition and then calls HttpProxy.closeSocket() to kill
|
||||||
|
// the running HttpProxy thread
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
try { Thread.sleep(3000); } catch (Exception e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we ever had a condition that stopped the loop above,
|
||||||
|
// we'd want to do this to kill the running thread
|
||||||
|
//jp.closeSocket();
|
||||||
|
//return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* the proxy server just listens for connections and creates
|
||||||
|
* a new thread for each connection attempt (the ProxyThread
|
||||||
|
* class really does all the work)
|
||||||
|
*/
|
||||||
|
public HttpProxy (int port)
|
||||||
|
{
|
||||||
|
thisPort = port;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpProxy (int port, String proxyServer, int proxyPort)
|
||||||
|
{
|
||||||
|
thisPort = port;
|
||||||
|
fwdServer = proxyServer;
|
||||||
|
fwdPort = proxyPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HttpProxy (int port, String proxyServer, int proxyPort, int timeout)
|
||||||
|
{
|
||||||
|
thisPort = port;
|
||||||
|
fwdServer = proxyServer;
|
||||||
|
fwdPort = proxyPort;
|
||||||
|
ptTimeout = timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setVpnService (final VpnService v)
|
||||||
|
{
|
||||||
|
vpnService = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* allow the user to decide whether or not to send debug
|
||||||
|
* output to the console or some other PrintStream
|
||||||
|
*/
|
||||||
|
public void setDebug (int level, PrintStream out)
|
||||||
|
{
|
||||||
|
debugLevel = level;
|
||||||
|
debugOut = out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* get the port that we're supposed to be listening on
|
||||||
|
*/
|
||||||
|
public int getPort ()
|
||||||
|
{
|
||||||
|
return thisPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* return whether or not the socket is currently open
|
||||||
|
*/
|
||||||
|
public boolean isRunning ()
|
||||||
|
{
|
||||||
|
if (server == null)
|
||||||
|
return false;
|
||||||
|
else
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* closeSocket will close the open ServerSocket; use this
|
||||||
|
* to halt a running HttpProxy thread
|
||||||
|
*/
|
||||||
|
public void closeSocket ()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// close the open server socket
|
||||||
|
server.close();
|
||||||
|
// send it a message to make it stop waiting immediately
|
||||||
|
// (not really necessary)
|
||||||
|
/*Socket s = new Socket("localhost", thisPort);
|
||||||
|
OutputStream os = s.getOutputStream();
|
||||||
|
os.write((byte)0);
|
||||||
|
os.close();
|
||||||
|
s.close();*/
|
||||||
|
} catch(Exception e) {
|
||||||
|
if (debugLevel > 0)
|
||||||
|
debugOut.println(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
server = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void run()
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
// create a server socket, and loop forever listening for
|
||||||
|
// client connections
|
||||||
|
server = new ServerSocket(thisPort);
|
||||||
|
if (debugLevel > 0)
|
||||||
|
debugOut.println("Started HttpProxy on port " + thisPort);
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
Socket client = server.accept();
|
||||||
|
HttpProxy.vpnService.protect(client);
|
||||||
|
ProxyThread t = new ProxyThread(client, fwdServer, fwdPort);
|
||||||
|
t.setDebug(debugLevel, debugOut);
|
||||||
|
t.setTimeout(ptTimeout);
|
||||||
|
t.start();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
if (debugLevel > 0)
|
||||||
|
debugOut.println("HttpProxy Thread error: " + e);
|
||||||
|
}
|
||||||
|
|
||||||
|
closeSocket();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The ProxyThread will take an HTTP request from the client
|
||||||
|
* socket and send it to either the server that the client is
|
||||||
|
* trying to contact, or another proxy server
|
||||||
|
*/
|
||||||
|
class ProxyThread extends Thread
|
||||||
|
{
|
||||||
|
private Socket pSocket;
|
||||||
|
private String fwdServer = "";
|
||||||
|
private int fwdPort = 0;
|
||||||
|
private int debugLevel = 0;
|
||||||
|
private PrintStream debugOut = System.out;
|
||||||
|
|
||||||
|
// the socketTimeout is used to time out the connection to
|
||||||
|
// the remote server after a certain period of inactivity;
|
||||||
|
// the value is in milliseconds -- use zero if you don't want
|
||||||
|
// a timeout
|
||||||
|
public static final int DEFAULT_TIMEOUT = 20 * 1000;
|
||||||
|
private int socketTimeout = DEFAULT_TIMEOUT;
|
||||||
|
|
||||||
|
|
||||||
|
public ProxyThread(Socket s)
|
||||||
|
{
|
||||||
|
pSocket = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ProxyThread(Socket s, String proxy, int port)
|
||||||
|
{
|
||||||
|
pSocket = s;
|
||||||
|
fwdServer = proxy;
|
||||||
|
fwdPort = port;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void setTimeout (int timeout)
|
||||||
|
{
|
||||||
|
// assume that the user will pass the timeout value
|
||||||
|
// in seconds (because that's just more intuitive)
|
||||||
|
socketTimeout = timeout * 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void setDebug (int level, PrintStream out)
|
||||||
|
{
|
||||||
|
debugLevel = level;
|
||||||
|
debugOut = out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void run()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
long startTime = System.currentTimeMillis();
|
||||||
|
|
||||||
|
// client streams (make sure you're using streams that use
|
||||||
|
// byte arrays, so things like GIF and JPEG files and file
|
||||||
|
// downloads will transfer properly)
|
||||||
|
BufferedInputStream clientIn = new BufferedInputStream(pSocket.getInputStream());
|
||||||
|
BufferedOutputStream clientOut = new BufferedOutputStream(pSocket.getOutputStream());
|
||||||
|
|
||||||
|
// the socket to the remote server
|
||||||
|
Socket server = null;
|
||||||
|
|
||||||
|
// other variables
|
||||||
|
byte[] request = null;
|
||||||
|
byte[] response = null;
|
||||||
|
int requestLength = 0;
|
||||||
|
int responseLength = 0;
|
||||||
|
int pos = -1;
|
||||||
|
StringBuffer host = new StringBuffer("");
|
||||||
|
String hostName = "";
|
||||||
|
int hostPort = 80;
|
||||||
|
|
||||||
|
// get the header info (the web browser won't disconnect after
|
||||||
|
// it's sent a request, so make sure the waitForDisconnect
|
||||||
|
// parameter is false)
|
||||||
|
request = getHTTPData(clientIn, host, false);
|
||||||
|
requestLength = Array.getLength(request);
|
||||||
|
|
||||||
|
// separate the host name from the host port, if necessary
|
||||||
|
// (like if it's "servername:8000")
|
||||||
|
hostName = host.toString();
|
||||||
|
pos = hostName.indexOf(":");
|
||||||
|
if (pos > 0)
|
||||||
|
{
|
||||||
|
try { hostPort = Integer.parseInt(hostName.substring(pos + 1));
|
||||||
|
} catch (Exception e) { }
|
||||||
|
hostName = hostName.substring(0, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
// either forward this request to another proxy server or
|
||||||
|
// send it straight to the Host
|
||||||
|
try
|
||||||
|
{
|
||||||
|
server = SocketChannel.open().socket();
|
||||||
|
|
||||||
|
if ((null != server) && (null != HttpProxy.vpnService)) {
|
||||||
|
HttpProxy.vpnService.protect(server);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((fwdServer.length() > 0) && (fwdPort > 0))
|
||||||
|
{
|
||||||
|
//server = new Socket(fwdServer, fwdPort);
|
||||||
|
server.connect(new InetSocketAddress(fwdServer, fwdPort));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
//server = new Socket(hostName, hostPort);
|
||||||
|
server.connect(new InetSocketAddress(hostName, hostPort));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HttpProxy.vpnService.protect(server);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
// tell the client there was an error
|
||||||
|
String errMsg = "HTTP/1.0 500\nContent Type: text/plain\n\n" +
|
||||||
|
"Error connecting to the server:\n" + e + "\n";
|
||||||
|
clientOut.write(errMsg.getBytes(), 0, errMsg.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (server != null)
|
||||||
|
{
|
||||||
|
server.setSoTimeout(socketTimeout);
|
||||||
|
BufferedInputStream serverIn = new BufferedInputStream(server.getInputStream());
|
||||||
|
BufferedOutputStream serverOut = new BufferedOutputStream(server.getOutputStream());
|
||||||
|
|
||||||
|
// send the request out
|
||||||
|
serverOut.write(request, 0, requestLength);
|
||||||
|
serverOut.flush();
|
||||||
|
|
||||||
|
// and get the response; if we're not at a debug level that
|
||||||
|
// requires us to return the data in the response, just stream
|
||||||
|
// it back to the client to save ourselves from having to
|
||||||
|
// create and destroy an unnecessary byte array. Also, we
|
||||||
|
// should set the waitForDisconnect parameter to 'true',
|
||||||
|
// because some servers (like Google) don't always set the
|
||||||
|
// Content-Length header field, so we have to listen until
|
||||||
|
// they decide to disconnect (or the connection times out).
|
||||||
|
if (debugLevel > 1)
|
||||||
|
{
|
||||||
|
response = getHTTPData(serverIn, true);
|
||||||
|
responseLength = Array.getLength(response);
|
||||||
|
} else {
|
||||||
|
responseLength = streamHTTPData(serverIn, clientOut, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
serverIn.close();
|
||||||
|
serverOut.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// send the response back to the client, if we haven't already
|
||||||
|
if (debugLevel > 1)
|
||||||
|
clientOut.write(response, 0, responseLength);
|
||||||
|
|
||||||
|
// if the user wants debug info, send them debug info; however,
|
||||||
|
// keep in mind that because we're using threads, the output won't
|
||||||
|
// necessarily be synchronous
|
||||||
|
if (debugLevel > 0)
|
||||||
|
{
|
||||||
|
long endTime = System.currentTimeMillis();
|
||||||
|
debugOut.println("Request from " + pSocket.getInetAddress().getHostAddress() +
|
||||||
|
" on Port " + pSocket.getLocalPort() +
|
||||||
|
" to host " + hostName + ":" + hostPort +
|
||||||
|
"\n (" + requestLength + " bytes sent, " +
|
||||||
|
responseLength + " bytes returned, " +
|
||||||
|
Long.toString(endTime - startTime) + " ms elapsed)");
|
||||||
|
debugOut.flush();
|
||||||
|
}
|
||||||
|
if (debugLevel > 1)
|
||||||
|
{
|
||||||
|
debugOut.println("REQUEST:\n" + (new String(request)));
|
||||||
|
debugOut.println("RESPONSE:\n" + (new String(response)));
|
||||||
|
debugOut.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
// close all the client streams so we can listen again
|
||||||
|
clientOut.close();
|
||||||
|
clientIn.close();
|
||||||
|
pSocket.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
if (debugLevel > 0)
|
||||||
|
debugOut.println("Error in ProxyThread: " + e);
|
||||||
|
//e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private byte[] getHTTPData (InputStream in, boolean waitForDisconnect)
|
||||||
|
{
|
||||||
|
// get the HTTP data from an InputStream, and return it as
|
||||||
|
// a byte array
|
||||||
|
// the waitForDisconnect parameter tells us what to do in case
|
||||||
|
// the HTTP header doesn't specify the Content-Length of the
|
||||||
|
// transmission
|
||||||
|
StringBuffer foo = new StringBuffer("");
|
||||||
|
return getHTTPData(in, foo, waitForDisconnect);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private byte[] getHTTPData (InputStream in, StringBuffer host, boolean waitForDisconnect)
|
||||||
|
{
|
||||||
|
// get the HTTP data from an InputStream, and return it as
|
||||||
|
// a byte array, and also return the Host entry in the header,
|
||||||
|
// if it's specified -- note that we have to use a StringBuffer
|
||||||
|
// for the 'host' variable, because a String won't return any
|
||||||
|
// information when it's used as a parameter like that
|
||||||
|
ByteArrayOutputStream bs = new ByteArrayOutputStream();
|
||||||
|
streamHTTPData(in, bs, host, waitForDisconnect);
|
||||||
|
return bs.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private int streamHTTPData (InputStream in, OutputStream out, boolean waitForDisconnect)
|
||||||
|
{
|
||||||
|
StringBuffer foo = new StringBuffer("");
|
||||||
|
return streamHTTPData(in, out, foo, waitForDisconnect);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int streamHTTPData (InputStream in, OutputStream out,
|
||||||
|
StringBuffer host, boolean waitForDisconnect)
|
||||||
|
{
|
||||||
|
// get the HTTP data from an InputStream, and send it to
|
||||||
|
// the designated OutputStream
|
||||||
|
StringBuffer header = new StringBuffer("");
|
||||||
|
String data = "";
|
||||||
|
int responseCode = 200;
|
||||||
|
int contentLength = 0;
|
||||||
|
int pos = -1;
|
||||||
|
int byteCount = 0;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// get the first line of the header, so we know the response code
|
||||||
|
data = readLine(in);
|
||||||
|
if (data != null)
|
||||||
|
{
|
||||||
|
header.append(data + "\r\n");
|
||||||
|
pos = data.indexOf(" ");
|
||||||
|
if ((data.toLowerCase().startsWith("http")) &&
|
||||||
|
(pos >= 0) && (data.indexOf(" ", pos+1) >= 0))
|
||||||
|
{
|
||||||
|
String rcString = data.substring(pos+1, data.indexOf(" ", pos+1));
|
||||||
|
try
|
||||||
|
{
|
||||||
|
responseCode = Integer.parseInt(rcString);
|
||||||
|
} catch (Exception e) {
|
||||||
|
if (debugLevel > 0)
|
||||||
|
debugOut.println("Error parsing response code " + rcString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the rest of the header info
|
||||||
|
while ((data = readLine(in)) != null)
|
||||||
|
{
|
||||||
|
// the header ends at the first blank line
|
||||||
|
if (data.length() == 0)
|
||||||
|
break;
|
||||||
|
header.append(data + "\r\n");
|
||||||
|
|
||||||
|
// check for the Host header
|
||||||
|
pos = data.toLowerCase().indexOf("host:");
|
||||||
|
if (pos >= 0)
|
||||||
|
{
|
||||||
|
host.setLength(0);
|
||||||
|
host.append(data.substring(pos + 5).trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for the Content-Length header
|
||||||
|
pos = data.toLowerCase().indexOf("content-length:");
|
||||||
|
if (pos >= 0)
|
||||||
|
contentLength = Integer.parseInt(data.substring(pos + 15).trim());
|
||||||
|
}
|
||||||
|
|
||||||
|
// add a blank line to terminate the header info
|
||||||
|
header.append("\r\n");
|
||||||
|
|
||||||
|
// convert the header to a byte array, and write it to our stream
|
||||||
|
out.write(header.toString().getBytes(), 0, header.length());
|
||||||
|
|
||||||
|
// if the header indicated that this was not a 200 response,
|
||||||
|
// just return what we've got if there is no Content-Length,
|
||||||
|
// because we may not be getting anything else
|
||||||
|
if ((responseCode != 200) && (contentLength == 0))
|
||||||
|
{
|
||||||
|
out.flush();
|
||||||
|
return header.length();
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the body, if any; we try to use the Content-Length header to
|
||||||
|
// determine how much data we're supposed to be getting, because
|
||||||
|
// sometimes the client/server won't disconnect after sending us
|
||||||
|
// information...
|
||||||
|
if (contentLength > 0)
|
||||||
|
waitForDisconnect = false;
|
||||||
|
|
||||||
|
if ((contentLength > 0) || (waitForDisconnect))
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
byte[] buf = new byte[4096];
|
||||||
|
int bytesIn = 0;
|
||||||
|
while ( ((byteCount < contentLength) || (waitForDisconnect))
|
||||||
|
&& ((bytesIn = in.read(buf)) >= 0) )
|
||||||
|
{
|
||||||
|
out.write(buf, 0, bytesIn);
|
||||||
|
byteCount += bytesIn;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
String errMsg = "Error getting HTTP body: " + e;
|
||||||
|
if (debugLevel > 0)
|
||||||
|
debugOut.println(errMsg);
|
||||||
|
//bs.write(errMsg.getBytes(), 0, errMsg.length());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
if (debugLevel > 0)
|
||||||
|
debugOut.println("Error getting HTTP data: " + e);
|
||||||
|
}
|
||||||
|
|
||||||
|
//flush the OutputStream and return
|
||||||
|
try { out.flush(); } catch (Exception e) {}
|
||||||
|
return (header.length() + byteCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private String readLine (InputStream in)
|
||||||
|
{
|
||||||
|
// reads a line of text from an InputStream
|
||||||
|
StringBuffer data = new StringBuffer("");
|
||||||
|
int c;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// if we have nothing to read, just return null
|
||||||
|
in.mark(1);
|
||||||
|
if (in.read() == -1)
|
||||||
|
return null;
|
||||||
|
else
|
||||||
|
in.reset();
|
||||||
|
|
||||||
|
while ((c = in.read()) >= 0)
|
||||||
|
{
|
||||||
|
// check for an end-of-line character
|
||||||
|
if ((c == 0) || (c == 10) || (c == 13))
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
data.append((char)c);
|
||||||
|
}
|
||||||
|
|
||||||
|
// deal with the case where the end-of-line terminator is \r\n
|
||||||
|
if (c == 13)
|
||||||
|
{
|
||||||
|
in.mark(1);
|
||||||
|
if (in.read() != 10)
|
||||||
|
in.reset();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
if (debugLevel > 0)
|
||||||
|
debugOut.println("Error getting header: " + e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// and return what we have
|
||||||
|
return data.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -52,9 +52,11 @@ public class OrbotVpnService extends VpnService implements Handler.Callback {
|
||||||
private ParcelFileDescriptor mInterface;
|
private ParcelFileDescriptor mInterface;
|
||||||
|
|
||||||
private int mSocksProxyPort = 9999;
|
private int mSocksProxyPort = 9999;
|
||||||
private ProxyServer mProxyServer;
|
private ProxyServer mSocksProxyServer;
|
||||||
private Thread mThreadProxy;
|
private Thread mThreadProxy;
|
||||||
|
|
||||||
|
private HttpProxy mHttpProxyServer;
|
||||||
|
|
||||||
private final static int VPN_MTU = 1500;
|
private final static int VPN_MTU = 1500;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -112,9 +114,9 @@ public class OrbotVpnService extends VpnService implements Handler.Callback {
|
||||||
{
|
{
|
||||||
|
|
||||||
try {
|
try {
|
||||||
mProxyServer = new ProxyServer(new ServerAuthenticatorNone(null, null));
|
mSocksProxyServer = new ProxyServer(new ServerAuthenticatorNone(null, null));
|
||||||
ProxyServer.setVpnService(OrbotVpnService.this);
|
ProxyServer.setVpnService(OrbotVpnService.this);
|
||||||
mProxyServer.start(mSocksProxyPort, 5, InetAddress.getLocalHost());
|
mSocksProxyServer.start(mSocksProxyPort, 5, InetAddress.getLocalHost());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Log.d(TAG,"proxy server error: " + e.getLocalizedMessage(),e);
|
Log.d(TAG,"proxy server error: " + e.getLocalizedMessage(),e);
|
||||||
}
|
}
|
||||||
|
@ -122,6 +124,11 @@ public class OrbotVpnService extends VpnService implements Handler.Callback {
|
||||||
};
|
};
|
||||||
|
|
||||||
mThreadProxy.start();
|
mThreadProxy.start();
|
||||||
|
|
||||||
|
mHttpProxyServer = new HttpProxy(8888);
|
||||||
|
HttpProxy.setVpnService(OrbotVpnService.this);
|
||||||
|
mHttpProxyServer.setDebug(5, System.out);
|
||||||
|
mHttpProxyServer.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -132,10 +139,16 @@ public class OrbotVpnService extends VpnService implements Handler.Callback {
|
||||||
|
|
||||||
private void stopVPN ()
|
private void stopVPN ()
|
||||||
{
|
{
|
||||||
if (mProxyServer != null){
|
if (mSocksProxyServer != null){
|
||||||
mProxyServer.stop();
|
mSocksProxyServer.stop();
|
||||||
mProxyServer = null;
|
mSocksProxyServer = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mHttpProxyServer != null)
|
||||||
|
{
|
||||||
|
mHttpProxyServer.closeSocket();
|
||||||
|
}
|
||||||
|
|
||||||
if (mInterface != null){
|
if (mInterface != null){
|
||||||
onRevoke();
|
onRevoke();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue