diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/android/net/ip/IpClient.java | 6 | ||||
-rw-r--r-- | src/android/net/ip/IpClientLinkObserver.java | 129 |
2 files changed, 132 insertions, 3 deletions
diff --git a/src/android/net/ip/IpClient.java b/src/android/net/ip/IpClient.java index 4ddcc13..3fb5001 100644 --- a/src/android/net/ip/IpClient.java +++ b/src/android/net/ip/IpClient.java @@ -583,7 +583,8 @@ public class IpClient extends StateMachine { mLinkObserver = new IpClientLinkObserver( mInterfaceName, - () -> sendMessage(EVENT_NETLINK_LINKPROPERTIES_CHANGED), config) { + () -> sendMessage(EVENT_NETLINK_LINKPROPERTIES_CHANGED), + config, getHandler(), mLog) { @Override public void onInterfaceAdded(String iface) { super.onInterfaceAdded(iface); @@ -1225,6 +1226,7 @@ public class IpClient extends StateMachine { newLp.addRoute(route); } addAllReachableDnsServers(newLp, netlinkLinkProperties.getDnsServers()); + newLp.setNat64Prefix(netlinkLinkProperties.getNat64Prefix()); // [3] Add in data from DHCPv4, if available. // @@ -1563,6 +1565,7 @@ public class IpClient extends StateMachine { public void enter() { stopAllIP(); + mLinkObserver.clearInterfaceParams(); resetLinkProperties(); if (mStartTimeMillis > 0) { // Completed a life-cycle; send a final empty LinkProperties @@ -1712,6 +1715,7 @@ public class IpClient extends StateMachine { transitionTo(mStoppedState); return; } + mLinkObserver.setInterfaceParams(mInterfaceParams); mCallback.setNeighborDiscoveryOffload(true); } diff --git a/src/android/net/ip/IpClientLinkObserver.java b/src/android/net/ip/IpClientLinkObserver.java index 02bf5f0..bbd2176 100644 --- a/src/android/net/ip/IpClientLinkObserver.java +++ b/src/android/net/ip/IpClientLinkObserver.java @@ -16,12 +16,27 @@ package android.net.ip; +import static android.system.OsConstants.AF_INET6; + +import static com.android.server.util.NetworkStackConstants.ICMPV6_ROUTER_ADVERTISEMENT; + import android.net.InetAddresses; +import android.net.IpPrefix; import android.net.LinkAddress; import android.net.LinkProperties; import android.net.RouteInfo; +import android.net.netlink.NduseroptMessage; +import android.net.netlink.NetlinkConstants; +import android.net.netlink.NetlinkMessage; +import android.net.netlink.StructNdOptPref64; +import android.net.util.InterfaceParams; +import android.net.util.SharedLog; +import android.os.Handler; +import android.system.OsConstants; import android.util.Log; +import com.android.networkstack.apishim.NetworkInformationShim; +import com.android.networkstack.apishim.NetworkInformationShimImpl; import com.android.server.NetworkObserver; import java.net.InetAddress; @@ -31,6 +46,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Set; +import java.util.concurrent.TimeUnit; /** * Keeps track of link configuration received from Netd. @@ -56,6 +72,10 @@ import java.util.Set; * - All accesses to mLinkProperties must be synchronized(this). All the other * member variables are immutable once the object is constructed. * + * TODO: Now that all the methods are called on the handler thread, remove synchronization and + * pass the LinkProperties to the update() callback. + * TODO: Stop extending NetworkObserver and get events from netlink directly. + * * @hide */ public class IpClientLinkObserver implements NetworkObserver { @@ -86,16 +106,21 @@ public class IpClientLinkObserver implements NetworkObserver { private DnsServerRepository mDnsServerRepository; private final Configuration mConfig; + private final MyNetlinkMonitor mNetlinkMonitor; + private static final boolean DBG = false; - public IpClientLinkObserver(String iface, Callback callback, Configuration config) { - mTag = "NetlinkTracker/" + iface; + public IpClientLinkObserver(String iface, Callback callback, Configuration config, + Handler h, SharedLog log) { mInterfaceName = iface; + mTag = "NetlinkTracker/" + mInterfaceName; mCallback = callback; mLinkProperties = new LinkProperties(); mLinkProperties.setInterfaceName(mInterfaceName); mConfig = config; mDnsServerRepository = new DnsServerRepository(config.minRdnssLifetime); + mNetlinkMonitor = new MyNetlinkMonitor(h, log, mTag); + h.post(mNetlinkMonitor::start); } private void maybeLog(String operation, String iface, LinkAddress address) { @@ -213,6 +238,106 @@ public class IpClientLinkObserver implements NetworkObserver { mLinkProperties.setInterfaceName(mInterfaceName); } + /** Notifies this object of new interface parameters. */ + public void setInterfaceParams(InterfaceParams params) { + mNetlinkMonitor.setIfindex(params.index); + } + + /** Notifies this object not to listen on any interface. */ + public void clearInterfaceParams() { + mNetlinkMonitor.setIfindex(0); // 0 is never a valid ifindex. + } + + /** + * Simple NetlinkMonitor. Currently only listens for PREF64 events. + * All methods except the constructor must be called on the handler thread. + */ + private class MyNetlinkMonitor extends NetlinkMonitor { + MyNetlinkMonitor(Handler h, SharedLog log, String tag) { + super(h, log, tag, OsConstants.NETLINK_ROUTE, NetlinkConstants.RTMGRP_ND_USEROPT); + } + + private final NetworkInformationShim mShim = NetworkInformationShimImpl.newInstance(); + + private long mNat64PrefixExpiry; + + /** + * Current interface index. Most of this class (and of IpClient), only uses interface names, + * not interface indices. This means that the interface index can in theory change, and that + * it's not necessarily correct to get the interface name at object creation time (and in + * fact, when the object is created, the interface might not even exist). + * TODO: once all netlink events pass through this class, stop depending on interface names. + */ + private int mIfindex; + + void setIfindex(int ifindex) { + mIfindex = ifindex; + } + + /** + * Processes a PREF64 ND option. + * + * @param prefix The NAT64 prefix. + * @param now The time (as determined by SystemClock.elapsedRealtime) when the event + * that triggered this method was received. + * @param expiry The time (as determined by SystemClock.elapsedRealtime) when the option + * expires. + */ + private synchronized void updatePref64(IpPrefix prefix, final long now, + final long expiry) { + final IpPrefix currentPrefix = mShim.getNat64Prefix(mLinkProperties); + + // If the prefix matches the current prefix, refresh its lifetime. + if (prefix.equals(currentPrefix)) { + mNat64PrefixExpiry = expiry; + } + + // If we already have a prefix, continue using it and ignore the new one. Stopping and + // restarting clatd is disruptive because it will break existing IPv4 connections. + if (mNat64PrefixExpiry > now) return; + + // The current prefix has expired. Either replace it with the new one or delete it. + if (expiry > now) { + // If expiry > now, then prefix != currentPrefix (due to the return statement above) + mShim.setNat64Prefix(mLinkProperties, prefix); + mNat64PrefixExpiry = expiry; + } else { + mShim.setNat64Prefix(mLinkProperties, null); + mNat64PrefixExpiry = 0; + } + + mCallback.update(); + + // TODO: send a delayed message to remove the prefix when it expires. + } + + private void processPref64Option(StructNdOptPref64 opt, final long now) { + final long expiry = now + TimeUnit.SECONDS.toMillis(opt.lifetime); + updatePref64(opt.prefix, now, expiry); + } + + private void processNduseroptMessage(NduseroptMessage msg, final long whenMs) { + if (msg.family != AF_INET6 || msg.option == null || msg.ifindex != mIfindex) return; + if (msg.icmp_type != (byte) ICMPV6_ROUTER_ADVERTISEMENT) return; + + switch (msg.option.type) { + case StructNdOptPref64.TYPE: + processPref64Option((StructNdOptPref64) msg.option, whenMs); + break; + + default: + // TODO: implement RDNSS and DNSSL. + break; + } + } + + @Override + protected void processNetlinkMessage(NetlinkMessage nlMsg, long whenMs) { + if (!(nlMsg instanceof NduseroptMessage)) return; + processNduseroptMessage((NduseroptMessage) nlMsg, whenMs); + } + } + /** * Tracks DNS server updates received from Netlink. * |