1. 程式人生 > >android4.4.2 VPN路由配置過程分析,ppp0預設路由設定過程分析

android4.4.2 VPN路由配置過程分析,ppp0預設路由設定過程分析

Android VPN啟動後會up一個ppp0的網路裝置,此網路裝置就是應用翻牆要發向的裝置。目前我的理解是,看下面的路由表,ppp0有一個預設路由所有的資料都先通過預設路由傳送到ppp0上,然後通過WIFI裝置的預設路由傳送出去。

//路由表:
[email protected]_sp7715ga:/ # busybox route                                         
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
default         *               0.0.0.0         U     0      0        0 ppp0
default         192.168.43.1    0.0.0.0         UG    207    0        0 wlan0
192.168.2.10    *               255.255.255.255 UH    0      0        0 ppp0
192.168.43.0    *               255.255.255.0   U     207    0        0 wlan0

//pppd啟動,有本地IP和一個遠端IP,所有的包都通過PPP協議將資料包發到遠端伺服器上,由於第三方應用的資料,所有的DNS請求都要傳送到8.8.8.8
05-01 10:44:01.434 I/mtpd    ( 1493): Starting pppd (pppox = 12)
05-01 10:44:01.494 I/pppd    ( 1495): Using PPPoX (socket = 12)
05-01 10:44:01.504 D/pppd    ( 1495): using channel 1
05-01 10:44:01.524 I/pppd    ( 1495): Using interface ppp0
05-01 10:44:01.524 I/pppd    ( 1495): Connect: ppp0 <-->
05-01 10:44:05.174 I/pppd    ( 1495): MPPE 128-bit stateless compression enabled
05-01 10:44:06.784 I/pppd    ( 1495): local  IP address 192.168.2.16
05-01 10:44:06.784 I/pppd    ( 1495): remote IP address 192.168.2.10
05-01 10:44:06.784 I/pppd    ( 1495): primary   DNS address 209.11.240.36
05-01 10:44:06.784 I/pppd    ( 1495): secondary DNS address 8.8.8.8



追蹤預設路由的新增過程,見LOG
05-01 10:43:24.434 D/WirelessSettings(  754): onPreferenceTreeClick: preference=VPN
05-01 10:43:58.014 I/Vpn     (  554): Switched from [Legacy VPN] to [Legacy VPN]
05-01 10:44:06.814 D/VPN     (  554): mConfig.routes is null.  add route parameters[2]=0.0.0.0/0
05-01 10:44:07.074 D/VPN     (  554): set the routes:[0.0.0.0/0 -> 0.0.0.0]
05-01 10:44:07.074 D/VPN     (  554): setRoutes route=0.0.0.0/0 -> 0.0.0.0

//程式碼解析,並添加里部分LOG
packages\apps\settings\src\com\android\settings\vpn2\VpnSettings.java
onClick(DialogInterface dialog, int button) --> connect(profile) -->mService.startLegacyVpn(profile)  

frameworks\base\services\java\com\android\server\ConnectivityService.java
startLegacyVpn(VpnProfile profile)  --> mVpns.get(user).startLegacyVpn(profile, mKeyStore, egress)

frameworks\base\services\java\com\android\server\connectivity\Vpn.java
startLegacyVpn(VpnProfile profile, KeyStore keyStore, LinkProperties egress)  --> startLegacyVpn(VpnConfig config, String[] racoon, String[] mtpd) --> mLegacyVpnRunner = new LegacyVpnRunner(config, racoon, mtpd); mLegacyVpnRunner.start(); // Start a new LegacyVpnRunner and we are done!

frameworks\base\services\java\com\android\server\connectivity\Vpn.java
private class LegacyVpnRunner extends Thread
run() --> execute() {

                // Set the routes if they are not set in the config.
                if (mConfig.routes == null || mConfig.routes.isEmpty()) {
                    Slog.d("VPN", "mConfig.routes is null.  add route parameters[2]=" + parameters[2]);
                    mConfig.addLegacyRoutes(parameters[2]);
                }

}     


//新增VPN的DNS 8.8.8.8
                // Set the DNS servers if they are not set in the config.
                if (mConfig.dnsServers == null || mConfig.dnsServers.size() == 0) {
                    String dnsServers = parameters[3].trim();
                    if (!dnsServers.isEmpty()) {
                        mConfig.dnsServers = Arrays.asList(dnsServers.split(" "));
                    }
                }


//parameters哪裡來的?
frameworks\base\services\java\com\android\server\connectivity\Vpn.java
                // Now we are connected. Read and parse the new state.
                String[] parameters = FileUtils.readTextFile(state, 0, null).split("\n", -1); //state 檔案哪裡來的?
                if (parameters.length != 6) {
                    throw new IllegalStateException("Cannot parse the state");
                }


//LegacyVpnRunner執行緒執行run->execute()
frameworks\base\services\java\com\android\server\connectivity\Vpn.java
private class LegacyVpnRunner extends Thread {
        private void execute() {
            // Catch all exceptions so we can clean up few things.
            boolean initFinished = false;
            try {
                // Initialize the timer.
                checkpoint(false);

                // Wait for the daemons to stop.
                for (String daemon : mDaemons) {
                    while (!SystemService.isStopped(daemon)) {
                        checkpoint(true);
                    }
                }

                // Clear the previous state.
                File state = new File("/data/misc/vpn/state");
                state.delete();
                if (state.exists()) {
                    throw new IllegalStateException("Cannot delete the state");
                }
                new File("/data/misc/vpn/abort").delete();
                initFinished = true;

                 //省略一部分程式碼
                 ......
                 ......
                 ......

                // Wait for the daemons to create the new state.  //deamons建立的檔案,那他們是誰?
                while (!state.exists()) {
                    // Check if a running daemon is dead.
                    for (int i = 0; i < mDaemons.length; ++i) {
                        String daemon = mDaemons[i];
                        if (mArguments[i] != null && !SystemService.isRunning(daemon)) {
                            throw new IllegalStateException(daemon + " is dead");
                        }
                    }
                    checkpoint(true);
                }

//原來deamons是他們"racoon", "mtpd"
frameworks\base\services\java\com\android\server\connectivity\Vpn.java
        public LegacyVpnRunner(VpnConfig config, String[] racoon, String[] mtpd) {
            super(TAG);
            mConfig = config;
            mDaemons = new String[] {"racoon", "mtpd"};


//我們看看這個檔案state
[email protected]
_sp7715ga:/data/misc/vpn # cat state                                
ppp0
192.168.2.16/32
0.0.0.0/0
209.11.240.36 8.8.8.8


//上接execute()的
frameworks\base\core\java\com\android\internal\net\VpnConfig.java

    public void addLegacyRoutes(String routesStr) {
        if (routesStr.trim().equals("")) {
            return;
        }
        String[] routes = routesStr.trim().split(" ");
        for (String route : routes) {
            //each route is ip/prefix
            String[] split = route.split("/");
            RouteInfo info = new RouteInfo(new LinkAddress
                    (InetAddress.parseNumericAddress(split[0]), Integer.parseInt(split[1])), null);
            this.routes.add(info);  //新增到List routes中。
        }
    }



frameworks\base\services\java\com\android\server\connectivity\Vpn.java

                long token = Binder.clearCallingIdentity();
                try {
                    mCallback.setMarkedForwarding(mConfig.interfaze);
                    Slog.d("VPN", "set the routes:" + mConfig.routes.toString());
                    mCallback.setRoutes(mConfig.interfaze, mConfig.routes);   //將List routes的路由都新增到路由表中
                } finally {
                    Binder.restoreCallingIdentity(token);
                }
 

//最終還是由ConnectivityService的介面來新增ppp0的預設路由,這也是開頭我們說的地方。
frameworks\base\services\java\com\android\server\ConnectivityService.java
public class VpnCallback {
        public void setRoutes(String interfaze, List<RouteInfo> routes) {
            for (RouteInfo route : routes) {
                try {
                    //@bug302150  //android4.4.2 vpn就有bug。
                    //mNetd.setMarkedForwardingRoute(interfaze, route);
                    Slog.d("VPN", "setRoutes route=" + route);
                    mNetd.addRoute(interfaze, route);
                } catch (RemoteException e) {
                }
            }
        }