本帖最后由 KnowledgeSeekers 于 2013-11-07 16:24:47 编辑

解决方案 »

  1.   

    更正一下:
    OpenVPN for PC的路由是这样的:
    XX.XX.XX.XX     0.0.0.0         255.255.255.255 H     0      0        0 eth0OpenVPN for Android的路由是这样的:
    XX.XX.XX.XX     0.0.0.0         255.255.255.255 H     0      0        0 tun0上面红色字体部分是改动内容
      

  2.   

    有很多种方法可以重定向的,如果可以root 可以使用SO_BINDTODEVICE来做。如果是UDP,可以打开套接字的IP_PKTINFO来做。不过貌似Android提供了一个接口在VpnService中大概内容如下:public boolean protect (int socket)
    Added in API level 14Protect a socket from VPN connections. The socket will be bound to the current default network interface, so its traffic will not be forwarded through 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.The socket is NOT closed by this method.
    Returns    true on success. 
      

  3.   

    protect这个函数会通过Binder调用到ConnectivityService.java中的protectVpn的函数。
    而ConnectivityService.java中的protectVpn函数,最终会调到jniProtect的函数。而jniProtect这个函数,最终会调用JNI层中com_android_server_connectivity_Vpn.cppprotect的函数。。而protect的函数最终将调用bind_to_interface的函数。而这个函数的定义如下:
    static int bind_to_interface(int socket, const char *name)
    {
        if (setsockopt(socket, SOL_SOCKET, SO_BINDTODEVICE, name, strlen(name))) {
            ALOGE("Cannot bind socket to %s: %s", name, strerror(errno));
            return SYSTEM_ERROR;
        }
        return 0;
    }其实最终他还是使用的SO_BINDTODEVICE给对应的套接字添加了出口标准。来完成的不用明细路由也可指定套接字出口设备的办法。但是当前路由表一定要存在一个可以从指定出口设置发送出去的接口。否则将不能发送出去。
      

  4.   

    既然是需要root才能使用,那他这个protect明确是可以再非root下使用的?