Loading src/android/net/apf/ApfFilter.java +23 −3 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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 Loading Loading @@ -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()) { Loading Loading @@ -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 Loading Loading @@ -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); } } Loading Loading @@ -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; Loading Loading @@ -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) {} Loading src/android/net/ip/IpClient.java +29 −1 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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; /** Loading Loading @@ -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, Loading Loading @@ -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); Loading Loading @@ -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. Loading src/android/net/ip/IpClientLinkObserver.java +24 −4 Original line number Diff line number Diff line Loading @@ -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) { Loading Loading @@ -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); } Loading Loading @@ -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. */ Loading @@ -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. Loading tests/integration/src/android/net/ip/IpClientIntegrationTest.java +31 −1 Original line number Diff line number Diff line Loading @@ -123,6 +123,7 @@ import java.net.NetworkInterface; import java.nio.ByteBuffer; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; Loading Loading @@ -235,6 +236,8 @@ public class IpClientIntegrationTest { private class Dependencies extends IpClient.Dependencies { private boolean mIsDhcpLeaseCacheEnabled; private boolean mIsDhcpRapidCommitEnabled; // Can't use SparseIntArray, it doesn't have an easy way to know if a key is not present. private HashMap<String, Integer> mIntConfigProperties = new HashMap<>(); public void setDhcpLeaseCacheEnabled(final boolean enable) { mIsDhcpLeaseCacheEnabled = enable; Loading Loading @@ -274,6 +277,19 @@ public class IpClientIntegrationTest { } }; } @Override public int getDeviceConfigPropertyInt(String name, int defaultValue) { Integer value = mIntConfigProperties.get(name); if (value == null) { throw new IllegalStateException("Non-mocked device config property " + name); } return value; } public void setDeviceConfigProperty(String name, int value) { mIntConfigProperties.put(name, value); } } @Before Loading @@ -288,6 +304,8 @@ public class IpClientIntegrationTest { when(mNetworkStackServiceManager.getIpMemoryStoreService()) .thenReturn(mIpMemoryStoreService); mDependencies.setDeviceConfigProperty(IpClient.CONFIG_MIN_RDNSS_LIFETIME, 67); setUpTapInterface(); setUpIpClient(); } Loading Loading @@ -410,6 +428,7 @@ public class IpClientIntegrationTest { try (FileOutputStream out = new FileOutputStream(mPacketReader.createFd())) { byte[] packetBytes = new byte[packet.limit()]; packet.get(packetBytes); packet.flip(); // So we can reuse it in the future. out.write(packetBytes); } } Loading Loading @@ -868,11 +887,22 @@ public class IpClientIntegrationTest { verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningSuccess(captor.capture()); LinkProperties lp = captor.getValue(); // Expect that DNS servers with lifetimes below CONFIG_MIN_RDNSS_LIFETIME are not accepted. assertNotNull(lp); assertEquals(1, lp.getDnsServers().size()); assertTrue(lp.getDnsServers().contains(InetAddress.getByName(dnsServer))); reset(mCb); // If the RDNSS lifetime is above the minimum, the DNS server is accepted. rdnss1 = buildRdnssOption(68, lowlifeDnsServer); ra = buildRaPacket(pio, rdnss1, rdnss2); sendResponse(ra); verify(mCb, timeout(TEST_TIMEOUT_MS)).onLinkPropertiesChange(captor.capture()); lp = captor.getValue(); assertNotNull(lp); assertEquals(2, lp.getDnsServers().size()); assertTrue(lp.getDnsServers().contains(InetAddress.getByName(dnsServer))); assertTrue(lp.getDnsServers().contains(InetAddress.getByName(lowlifeDnsServer))); reset(mCb); // Expect that setting RDNSS lifetime of 0 causes loss of provisioning. Loading tests/unit/src/android/net/apf/ApfTest.java +16 −1 Original line number Diff line number Diff line Loading @@ -130,6 +130,8 @@ public class ApfTest { private static final boolean DROP_802_3_FRAMES = true; private static final boolean ALLOW_802_3_FRAMES = false; private static final int MIN_RDNSS_LIFETIME_SEC = 0; // Constants for opcode encoding private static final byte LI_OP = (byte)(13 << 3); private static final byte LDDW_OP = (byte)(22 << 3); Loading @@ -146,6 +148,8 @@ public class ApfTest { config.multicastFilter = ALLOW_MULTICAST; config.ieee802_3Filter = ALLOW_802_3_FRAMES; config.ethTypeBlackList = new int[0]; config.minRdnssLifetimeSec = MIN_RDNSS_LIFETIME_SEC; config.minRdnssLifetimeSec = 67; return config; } Loading Loading @@ -2090,6 +2094,16 @@ public class ApfTest { verifyRaLifetime(apfFilter, ipClientCallback, rdnssOptionPacket, RDNSS_LIFETIME); verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, -1, RDNSS_LIFETIME, -1)); final int lowLifetime = 60; ByteBuffer lowLifetimeRdnssOptionPacket = ByteBuffer.wrap( new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN + IPV6_ADDR_LEN]); basePacket.clear(); lowLifetimeRdnssOptionPacket.put(basePacket); addRdnssOption(lowLifetimeRdnssOptionPacket, lowLifetime, "2620:fe::9"); verifyRaLifetime(apfFilter, ipClientCallback, lowLifetimeRdnssOptionPacket, ROUTER_LIFETIME); verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, -1, lowLifetime, -1)); ByteBuffer routeInfoOptionPacket = ByteBuffer.wrap( new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN + IPV6_ADDR_LEN]); basePacket.clear(); Loading Loading @@ -2123,12 +2137,13 @@ public class ApfTest { verifyRaLifetime(apfFilter, ipClientCallback, largeRaPacket, 300); verifyRaEvent(new RaEvent(1800, 600, 300, 1200, 7200, -1)); // Verify that current program filters all the RAs: // Verify that current program filters all the RAs (note: ApfFilter.MAX_RAS == 10). program = ipClientCallback.getApfProgram(); verifyRaLifetime(program, basePacket, ROUTER_LIFETIME); verifyRaLifetime(program, newFlowLabelPacket, ROUTER_LIFETIME); verifyRaLifetime(program, prefixOptionPacket, PREFIX_PREFERRED_LIFETIME); verifyRaLifetime(program, rdnssOptionPacket, RDNSS_LIFETIME); verifyRaLifetime(program, lowLifetimeRdnssOptionPacket, ROUTER_LIFETIME); verifyRaLifetime(program, routeInfoOptionPacket, ROUTE_LIFETIME); verifyRaLifetime(program, dnsslOptionPacket, ROUTER_LIFETIME); verifyRaLifetime(program, largeRaPacket, 300); Loading Loading
src/android/net/apf/ApfFilter.java +23 −3 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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 Loading Loading @@ -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()) { Loading Loading @@ -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 Loading Loading @@ -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); } } Loading Loading @@ -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; Loading Loading @@ -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) {} Loading
src/android/net/ip/IpClient.java +29 −1 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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; /** Loading Loading @@ -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, Loading Loading @@ -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); Loading Loading @@ -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. Loading
src/android/net/ip/IpClientLinkObserver.java +24 −4 Original line number Diff line number Diff line Loading @@ -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) { Loading Loading @@ -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); } Loading Loading @@ -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. */ Loading @@ -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. Loading
tests/integration/src/android/net/ip/IpClientIntegrationTest.java +31 −1 Original line number Diff line number Diff line Loading @@ -123,6 +123,7 @@ import java.net.NetworkInterface; import java.nio.ByteBuffer; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; Loading Loading @@ -235,6 +236,8 @@ public class IpClientIntegrationTest { private class Dependencies extends IpClient.Dependencies { private boolean mIsDhcpLeaseCacheEnabled; private boolean mIsDhcpRapidCommitEnabled; // Can't use SparseIntArray, it doesn't have an easy way to know if a key is not present. private HashMap<String, Integer> mIntConfigProperties = new HashMap<>(); public void setDhcpLeaseCacheEnabled(final boolean enable) { mIsDhcpLeaseCacheEnabled = enable; Loading Loading @@ -274,6 +277,19 @@ public class IpClientIntegrationTest { } }; } @Override public int getDeviceConfigPropertyInt(String name, int defaultValue) { Integer value = mIntConfigProperties.get(name); if (value == null) { throw new IllegalStateException("Non-mocked device config property " + name); } return value; } public void setDeviceConfigProperty(String name, int value) { mIntConfigProperties.put(name, value); } } @Before Loading @@ -288,6 +304,8 @@ public class IpClientIntegrationTest { when(mNetworkStackServiceManager.getIpMemoryStoreService()) .thenReturn(mIpMemoryStoreService); mDependencies.setDeviceConfigProperty(IpClient.CONFIG_MIN_RDNSS_LIFETIME, 67); setUpTapInterface(); setUpIpClient(); } Loading Loading @@ -410,6 +428,7 @@ public class IpClientIntegrationTest { try (FileOutputStream out = new FileOutputStream(mPacketReader.createFd())) { byte[] packetBytes = new byte[packet.limit()]; packet.get(packetBytes); packet.flip(); // So we can reuse it in the future. out.write(packetBytes); } } Loading Loading @@ -868,11 +887,22 @@ public class IpClientIntegrationTest { verify(mCb, timeout(TEST_TIMEOUT_MS)).onProvisioningSuccess(captor.capture()); LinkProperties lp = captor.getValue(); // Expect that DNS servers with lifetimes below CONFIG_MIN_RDNSS_LIFETIME are not accepted. assertNotNull(lp); assertEquals(1, lp.getDnsServers().size()); assertTrue(lp.getDnsServers().contains(InetAddress.getByName(dnsServer))); reset(mCb); // If the RDNSS lifetime is above the minimum, the DNS server is accepted. rdnss1 = buildRdnssOption(68, lowlifeDnsServer); ra = buildRaPacket(pio, rdnss1, rdnss2); sendResponse(ra); verify(mCb, timeout(TEST_TIMEOUT_MS)).onLinkPropertiesChange(captor.capture()); lp = captor.getValue(); assertNotNull(lp); assertEquals(2, lp.getDnsServers().size()); assertTrue(lp.getDnsServers().contains(InetAddress.getByName(dnsServer))); assertTrue(lp.getDnsServers().contains(InetAddress.getByName(lowlifeDnsServer))); reset(mCb); // Expect that setting RDNSS lifetime of 0 causes loss of provisioning. Loading
tests/unit/src/android/net/apf/ApfTest.java +16 −1 Original line number Diff line number Diff line Loading @@ -130,6 +130,8 @@ public class ApfTest { private static final boolean DROP_802_3_FRAMES = true; private static final boolean ALLOW_802_3_FRAMES = false; private static final int MIN_RDNSS_LIFETIME_SEC = 0; // Constants for opcode encoding private static final byte LI_OP = (byte)(13 << 3); private static final byte LDDW_OP = (byte)(22 << 3); Loading @@ -146,6 +148,8 @@ public class ApfTest { config.multicastFilter = ALLOW_MULTICAST; config.ieee802_3Filter = ALLOW_802_3_FRAMES; config.ethTypeBlackList = new int[0]; config.minRdnssLifetimeSec = MIN_RDNSS_LIFETIME_SEC; config.minRdnssLifetimeSec = 67; return config; } Loading Loading @@ -2090,6 +2094,16 @@ public class ApfTest { verifyRaLifetime(apfFilter, ipClientCallback, rdnssOptionPacket, RDNSS_LIFETIME); verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, -1, RDNSS_LIFETIME, -1)); final int lowLifetime = 60; ByteBuffer lowLifetimeRdnssOptionPacket = ByteBuffer.wrap( new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN + IPV6_ADDR_LEN]); basePacket.clear(); lowLifetimeRdnssOptionPacket.put(basePacket); addRdnssOption(lowLifetimeRdnssOptionPacket, lowLifetime, "2620:fe::9"); verifyRaLifetime(apfFilter, ipClientCallback, lowLifetimeRdnssOptionPacket, ROUTER_LIFETIME); verifyRaEvent(new RaEvent(ROUTER_LIFETIME, -1, -1, -1, lowLifetime, -1)); ByteBuffer routeInfoOptionPacket = ByteBuffer.wrap( new byte[ICMP6_RA_OPTION_OFFSET + ICMP6_4_BYTE_OPTION_LEN + IPV6_ADDR_LEN]); basePacket.clear(); Loading Loading @@ -2123,12 +2137,13 @@ public class ApfTest { verifyRaLifetime(apfFilter, ipClientCallback, largeRaPacket, 300); verifyRaEvent(new RaEvent(1800, 600, 300, 1200, 7200, -1)); // Verify that current program filters all the RAs: // Verify that current program filters all the RAs (note: ApfFilter.MAX_RAS == 10). program = ipClientCallback.getApfProgram(); verifyRaLifetime(program, basePacket, ROUTER_LIFETIME); verifyRaLifetime(program, newFlowLabelPacket, ROUTER_LIFETIME); verifyRaLifetime(program, prefixOptionPacket, PREFIX_PREFERRED_LIFETIME); verifyRaLifetime(program, rdnssOptionPacket, RDNSS_LIFETIME); verifyRaLifetime(program, lowLifetimeRdnssOptionPacket, ROUTER_LIFETIME); verifyRaLifetime(program, routeInfoOptionPacket, ROUTE_LIFETIME); verifyRaLifetime(program, dnsslOptionPacket, ROUTER_LIFETIME); verifyRaLifetime(program, largeRaPacket, 300); Loading