簡體   English   中英

Android VpnService如何保護fd工作?

[英]How does Android VpnService protect fd work?

根據https://developer.android.com/reference/android/net/VpnService.html#protect(int)

保護套接字免受VPN連接后,通過此套接字發送的數據將直接進入底層網絡,因此其流量不會通過VPN轉發。 如果某些連接需要保留在VPN之外,則此方法很有用。 例如,如果VPN路由覆蓋其目的地,則VPN隧道應該自我保護。 否則,其傳出的數據包將被發送回VPN接口並導致無限循環。 如果應用程序未准備好或已撤銷,則此方法將失敗。

我知道Android是建立在Linux之上的,這個函數背后使用了什么Linux機制或工具,只是通過這個套接字發送數據繞過VPN,但所有其他的都通過VPN?

簡而言之,Android VPNService通過策略路由保護fd工作,所有通過protected fd數據包都會標記一個特殊的fwmark ,所有帶有這個fwmark數據包都會繞過VPN。

關鍵代碼段如下所示:

// android/frameworks/base/core/java/android/net/VpnService.java

 /**
     * Protect a socket from VPN connections. After protecting, data sent
     * through this socket will go directly to the underlying network,
     * so its traffic will not be forwarded through the VPN.
     * This method is useful if some connections need to be kept
     * outside of VPN. For example, a VPN tunnel should protect itself if its
     * destination is covered by VPN routes. Otherwise its outgoing packets
     * will be sent back to the VPN interface and cause an infinite loop. This
     * method will fail if the application is not prepared or is revoked.
     *
     * <p class="note">The socket is NOT closed by this method.
     *
     * @return {@code true} on success.
     */
    public boolean protect(int socket) {
        return NetworkUtils.protectFromVpn(socket);
    }


// android/frameworks/base/core/java/android/net/VpnService.java

    /**
     * Protect {@code fd} from VPN connections.  After protecting, data sent through
     * this socket will go directly to the underlying network, so its traffic will not be
     * forwarded through the VPN.
     */
    public static boolean protectFromVpn(FileDescriptor fd) {
        return protectFromVpn(fd.getInt$());
    }

// android/system/netd/server/FwmarkServer.cpp

    fwmark.permission = permission;

    if (setsockopt(*socketFd, SOL_SOCKET, SO_MARK, &fwmark.intValue,
                   sizeof(fwmark.intValue)) == -1) {
        return -errno;
    }


// android/system/netd/include/Fwmark.h 

union Fwmark {
    uint32_t intValue;
    struct {
        unsigned netId          : 16;
        bool explicitlySelected :  1;
        bool protectedFromVpn   :  1;
        Permission permission   :  2;
    };
    Fwmark() : intValue(0) {}
};

static const unsigned FWMARK_NET_ID_MASK = 0xffff;

在打開VPN服務的應用程序之后的路由策略示例:

root@CP8692:/ # ip rule
0:  from all lookup local 
10000:  from all fwmark 0xc0000/0xd0000 lookup legacy_system 
11000:  from all iif tun0 lookup local_network 
12000:  from all fwmark 0xc0072/0xcffff lookup tun0 
12000:  from all fwmark 0x0/0x20000 uidrange 0-99999 lookup tun0 
13000:  from all fwmark 0x10063/0x1ffff lookup local_network 
13000:  from all fwmark 0x10071/0x1ffff lookup wlan0 
13000:  from all fwmark 0x10072/0x1ffff uidrange 0-0 lookup tun0 
13000:  from all fwmark 0x10072/0x1ffff uidrange 0-99999 lookup tun0 
14000:  from all oif wlan0 lookup wlan0 
14000:  from all oif tun0 uidrange 0-99999 lookup tun0 
15000:  from all fwmark 0x0/0x10000 lookup legacy_system 
16000:  from all fwmark 0x0/0x10000 lookup legacy_network 
17000:  from all fwmark 0x0/0x10000 lookup local_network 
19000:  from all fwmark 0x71/0x1ffff lookup wlan0 
21000:  from all fwmark 0x72/0x1ffff lookup wlan0 
22000:  from all fwmark 0x0/0xffff lookup wlan0 
23000:  from all fwmark 0x0/0xffff uidrange 0-0 lookup main 
32000:  from all unreachable

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM