以编程方式连接VPN

时间:2015-07-30 05:16:14

标签: android vpn

我想在我的应用程序中连接VPN。 我从https://github.com/guardianproject/OrbotVPN

下载了演示版
package org.torproject.android.vpn;

import java.io.FileInputStream;
import java.io.FileOutputStream;
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 android.app.PendingIntent;
import android.content.Intent;
import android.net.VpnService;
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;

public class OrbotVpnService extends VpnService implements Handler.Callback, Runnable {
    private static final String TAG = "OrbotVpnService";

    private String mServerAddress = "192.xx.xx.xx";
    private int mServerPort = xxxx;
    private PendingIntent mConfigureIntent;

    private Handler mHandler;
    private Thread mThread;

    private String mSessionName = "OrbotVPN";
    private ParcelFileDescriptor mInterface;

    private int mSocksProxyPort = 9999;

    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();
        }
        // Start a new session by creating a new thread.
        mThread = new Thread(this, "OrbotVpnThread");
        mThread.start();

        startSocksBypass ();

        return START_STICKY;
    }

    private void startSocksBypass ()
    {
        Thread thread = new Thread ()
        {
            public void run ()
            {

                try {

                    final ProxyServer server = new ProxyServer(new ServerAuthenticatorNone(null, null));
                    server.setVpnService(OrbotVpnService.this);
                    server.start(9999, 5, InetAddress.getLocalHost());
                } catch (UnknownHostException e) {
                    e.printStackTrace();
                }
            }
        };

        thread.start();
    }

    @Override
    public void onDestroy() {
        if (mThread != null) {
            mKeepRunning = false;
            mThread.interrupt();
        }
    }

    @Override
    public boolean handleMessage(Message message) {
        if (message != null) {
            Toast.makeText(this, message.what, Toast.LENGTH_SHORT).show();
        }
        return true;
    }

    @Override
    public synchronized void run() {
        try {
            Log.i(TAG, "Starting");

            // If anything needs to be obtained using the network, get it now.
            // This greatly reduces the complexity of seamless handover, which
            // tries to recreate the tunnel without shutting down everything.
            // In this demo, all we need to know is the server address.
            InetSocketAddress server = new InetSocketAddress(
                    mServerAddress, mServerPort);
            mHandler.sendEmptyMessage(R.string.connecting);

            run(server);

              } catch (Exception e) {
            Log.e(TAG, "Got " + e.toString());
            try {
                mInterface.close();
            } catch (Exception e2) {
                // ignore
            }
            mHandler.sendEmptyMessage(R.string.disconnected);

        } finally {

        }
    }
    /*
    @Override
    public synchronized void run() {
        try {
            Log.i(TAG, "Starting");

            // If anything needs to be obtained using the network, get it now.
            // This greatly reduces the complexity of seamless handover, which
            // tries to recreate the tunnel without shutting down everything.
            // In this demo, all we need to know is the server address.
            InetSocketAddress server = new InetSocketAddress(
                    mServerAddress, mServerPort);

            // We try to create the tunnel for several times. The better way
            // is to work with ConnectivityManager, such as trying only when
            // the network is avaiable. Here we just use a counter to keep
            // things simple.
            for (int attempt = 0; attempt < 10; ++attempt) {
                mHandler.sendEmptyMessage(R.string.connecting);

                // Reset the counter if we were connected.
                if (run(server)) {
                    attempt = 0;
                }

                // Sleep for a while. This also checks if we got interrupted.
                Thread.sleep(3000);
            }
            Log.i(TAG, "Giving up");
        } catch (Exception e) {
            Log.e(TAG, "Got " + e.toString());
        } finally {
            try {
                mInterface.close();
            } catch (Exception e) {
                // ignore
            }
            mInterface = null;

            mHandler.sendEmptyMessage(R.string.disconnected);
            Log.i(TAG, "Exiting");
        }
    }*/

    DatagramChannel mTunnel = null;


    private boolean run(InetSocketAddress server) throws Exception {
        boolean connected = false;

            // Create a DatagramChannel as the VPN tunnel.
            mTunnel = DatagramChannel.open();
            DatagramSocket s = mTunnel.socket();

            // Protect the tunnel before connecting to avoid loopback.          
            if (!protect(s)) {
                throw new IllegalStateException("Cannot protect the tunnel");
            }

            mTunnel.connect(server);

            // For simplicity, we use the same thread for both reading and
            // writing. Here we put the tunnel into non-blocking mode.
            mTunnel.configureBlocking(false);

            // Authenticate and configure the virtual network interface.
            handshake();

            // Now we are connected. Set the flag and show the message.
            connected = true;
            mHandler.sendEmptyMessage(R.string.connected);

            new Thread ()
            {

                public void run ()
                {
                  // Allocate the buffer for a single packet.
                    ByteBuffer packet = ByteBuffer.allocate(32767);

                    // Packets to be sent are queued in this input stream.
                    FileInputStream in = new FileInputStream(mInterface.getFileDescriptor());

                    // Packets received need to be written to this output stream.
                    FileOutputStream out = new FileOutputStream(mInterface.getFileDescriptor());

                    // We use a timer to determine the status of the tunnel. It
                    // works on both sides. A positive value means sending, and
                    // any other means receiving. We start with receiving.
                    int timer = 0;
                    Log.d(TAG,"tunnel open:" + mTunnel.isOpen() + " connected:" + mTunnel.isConnected());

                    // We keep forwarding packets till something goes wrong.
                    while (true) {

                        try
                        {
                            // Assume that we did not make any progress in this iteration.
                            boolean idle = true;

                            // Read the outgoing packet from the input stream.
                            int length = in.read(packet.array());
                            if (length > 0) {

                                Log.d(TAG,"got outgoing packet; length=" + length);
                                // Write the outgoing packet to the tunnel.
                                packet.limit(length);                               
                                mTunnel.write(packet);
                                packet.clear();

                                // There might be more outgoing packets.
                                idle = false;

                                // If we were receiving, switch to sending.
                                if (timer < 1) {
                                    timer = 1;
                                }
                            }

                            // Read the incoming packet from the mTunnel.
                            length = mTunnel.read(packet);
                            if (length > 0) {             

                                Log.d(TAG,"got inbound packet; length=" + length);
                                    // Write the incoming packet to the output stream.
                                out.write(packet.array(), 0, length);                        
                                packet.clear();

                                // There might be more incoming packets.
                                idle = false;

                                // If we were sending, switch to receiving.
                                if (timer > 0) {
                                    timer = 0;
                                }
                            }

                            // If we are idle or waiting for the network, sleep for a
                            // fraction of time to avoid busy looping.
                            if (idle) {
                                Thread.sleep(100);

                                // Increase the timer. This is inaccurate but good enough,
                                // since everything is operated in non-blocking mode.
                                timer += (timer > 0) ? 100 : -100;

                                // We are receiving for a long time but not sending.
                                if (timer < -15000) {
                                   // Switch to sending.
                                    timer = 1;
                                }

                                // We are sending for a long time but not receiving.
                                if (timer > 20000) {
                                    //throw new IllegalStateException("Timed out");
                                    //Log.d(TAG,"receiving timed out? timer=" + timer);
                                }
                            }
                        }
                        catch (Exception e)
                        {
                            Log.d(TAG,"error in tunnel",e);
                        }
                    }
                }
            }.start();


        return connected;
    }

    private void handshake() throws Exception {

        if (mInterface == null)
        {
            Builder builder = new Builder();

            builder.setMtu(1500);
            builder.addAddress("10.0.2.0",24);
            builder.setSession("OrbotVPN");             
            builder.addRoute("0.0.0.0",0);
            builder.addDnsServer("8.8.8.8");
       //     builder.addDnsServer("127.0.0.1:5400");
            // 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();
        }
    }

    private void debugPacket(ByteBuffer packet)
    {
        /*
        for(int i = 0; i < length; ++i)
        {
            byte buffer = packet.get();

            Log.d(TAG, "byte:"+buffer);
        }*/



        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
        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());

    }
}

它还与VPN连接并在条​​形图顶部显示关键符号,但在我的服务器Interfaces.Same服务器中没有找到任何服务器条目我在移动网络中注册它已连接,我在服务器接口中找到了服务器条目。

是否需要服务器实施?

上面的VPN服务我错了还是我弄错了?

是否有其他方法可以使用用户名,密码和服务器ID连接VPN?

1 个答案:

答案 0 :(得分:0)

试试这个:

void startVPN(String name) {
    Intent i=new Intent("doenter.onevpn.ACTION_CONNECT");
    i.putExtra("name",name);
    i.putExtra("force", true); 
    i.putExtra("force_same", false); 
    startActivity(i);
}

void restartVPN(String name) {
    Intent i=new Intent("doenter.onevpn.ACTION_CONNECT");
    i.putExtra("name",name);
    i.putExtra("force", true); 
    i.putExtra("force_same", true); 
    startActivity(i);
}

void stopVPN() {
    Intent i=new Intent("doenter.onevpn.ACTION_DISCONNECT");
    // Stops any VPN regardless of name
    startActivity(i);
}