Android 12(S) IPV4优先IPV6(优先使用IPv4地址)的实现
根据RFC 6724中 规定 android 会优先选择IPv6 地址而不是 IPv4 地址,当整个网络中,同时支持IPv4和IPv6 地址时,设备中的应用请求服务器DNS时,会优先返回IPv6地址。
假如IPv6服务器支持内容不够完善,则应用显示内容会与IPv4服务器不一致,甚至有问题。
因此有需求是定制设备平台,使得 IPV4优先IPV6,主要修改2个地方:
1. 当设备或平台连接网络时,原来是先请求ipv6地址,再请求ipv4地址,这样会使用应用会先拿到ipv6地址,所以需要调整顺序,让ipv4先请求dhcp地址,再请求ipv6。
2. DNS域名解析时,调整解析DNS的优先顺序,即先解析IPv4地址,再解析IPv6地址,注:android 12在DnsResolver代码中。
接下来对这2个修改点进行逐一修改并说明。
1. 当设备或平台连接网络时,原来是先请求ipv6地址,再请求ipv4地址,这样会使用应用会先拿到ipv6地址,所以需要调整顺序,让ipv4先请求dhcp地址,再请求ipv6。
文件:packages/modules/NetworkStack/src/android/net/ip/IpClient.java
修改差异如下:
--- a/modules/NetworkStack/src/android/net/ip/IpClient.java
+++ b/modules/NetworkStack/src/android/net/ip/IpClient.java
@@ -161,6 +161,8 @@
private final NetworkInformationShim mShim = NetworkInformationShimImpl.newInstance();
private final IpProvisioningMetrics mIpProvisioningMetrics = new IpProvisioningMetrics();
private final NetworkQuirkMetrics mNetworkQuirkMetrics;
+ //CN project let get ipv4 first and then ipv6, tiangui.tang @2023.9.7
//用于区别自定义code与AOSP
+ private final boolean bStartIPv6AfterIPv4 = true;
/**
* Dump all state machine and connectivity packet logs to the specified writer.
@@ -1734,7 +1736,21 @@
recordMetric(failureType);
mCallback.onProvisioningFailure(mLinkProperties);
}
+ private void enqueueJumpToStoppingState(final DisconnectCode code) {
+ deferMessage(obtainMessage(CMD_JUMP_RUNNING_TO_STOPPING, code.getNumber()));
+ }
+ private void startIPv6AfterIPv4() {
+ if (bStartIPv6AfterIPv4 == false) {
+ return;
+ }
+ Log.d(mTag, "startIPv6AfterIPv4");
+ if (mConfiguration.mEnableIPv6 && !startIPv6()) {
+ doImmediateProvisioningFailure(IpManagerEvent.ERROR_STARTING_IPV6);
+ enqueueJumpToStoppingState(DisconnectCode.DC_ERROR_STARTING_IPV6);
+ return;
+ }
+ }
private boolean startIPv4() {
// If we have a StaticIpConfiguration attempt to apply it and
// handle the result accordingly.
@@ -1744,6 +1760,7 @@
} else {
return false;
}
+ startIPv6AfterIPv4();
} else {
if (mDhcpClient != null) {
Log.wtf(mTag, "DhcpClient should never be non-null in startIPv4()");
@@ -2229,7 +2246,7 @@
mPacketTracker = createPacketTracker();
if (mPacketTracker != null) mPacketTracker.start(mConfiguration.mDisplayName);
- if (mConfiguration.mEnableIPv6 && !startIPv6()) {
+ if ((bStartIPv6AfterIPv4 == false) && mConfiguration.mEnableIPv6 && !startIPv6()) {
doImmediateProvisioningFailure(IpManagerEvent.ERROR_STARTING_IPV6);
enqueueJumpToStoppingState(DisconnectCode.DC_ERROR_STARTING_IPV6);
return;
@@ -2414,6 +2431,7 @@
}
case EVENT_DHCPACTION_TIMEOUT:
+ startIPv6AfterIPv4();
stopDhcpAction();
break;
@@ -2431,6 +2449,7 @@
case DhcpClient.CMD_CONFIGURE_LINKADDRESS: {
final LinkAddress ipAddress = (LinkAddress) msg.obj;
+ startIPv6AfterIPv4();
if (mInterfaceCtrl.setIPv4Address(ipAddress)) {
mDhcpClient.sendMessage(DhcpClient.EVENT_LINKADDRESS_CONFIGURED);
} else {
2. DNS域名解析时,调整解析DNS的优先顺序,即先解析IPv4地址,再解析IPv6地址,注:android 12在DnsResolver代码中。
diff --git a/modules/DnsResolver/getaddrinfo.cpp b/modules/DnsResolver/getaddrinfo.cpp
--- a/modules/DnsResolver/getaddrinfo.cpp
+++ b/modules/DnsResolver/getaddrinfo.cpp
@@ -1147,7 +1147,8 @@
return 1;
} else {
/* All other IPv6 addresses, including global unicast addresses. */
//DNS解析出来的地址进行排序,IPv4(return 35) 比IPv6(改为return 34)更高优先级
- return 40;
+ LOG(DEBUG) << __func__ << " ttgctt force 34 for ipv6";
+ return 34;
}
} else {
return 1;
@@ -1406,16 +1407,17 @@
query_ipv6 = have_ipv6(netcontext->app_mark, netcontext->uid);
query_ipv4 = have_ipv4(netcontext->app_mark, netcontext->uid);
}
//调整顺序,先请求IPv4对应的DNS,再请求IPv6
- if (query_ipv6) {
- q.qtype = T_AAAA;
- if (query_ipv4) {
+ //query_ipv6 = 0;
+ if (query_ipv4) {
+ q.qtype = T_A;
+ if (query_ipv6) {
q.next = &q2;
q2.name = name;
q2.qclass = C_IN;
- q2.qtype = T_A;
+ q2.qtype = T_AAAA;
}
- } else if (query_ipv4) {
- q.qtype = T_A;
+ } else if (query_ipv6) {
+ q.qtype = T_AAAA;
} else {
return EAI_NODATA;
}
@@ -1452,7 +1454,7 @@
cur->ai_next = ai;
while (cur && cur->ai_next) cur = cur->ai_next;
}
if (q.next) {
ai = getanswer(q2.answer, q2.n, q2.name, q2.qtype, pai, &he);
if (ai) cur->ai_next = ai;
}