Android 网络共享

Tethering

Posted by LXG on July 3, 2021

网络共享-AOSP

rk-ethernet-github

RK3288-7.1下实现4G路由功能-CSDN

移动网络共享到以太网

RK3288 android 7.1

  1. 实现4G和以太网共存—《Android 支持双以太网卡补丁20180108》
  2. 再把4G信号通过iptables实现路由转发

开启双以太网共存

adb shell setprop persist.net.ethernet.mode multi

adb路由转发

  1. ip rule add from all lookup main pref 9999
  2. ifconfig eth0 down
  3. ifconfig eth0 up
  4. busybox ifconfig eth0 192.168.43.1
  5. ndc netd 5003 tether start 192.168.43.2 192.168.43.254
  6. ndc netd 7 nat enable eth0 usb0 1 10.80.71.155/24 (4G ip)
  7. echo 1 > /proc/sys/net/ipv4/ip_forward
  8. getprop grep dns
  9. iptables -t nat -I PREROUTING -i eth0 -p udp –dport 53 -j DNAT –to-destination 120.196.165.7(usb0 dns)

ifconfig

网络共享前


$ ifconfig
lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0 
          inet6 addr: ::1/128 Scope: Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:10 errors:0 dropped:0 overruns:0 frame:0 
          TX packets:10 errors:0 dropped:0 overruns:0 carrier:0 
          collisions:0 txqueuelen:1 
          RX bytes:762 TX bytes:762 

eth0      Link encap:Ethernet  HWaddr 8a:5b:57:f2:44:77
          inet6 addr: fe80::885b:57ff:fef2:4477/64 Scope: Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:2 errors:0 dropped:0 overruns:0 frame:0 
          TX packets:56 errors:0 dropped:0 overruns:0 carrier:0 
          collisions:0 txqueuelen:1000 
          RX bytes:700 TX bytes:14176 
          Interrupt:42 

usb0      Link encap:Ethernet  HWaddr ae:0c:29:a3:9b:6d
          inet addr:10.52.206.88  Bcast:10.255.255.255  Mask:255.0.0.0 
          inet6 addr: fe80::ac0c:29ff:fea3:9b6d/64 Scope: Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:1479 errors:0 dropped:0 overruns:0 frame:0 
          TX packets:1718 errors:0 dropped:0 overruns:0 carrier:0 
          collisions:0 txqueuelen:1000 
          RX bytes:123222 TX bytes:180776 

网络共享后


# ifconfig
lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0 
          inet6 addr: ::1/128 Scope: Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:2 errors:0 dropped:0 overruns:0 frame:0 
          TX packets:2 errors:0 dropped:0 overruns:0 carrier:0 
          collisions:0 txqueuelen:1 
          RX bytes:106 TX bytes:106 

eth0      Link encap:Ethernet  HWaddr 8a:5b:57:f2:44:77
          inet addr:192.168.43.1  Bcast:192.168.43.255  Mask:255.255.255.0 
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:735 errors:0 dropped:0 overruns:0 frame:0 
          TX packets:802 errors:0 dropped:0 overruns:0 carrier:0 
          collisions:0 txqueuelen:1000 
          RX bytes:84584 TX bytes:965347 
          Interrupt:42 

usb0      Link encap:Ethernet  HWaddr ae:0c:29:a3:9b:6d
          inet addr:10.129.70.7  Bcast:10.255.255.255  Mask:255.0.0.0 
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:1274 errors:0 dropped:0 overruns:0 frame:0 
          TX packets:1247 errors:0 dropped:0 overruns:0 carrier:0 
          collisions:0 txqueuelen:1000 
          RX bytes:1390060 TX bytes:135432

app

TetherUtils


import android.content.Context;
import android.os.SystemProperties;
import android.util.Log;

import com.wif.settings.frameworks.NetworkManagement;
import com.wif.settings.reflex.EthernetReflex;

public class TetherUtils {
    public static final String TAG = "TetherUtils";

    public static final String DEFAULT_IP = "192.168.43.1";
    public static final String DEFAULT_IP_MASK = "192.168.43.1/24";

    public static final String ROUTE_ADDRESS = "10.6.194.114/24";

    private static final String[] DHCP_DEFAULT_RANGE = {
//            "192.168.42.2", "192.168.42.254",
            "192.168.43.2", "192.168.43.254",
//            "192.168.44.2", "192.168.44.254",
//            "192.168.45.2", "192.168.45.254",
//            "192.168.46.2", "192.168.46.254",
//            "192.168.47.2", "192.168.47.254",
//            "192.168.48.2", "192.168.48.254",
//            "192.168.49.2", "192.168.49.254",
    };

    public static final String INTERFACE_ETHERNET = "eth0";
    public static final String INTERFACE_4G = "usb0";

    public static final String PROP_ETHERNET_MODE = "persist.net.ethernet.mode";
    public static final String MULTI = "multi";
    public static final String NORMAL = "normal";

    public static void startTetherShare(Context context) {
        Log.i(TAG, "startTetherShare");
        NetworkManagement.ipRuleConfig();
        NetworkManagement.ifconfig(INTERFACE_ETHERNET, "down");
        threadSleep(100);
        NetworkManagement.ifconfig(INTERFACE_ETHERNET, "up");
        //NetworkManagement.ifconfig(INTERFACE_ETHERNET, DEFAULT_IP);
        setStaticIpEth0(context);
        NetworkManagement.startTethering(DHCP_DEFAULT_RANGE);
        NetworkManagement.enableNatRoute(INTERFACE_ETHERNET, INTERFACE_4G, "1", DEFAULT_IP_MASK);
        NetworkManagement.setIpForwardingEnabled(true);
        String dns = SystemProperties.get("net.dns1");
        NetworkManagement.iptablesRoute(INTERFACE_ETHERNET, dns);
    }

    public static void stopTetherShare() {
        Log.i(TAG, "stopTetherShare");
        NetworkManagement.disableNat(INTERFACE_ETHERNET, INTERFACE_4G);
        NetworkManagement.stopTethering();
        NetworkManagement.setIpForwardingEnabled(false);
        NetworkManagement.ifconfig(INTERFACE_ETHERNET, "down");
        threadSleep(100);
        NetworkManagement.ifconfig(INTERFACE_ETHERNET, "up");
    }

    public static void setStaticIpEth0(Context context) {
        String dns1 = SystemProperties.get("net.usb0.dns1");
        String dns2 = SystemProperties.get("net.usb0.dns2");
        EthernetReflex.setEthernetStaticIp(context, DEFAULT_IP,
                "255.255.255.0", "192.168.1.1", dns1, dns2);
    }

    public static void threadSleep(long millis) {
        try {
            Thread.sleep(millis);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

NetworkManagement


import android.annotation.SuppressLint;
import android.net.LinkAddress;
import android.os.INetworkManagementService;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;

public class NetworkManagement {
    public static final String TAG = "NetworkManagement";

    private static final String NETWORK_MANAGEMENT_SERVICE = "network_management";

    public static INetworkManagementService sNMS = getNMS();

    public static INetworkManagementService getNMS() {
        if (sNMS != null) {
            return sNMS;
        }
        return INetworkManagementService.Stub.asInterface(ServiceManager.getService(NETWORK_MANAGEMENT_SERVICE));
    }

    public static void ipRuleConfig() {
        final INetworkManagementService netManager = getNMS();
        if (netManager == null) {
            Log.e(TAG, "netManager is null");
            return;
        }

        try {
            netManager.ipRuleConfig();
        } catch (RemoteException | NoSuchMethodError | IllegalStateException e) {
            e.printStackTrace();
        }

    }

    public static void ifconfig(String iface, String args) {
        final INetworkManagementService netManager = getNMS();
        if (netManager == null) {
            Log.e(TAG, "netManager is null");
            return;
        }

        try {
            netManager.ifconfig(iface, args);
        } catch (RemoteException | NoSuchMethodError | IllegalStateException e) {
            e.printStackTrace();
        }

    }

    public static void setInterfaceDown(String iface) {
        final INetworkManagementService netManager = getNMS();
        if (netManager == null) {
            Log.e(TAG, "netManager is null");
            return;
        }

        try {
            netManager.setInterfaceDown(iface);
        } catch (RemoteException | NoSuchMethodError | IllegalStateException e) {
            e.printStackTrace();
        }

    }


    public static void setInterfaceUp(String iface) {
        final INetworkManagementService netManager = getNMS();
        if (netManager == null) {
            Log.e(TAG, "netManager is null");
            return;
        }

        try {
            netManager.setInterfaceUp(iface);
        } catch (RemoteException | NoSuchMethodError | IllegalStateException e) {
            e.printStackTrace();
        }

    }

    public static boolean isTetheringStarted() {
        final INetworkManagementService netManager = getNMS();
        if (netManager == null) {
            Log.e(TAG, "netManager is null");
            return false;
        }

        try {
            return netManager.isTetheringStarted();
        } catch (RemoteException | NoSuchMethodError | IllegalStateException e) {
            e.printStackTrace();
        }
        return false;
    }

    public static void startTethering(String[] dhcpRange) {
        final INetworkManagementService netManager = getNMS();
        if (netManager == null) {
            Log.e(TAG, "netManager is null");
            return;
        }

        try {
            netManager.startTethering(dhcpRange);
        } catch (RemoteException | NoSuchMethodError | IllegalStateException e) {
            e.printStackTrace();
        }

    }

    public static void stopTethering() {
        final INetworkManagementService netManager = getNMS();
        if (netManager == null) {
            Log.e(TAG, "netManager is null");
            return;
        }

        try {
            netManager.stopTethering();
        } catch (RemoteException | NoSuchMethodError | IllegalStateException e) {
            e.printStackTrace();
        }

    }

    public static void enableNat(String internalInterface, String externalInterface) {
        final INetworkManagementService netManager = getNMS();
        if (netManager == null) {
            Log.e(TAG, "netManager is null");
            return;
        }

        try {
            netManager.enableNat(internalInterface, externalInterface);
        } catch (RemoteException | NoSuchMethodError | IllegalStateException e) {
            e.printStackTrace();
        }

    }

    public static void enableNatRoute(String internalInterface, String externalInterface, String addressSize, String address) {
        final INetworkManagementService netManager = getNMS();
        if (netManager == null) {
            Log.e(TAG, "netManager is null");
            return;
        }

        try {
            netManager.enableNatRoute(internalInterface, externalInterface, addressSize, address);
        } catch (RemoteException | NoSuchMethodError | IllegalStateException e) {
            e.printStackTrace();
        }

    }

    public static void disableNat(String internalInterface, String externalInterface) {
        final INetworkManagementService netManager = getNMS();
        if (netManager == null) {
            Log.e(TAG, "netManager is null");
            return;
        }

        try {
            netManager.disableNat(internalInterface, externalInterface);
        } catch (RemoteException | NoSuchMethodError | IllegalStateException e) {
            e.printStackTrace();
        }

    }

    public static void setIpForwardingEnabled(boolean enabled) {
        final INetworkManagementService netManager = getNMS();
        if (netManager == null) {
            Log.e(TAG, "netManager is null");
            return;
        }

        try {
            netManager.setIpForwardingEnabled(enabled);
        } catch (RemoteException | NoSuchMethodError | IllegalStateException e) {
            e.printStackTrace();
        }
    }

    public static void iptablesRoute(String iface, String dns) {
        final INetworkManagementService netManager = getNMS();
        if (netManager == null) {
            Log.e(TAG, "netManager is null");
            return;
        }

        try {
            netManager.iptablesRoute(iface, dns);
        } catch (RemoteException | NoSuchMethodError | IllegalStateException e) {
            e.printStackTrace();
        }
    }

    public static LinkAddress getInterfaceAddress(String iface){
        final INetworkManagementService netManager = getNMS();
        if (netManager == null) {
            Log.e(TAG, "netManager is null");
            return null;
        }

        try {
            return netManager.getInterfaceAddress(iface);
        } catch (RemoteException | NoSuchMethodError | IllegalStateException e) {
            e.printStackTrace();
        }
        return null;
    }

    @SuppressLint("NewApi")
    public static String getInterfaceIpAddress(String iface){
        LinkAddress linkAddress = getInterfaceAddress(iface);
        if (linkAddress == null) {
            return null;
        }

        if (linkAddress.getAddress() == null) {
            return null;
        }

        return linkAddress.getAddress().getHostAddress();
    }

}

system_server

NetworkManagementService


public class NetworkManagementService extends INetworkManagementService.Stub
        implements Watchdog.Monitor {

    @Override
    public void ipRuleConfig() {
        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
        Slog.d(TAG, "ipRuleConfig");
        try {
            mConnector.execute("tether", "ip_rule");
        } catch (NativeDaemonConnectorException e) {
            throw e.rethrowAsParcelableException();
        }
    }

    @Override
    public void ifconfig(String iface, String args) {
        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
        Slog.d(TAG, "ifconfig " + iface + " " + args);
        try {
            mConnector.execute("tether", "ifconfig", iface, args);
        } catch (NativeDaemonConnectorException e) {
            throw e.rethrowAsParcelableException();
        }
    }

    @Override
    public void enableNatRoute(String internalInterface, String externalInterface, String addressSize, String address) {
        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
        Slog.d(TAG, "enableNatRoute " + internalInterface + " " + externalInterface + " " + address);

        final Command cmd = new Command("nat", "enable", internalInterface, externalInterface);

        try {
            final NetworkInterface internalNetworkInterface = NetworkInterface.getByName(
                    internalInterface);
            if (internalNetworkInterface == null) {
                cmd.appendArg("0");
            } else {
                cmd.appendArg(addressSize);
                cmd.appendArg(address);
            }
            mConnector.execute(cmd);
        } catch (NativeDaemonConnectorException e) {
            throw e.rethrowAsParcelableException();
        } catch (SocketException e) {
            throw new IllegalStateException(e);
        }
    }

    @Override
    public void iptablesRoute(String iface, String dns) {
        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
        Slog.d(TAG, "iptablesRoute " + iface + " " + dns);
        try {
            mConnector.execute("tether", "iptables_route", iface, dns);
        } catch (NativeDaemonConnectorException e) {
            throw e.rethrowAsParcelableException();
        }
    }

    public LinkAddress getInterfaceAddress(String iface) {
        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
        //Slog.d(TAG, "getInterfaceAddress: " + iface);
        final InterfaceConfiguration ifcg = getInterfaceConfig(iface);
        if (ifcg == null) {
            return null;
        }

        return ifcg.getLinkAddress();
    }

}

netd

CommandListener.cpp


int CommandListener::TetherCmd::runCommand(SocketClient *cli,
                                                      int argc, char **argv) {

    else if (!strcmp(argv[1], "ip_rule")) {
        gCtls->tetherCtrl.ipRuleConfig();
    } else if (!strcmp(argv[1], "ifconfig")) {
        gCtls->tetherCtrl.ifconfig(argv[2], argv[3]);
    } else if (!strcmp(argv[1], "iptables_route")) {
        gCtls->tetherCtrl.iptablesRoute(argv[2], argv[3]);
    }

}

TetherController.cpp


int TetherController::ipRuleConfig() {
    ALOGW("runCommand: ip rule add from all lookup main pref 9999");
    for (size_t i = 0; i < ARRAY_SIZE(IP_VERSIONS); ++i) {
        const char* argv[] = {
            IP_PATH,
            IP_VERSIONS[i],
            "rule",
            "add",
            "from",
            "all",
            "lookup",
            "main",
            "pref",
            "9999",
        };
        if (android_fork_execvp(ARRAY_SIZE(argv), const_cast<char**>(argv), NULL, false, false)) {
            ALOGE("ip rule add from all lookup main pref 9999------fail");
            return -EREMOTEIO;
        }
    }
    return 0;
}

int TetherController::ifconfig(const char* interface, const char* args) {
    ALOGW("runCommand: ifconfig %s %s", interface, args);

    if (!isIfaceName(interface)) {
        errno = ENOENT;
        return -1;
    }

    const char* argv[] = {
            "/system/bin/ifconfig",
            interface,
            args,
    };
    if (android_fork_execvp(ARRAY_SIZE(argv), const_cast<char**>(argv), NULL, false, false)) {
        ALOGE("ifconfig %s %s------fail", interface, args);
        return -EREMOTEIO;
    }
    return 0;
}

int TetherController::iptablesRoute(const char* interface, const char* dns) {
    ALOGW("runCommand: iptablesRoute %s %s", interface, dns);

    if (!isIfaceName(interface)) {
        errno = ENOENT;
        return -1;
    }

    const char* argv[] = {
            IPTABLES_PATH,
            "-t",
            "nat",
            "-I",
            "PREROUTING",
            "-i",
            interface,
            "-p",
            "udp",
            "--dport",
            "53",
            "-j",
            "DNAT",
            "--to-destination",
            dns
    };
    if (android_fork_execvp(ARRAY_SIZE(argv), const_cast<char**>(argv), NULL, false, false)) {
        ALOGE("iptables -t nat -I PREROUTING -i %s -p udp --dport 53 -j DNAT --to-destination %s", interface, dns);
        return -EREMOTEIO;
    }
    return 0;
}