Android 调整DNS顺序

目前IPV6的大力推广,所以现在越来越多的Android设备都开始支持IPV6了,那么在网络上就是IPV4//IPV6双栈连接

IPV4/IPV6双栈连接那么系统就会得到下发的ipv4 dns服务器和ipv6 dns服务器,DNS服务器地址在dns协议中保存在一个数组中,后面进行DNS请求也是对该数组进行遍历,所以首先进行请求的目标DNS就是保存在数组中的第一个(具体DNS原理可以查看

https://blog.csdn.net/cc0410/article/details/103288483 这篇文章)

而数组中保存的DNS顺序依据是什么呢?依据的是IPV4或者IPV6哪个先连接成功,如果IPV4先连接成功,那么DNS数组中优先存储的就是IPV4下发的DNS服务器,如果是IPV6先连接成功,那么DNS数组中优先存储的就是IPV6下发的DNS服务器

IPV4先连成功:

dns_list[0] = 8.8.8.8

dns_list[1] = 114.114.114.114

dns_list[2] = fe80::1

dns_list[3] = 2000::1

IPV6先连成功:

dns_list[0] = fe80::1

dns_list[1] = 2000::1

dns_list[2] = 8.8.8.8

dns_list[3] = 114.114.114.114

假设我们想先向IPV6 DNS发起请求,但这时是IPV4先连成功,那么Android原生流程就无法满足,所以这个时候我们需要对DNS的保存过程做一个调整:

/**
 * set dns priority according to sys.network.priority(4 ro 6)
 */
private Collection<InetAddress> sortDnsesByPriority(Collection<InetAddress> dnses) {
	Collection<InetAddress> dnsesList = new ArrayList<InetAddress>();
	if (dnses == null || (dnses != null && dnses.size() < 2)) {
		return dnses;
	}

	ArrayList<InetAddress> dnsTempListV6 = new ArrayList<InetAddress>();
	ArrayList<InetAddress> dnsTempListV4 = new ArrayList<InetAddress>();
	for (InetAddress inet : dnses) {
		if (inet instanceof Inet6Address) {
			dnsTempListV6.add(inet);
		} else if (inet instanceof Inet4Address) {
			dnsTempListV4.add(inet);
		} else {
			loge("sortDnsesByPriority failed for InetAddress: " + inet.getHostAddress());
		}
	}

	if (DNS_HIGH_PRORITY_IPV6.equals(
			SystemProperties.get("sys.dns.priority", DNS_HIGH_PRORITY_IPV6))) { // dns priority: v6 > v4
		dnsesList.addAll(dnsTempListV6);
		dnsesList.addAll(dnsTempListV4);
	} else { // dns priority: v6 < v4
		dnsesList.addAll(dnsTempListV4);
		dnsesList.addAll(dnsTempListV6);
	}

	return dnsesList;
}

上面的代码就是调整DNS顺序的代码,根据需求读取属性sys.dns.priority的值来确定是将ipv6 dns放在前面还是ipv4 dns放在前面

接下来就是在什么地方调用这个函数了:

IPV4和IPV6连接成功后,都会通知ConnectivityService,将获取到的地址,DNS这些设置到系统中,而设置DNS就是调用

handleDnsConfigurationChange,当然新的android版本可能换了接口,但是流程肯定是不变的,我们可以找调用了setDnsServersForInterface这个接口的函数,设置DNS就是靠的setDnsServersForInterface函数

所以我们在setDnsServersForInterface之前把DNS顺序调整好再设置下去就可以了,如下所示:

    private void handleDnsConfigurationChange(int netType) {
        // add default net's dns entries
        NetworkStateTracker nt = mNetTrackers[netType];
        if (nt != null && nt.getNetworkInfo().isConnected() && !nt.isTeardownRequested()) {
            LinkProperties p = nt.getLinkProperties();
            if (p == null) return;
            Collection<InetAddress> dnses = p.getDnses();
            // set dns priority for chinamobile
            dnses = sortDnsesByPriority(dnses);   //这里进行DNS排序,排好序之后再走后面设置流程
            if (mNetConfigs[netType].isDefault()) {
                String network = nt.getNetworkInfo().getTypeName();
                synchronized (mDnsLock) {
                    boolean isDefaultDns = true;
                    if((mEthernetManager.getWifiEthernetCoexistState() == mEthernetManager.WIFI_ETHERNET_COEXIST_ENABLED)
                    && (mActiveDefaultNetwork != -1) && (mActiveDefaultNetwork != netType)
                    && (mNetConfigs[mActiveDefaultNetwork].priority > mNetConfigs[netType].priority))
                        isDefaultDns = false;
                    if (isDoubleNetCoexist(netType) &&
                            (mActiveDefaultNetwork != -1) &&
                            (mNetConfigs[mActiveDefaultNetwork].priority > mNetConfigs[netType].priority)) {
                        loge(
                            "handleDnsConfigurationChange:Coexist for double net,no need to set defaulte DNS");
                        isDefaultDns = false;
                    }
 
                    loge("handleDnsConfigurationChange: isDefaultDns = " +
                        isDefaultDns);
                    updateDnsLocked(network, p.getInterfaceName(), dnses, p.getDomains(), isDefaultDns);
                }
            } else {
                try {
                    mNetd.setDnsServersForInterface(p.getInterfaceName(),
                            NetworkUtils.makeStrings(dnses), p.getDomains());
                } catch (Exception e) {
                    if (DBG) loge("exception setting dns servers: " + e);
                }
                // set per-pid dns for attached secondary nets
                List<Integer> pids = mNetRequestersPids[netType];
                for (Integer pid : pids) {
                    try {
                        mNetd.setDnsInterfaceForPid(p.getInterfaceName(), pid);
                    } catch (Exception e) {
                        Slog.e(TAG, "exception setting interface for pid: " + e);
                    }
                }
            }
            flushVmDnsCache();
        } else if (nt != null && !nt.getNetworkInfo().isConnected()) {
            Slog.e(TAG, "handle Disconnect delete dnses");
            LinkProperties p = mCurrentLinkProperties[netType];
            if (p == null) return;
            Collection<InetAddress> dnses = p.getDnses();
            Slog.e(TAG, "netType(" + netType + ") dnses: " + dnses);
            if (mNetConfigs[netType].isDefault()) {
                String network = nt.getNetworkInfo().getTypeName();
                synchronized (mDnsLock) {
                    deleteDnsLocked(network, dnses);
                }
            }
            flushVmDnsCache();
        }
    }

有一点需要注意,调整DNS顺序要在系统设置DNS之前,如果在已经保存后,再调整顺序再保存,就无法生效了,dns协议中的DNS顺序不会改变,因为只要设置下去的DNS和保存过的DNS不管顺序上是否有区别,只要是一样的,就不会更改dns协议中保存过的DNS了

出自该处

0

留下评论