summaryrefslogtreecommitdiff
path: root/packages/NetworkStack
diff options
context:
space:
mode:
authorSteven Laver <lavers@google.com>2019-05-08 06:18:42 -0700
committerSteven Laver <lavers@google.com>2019-05-08 06:18:42 -0700
commit4a30c150e58ec67edb92a7bec5ea48cebd6b90d4 (patch)
tree6d902794d7e59acd54f54ef235feb75becfb01e3 /packages/NetworkStack
parenta6c7c402af360214e509d15980957e74fc673f42 (diff)
parente4f4eabc31685c001c2b46d8fa87b443f4af5b21 (diff)
Merge QP1A.190501.001
Change-Id: I0f9f887d6a33702a6988709d8296731cfdb8f73d
Diffstat (limited to 'packages/NetworkStack')
-rw-r--r--packages/NetworkStack/res/values-mcc460/config.xml12
-rw-r--r--packages/NetworkStack/res/values/config.xml10
-rw-r--r--packages/NetworkStack/res/values/overlayable.xml28
-rw-r--r--packages/NetworkStack/src/android/net/apf/ApfFilter.java17
-rw-r--r--packages/NetworkStack/src/android/net/dhcp/DhcpClient.java14
-rw-r--r--packages/NetworkStack/src/android/net/dhcp/DhcpPacket.java36
-rw-r--r--packages/NetworkStack/src/android/net/dhcp/DhcpServer.java5
-rw-r--r--packages/NetworkStack/src/android/net/ip/IpClient.java39
-rw-r--r--packages/NetworkStack/src/android/net/util/NetworkStackUtils.java71
-rw-r--r--packages/NetworkStack/src/com/android/server/NetworkStackService.java10
-rw-r--r--packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java121
-rw-r--r--packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreService.java5
-rw-r--r--packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/RegularMaintenanceJobService.java5
-rw-r--r--packages/NetworkStack/tests/src/android/net/apf/ApfTest.java8
-rw-r--r--packages/NetworkStack/tests/src/android/net/dhcp/DhcpPacketTest.java49
-rw-r--r--packages/NetworkStack/tests/src/android/net/dhcp/DhcpServerTest.java5
-rw-r--r--packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java131
-rw-r--r--packages/NetworkStack/tests/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java25
18 files changed, 539 insertions, 52 deletions
diff --git a/packages/NetworkStack/res/values-mcc460/config.xml b/packages/NetworkStack/res/values-mcc460/config.xml
new file mode 100644
index 000000000000..fd4a8481ab22
--- /dev/null
+++ b/packages/NetworkStack/res/values-mcc460/config.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- Network validation URL configuration for devices using a Chinese SIM (MCC 460).
+ The below URLs are often whitelisted by captive portals, so they should not be used in the
+ general case as this could degrade the user experience (portals not detected properly).
+ However in China the default URLs are not accessible in general. The below alternatives
+ should allow users to connect to local networks normally. -->
+ <string name="default_captive_portal_https_url" translatable="false">https://connectivitycheck.gstatic.com/generate_204</string>
+ <string-array name="default_captive_portal_fallback_urls" translatable="false">
+ <item>http://www.googleapis.cn/generate_204</item>
+ </string-array>
+</resources>
diff --git a/packages/NetworkStack/res/values/config.xml b/packages/NetworkStack/res/values/config.xml
index 90f96e0f7a18..478ed6b06596 100644
--- a/packages/NetworkStack/res/values/config.xml
+++ b/packages/NetworkStack/res/values/config.xml
@@ -7,6 +7,9 @@
values are meant to be the default when no other configuration is specified.
-->
+ <!-- DNS probe timeout for network validation. Enough for 3 DNS queries 5 seconds apart. -->
+ <integer name="default_captive_portal_dns_probe_timeout">12500</integer>
+
<!-- HTTP URL for network validation, to use for detecting captive portals. -->
<string name="default_captive_portal_http_url" translatable="false">http://connectivitycheck.gstatic.com/generate_204</string>
@@ -27,6 +30,7 @@
<!-- Configuration hooks for the above settings.
Empty by default but may be overridden by RROs. -->
+ <integer name="config_captive_portal_dns_probe_timeout"></integer>
<!--suppress CheckTagEmptyBody: overlayable resource to use as configuration hook -->
<string name="config_captive_portal_http_url" translatable="false"></string>
<!--suppress CheckTagEmptyBody: overlayable resource to use as configuration hook -->
@@ -35,4 +39,8 @@
</string-array>
<string-array name="config_captive_portal_fallback_probe_specs" translatable="false">
</string-array>
-</resources> \ No newline at end of file
+
+ <!-- Customized default DNS Servers address. -->
+ <string-array name="config_default_dns_servers" translatable="false">
+ </string-array>
+</resources>
diff --git a/packages/NetworkStack/res/values/overlayable.xml b/packages/NetworkStack/res/values/overlayable.xml
new file mode 100644
index 000000000000..b9d5337ec572
--- /dev/null
+++ b/packages/NetworkStack/res/values/overlayable.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources xmlns:android="http://schemas.android.com/apk/res/android">
+ <overlayable name="NetworkStackConfig">
+ <policy type="product|system|vendor">
+ <!-- Configuration values for NetworkMonitor -->
+ <item type="integer" name="config_captive_portal_dns_probe_timeout"/>
+ <item type="string" name="config_captive_portal_http_url"/>
+ <item type="string" name="config_captive_portal_https_url"/>
+ <item type="array" name="config_captive_portal_fallback_urls"/>
+ <!-- Configuration value for DhcpResults -->
+ <item type="array" name="config_default_dns_servers"/>
+ </policy>
+ </overlayable>
+</resources>
diff --git a/packages/NetworkStack/src/android/net/apf/ApfFilter.java b/packages/NetworkStack/src/android/net/apf/ApfFilter.java
index 663e2f10ffe2..359c85983a94 100644
--- a/packages/NetworkStack/src/android/net/apf/ApfFilter.java
+++ b/packages/NetworkStack/src/android/net/apf/ApfFilter.java
@@ -39,6 +39,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.net.LinkAddress;
import android.net.LinkProperties;
+import android.net.NattKeepalivePacketDataParcelable;
import android.net.TcpKeepalivePacketDataParcelable;
import android.net.apf.ApfGenerator.IllegalInstructionException;
import android.net.apf.ApfGenerator.Register;
@@ -1691,13 +1692,13 @@ public class ApfFilter {
}
/**
- * Add keepalive ack packet filter.
+ * Add TCP keepalive ack packet filter.
* This will add a filter to drop acks to the keepalive packet passed as an argument.
*
* @param slot The index used to access the filter.
* @param sentKeepalivePacket The attributes of the sent keepalive packet.
*/
- public synchronized void addKeepalivePacketFilter(final int slot,
+ public synchronized void addTcpKeepalivePacketFilter(final int slot,
final TcpKeepalivePacketDataParcelable sentKeepalivePacket) {
log("Adding keepalive ack(" + slot + ")");
if (null != mKeepaliveAcks.get(slot)) {
@@ -1711,6 +1712,18 @@ public class ApfFilter {
}
/**
+ * Add NATT keepalive packet filter.
+ * This will add a filter to drop NATT keepalive packet which is passed as an argument.
+ *
+ * @param slot The index used to access the filter.
+ * @param sentKeepalivePacket The attributes of the sent keepalive packet.
+ */
+ public synchronized void addNattKeepalivePacketFilter(final int slot,
+ final NattKeepalivePacketDataParcelable sentKeepalivePacket) {
+ Log.e(TAG, "APF add NATT keepalive filter is not implemented");
+ }
+
+ /**
* Remove keepalive packet filter.
*
* @param slot The index used to access the filter.
diff --git a/packages/NetworkStack/src/android/net/dhcp/DhcpClient.java b/packages/NetworkStack/src/android/net/dhcp/DhcpClient.java
index 8e41ab1b5df4..c47231d80948 100644
--- a/packages/NetworkStack/src/android/net/dhcp/DhcpClient.java
+++ b/packages/NetworkStack/src/android/net/dhcp/DhcpClient.java
@@ -45,6 +45,7 @@ import static com.android.server.util.NetworkStackConstants.IPV4_ADDR_ANY;
import android.content.Context;
import android.net.DhcpResults;
+import android.net.InetAddresses;
import android.net.TrafficStats;
import android.net.ip.IpClient;
import android.net.metrics.DhcpClientEvent;
@@ -67,6 +68,7 @@ import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
import com.android.internal.util.TrafficStatsConstants;
import com.android.internal.util.WakeupMessage;
+import com.android.networkstack.R;
import java.io.FileDescriptor;
import java.io.IOException;
@@ -516,6 +518,18 @@ public class DhcpClient extends StateMachine {
private void acceptDhcpResults(DhcpResults results, String msg) {
mDhcpLease = results;
+ if (mDhcpLease.dnsServers.isEmpty()) {
+ // supplement customized dns servers
+ String[] dnsServersList =
+ mContext.getResources().getStringArray(R.array.config_default_dns_servers);
+ for (final String dnsServer : dnsServersList) {
+ try {
+ mDhcpLease.dnsServers.add(InetAddresses.parseNumericAddress(dnsServer));
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "Invalid default DNS server: " + dnsServer, e);
+ }
+ }
+ }
mOffer = null;
Log.d(TAG, msg + " lease: " + mDhcpLease);
notifySuccess();
diff --git a/packages/NetworkStack/src/android/net/dhcp/DhcpPacket.java b/packages/NetworkStack/src/android/net/dhcp/DhcpPacket.java
index b4ebf264608b..c382733041e0 100644
--- a/packages/NetworkStack/src/android/net/dhcp/DhcpPacket.java
+++ b/packages/NetworkStack/src/android/net/dhcp/DhcpPacket.java
@@ -195,6 +195,18 @@ public abstract class DhcpPacket {
public static final String VENDOR_INFO_ANDROID_METERED = "ANDROID_METERED";
/**
+ * DHCP Optional Type: Option overload option
+ */
+ protected static final byte DHCP_OPTION_OVERLOAD = 52;
+
+ /**
+ * Possible values of the option overload option.
+ */
+ private static final byte OPTION_OVERLOAD_FILE = 1;
+ private static final byte OPTION_OVERLOAD_SNAME = 2;
+ private static final byte OPTION_OVERLOAD_BOTH = 3;
+
+ /**
* DHCP Optional Type: DHCP Requested IP Address
*/
protected static final byte DHCP_REQUESTED_IP = 50;
@@ -314,6 +326,11 @@ public abstract class DhcpPacket {
protected final byte[] mClientMac;
/**
+ * The server host name from server.
+ */
+ protected String mServerHostName;
+
+ /**
* Whether the packet should be built with rapid commit option
*/
protected boolean mRapidCommit;
@@ -874,6 +891,8 @@ public abstract class DhcpPacket {
Inet4Address ipDst = null;
Inet4Address bcAddr = null;
Inet4Address requestedIp = null;
+ String serverHostName;
+ byte optionOverload = 0;
// The following are all unsigned integers. Internally we store them as signed integers of
// the same length because that way we're guaranteed that they can't be out of the range of
@@ -1015,9 +1034,9 @@ public abstract class DhcpPacket {
packet.get(clientMac);
// skip over address padding (16 octets allocated)
- packet.position(packet.position() + (16 - addrLen)
- + 64 // skip server host name (64 chars)
- + 128); // skip boot file name (128 chars)
+ packet.position(packet.position() + (16 - addrLen));
+ serverHostName = readAsciiString(packet, 64, false);
+ packet.position(packet.position() + 128);
// Ensure this is a DHCP packet with a magic cookie, and not BOOTP. http://b/31850211
if (packet.remaining() < 4) {
@@ -1128,6 +1147,11 @@ public abstract class DhcpPacket {
// Embedded nulls are safe as this does not get passed to netd.
vendorInfo = readAsciiString(packet, optionLen, true);
break;
+ case DHCP_OPTION_OVERLOAD:
+ expectedLen = 1;
+ optionOverload = packet.get();
+ optionOverload &= OPTION_OVERLOAD_BOTH;
+ break;
default:
// ignore any other parameters
for (int i = 0; i < optionLen; i++) {
@@ -1218,6 +1242,11 @@ public abstract class DhcpPacket {
newPacket.mT2 = T2;
newPacket.mVendorId = vendorId;
newPacket.mVendorInfo = vendorInfo;
+ if ((optionOverload & OPTION_OVERLOAD_SNAME) == 0) {
+ newPacket.mServerHostName = serverHostName;
+ } else {
+ newPacket.mServerHostName = "";
+ }
return newPacket;
}
@@ -1277,6 +1306,7 @@ public abstract class DhcpPacket {
results.vendorInfo = mVendorInfo;
results.leaseDuration = (mLeaseTime != null) ? mLeaseTime : INFINITE_LEASE;
results.mtu = (mMtu != null && MIN_MTU <= mMtu && mMtu <= MAX_MTU) ? mMtu : 0;
+ results.serverHostName = mServerHostName;
return results;
}
diff --git a/packages/NetworkStack/src/android/net/dhcp/DhcpServer.java b/packages/NetworkStack/src/android/net/dhcp/DhcpServer.java
index d21b5f7853bb..b8ab94ce3830 100644
--- a/packages/NetworkStack/src/android/net/dhcp/DhcpServer.java
+++ b/packages/NetworkStack/src/android/net/dhcp/DhcpServer.java
@@ -647,4 +647,9 @@ public class DhcpServer extends IDhcpServer.Stub {
}
}
}
+
+ @Override
+ public int getInterfaceVersion() {
+ return this.VERSION;
+ }
}
diff --git a/packages/NetworkStack/src/android/net/ip/IpClient.java b/packages/NetworkStack/src/android/net/ip/IpClient.java
index 06e1f05a40e6..e48b065409be 100644
--- a/packages/NetworkStack/src/android/net/ip/IpClient.java
+++ b/packages/NetworkStack/src/android/net/ip/IpClient.java
@@ -29,6 +29,7 @@ import android.net.INetd;
import android.net.IpPrefix;
import android.net.LinkAddress;
import android.net.LinkProperties;
+import android.net.NattKeepalivePacketDataParcelable;
import android.net.NetworkStackIpMemoryStore;
import android.net.ProvisioningConfigurationParcelable;
import android.net.ProxyInfo;
@@ -372,6 +373,10 @@ public class IpClient extends StateMachine {
private boolean mMulticastFiltering;
private long mStartTimeMillis;
+ /* This must match the definition in KeepaliveTracker.KeepaliveInfo */
+ private static final int TYPE_NATT = 1;
+ private static final int TYPE_TCP = 2;
+
/**
* Reading the snapshot is an asynchronous operation initiated by invoking
* Callback.startReadPacketFilter() and completed when the WiFi Service responds with an
@@ -554,10 +559,20 @@ public class IpClient extends StateMachine {
IpClient.this.addKeepalivePacketFilter(slot, pkt);
}
@Override
+ public void addNattKeepalivePacketFilter(int slot, NattKeepalivePacketDataParcelable pkt) {
+ checkNetworkStackCallingPermission();
+ IpClient.this.addNattKeepalivePacketFilter(slot, pkt);
+ }
+ @Override
public void removeKeepalivePacketFilter(int slot) {
checkNetworkStackCallingPermission();
IpClient.this.removeKeepalivePacketFilter(slot);
}
+
+ @Override
+ public int getInterfaceVersion() {
+ return this.VERSION;
+ }
}
public String getInterfaceName() {
@@ -687,11 +702,20 @@ public class IpClient extends StateMachine {
}
/**
- * Called by WifiStateMachine to add keepalive packet filter before setting up
+ * Called by WifiStateMachine to add TCP keepalive packet filter before setting up
* keepalive offload.
*/
public void addKeepalivePacketFilter(int slot, @NonNull TcpKeepalivePacketDataParcelable pkt) {
- sendMessage(CMD_ADD_KEEPALIVE_PACKET_FILTER_TO_APF, slot, 0 /* Unused */, pkt);
+ sendMessage(CMD_ADD_KEEPALIVE_PACKET_FILTER_TO_APF, slot, TYPE_TCP, pkt);
+ }
+
+ /**
+ * Called by WifiStateMachine to add NATT keepalive packet filter before setting up
+ * keepalive offload.
+ */
+ public void addNattKeepalivePacketFilter(int slot,
+ @NonNull NattKeepalivePacketDataParcelable pkt) {
+ sendMessage(CMD_ADD_KEEPALIVE_PACKET_FILTER_TO_APF, slot, TYPE_NATT, pkt);
}
/**
@@ -1613,9 +1637,16 @@ public class IpClient extends StateMachine {
case CMD_ADD_KEEPALIVE_PACKET_FILTER_TO_APF: {
final int slot = msg.arg1;
+ final int type = msg.arg2;
+
if (mApfFilter != null) {
- mApfFilter.addKeepalivePacketFilter(slot,
- (TcpKeepalivePacketDataParcelable) msg.obj);
+ if (type == TYPE_NATT) {
+ mApfFilter.addNattKeepalivePacketFilter(slot,
+ (NattKeepalivePacketDataParcelable) msg.obj);
+ } else {
+ mApfFilter.addTcpKeepalivePacketFilter(slot,
+ (TcpKeepalivePacketDataParcelable) msg.obj);
+ }
}
break;
}
diff --git a/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java b/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java
index 822678717092..2934e1cf0c82 100644
--- a/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java
+++ b/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java
@@ -35,6 +35,77 @@ public class NetworkStackUtils {
// TODO: Refer to DeviceConfig definition.
public static final String NAMESPACE_CONNECTIVITY = "connectivity";
+ /**
+ * A list of captive portal detection specifications used in addition to the fallback URLs.
+ * Each spec has the format url@@/@@statusCodeRegex@@/@@contentRegex. Specs are separated
+ * by "@@,@@".
+ */
+ public static final String CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS =
+ "captive_portal_fallback_probe_specs";
+
+ /**
+ * A comma separated list of URLs used for captive portal detection in addition to the
+ * fallback HTTP url associated with the CAPTIVE_PORTAL_FALLBACK_URL settings.
+ */
+ public static final String CAPTIVE_PORTAL_OTHER_FALLBACK_URLS =
+ "captive_portal_other_fallback_urls";
+
+ /**
+ * Which User-Agent string to use in the header of the captive portal detection probes.
+ * The User-Agent field is unset when this setting has no value (HttpUrlConnection default).
+ */
+ public static final String CAPTIVE_PORTAL_USER_AGENT = "captive_portal_user_agent";
+
+ /**
+ * Whether to use HTTPS for network validation. This is enabled by default and the setting
+ * needs to be set to 0 to disable it. This setting is a misnomer because captive portals
+ * don't actually use HTTPS, but it's consistent with the other settings.
+ */
+ public static final String CAPTIVE_PORTAL_USE_HTTPS = "captive_portal_use_https";
+
+ /**
+ * The URL used for HTTPS captive portal detection upon a new connection.
+ * A 204 response code from the server is used for validation.
+ */
+ public static final String CAPTIVE_PORTAL_HTTPS_URL = "captive_portal_https_url";
+
+ /**
+ * The URL used for HTTP captive portal detection upon a new connection.
+ * A 204 response code from the server is used for validation.
+ */
+ public static final String CAPTIVE_PORTAL_HTTP_URL = "captive_portal_http_url";
+
+ /**
+ * The URL used for fallback HTTP captive portal detection when previous HTTP
+ * and HTTPS captive portal detection attemps did not return a conclusive answer.
+ */
+ public static final String CAPTIVE_PORTAL_FALLBACK_URL = "captive_portal_fallback_url";
+
+ /**
+ * What to do when connecting a network that presents a captive portal.
+ * Must be one of the CAPTIVE_PORTAL_MODE_* constants above.
+ *
+ * The default for this setting is CAPTIVE_PORTAL_MODE_PROMPT.
+ */
+ public static final String CAPTIVE_PORTAL_MODE = "captive_portal_mode";
+
+ /**
+ * Don't attempt to detect captive portals.
+ */
+ public static final int CAPTIVE_PORTAL_MODE_IGNORE = 0;
+
+ /**
+ * When detecting a captive portal, display a notification that
+ * prompts the user to sign in.
+ */
+ public static final int CAPTIVE_PORTAL_MODE_PROMPT = 1;
+
+ /**
+ * When detecting a captive portal, immediately disconnect from the
+ * network and do not reconnect to that network in the future.
+ */
+ public static final int CAPTIVE_PORTAL_MODE_AVOID = 2;
+
static {
System.loadLibrary("networkstackutilsjni");
}
diff --git a/packages/NetworkStack/src/com/android/server/NetworkStackService.java b/packages/NetworkStack/src/com/android/server/NetworkStackService.java
index a0a90fde518f..a6d74842f631 100644
--- a/packages/NetworkStack/src/com/android/server/NetworkStackService.java
+++ b/packages/NetworkStack/src/com/android/server/NetworkStackService.java
@@ -251,6 +251,11 @@ public class NetworkStackService extends Service {
}
}
}
+
+ @Override
+ public int getInterfaceVersion() {
+ return this.VERSION;
+ }
}
private static class NetworkMonitorImpl extends INetworkMonitor.Stub {
@@ -325,5 +330,10 @@ public class NetworkStackService extends Service {
checkNetworkStackCallingPermission();
mNm.notifyNetworkCapabilitiesChanged(nc);
}
+
+ @Override
+ public int getInterfaceVersion() {
+ return this.VERSION;
+ }
}
}
diff --git a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
index 27d420328017..bacec78e5699 100644
--- a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
+++ b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
@@ -43,6 +43,16 @@ import static android.net.util.DataStallUtils.DEFAULT_DATA_STALL_EVALUATION_TYPE
import static android.net.util.DataStallUtils.DEFAULT_DATA_STALL_MIN_EVALUATE_TIME_MS;
import static android.net.util.DataStallUtils.DEFAULT_DATA_STALL_VALID_DNS_TIME_THRESHOLD_MS;
import static android.net.util.DataStallUtils.DEFAULT_DNS_LOG_SIZE;
+import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS;
+import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_FALLBACK_URL;
+import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_HTTPS_URL;
+import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_HTTP_URL;
+import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_MODE;
+import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_MODE_IGNORE;
+import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_MODE_PROMPT;
+import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS;
+import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_USER_AGENT;
+import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_USE_HTTPS;
import static android.net.util.NetworkStackUtils.NAMESPACE_CONNECTIVITY;
import static android.net.util.NetworkStackUtils.isEmpty;
@@ -55,6 +65,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Resources;
import android.net.ConnectivityManager;
+import android.net.DnsResolver;
import android.net.INetworkMonitor;
import android.net.INetworkMonitorCallbacks;
import android.net.LinkProperties;
@@ -118,6 +129,7 @@ import java.util.Random;
import java.util.UUID;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
/**
@@ -132,8 +144,13 @@ public class NetworkMonitor extends StateMachine {
+ "AppleWebKit/537.36 (KHTML, like Gecko) "
+ "Chrome/60.0.3112.32 Safari/537.36";
+ @VisibleForTesting
+ static final String CONFIG_CAPTIVE_PORTAL_DNS_PROBE_TIMEOUT =
+ "captive_portal_dns_probe_timeout";
+
private static final int SOCKET_TIMEOUT_MS = 10000;
private static final int PROBE_TIMEOUT_MS = 3000;
+
enum EvaluationResult {
VALIDATED(true),
CAPTIVE_PORTAL(false);
@@ -1164,20 +1181,47 @@ public class NetworkMonitor extends StateMachine {
}
private boolean getIsCaptivePortalCheckEnabled() {
- String symbol = Settings.Global.CAPTIVE_PORTAL_MODE;
- int defaultValue = Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT;
+ String symbol = CAPTIVE_PORTAL_MODE;
+ int defaultValue = CAPTIVE_PORTAL_MODE_PROMPT;
int mode = mDependencies.getSetting(mContext, symbol, defaultValue);
- return mode != Settings.Global.CAPTIVE_PORTAL_MODE_IGNORE;
+ return mode != CAPTIVE_PORTAL_MODE_IGNORE;
}
private boolean getUseHttpsValidation() {
- return mDependencies.getSetting(mContext, Settings.Global.CAPTIVE_PORTAL_USE_HTTPS, 1) == 1;
+ return mDependencies.getDeviceConfigPropertyInt(NAMESPACE_CONNECTIVITY,
+ CAPTIVE_PORTAL_USE_HTTPS, 1) == 1;
}
private String getCaptivePortalServerHttpsUrl() {
return getSettingFromResource(mContext, R.string.config_captive_portal_https_url,
- R.string.default_captive_portal_https_url,
- Settings.Global.CAPTIVE_PORTAL_HTTPS_URL);
+ R.string.default_captive_portal_https_url, CAPTIVE_PORTAL_HTTPS_URL);
+ }
+
+ private int getDnsProbeTimeout() {
+ return getIntSetting(mContext, R.integer.config_captive_portal_dns_probe_timeout,
+ CONFIG_CAPTIVE_PORTAL_DNS_PROBE_TIMEOUT,
+ R.integer.default_captive_portal_dns_probe_timeout);
+ }
+
+ /**
+ * Gets an integer setting from resources or device config
+ *
+ * configResource is used if set, followed by device config if set, followed by defaultResource.
+ * If none of these are set then an exception is thrown.
+ *
+ * TODO: move to a common location such as a ConfigUtils class.
+ * TODO(b/130324939): test that the resources can be overlayed by an RRO package.
+ */
+ @VisibleForTesting
+ int getIntSetting(@NonNull final Context context, @StringRes int configResource,
+ @NonNull String symbol, @StringRes int defaultResource) {
+ final Resources res = context.getResources();
+ try {
+ return res.getInteger(configResource);
+ } catch (Resources.NotFoundException e) {
+ return mDependencies.getDeviceConfigPropertyInt(NAMESPACE_CONNECTIVITY,
+ symbol, res.getInteger(defaultResource));
+ }
}
/**
@@ -1189,8 +1233,7 @@ public class NetworkMonitor extends StateMachine {
*/
public String getCaptivePortalServerHttpUrl() {
return getSettingFromResource(mContext, R.string.config_captive_portal_http_url,
- R.string.default_captive_portal_http_url,
- Settings.Global.CAPTIVE_PORTAL_HTTP_URL);
+ R.string.default_captive_portal_http_url, CAPTIVE_PORTAL_HTTP_URL);
}
private int getConsecutiveDnsTimeoutThreshold() {
@@ -1219,13 +1262,13 @@ public class NetworkMonitor extends StateMachine {
private URL[] makeCaptivePortalFallbackUrls() {
try {
- final String firstUrl = mDependencies.getSetting(mContext,
- Settings.Global.CAPTIVE_PORTAL_FALLBACK_URL, null);
+ final String firstUrl = mDependencies.getSetting(mContext, CAPTIVE_PORTAL_FALLBACK_URL,
+ null);
final URL[] settingProviderUrls;
if (!TextUtils.isEmpty(firstUrl)) {
- final String otherUrls = mDependencies.getSetting(mContext,
- Settings.Global.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS, "");
+ final String otherUrls = mDependencies.getDeviceConfigProperty(
+ NAMESPACE_CONNECTIVITY, CAPTIVE_PORTAL_OTHER_FALLBACK_URLS, "");
// otherUrls may be empty, but .split() ignores trailing empty strings
final String separator = ",";
final String[] urls = (firstUrl + separator + otherUrls).split(separator);
@@ -1245,8 +1288,9 @@ public class NetworkMonitor extends StateMachine {
private CaptivePortalProbeSpec[] makeCaptivePortalFallbackProbeSpecs() {
try {
- final String settingsValue = mDependencies.getSetting(
- mContext, Settings.Global.CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS, null);
+ final String settingsValue = mDependencies.getDeviceConfigProperty(
+ NAMESPACE_CONNECTIVITY, CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS, null);
+
final CaptivePortalProbeSpec[] emptySpecs = new CaptivePortalProbeSpec[0];
final CaptivePortalProbeSpec[] providerValue = TextUtils.isEmpty(settingsValue)
? emptySpecs
@@ -1340,8 +1384,8 @@ public class NetworkMonitor extends StateMachine {
}
private String getCaptivePortalUserAgent() {
- return mDependencies.getSetting(mContext,
- Settings.Global.CAPTIVE_PORTAL_USER_AGENT, DEFAULT_USER_AGENT);
+ return mDependencies.getDeviceConfigProperty(NAMESPACE_CONNECTIVITY,
+ CAPTIVE_PORTAL_USER_AGENT, DEFAULT_USER_AGENT);
}
private URL nextFallbackUrl() {
@@ -1440,6 +1484,45 @@ public class NetworkMonitor extends StateMachine {
return sendHttpProbe(url, probeType, null);
}
+ /** Do a DNS lookup for the given server, or throw UnknownHostException after timeoutMs */
+ @VisibleForTesting
+ protected InetAddress[] sendDnsProbeWithTimeout(String host, int timeoutMs)
+ throws UnknownHostException {
+ final CountDownLatch latch = new CountDownLatch(1);
+ final AtomicReference<List<InetAddress>> resultRef = new AtomicReference<>();
+ final DnsResolver.Callback<List<InetAddress>> callback =
+ new DnsResolver.Callback<List<InetAddress>>() {
+ public void onAnswer(List<InetAddress> answer, int rcode) {
+ if (rcode == 0) {
+ resultRef.set(answer);
+ }
+ latch.countDown();
+ }
+ public void onError(@NonNull DnsResolver.DnsException e) {
+ validationLog("DNS error resolving " + host + ": " + e.getMessage());
+ latch.countDown();
+ }
+ };
+
+ final int oldTag = TrafficStats.getAndSetThreadStatsTag(
+ TrafficStatsConstants.TAG_SYSTEM_PROBE);
+ mDependencies.getDnsResolver().query(mNetwork, host, DnsResolver.FLAG_EMPTY,
+ r -> r.run() /* executor */, null /* cancellationSignal */, callback);
+ TrafficStats.setThreadStatsTag(oldTag);
+
+ try {
+ latch.await(timeoutMs, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ }
+
+ List<InetAddress> result = resultRef.get();
+ if (result == null || result.size() == 0) {
+ throw new UnknownHostException(host);
+ }
+
+ return result.toArray(new InetAddress[0]);
+ }
+
/** Do a DNS resolution of the given server. */
private void sendDnsProbe(String host) {
if (TextUtils.isEmpty(host)) {
@@ -1451,7 +1534,7 @@ public class NetworkMonitor extends StateMachine {
int result;
String connectInfo;
try {
- InetAddress[] addresses = mNetwork.getAllByName(host);
+ InetAddress[] addresses = sendDnsProbeWithTimeout(host, getDnsProbeTimeout());
StringBuffer buffer = new StringBuffer();
for (InetAddress address : addresses) {
buffer.append(',').append(address.getHostAddress());
@@ -1776,6 +1859,10 @@ public class NetworkMonitor extends StateMachine {
return new OneAddressPerFamilyNetwork(network);
}
+ public DnsResolver getDnsResolver() {
+ return DnsResolver.getInstance();
+ }
+
public Random getRandom() {
return new Random();
}
diff --git a/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreService.java b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreService.java
index bee4bbd9f42d..6a6bf83bd3c8 100644
--- a/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreService.java
+++ b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreService.java
@@ -494,4 +494,9 @@ public class IpMemoryStoreService extends IIpMemoryStore.Stub {
listener.onComplete(makeStatus(ERROR_INTERNAL_INTERRUPTED));
return true;
}
+
+ @Override
+ public int getInterfaceVersion() {
+ return this.VERSION;
+ }
}
diff --git a/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/RegularMaintenanceJobService.java b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/RegularMaintenanceJobService.java
index 2775fde4c8b9..bea7052d8af2 100644
--- a/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/RegularMaintenanceJobService.java
+++ b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/RegularMaintenanceJobService.java
@@ -91,6 +91,11 @@ public final class RegularMaintenanceJobService extends JobService {
}
@Override
+ public int getInterfaceVersion() {
+ return this.VERSION;
+ }
+
+ @Override
public IBinder asBinder() {
return null;
}
diff --git a/packages/NetworkStack/tests/src/android/net/apf/ApfTest.java b/packages/NetworkStack/tests/src/android/net/apf/ApfTest.java
index a0e508f130a5..93ab3be28fc7 100644
--- a/packages/NetworkStack/tests/src/android/net/apf/ApfTest.java
+++ b/packages/NetworkStack/tests/src/android/net/apf/ApfTest.java
@@ -1553,7 +1553,7 @@ public class ApfTest {
parcel.seq = seqNum;
parcel.ack = ackNum;
- apfFilter.addKeepalivePacketFilter(slot1, parcel);
+ apfFilter.addTcpKeepalivePacketFilter(slot1, parcel);
program = cb.getApfProgram();
// Verify IPv4 keepalive ack packet is dropped
@@ -1592,7 +1592,7 @@ public class ApfTest {
ipv6Parcel.seq = seqNum;
ipv6Parcel.ack = ackNum;
- apfFilter.addKeepalivePacketFilter(slot1, ipv6Parcel);
+ apfFilter.addTcpKeepalivePacketFilter(slot1, ipv6Parcel);
program = cb.getApfProgram();
// Verify IPv6 keepalive ack packet is dropped
@@ -1614,8 +1614,8 @@ public class ApfTest {
apfFilter.removeKeepalivePacketFilter(slot1);
// Verify multiple filters
- apfFilter.addKeepalivePacketFilter(slot1, parcel);
- apfFilter.addKeepalivePacketFilter(slot2, ipv6Parcel);
+ apfFilter.addTcpKeepalivePacketFilter(slot1, parcel);
+ apfFilter.addTcpKeepalivePacketFilter(slot2, ipv6Parcel);
program = cb.getApfProgram();
// Verify IPv4 keepalive ack packet is dropped
diff --git a/packages/NetworkStack/tests/src/android/net/dhcp/DhcpPacketTest.java b/packages/NetworkStack/tests/src/android/net/dhcp/DhcpPacketTest.java
index 4d98403bfd4e..a30d3e492406 100644
--- a/packages/NetworkStack/tests/src/android/net/dhcp/DhcpPacketTest.java
+++ b/packages/NetworkStack/tests/src/android/net/dhcp/DhcpPacketTest.java
@@ -302,8 +302,9 @@ public class DhcpPacketTest {
}
private void assertDhcpResults(String ipAddress, String gateway, String dnsServersString,
- String domains, String serverAddress, String vendorInfo, int leaseDuration,
- boolean hasMeteredHint, int mtu, DhcpResults dhcpResults) throws Exception {
+ String domains, String serverAddress, String serverHostName, String vendorInfo,
+ int leaseDuration, boolean hasMeteredHint, int mtu, DhcpResults dhcpResults)
+ throws Exception {
assertEquals(new LinkAddress(ipAddress), dhcpResults.ipAddress);
assertEquals(v4Address(gateway), dhcpResults.gateway);
@@ -316,6 +317,7 @@ public class DhcpPacketTest {
assertEquals(domains, dhcpResults.domains);
assertEquals(v4Address(serverAddress), dhcpResults.serverAddress);
+ assertEquals(serverHostName, dhcpResults.serverHostName);
assertEquals(vendorInfo, dhcpResults.vendorInfo);
assertEquals(leaseDuration, dhcpResults.leaseDuration);
assertEquals(hasMeteredHint, dhcpResults.hasMeteredHint());
@@ -327,6 +329,7 @@ public class DhcpPacketTest {
// TODO: Turn all of these into golden files. This will probably require using
// androidx.test.InstrumentationRegistry for obtaining a Context object
// to read such golden files, along with an appropriate Android.mk.
+ // CHECKSTYLE:OFF Generated code
final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
// IP header.
"451001480000000080118849c0a89003c0a89ff7" +
@@ -347,16 +350,18 @@ public class DhcpPacketTest {
// Options
"638253633501023604c0a89003330400001c200104fffff0000304c0a89ffe06080808080808080404" +
"3a0400000e103b040000189cff00000000000000000000"));
+ // CHECKSTYLE:ON Generated code
DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
assertTrue(offerPacket instanceof DhcpOfferPacket); // Implicitly checks it's non-null.
DhcpResults dhcpResults = offerPacket.toDhcpResults();
assertDhcpResults("192.168.159.247/20", "192.168.159.254", "8.8.8.8,8.8.4.4",
- null, "192.168.144.3", null, 7200, false, 0, dhcpResults);
+ null, "192.168.144.3", "", null, 7200, false, 0, dhcpResults);
}
@Test
public void testOffer2() throws Exception {
+ // CHECKSTYLE:OFF Generated code
final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
// IP header.
"450001518d0600004011144dc0a82b01c0a82bf7" +
@@ -366,9 +371,9 @@ public class DhcpPacketTest {
"02010600dfc23d1f0002000000000000c0a82bf7c0a82b0100000000" +
// MAC address.
"30766ff2a90c00000000000000000000" +
- // Server name.
- "0000000000000000000000000000000000000000000000000000000000000000" +
- "0000000000000000000000000000000000000000000000000000000000000000" +
+ // Server name ("dhcp.android.com" plus invalid "AAAA" after null terminator).
+ "646863702e616e64726f69642e636f6d00000000000000000000000000000000" +
+ "0000000000004141414100000000000000000000000000000000000000000000" +
// File.
"0000000000000000000000000000000000000000000000000000000000000000" +
"0000000000000000000000000000000000000000000000000000000000000000" +
@@ -377,13 +382,15 @@ public class DhcpPacketTest {
// Options
"638253633501023604c0a82b01330400000e103a04000007083b0400000c4e0104ffffff00" +
"1c04c0a82bff0304c0a82b010604c0a82b012b0f414e44524f49445f4d455445524544ff"));
+ // CHECKSTYLE:ON Generated code
assertEquals(337, packet.limit());
DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
assertTrue(offerPacket instanceof DhcpOfferPacket); // Implicitly checks it's non-null.
DhcpResults dhcpResults = offerPacket.toDhcpResults();
assertDhcpResults("192.168.43.247/24", "192.168.43.1", "192.168.43.1",
- null, "192.168.43.1", "ANDROID_METERED", 3600, true, 0, dhcpResults);
+ null, "192.168.43.1", "dhcp.android.com", "ANDROID_METERED", 3600, true, 0,
+ dhcpResults);
assertTrue(dhcpResults.hasMeteredHint());
}
@@ -588,11 +595,12 @@ public class DhcpPacketTest {
assertTrue(offerPacket instanceof DhcpOfferPacket); // Implicitly checks it's non-null.
DhcpResults dhcpResults = offerPacket.toDhcpResults();
assertDhcpResults("192.168.159.247/20", "192.168.159.254", "8.8.8.8,8.8.4.4",
- null, "192.168.144.3", null, 7200, false, expectedMtu, dhcpResults);
+ null, "192.168.144.3", "", null, 7200, false, expectedMtu, dhcpResults);
}
@Test
public void testMtu() throws Exception {
+ // CHECKSTYLE:OFF Generated code
final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
// IP header.
"451001480000000080118849c0a89003c0a89ff7" +
@@ -613,6 +621,7 @@ public class DhcpPacketTest {
// Options
"638253633501023604c0a89003330400001c200104fffff0000304c0a89ffe06080808080808080404" +
"3a0400000e103b040000189cff00000000"));
+ // CHECKSTYLE:ON Generated code
checkMtu(packet, 0, null);
checkMtu(packet, 0, mtuBytes(1501));
@@ -629,6 +638,7 @@ public class DhcpPacketTest {
@Test
public void testBadHwaddrLength() throws Exception {
+ // CHECKSTYLE:OFF Generated code
final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
// IP header.
"450001518d0600004011144dc0a82b01c0a82bf7" +
@@ -649,6 +659,7 @@ public class DhcpPacketTest {
// Options
"638253633501023604c0a82b01330400000e103a04000007083b0400000c4e0104ffffff00" +
"1c04c0a82bff0304c0a82b010604c0a82b012b0f414e44524f49445f4d455445524544ff"));
+ // CHECKSTYLE:ON Generated code
String expectedClientMac = "30766FF2A90C";
final int hwAddrLenOffset = 20 + 8 + 2;
@@ -705,6 +716,7 @@ public class DhcpPacketTest {
// store any information in the overloaded fields).
//
// For now, we just check that it parses correctly.
+ // CHECKSTYLE:OFF Generated code
final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
// Ethernet header.
"b4cef6000000e80462236e300800" +
@@ -727,16 +739,18 @@ public class DhcpPacketTest {
// Options
"638253633501023604010101010104ffff000033040000a8c03401030304ac1101010604ac110101" +
"0000000000000000000000000000000000000000000000ff000000"));
+ // CHECKSTYLE:ON Generated code
DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L2);
assertTrue(offerPacket instanceof DhcpOfferPacket);
DhcpResults dhcpResults = offerPacket.toDhcpResults();
assertDhcpResults("172.17.152.118/16", "172.17.1.1", "172.17.1.1",
- null, "1.1.1.1", null, 43200, false, 0, dhcpResults);
+ null, "1.1.1.1", "", null, 43200, false, 0, dhcpResults);
}
@Test
public void testBug2111() throws Exception {
+ // CHECKSTYLE:OFF Generated code
final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
// IP header.
"4500014c00000000ff119beac3eaf3880a3f5d04" +
@@ -757,16 +771,18 @@ public class DhcpPacketTest {
// Options.
"638253633501023604c00002fe33040000bfc60104fffff00003040a3f50010608c0000201c0000202" +
"0f0f646f6d61696e3132332e636f2e756b0000000000ff00000000"));
+ // CHECKSTYLE:ON Generated code
DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
assertTrue(offerPacket instanceof DhcpOfferPacket);
DhcpResults dhcpResults = offerPacket.toDhcpResults();
assertDhcpResults("10.63.93.4/20", "10.63.80.1", "192.0.2.1,192.0.2.2",
- "domain123.co.uk", "192.0.2.254", null, 49094, false, 0, dhcpResults);
+ "domain123.co.uk", "192.0.2.254", "", null, 49094, false, 0, dhcpResults);
}
@Test
public void testBug2136() throws Exception {
+ // CHECKSTYLE:OFF Generated code
final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
// Ethernet header.
"bcf5ac000000d0c7890000000800" +
@@ -789,17 +805,19 @@ public class DhcpPacketTest {
// Options.
"6382536335010236040a20ff80330400001c200104fffff00003040a20900106089458413494584135" +
"0f0b6c616e63732e61632e756b000000000000000000ff00000000"));
+ // CHECKSTYLE:ON Generated code
DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L2);
assertTrue(offerPacket instanceof DhcpOfferPacket);
assertEquals("BCF5AC000000", HexDump.toHexString(offerPacket.getClientMac()));
DhcpResults dhcpResults = offerPacket.toDhcpResults();
assertDhcpResults("10.32.158.205/20", "10.32.144.1", "148.88.65.52,148.88.65.53",
- "lancs.ac.uk", "10.32.255.128", null, 7200, false, 0, dhcpResults);
+ "lancs.ac.uk", "10.32.255.128", "", null, 7200, false, 0, dhcpResults);
}
@Test
public void testUdpServerAnySourcePort() throws Exception {
+ // CHECKSTYLE:OFF Generated code
final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
// Ethernet header.
"9cd917000000001c2e0000000800" +
@@ -823,6 +841,7 @@ public class DhcpPacketTest {
// Options.
"6382536335010236040a0169fc3304000151800104ffff000003040a0fc817060cd1818003d1819403" +
"d18180060f0777766d2e6564751c040a0fffffff000000"));
+ // CHECKSTYLE:ON Generated code
DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L2);
assertTrue(offerPacket instanceof DhcpOfferPacket);
@@ -830,11 +849,12 @@ public class DhcpPacketTest {
DhcpResults dhcpResults = offerPacket.toDhcpResults();
assertDhcpResults("10.15.122.242/16", "10.15.200.23",
"209.129.128.3,209.129.148.3,209.129.128.6",
- "wvm.edu", "10.1.105.252", null, 86400, false, 0, dhcpResults);
+ "wvm.edu", "10.1.105.252", "", null, 86400, false, 0, dhcpResults);
}
@Test
public void testUdpInvalidDstPort() throws Exception {
+ // CHECKSTYLE:OFF Generated code
final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
// Ethernet header.
"9cd917000000001c2e0000000800" +
@@ -858,6 +878,7 @@ public class DhcpPacketTest {
// Options.
"6382536335010236040a0169fc3304000151800104ffff000003040a0fc817060cd1818003d1819403" +
"d18180060f0777766d2e6564751c040a0fffffff000000"));
+ // CHECKSTYLE:ON Generated code
try {
DhcpPacket.decodeFullPacket(packet, ENCAP_L2);
@@ -867,6 +888,7 @@ public class DhcpPacketTest {
@Test
public void testMultipleRouters() throws Exception {
+ // CHECKSTYLE:OFF Generated code
final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
// Ethernet header.
"fc3d93000000" + "081735000000" + "0800" +
@@ -889,13 +911,14 @@ public class DhcpPacketTest {
// Options.
"638253633501023604c0abbd023304000070803a04000038403b04000062700104ffffff00" +
"0308c0a8bd01ffffff0006080808080808080404ff000000000000"));
+ // CHECKSTYLE:ON Generated code
DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L2);
assertTrue(offerPacket instanceof DhcpOfferPacket);
assertEquals("FC3D93000000", HexDump.toHexString(offerPacket.getClientMac()));
DhcpResults dhcpResults = offerPacket.toDhcpResults();
assertDhcpResults("192.168.189.49/24", "192.168.189.1", "8.8.8.8,8.8.4.4",
- null, "192.171.189.2", null, 28800, false, 0, dhcpResults);
+ null, "192.171.189.2", "", null, 28800, false, 0, dhcpResults);
}
@Test
diff --git a/packages/NetworkStack/tests/src/android/net/dhcp/DhcpServerTest.java b/packages/NetworkStack/tests/src/android/net/dhcp/DhcpServerTest.java
index 7d5e9e3ba174..f0e2f1b8d459 100644
--- a/packages/NetworkStack/tests/src/android/net/dhcp/DhcpServerTest.java
+++ b/packages/NetworkStack/tests/src/android/net/dhcp/DhcpServerTest.java
@@ -133,6 +133,11 @@ public class DhcpServerTest {
public void onStatusAvailable(int statusCode) {
assertEquals(STATUS_SUCCESS, statusCode);
}
+
+ @Override
+ public int getInterfaceVersion() {
+ return this.VERSION;
+ }
};
@Before
diff --git a/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java b/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java
index 910bdc7e600f..0dc1cbf8a984 100644
--- a/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java
+++ b/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java
@@ -26,10 +26,14 @@ import static android.net.util.DataStallUtils.CONFIG_DATA_STALL_EVALUATION_TYPE;
import static android.net.util.DataStallUtils.CONFIG_DATA_STALL_MIN_EVALUATE_INTERVAL;
import static android.net.util.DataStallUtils.CONFIG_DATA_STALL_VALID_DNS_TIME_THRESHOLD;
import static android.net.util.DataStallUtils.DATA_STALL_EVALUATION_TYPE_DNS;
+import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS;
+import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS;
+import static android.net.util.NetworkStackUtils.CAPTIVE_PORTAL_USE_HTTPS;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
+import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@@ -38,6 +42,7 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.never;
@@ -52,6 +57,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.net.ConnectivityManager;
+import android.net.DnsResolver;
import android.net.INetworkMonitorCallbacks;
import android.net.InetAddresses;
import android.net.LinkProperties;
@@ -66,6 +72,7 @@ import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.os.ConditionVariable;
import android.os.Handler;
+import android.os.Looper;
import android.os.RemoteException;
import android.os.SystemClock;
import android.provider.Settings;
@@ -76,6 +83,7 @@ import android.util.ArrayMap;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.networkstack.R;
import com.android.networkstack.metrics.DataStallDetectionStats;
import com.android.networkstack.metrics.DataStallStatsUtils;
@@ -93,8 +101,12 @@ import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.URL;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
import java.util.HashSet;
+import java.util.List;
import java.util.Random;
+import java.util.concurrent.Executor;
import javax.net.ssl.SSLHandshakeException;
@@ -108,6 +120,7 @@ public class NetworkMonitorTest {
private @Mock IpConnectivityLog mLogger;
private @Mock SharedLog mValidationLogger;
private @Mock NetworkInfo mNetworkInfo;
+ private @Mock DnsResolver mDnsResolver;
private @Mock ConnectivityManager mCm;
private @Mock TelephonyManager mTelephony;
private @Mock WifiManager mWifi;
@@ -153,14 +166,40 @@ public class NetworkMonitorTest {
private static final NetworkCapabilities NO_INTERNET_CAPABILITIES = new NetworkCapabilities()
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
+ private void setDnsAnswers(String[] answers) throws UnknownHostException {
+ if (answers == null) {
+ doThrow(new UnknownHostException()).when(mNetwork).getAllByName(any());
+ doNothing().when(mDnsResolver).query(any(), any(), anyInt(), any(), any(), any());
+ return;
+ }
+
+ List<InetAddress> answerList = new ArrayList<>();
+ for (String answer : answers) {
+ answerList.add(InetAddresses.parseNumericAddress(answer));
+ }
+ InetAddress[] answerArray = answerList.toArray(new InetAddress[0]);
+
+ doReturn(answerArray).when(mNetwork).getAllByName(any());
+
+ doAnswer((invocation) -> {
+ Executor executor = (Executor) invocation.getArgument(3);
+ DnsResolver.Callback<List<InetAddress>> callback = invocation.getArgument(5);
+ new Handler(Looper.getMainLooper()).post(() -> {
+ executor.execute(() -> callback.onAnswer(answerList, 0));
+ });
+ return null;
+ }).when(mDnsResolver).query(eq(mNetwork), any(), anyInt(), any(), any(), any());
+ }
+
@Before
public void setUp() throws IOException {
MockitoAnnotations.initMocks(this);
when(mDependencies.getPrivateDnsBypassNetwork(any())).thenReturn(mNetwork);
+ when(mDependencies.getDnsResolver()).thenReturn(mDnsResolver);
when(mDependencies.getRandom()).thenReturn(mRandom);
when(mDependencies.getSetting(any(), eq(Settings.Global.CAPTIVE_PORTAL_MODE), anyInt()))
.thenReturn(Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT);
- when(mDependencies.getSetting(any(), eq(Settings.Global.CAPTIVE_PORTAL_USE_HTTPS),
+ when(mDependencies.getDeviceConfigPropertyInt(any(), eq(CAPTIVE_PORTAL_USE_HTTPS),
anyInt())).thenReturn(1);
when(mDependencies.getSetting(any(), eq(Settings.Global.CAPTIVE_PORTAL_HTTP_URL), any()))
.thenReturn(TEST_HTTP_URL);
@@ -201,9 +240,8 @@ public class NetworkMonitorTest {
}).when(mNetwork).openConnection(any());
when(mHttpConnection.getRequestProperties()).thenReturn(new ArrayMap<>());
when(mHttpsConnection.getRequestProperties()).thenReturn(new ArrayMap<>());
- doReturn(new InetAddress[] {
- InetAddresses.parseNumericAddress("192.168.0.0")
- }).when(mNetwork).getAllByName(any());
+
+ setDnsAnswers(new String[]{"2001:db8::1", "192.0.2.2"});
when(mContext.registerReceiver(any(BroadcastReceiver.class), any())).then((invocation) -> {
mRegisteredReceivers.add(invocation.getArgument(0));
@@ -310,6 +348,44 @@ public class NetworkMonitorTest {
}
@Test
+ public void testGetIntSetting() throws Exception {
+ WrappedNetworkMonitor wnm = makeNotMeteredNetworkMonitor();
+
+ // No config resource, no device config. Expect to get default resource.
+ doThrow(new Resources.NotFoundException())
+ .when(mResources).getInteger(eq(R.integer.config_captive_portal_dns_probe_timeout));
+ doAnswer(invocation -> {
+ int defaultValue = invocation.getArgument(2);
+ return defaultValue;
+ }).when(mDependencies).getDeviceConfigPropertyInt(any(),
+ eq(NetworkMonitor.CONFIG_CAPTIVE_PORTAL_DNS_PROBE_TIMEOUT),
+ anyInt());
+ when(mResources.getInteger(eq(R.integer.default_captive_portal_dns_probe_timeout)))
+ .thenReturn(42);
+ assertEquals(42, wnm.getIntSetting(mContext,
+ R.integer.config_captive_portal_dns_probe_timeout,
+ NetworkMonitor.CONFIG_CAPTIVE_PORTAL_DNS_PROBE_TIMEOUT,
+ R.integer.default_captive_portal_dns_probe_timeout));
+
+ // Set device config. Expect to get device config.
+ when(mDependencies.getDeviceConfigPropertyInt(any(),
+ eq(NetworkMonitor.CONFIG_CAPTIVE_PORTAL_DNS_PROBE_TIMEOUT), anyInt()))
+ .thenReturn(1234);
+ assertEquals(1234, wnm.getIntSetting(mContext,
+ R.integer.config_captive_portal_dns_probe_timeout,
+ NetworkMonitor.CONFIG_CAPTIVE_PORTAL_DNS_PROBE_TIMEOUT,
+ R.integer.default_captive_portal_dns_probe_timeout));
+
+ // Set config resource. Expect to get config resource.
+ when(mResources.getInteger(eq(R.integer.config_captive_portal_dns_probe_timeout)))
+ .thenReturn(5678);
+ assertEquals(5678, wnm.getIntSetting(mContext,
+ R.integer.config_captive_portal_dns_probe_timeout,
+ NetworkMonitor.CONFIG_CAPTIVE_PORTAL_DNS_PROBE_TIMEOUT,
+ R.integer.default_captive_portal_dns_probe_timeout));
+ }
+
+ @Test
public void testIsCaptivePortal_HttpProbeIsPortal() throws IOException {
setSslException(mHttpsConnection);
setPortal302(mHttpConnection);
@@ -639,6 +715,45 @@ public class NetworkMonitorTest {
runPartialConnectivityNetworkTest();
}
+ private void assertIpAddressArrayEquals(String[] expected, InetAddress[] actual) {
+ String[] actualStrings = new String[actual.length];
+ for (int i = 0; i < actual.length; i++) {
+ actualStrings[i] = actual[i].getHostAddress();
+ }
+ assertArrayEquals("Array of IP addresses differs", expected, actualStrings);
+ }
+
+ @Test
+ public void testSendDnsProbeWithTimeout() throws Exception {
+ WrappedNetworkMonitor wnm = makeNotMeteredNetworkMonitor();
+ final int shortTimeoutMs = 200;
+
+ String[] expected = new String[]{"2001:db8::"};
+ setDnsAnswers(expected);
+ InetAddress[] actual = wnm.sendDnsProbeWithTimeout("www.google.com", shortTimeoutMs);
+ assertIpAddressArrayEquals(expected, actual);
+
+ expected = new String[]{"2001:db8::", "192.0.2.1"};
+ setDnsAnswers(expected);
+ actual = wnm.sendDnsProbeWithTimeout("www.google.com", shortTimeoutMs);
+ assertIpAddressArrayEquals(expected, actual);
+
+ expected = new String[0];
+ setDnsAnswers(expected);
+ try {
+ wnm.sendDnsProbeWithTimeout("www.google.com", shortTimeoutMs);
+ fail("No DNS results, expected UnknownHostException");
+ } catch (UnknownHostException e) {
+ }
+
+ setDnsAnswers(null);
+ try {
+ wnm.sendDnsProbeWithTimeout("www.google.com", shortTimeoutMs);
+ fail("DNS query timed out, expected UnknownHostException");
+ } catch (UnknownHostException e) {
+ }
+ }
+
private void makeDnsTimeoutEvent(WrappedNetworkMonitor wrappedMonitor, int count) {
for (int i = 0; i < count; i++) {
wrappedMonitor.getDnsStallDetector().accumulateConsecutiveDnsTimeoutCount(
@@ -683,13 +798,13 @@ public class NetworkMonitorTest {
}
private void setOtherFallbackUrls(String urls) {
- when(mDependencies.getSetting(any(),
- eq(Settings.Global.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS), any())).thenReturn(urls);
+ when(mDependencies.getDeviceConfigProperty(any(),
+ eq(CAPTIVE_PORTAL_OTHER_FALLBACK_URLS), any())).thenReturn(urls);
}
private void setFallbackSpecs(String specs) {
- when(mDependencies.getSetting(any(),
- eq(Settings.Global.CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS), any())).thenReturn(specs);
+ when(mDependencies.getDeviceConfigProperty(any(),
+ eq(CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS), any())).thenReturn(specs);
}
private void setCaptivePortalMode(int mode) {
diff --git a/packages/NetworkStack/tests/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java b/packages/NetworkStack/tests/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java
index a00eff7992d4..87346e5d6a28 100644
--- a/packages/NetworkStack/tests/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java
+++ b/packages/NetworkStack/tests/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java
@@ -136,6 +136,11 @@ public class IpMemoryStoreServiceTest {
public IBinder asBinder() {
return null;
}
+
+ @Override
+ public int getInterfaceVersion() {
+ return this.VERSION;
+ }
};
}
@@ -156,6 +161,11 @@ public class IpMemoryStoreServiceTest {
public IBinder asBinder() {
return null;
}
+
+ @Override
+ public int getInterfaceVersion() {
+ return this.VERSION;
+ }
};
}
@@ -178,6 +188,11 @@ public class IpMemoryStoreServiceTest {
public IBinder asBinder() {
return null;
}
+
+ @Override
+ public int getInterfaceVersion() {
+ return this.VERSION;
+ }
};
}
@@ -200,6 +215,11 @@ public class IpMemoryStoreServiceTest {
public IBinder asBinder() {
return null;
}
+
+ @Override
+ public int getInterfaceVersion() {
+ return this.VERSION;
+ }
};
}
@@ -219,6 +239,11 @@ public class IpMemoryStoreServiceTest {
public IBinder asBinder() {
return null;
}
+
+ @Override
+ public int getInterfaceVersion() {
+ return this.VERSION;
+ }
};
}