diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/android/net/apf/ApfFilter.java | 26 | ||||
-rw-r--r-- | src/android/net/ip/IpClient.java | 30 | ||||
-rw-r--r-- | src/android/net/ip/IpClientLinkObserver.java | 28 |
3 files changed, 76 insertions, 8 deletions
diff --git a/src/android/net/apf/ApfFilter.java b/src/android/net/apf/ApfFilter.java index 75a737d..165e37b 100644 --- a/src/android/net/apf/ApfFilter.java +++ b/src/android/net/apf/ApfFilter.java @@ -105,6 +105,7 @@ public class ApfFilter { public boolean multicastFilter; public boolean ieee802_3Filter; public int[] ethTypeBlackList; + public int minRdnssLifetimeSec; } // Enums describing the outcome of receiving an RA packet. @@ -358,6 +359,9 @@ public class ApfFilter { private final boolean mDrop802_3Frames; private final int[] mEthTypeBlackList; + // Ignore non-zero RDNSS lifetimes below this value. + private final int mMinRdnssLifetimeSec; + // Detects doze mode state transitions. private final BroadcastReceiver mDeviceIdleReceiver = new BroadcastReceiver() { @Override @@ -388,6 +392,7 @@ public class ApfFilter { mInterfaceParams = ifParams; mMulticastFilter = config.multicastFilter; mDrop802_3Frames = config.ieee802_3Filter; + mMinRdnssLifetimeSec = config.minRdnssLifetimeSec; mContext = context; if (mApfCapabilities.hasDataAccess()) { @@ -748,6 +753,19 @@ public class ApfFilter { return lifetime; } + // http://b/66928272 http://b/65056012 + // DnsServerRepository ignores RDNSS servers with lifetimes that are too low. Ignore these + // lifetimes for the purpose of filter lifetime calculations. + private boolean shouldIgnoreLifetime(int optionType, long lifetime) { + return optionType == ICMP6_RDNSS_OPTION_TYPE + && lifetime != 0 && lifetime < mMinRdnssLifetimeSec; + } + + private boolean isRelevantLifetime(PacketSection section) { + return section.type == PacketSection.Type.LIFETIME + && !shouldIgnoreLifetime(section.option, section.lifetime); + } + // Note that this parses RA and may throw InvalidRaException (from // Buffer.position(int) or due to an invalid-length option) or IndexOutOfBoundsException // (from ByteBuffer.get(int) ) if parsing encounters something non-compliant with @@ -862,7 +880,7 @@ public class ApfFilter { long minLifetime() { long minLifetime = Long.MAX_VALUE; for (PacketSection section : mPacketSections) { - if (section.type == PacketSection.Type.LIFETIME) { + if (isRelevantLifetime(section)) { minLifetime = Math.min(minLifetime, section.lifetime); } } @@ -902,9 +920,10 @@ public class ApfFilter { section.start + section.length), nextFilterLabel); } + // Generate code to test the lifetimes haven't gone down too far. - // The packet is accepted if any of its lifetimes are lower than filterLifetime. - if (section.type == PacketSection.Type.LIFETIME) { + // The packet is accepted if any non-ignored lifetime is lower than filterLifetime. + if (isRelevantLifetime(section)) { switch (section.length) { case 4: gen.addLoad32(Register.R0, section.start); break; case 2: gen.addLoad16(Register.R0, section.start); break; @@ -1913,6 +1932,7 @@ public class ApfFilter { pw.println("Capabilities: " + mApfCapabilities); pw.println("Receive thread: " + (mReceiveThread != null ? "RUNNING" : "STOPPED")); pw.println("Multicast: " + (mMulticastFilter ? "DROP" : "ALLOW")); + pw.println("Minimum RDNSS lifetime: " + mMinRdnssLifetimeSec); try { pw.println("IPv4 address: " + InetAddress.getByAddress(mIPv4Address).getHostAddress()); } catch (UnknownHostException|NullPointerException e) {} diff --git a/src/android/net/ip/IpClient.java b/src/android/net/ip/IpClient.java index 9f1f17c..8808ee2 100644 --- a/src/android/net/ip/IpClient.java +++ b/src/android/net/ip/IpClient.java @@ -18,6 +18,7 @@ package android.net.ip; import static android.net.RouteInfo.RTN_UNICAST; import static android.net.shared.IpConfigurationParcelableUtil.toStableParcelable; +import static android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY; import static com.android.server.util.PermissionUtil.enforceNetworkStackCallingPermission; @@ -42,7 +43,9 @@ import android.net.metrics.IpManagerEvent; import android.net.shared.InitialConfiguration; import android.net.shared.ProvisioningConfiguration; import android.net.util.InterfaceParams; +import android.net.util.NetworkStackUtils; import android.net.util.SharedLog; +import android.os.Build; import android.os.ConditionVariable; import android.os.IBinder; import android.os.Message; @@ -65,6 +68,7 @@ import com.android.internal.util.Preconditions; import com.android.internal.util.State; import com.android.internal.util.StateMachine; import com.android.internal.util.WakeupMessage; +import com.android.networkstack.apishim.ShimUtils; import com.android.server.NetworkObserverRegistry; import com.android.server.NetworkStackService.NetworkStackServiceManager; @@ -313,9 +317,15 @@ public class IpClient extends StateMachine { // IpClient shares a handler with DhcpClient: commands must not overlap public static final int DHCPCLIENT_CMD_BASE = 1000; + // Settings and default values. private static final int MAX_LOG_RECORDS = 500; private static final int MAX_PACKET_RECORDS = 100; + @VisibleForTesting + static final String CONFIG_MIN_RDNSS_LIFETIME = "ipclient_min_rdnss_lifetime"; + private static final int DEFAULT_MIN_RDNSS_LIFETIME = + ShimUtils.isReleaseOrDevelopmentApiAbove(Build.VERSION_CODES.Q) ? 120 : 0; + private static final boolean NO_CALLBACKS = false; private static final boolean SEND_CALLBACKS = true; @@ -355,6 +365,9 @@ public class IpClient extends StateMachine { private final IpConnectivityLog mMetricsLog = new IpConnectivityLog(); private final InterfaceController mInterfaceCtrl; + // Ignore nonzero RDNSS option lifetimes below this value. 0 = disabled. + private final int mMinRdnssLifetimeSec; + private InterfaceParams mInterfaceParams; /** @@ -411,6 +424,14 @@ public class IpClient extends StateMachine { NetworkStackIpMemoryStore ipMemoryStore) { return new DhcpClient.Dependencies(ipMemoryStore); } + + /** + * Read an integer DeviceConfig property. + */ + public int getDeviceConfigPropertyInt(String name, int defaultValue) { + return NetworkStackUtils.getDeviceConfigPropertyInt(NAMESPACE_CONNECTIVITY, name, + defaultValue); + } } public IpClient(Context context, String ifName, IIpClientCallbacks callback, @@ -449,9 +470,15 @@ public class IpClient extends StateMachine { mNetd = deps.getNetd(mContext); mInterfaceCtrl = new InterfaceController(mInterfaceName, mNetd, mLog); + mMinRdnssLifetimeSec = mDependencies.getDeviceConfigPropertyInt( + CONFIG_MIN_RDNSS_LIFETIME, DEFAULT_MIN_RDNSS_LIFETIME); + + IpClientLinkObserver.Configuration config = new IpClientLinkObserver.Configuration( + mMinRdnssLifetimeSec); + mLinkObserver = new IpClientLinkObserver( mInterfaceName, - () -> sendMessage(EVENT_NETLINK_LINKPROPERTIES_CHANGED)) { + () -> sendMessage(EVENT_NETLINK_LINKPROPERTIES_CHANGED), config) { @Override public void onInterfaceAdded(String iface) { super.onInterfaceAdded(iface); @@ -1500,6 +1527,7 @@ public class IpClient extends StateMachine { // Get the Configuration for ApfFilter from Context apfConfig.ieee802_3Filter = ApfCapabilities.getApfDrop8023Frames(); apfConfig.ethTypeBlackList = ApfCapabilities.getApfEtherTypeBlackList(); + apfConfig.minRdnssLifetimeSec = mMinRdnssLifetimeSec; mApfFilter = ApfFilter.maybeCreate(mContext, apfConfig, mInterfaceParams, mCallback); // TODO: investigate the effects of any multicast filtering racing/interfering with the // rest of this IP configuration startup. diff --git a/src/android/net/ip/IpClientLinkObserver.java b/src/android/net/ip/IpClientLinkObserver.java index 3f399e9..02bf5f0 100644 --- a/src/android/net/ip/IpClientLinkObserver.java +++ b/src/android/net/ip/IpClientLinkObserver.java @@ -71,20 +71,31 @@ public class IpClientLinkObserver implements NetworkObserver { void update(); } + /** Configuration parameters for IpClientLinkObserver. */ + public static class Configuration { + public final int minRdnssLifetime; + + public Configuration(int minRdnssLifetime) { + this.minRdnssLifetime = minRdnssLifetime; + } + } + private final String mInterfaceName; private final Callback mCallback; private final LinkProperties mLinkProperties; private DnsServerRepository mDnsServerRepository; + private final Configuration mConfig; private static final boolean DBG = false; - public IpClientLinkObserver(String iface, Callback callback) { + public IpClientLinkObserver(String iface, Callback callback, Configuration config) { mTag = "NetlinkTracker/" + iface; mInterfaceName = iface; mCallback = callback; mLinkProperties = new LinkProperties(); mLinkProperties.setInterfaceName(mInterfaceName); - mDnsServerRepository = new DnsServerRepository(); + mConfig = config; + mDnsServerRepository = new DnsServerRepository(config.minRdnssLifetime); } private void maybeLog(String operation, String iface, LinkAddress address) { @@ -197,7 +208,7 @@ public class IpClientLinkObserver implements NetworkObserver { // Clear the repository before clearing mLinkProperties. That way, if a clear() happens // while interfaceDnsServerInfo() is being called, we'll end up with no DNS servers in // mLinkProperties, as desired. - mDnsServerRepository = new DnsServerRepository(); + mDnsServerRepository = new DnsServerRepository(mConfig.minRdnssLifetime); mLinkProperties.clear(); mLinkProperties.setInterfaceName(mInterfaceName); } @@ -260,10 +271,16 @@ public class IpClientLinkObserver implements NetworkObserver { */ private HashMap<InetAddress, DnsServerEntry> mIndex; - DnsServerRepository() { + /** + * Minimum (non-zero) RDNSS lifetime to accept. + */ + private final int mMinLifetime; + + DnsServerRepository(int minLifetime) { mCurrentServers = new HashSet<>(); mAllServers = new ArrayList<>(NUM_SERVERS); mIndex = new HashMap<>(NUM_SERVERS); + mMinLifetime = minLifetime; } /** Sets the DNS servers of the provided LinkProperties object to the current servers. */ @@ -277,6 +294,9 @@ public class IpClientLinkObserver implements NetworkObserver { * @param addresses the string representations of the IP addresses of DNS servers to use. */ public synchronized boolean addServers(long lifetime, String[] addresses) { + // If the servers are below the minimum lifetime, don't change anything. + if (lifetime != 0 && lifetime < mMinLifetime) return false; + // The lifetime is actually an unsigned 32-bit number, but Java doesn't have unsigned. // Technically 0xffffffff (the maximum) is special and means "forever", but 2^32 seconds // (136 years) is close enough. |