• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.net.ip;
18 
19 import static android.system.OsConstants.AF_INET6;
20 import static android.system.OsConstants.AF_UNSPEC;
21 import static android.system.OsConstants.IFF_LOOPBACK;
22 
23 import static com.android.modules.utils.build.SdkLevel.isAtLeastT;
24 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ROUTER_ADVERTISEMENT;
25 import static com.android.net.module.util.netlink.NetlinkConstants.IFF_LOWER_UP;
26 import static com.android.net.module.util.netlink.NetlinkConstants.RTM_F_CLONED;
27 import static com.android.net.module.util.netlink.NetlinkConstants.RTN_UNICAST;
28 import static com.android.net.module.util.netlink.NetlinkConstants.RTPROT_KERNEL;
29 import static com.android.net.module.util.netlink.NetlinkConstants.RTPROT_RA;
30 import static com.android.net.module.util.netlink.NetlinkConstants.RT_SCOPE_UNIVERSE;
31 import static com.android.networkstack.util.NetworkStackUtils.IPCLIENT_ACCEPT_IPV6_LINK_LOCAL_DNS_VERSION;
32 import static com.android.networkstack.util.NetworkStackUtils.IPCLIENT_PARSE_NETLINK_EVENTS_VERSION;
33 
34 import android.app.AlarmManager;
35 import android.content.Context;
36 import android.net.InetAddresses;
37 import android.net.IpPrefix;
38 import android.net.LinkAddress;
39 import android.net.LinkProperties;
40 import android.net.RouteInfo;
41 import android.os.Handler;
42 import android.system.OsConstants;
43 import android.util.Log;
44 
45 import androidx.annotation.NonNull;
46 import androidx.annotation.Nullable;
47 
48 import com.android.internal.annotations.VisibleForTesting;
49 import com.android.net.module.util.HexDump;
50 import com.android.net.module.util.InetAddressUtils;
51 import com.android.net.module.util.InterfaceParams;
52 import com.android.net.module.util.SharedLog;
53 import com.android.net.module.util.ip.NetlinkMonitor;
54 import com.android.net.module.util.netlink.NduseroptMessage;
55 import com.android.net.module.util.netlink.NetlinkConstants;
56 import com.android.net.module.util.netlink.NetlinkMessage;
57 import com.android.net.module.util.netlink.RtNetlinkAddressMessage;
58 import com.android.net.module.util.netlink.RtNetlinkLinkMessage;
59 import com.android.net.module.util.netlink.RtNetlinkRouteMessage;
60 import com.android.net.module.util.netlink.StructIfaddrMsg;
61 import com.android.net.module.util.netlink.StructIfinfoMsg;
62 import com.android.net.module.util.netlink.StructNdOptPref64;
63 import com.android.net.module.util.netlink.StructNdOptRdnss;
64 import com.android.networkstack.apishim.NetworkInformationShimImpl;
65 import com.android.networkstack.apishim.common.NetworkInformationShim;
66 import com.android.server.NetworkObserver;
67 
68 import java.net.Inet6Address;
69 import java.net.InetAddress;
70 import java.util.ArrayList;
71 import java.util.Arrays;
72 import java.util.Collections;
73 import java.util.HashMap;
74 import java.util.HashSet;
75 import java.util.Set;
76 import java.util.concurrent.TimeUnit;
77 
78 /**
79  * Keeps track of link configuration received from Netd.
80  *
81  * An instance of this class is constructed by passing in an interface name and a callback. The
82  * owner is then responsible for registering the tracker with NetworkObserverRegistry. When the
83  * class receives update notifications, it applies the update to its local LinkProperties, and if
84  * something has changed, notifies its owner of the update via the callback.
85  *
86  * The owner can then call {@code getLinkProperties()} in order to find out
87  * what changed. If in the meantime the LinkProperties stored here have changed,
88  * this class will return the current LinkProperties. Because each change
89  * triggers an update callback after the change is made, the owner may get more
90  * callbacks than strictly necessary (some of which may be no-ops), but will not
91  * be out of sync once all callbacks have been processed.
92  *
93  * Threading model:
94  *
95  * - The owner of this class is expected to create it, register it, and call
96  *   getLinkProperties or clearLinkProperties on its thread.
97  * - Most of the methods in the class are implementing NetworkObserver and are called
98  *   on the handler used to register the observer.
99  * - All accesses to mLinkProperties must be synchronized(this). All the other
100  *   member variables are immutable once the object is constructed.
101  *
102  * TODO: Now that all the methods are called on the handler thread, remove synchronization and
103  *       pass the LinkProperties to the update() callback.
104  * TODO: Stop extending NetworkObserver and get events from netlink directly.
105  *
106  * @hide
107  */
108 public class IpClientLinkObserver implements NetworkObserver {
109     private final String mTag;
110 
111     /**
112      * Callback used by {@link IpClientLinkObserver} to send update notifications.
113      */
114     public interface Callback {
115         /**
116          * Called when some properties of the link were updated.
117          *
118          * @param linkState Whether the interface link state is up as per the latest
119          *                  {@link #onInterfaceLinkStateChanged(String, boolean)} callback. This
120          *                  should only be used for metrics purposes, as it could be inconsistent
121          *                  with {@link #getLinkProperties()} in particular.
122          */
update(boolean linkState)123         void update(boolean linkState);
124 
125         /**
126          * Called when an IPv6 address was removed from the interface.
127          *
128          * @param addr The removed IPv6 address.
129          */
onIpv6AddressRemoved(Inet6Address addr)130         void onIpv6AddressRemoved(Inet6Address addr);
131 
132         /**
133          * Called when the clat interface was added/removed.
134          *
135          * @param add True: clat interface was added.
136          *            False: clat interface was removed.
137          */
onClatInterfaceStateUpdate(boolean add)138         void onClatInterfaceStateUpdate(boolean add);
139     }
140 
141     /** Configuration parameters for IpClientLinkObserver. */
142     public static class Configuration {
143         public final int minRdnssLifetime;
144 
Configuration(int minRdnssLifetime)145         public Configuration(int minRdnssLifetime) {
146             this.minRdnssLifetime = minRdnssLifetime;
147         }
148     }
149 
150     private final Context mContext;
151     private final String mInterfaceName;
152     private final Callback mCallback;
153     private final LinkProperties mLinkProperties;
154     private boolean mInterfaceLinkState;
155     private DnsServerRepository mDnsServerRepository;
156     private final AlarmManager mAlarmManager;
157     private final Configuration mConfig;
158     private final Handler mHandler;
159     private final IpClient.Dependencies mDependencies;
160     private final String mClatInterfaceName;
161     private final MyNetlinkMonitor mNetlinkMonitor;
162     private final boolean mNetlinkEventParsingEnabled;
163 
164     private boolean mClatInterfaceExists;
165 
166     // This must match the interface prefix in clatd.c.
167     // TODO: Revert this hack once IpClient and Nat464Xlat work in concert.
168     protected static final String CLAT_PREFIX = "v4-";
169     private static final boolean DBG = true;
170 
171     // The default socket receive buffer size in bytes(4MB). If too many netlink messages are
172     // sent too quickly, those messages can overflow the socket receive buffer. Set a large-enough
173     // recv buffer size to avoid the ENOBUFS as much as possible.
174     @VisibleForTesting
175     static final String CONFIG_SOCKET_RECV_BUFSIZE = "ipclient_netlink_sock_recv_buf_size";
176     private static final int SOCKET_RECV_BUFSIZE = 4 * 1024 * 1024;
177 
IpClientLinkObserver(Context context, Handler h, String iface, Callback callback, Configuration config, SharedLog log, IpClient.Dependencies deps)178     public IpClientLinkObserver(Context context, Handler h, String iface, Callback callback,
179             Configuration config, SharedLog log, IpClient.Dependencies deps) {
180         mContext = context;
181         mInterfaceName = iface;
182         mClatInterfaceName = CLAT_PREFIX + iface;
183         mTag = "IpClient/" + mInterfaceName;
184         mCallback = callback;
185         mLinkProperties = new LinkProperties();
186         mLinkProperties.setInterfaceName(mInterfaceName);
187         mConfig = config;
188         mHandler = h;
189         mInterfaceLinkState = true; // Assume up by default
190         mDnsServerRepository = new DnsServerRepository(config.minRdnssLifetime);
191         mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
192         mDependencies = deps;
193         mNetlinkEventParsingEnabled = deps.isFeatureEnabled(context,
194                 IPCLIENT_PARSE_NETLINK_EVENTS_VERSION, isAtLeastT() /* default value */);
195         mNetlinkMonitor = new MyNetlinkMonitor(h, log, mTag);
196         mHandler.post(() -> {
197             if (!mNetlinkMonitor.start()) {
198                 Log.wtf(mTag, "Fail to start NetlinkMonitor.");
199             }
200         });
201     }
202 
shutdown()203     public void shutdown() {
204         mHandler.post(mNetlinkMonitor::stop);
205     }
206 
isIpv6LinkLocalDnsAccepted()207     private boolean isIpv6LinkLocalDnsAccepted() {
208         return mDependencies.isFeatureEnabled(mContext,
209                 IPCLIENT_ACCEPT_IPV6_LINK_LOCAL_DNS_VERSION, true /* default value */);
210     }
211 
maybeLog(String operation, String iface, LinkAddress address)212     private void maybeLog(String operation, String iface, LinkAddress address) {
213         if (DBG) {
214             Log.d(mTag, operation + ": " + address + " on " + iface
215                     + " flags " + "0x" + HexDump.toHexString(address.getFlags())
216                     + " scope " + address.getScope());
217         }
218     }
219 
maybeLog(String operation, int ifindex, LinkAddress address)220     private void maybeLog(String operation, int ifindex, LinkAddress address) {
221         maybeLog(operation, "ifindex " + ifindex, address);
222     }
223 
maybeLog(String operation, Object o)224     private void maybeLog(String operation, Object o) {
225         if (DBG) {
226             Log.d(mTag, operation + ": " + o.toString());
227         }
228     }
229 
getSocketReceiveBufferSize()230     private int getSocketReceiveBufferSize() {
231         final int size = mDependencies.getDeviceConfigPropertyInt(CONFIG_SOCKET_RECV_BUFSIZE,
232                 SOCKET_RECV_BUFSIZE /* default value */);
233         if (size < 0) {
234             throw new IllegalArgumentException("Invalid SO_RCVBUF " + size);
235         }
236         return size;
237     }
238 
239     @Override
onInterfaceAdded(String iface)240     public void onInterfaceAdded(String iface) {
241         if (mNetlinkEventParsingEnabled) return;
242         maybeLog("interfaceAdded", iface);
243         if (mClatInterfaceName.equals(iface)) {
244             mCallback.onClatInterfaceStateUpdate(true /* add interface */);
245         }
246     }
247 
248     @Override
onInterfaceRemoved(String iface)249     public void onInterfaceRemoved(String iface) {
250         if (mNetlinkEventParsingEnabled) return;
251         maybeLog("interfaceRemoved", iface);
252         if (mClatInterfaceName.equals(iface)) {
253             mCallback.onClatInterfaceStateUpdate(false /* remove interface */);
254         } else if (mInterfaceName.equals(iface)) {
255             updateInterfaceRemoved();
256         }
257     }
258 
259     @Override
onInterfaceLinkStateChanged(String iface, boolean state)260     public void onInterfaceLinkStateChanged(String iface, boolean state) {
261         if (mNetlinkEventParsingEnabled) return;
262         if (!mInterfaceName.equals(iface)) return;
263         maybeLog("interfaceLinkStateChanged", iface + (state ? " up" : " down"));
264         updateInterfaceLinkStateChanged(state);
265     }
266 
267     @Override
onInterfaceAddressUpdated(LinkAddress address, String iface)268     public void onInterfaceAddressUpdated(LinkAddress address, String iface) {
269         if (mNetlinkEventParsingEnabled) return;
270         if (!mInterfaceName.equals(iface)) return;
271         maybeLog("addressUpdated", iface, address);
272         updateInterfaceAddress(address, true /* add address */);
273     }
274 
275     @Override
onInterfaceAddressRemoved(LinkAddress address, String iface)276     public void onInterfaceAddressRemoved(LinkAddress address, String iface) {
277         if (mNetlinkEventParsingEnabled) return;
278         if (!mInterfaceName.equals(iface)) return;
279         maybeLog("addressRemoved", iface, address);
280         updateInterfaceAddress(address, false /* remove address */);
281     }
282 
283     @Override
onRouteUpdated(RouteInfo route)284     public void onRouteUpdated(RouteInfo route) {
285         if (mNetlinkEventParsingEnabled) return;
286         if (!mInterfaceName.equals(route.getInterface())) return;
287         maybeLog("routeUpdated", route);
288         updateInterfaceRoute(route, true /* add route */);
289     }
290 
291     @Override
onRouteRemoved(RouteInfo route)292     public void onRouteRemoved(RouteInfo route) {
293         if (mNetlinkEventParsingEnabled) return;
294         if (!mInterfaceName.equals(route.getInterface())) return;
295         maybeLog("routeRemoved", route);
296         updateInterfaceRoute(route, false /* remove route */);
297     }
298 
299     @Override
onInterfaceDnsServerInfo(String iface, long lifetime, String[] addresses)300     public void onInterfaceDnsServerInfo(String iface, long lifetime, String[] addresses) {
301         if (mNetlinkEventParsingEnabled) return;
302         if (!mInterfaceName.equals(iface)) return;
303         updateInterfaceDnsServerInfo(lifetime, addresses);
304     }
305 
updateInterfaceLinkStateChanged(boolean state)306     private synchronized void updateInterfaceLinkStateChanged(boolean state) {
307         setInterfaceLinkStateLocked(state);
308     }
309 
updateInterfaceDnsServerInfo(long lifetime, final String[] addresses)310     private void updateInterfaceDnsServerInfo(long lifetime, final String[] addresses) {
311         final boolean changed = mDnsServerRepository.addServers(lifetime, addresses);
312         final boolean linkState;
313         if (changed) {
314             maybeLog("interfaceDnsServerInfo", Arrays.toString(addresses));
315             synchronized (this) {
316                 mDnsServerRepository.setDnsServersOn(mLinkProperties);
317                 linkState = getInterfaceLinkStateLocked();
318             }
319             mCallback.update(linkState);
320         }
321     }
322 
updateInterfaceAddress(@onNull final LinkAddress address, boolean add)323     private boolean updateInterfaceAddress(@NonNull final LinkAddress address, boolean add) {
324         final boolean changed;
325         final boolean linkState;
326         synchronized (this) {
327             if (add) {
328                 changed = mLinkProperties.addLinkAddress(address);
329             } else {
330                 changed = mLinkProperties.removeLinkAddress(address);
331             }
332             linkState = getInterfaceLinkStateLocked();
333         }
334         if (changed) {
335             mCallback.update(linkState);
336             if (!add && address.isIpv6()) {
337                 final Inet6Address addr = (Inet6Address) address.getAddress();
338                 mCallback.onIpv6AddressRemoved(addr);
339             }
340         }
341         return changed;
342     }
343 
updateInterfaceRoute(final RouteInfo route, boolean add)344     private boolean updateInterfaceRoute(final RouteInfo route, boolean add) {
345         final boolean changed;
346         final boolean linkState;
347         synchronized (this) {
348             if (add) {
349                 changed = mLinkProperties.addRoute(route);
350             } else {
351                 changed = mLinkProperties.removeRoute(route);
352             }
353             linkState = getInterfaceLinkStateLocked();
354         }
355         if (changed) {
356             mCallback.update(linkState);
357         }
358         return changed;
359     }
360 
updateInterfaceRemoved()361     private void updateInterfaceRemoved() {
362         // Our interface was removed. Clear our LinkProperties and tell our owner that they are
363         // now empty. Note that from the moment that the interface is removed, any further
364         // interface-specific messages (e.g., RTM_DELADDR) will not reach us, because the netd
365         // code that parses them will not be able to resolve the ifindex to an interface name.
366         final boolean linkState;
367         synchronized (this) {
368             clearLinkProperties();
369             linkState = getInterfaceLinkStateLocked();
370         }
371         mCallback.update(linkState);
372     }
373 
374     /**
375      * Returns a copy of this object's LinkProperties.
376      */
getLinkProperties()377     public synchronized LinkProperties getLinkProperties() {
378         return new LinkProperties(mLinkProperties);
379     }
380 
381     /**
382      * Reset this object's LinkProperties.
383      */
clearLinkProperties()384     public synchronized void clearLinkProperties() {
385         // Clear the repository before clearing mLinkProperties. That way, if a clear() happens
386         // while interfaceDnsServerInfo() is being called, we'll end up with no DNS servers in
387         // mLinkProperties, as desired.
388         mDnsServerRepository = new DnsServerRepository(mConfig.minRdnssLifetime);
389         mNetlinkMonitor.clearAlarms();
390         mLinkProperties.clear();
391         mLinkProperties.setInterfaceName(mInterfaceName);
392     }
393 
getInterfaceLinkStateLocked()394     private boolean getInterfaceLinkStateLocked() {
395         return mInterfaceLinkState;
396     }
397 
setInterfaceLinkStateLocked(boolean state)398     private void setInterfaceLinkStateLocked(boolean state) {
399         mInterfaceLinkState = state;
400     }
401 
402     /** Notifies this object of new interface parameters. */
setInterfaceParams(InterfaceParams params)403     public void setInterfaceParams(InterfaceParams params) {
404         mNetlinkMonitor.setIfindex(params.index);
405     }
406 
407     /** Notifies this object not to listen on any interface. */
clearInterfaceParams()408     public void clearInterfaceParams() {
409         mNetlinkMonitor.setIfindex(0);  // 0 is never a valid ifindex.
410     }
411 
isSupportedRouteProtocol(RtNetlinkRouteMessage msg)412     private static boolean isSupportedRouteProtocol(RtNetlinkRouteMessage msg) {
413         // Checks whether the protocol is supported. The behaviour is defined by the legacy
414         // implementation in NetlinkEvent.cpp.
415         return msg.getRtMsgHeader().protocol == RTPROT_KERNEL
416                 || msg.getRtMsgHeader().protocol == RTPROT_RA;
417     }
418 
isGlobalUnicastRoute(RtNetlinkRouteMessage msg)419     private static boolean isGlobalUnicastRoute(RtNetlinkRouteMessage msg) {
420         return msg.getRtMsgHeader().scope == RT_SCOPE_UNIVERSE
421                 && msg.getRtMsgHeader().type == RTN_UNICAST;
422     }
423 
424     /**
425      * Simple NetlinkMonitor. Listen for netlink events from kernel.
426      * All methods except the constructor must be called on the handler thread.
427      */
428     private class MyNetlinkMonitor extends NetlinkMonitor {
429         private final Handler mHandler;
430 
MyNetlinkMonitor(Handler h, SharedLog log, String tag)431         MyNetlinkMonitor(Handler h, SharedLog log, String tag) {
432             super(h, log, tag, OsConstants.NETLINK_ROUTE,
433                     !mNetlinkEventParsingEnabled
434                         ? NetlinkConstants.RTMGRP_ND_USEROPT
435                         : (NetlinkConstants.RTMGRP_ND_USEROPT | NetlinkConstants.RTMGRP_LINK
436                                 | NetlinkConstants.RTMGRP_IPV4_IFADDR
437                                 | NetlinkConstants.RTMGRP_IPV6_IFADDR
438                                 | NetlinkConstants.RTMGRP_IPV6_ROUTE),
439                     getSocketReceiveBufferSize());
440 
441             mHandler = h;
442         }
443 
444         private final NetworkInformationShim mShim = NetworkInformationShimImpl.newInstance();
445 
446         private long mNat64PrefixExpiry;
447 
448         /**
449          * Current interface index. Most of this class (and of IpClient), only uses interface names,
450          * not interface indices. This means that the interface index can in theory change, and that
451          * it's not necessarily correct to get the interface name at object creation time (and in
452          * fact, when the object is created, the interface might not even exist).
453          * TODO: once all netlink events pass through this class, stop depending on interface names.
454          */
455         private int mIfindex;
456 
setIfindex(int ifindex)457         void setIfindex(int ifindex) {
458             if (!isRunning()) {
459                 Log.wtf(mTag, "NetlinkMonitor is not running when setting interface parameter!");
460             }
461             mIfindex = ifindex;
462         }
463 
clearAlarms()464         void clearAlarms() {
465             cancelPref64Alarm();
466         }
467 
468         private final AlarmManager.OnAlarmListener mExpirePref64Alarm = () -> {
469             // Ignore the alarm if cancelPref64Alarm has already been called.
470             //
471             // TODO: in the rare case where the alarm fires and posts the lambda to the handler
472             // thread while we are processing an RA that changes the lifetime of the same prefix,
473             // this code will run anyway even if the alarm is rescheduled or cancelled. If the
474             // lifetime in the RA is zero this code will correctly do nothing, but if the lifetime
475             // is nonzero then the prefix will be added and immediately removed by this code.
476             if (mNat64PrefixExpiry == 0) return;
477             updatePref64(mShim.getNat64Prefix(mLinkProperties),
478                     mNat64PrefixExpiry, mNat64PrefixExpiry);
479         };
480 
cancelPref64Alarm()481         private void cancelPref64Alarm() {
482             // Clear the expiry in case the alarm just fired and has not been processed yet.
483             if (mNat64PrefixExpiry == 0) return;
484             mNat64PrefixExpiry = 0;
485             mAlarmManager.cancel(mExpirePref64Alarm);
486         }
487 
schedulePref64Alarm()488         private void schedulePref64Alarm() {
489             // There is no need to cancel any existing alarms, because we are using the same
490             // OnAlarmListener object, and each such listener can only have at most one alarm.
491             final String tag = mTag + ".PREF64";
492             mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, mNat64PrefixExpiry, tag,
493                     mExpirePref64Alarm, mHandler);
494         }
495 
496         /**
497          * Processes a PREF64 ND option.
498          *
499          * @param prefix The NAT64 prefix.
500          * @param now The time (as determined by SystemClock.elapsedRealtime) when the event
501          *            that triggered this method was received.
502          * @param expiry The time (as determined by SystemClock.elapsedRealtime) when the option
503          *               expires.
504          */
updatePref64(IpPrefix prefix, final long now, final long expiry)505         private synchronized void updatePref64(IpPrefix prefix, final long now,
506                 final long expiry) {
507             final IpPrefix currentPrefix = mShim.getNat64Prefix(mLinkProperties);
508 
509             // If the prefix matches the current prefix, refresh its lifetime.
510             if (prefix.equals(currentPrefix)) {
511                 mNat64PrefixExpiry = expiry;
512                 if (expiry > now) {
513                     schedulePref64Alarm();
514                 }
515             }
516 
517             // If we already have a prefix, continue using it and ignore the new one. Stopping and
518             // restarting clatd is disruptive because it will break existing IPv4 connections.
519             // Note: this means that if we receive an RA that adds a new prefix and deletes the old
520             // prefix, we might receive and ignore the new prefix, then delete the old prefix, and
521             // have no prefix until the next RA is received. This is because the kernel returns ND
522             // user options one at a time even if they are in the same RA.
523             // TODO: keep track of the last few prefixes seen, like DnsServerRepository does.
524             if (mNat64PrefixExpiry > now) return;
525 
526             // The current prefix has expired. Either replace it with the new one or delete it.
527             if (expiry > now) {
528                 // If expiry > now, then prefix != currentPrefix (due to the return statement above)
529                 mShim.setNat64Prefix(mLinkProperties, prefix);
530                 mNat64PrefixExpiry = expiry;
531                 schedulePref64Alarm();
532             } else {
533                 mShim.setNat64Prefix(mLinkProperties, null);
534                 cancelPref64Alarm();
535             }
536 
537             mCallback.update(getInterfaceLinkStateLocked());
538         }
539 
processPref64Option(StructNdOptPref64 opt, final long now)540         private void processPref64Option(StructNdOptPref64 opt, final long now) {
541             final long expiry = now + TimeUnit.SECONDS.toMillis(opt.lifetime);
542             updatePref64(opt.prefix, now, expiry);
543         }
544 
processRdnssOption(StructNdOptRdnss opt)545         private void processRdnssOption(StructNdOptRdnss opt) {
546             if (!mNetlinkEventParsingEnabled) return;
547             final String[] addresses = new String[opt.servers.length];
548             for (int i = 0; i < opt.servers.length; i++) {
549                 final Inet6Address addr = isIpv6LinkLocalDnsAccepted()
550                         ? InetAddressUtils.withScopeId(opt.servers[i], mIfindex)
551                         : opt.servers[i];
552                 addresses[i] = addr.getHostAddress();
553             }
554             updateInterfaceDnsServerInfo(opt.header.lifetime, addresses);
555         }
556 
processNduseroptMessage(NduseroptMessage msg, final long whenMs)557         private void processNduseroptMessage(NduseroptMessage msg, final long whenMs) {
558             if (msg.family != AF_INET6 || msg.option == null || msg.ifindex != mIfindex) return;
559             if (msg.icmp_type != (byte) ICMPV6_ROUTER_ADVERTISEMENT) return;
560 
561             switch (msg.option.type) {
562                 case StructNdOptPref64.TYPE:
563                     processPref64Option((StructNdOptPref64) msg.option, whenMs);
564                     break;
565 
566                 case StructNdOptRdnss.TYPE:
567                     processRdnssOption((StructNdOptRdnss) msg.option);
568                     break;
569 
570                 default:
571                     // TODO: implement DNSSL.
572                     break;
573             }
574         }
575 
updateClatInterfaceLinkState(@onNull final StructIfinfoMsg ifinfoMsg, @Nullable final String ifname, short nlMsgType)576         private void updateClatInterfaceLinkState(@NonNull final StructIfinfoMsg ifinfoMsg,
577                 @Nullable final String ifname, short nlMsgType) {
578             switch (nlMsgType) {
579                 case NetlinkConstants.RTM_NEWLINK:
580                     if (mClatInterfaceExists) break;
581                     maybeLog("clatInterfaceAdded", ifname);
582                     mCallback.onClatInterfaceStateUpdate(true /* add interface */);
583                     mClatInterfaceExists = true;
584                     break;
585 
586                 case NetlinkConstants.RTM_DELLINK:
587                     if (!mClatInterfaceExists) break;
588                     maybeLog("clatInterfaceRemoved", ifname);
589                     mCallback.onClatInterfaceStateUpdate(false /* remove interface */);
590                     mClatInterfaceExists = false;
591                     break;
592 
593                 default:
594                     Log.e(mTag, "unsupported rtnetlink link msg type " + nlMsgType);
595                     break;
596             }
597         }
598 
processRtNetlinkLinkMessage(RtNetlinkLinkMessage msg)599         private void processRtNetlinkLinkMessage(RtNetlinkLinkMessage msg) {
600             if (!mNetlinkEventParsingEnabled) return;
601 
602             // Check if receiving netlink link state update for clat interface.
603             final String ifname = msg.getInterfaceName();
604             final short nlMsgType = msg.getHeader().nlmsg_type;
605             final StructIfinfoMsg ifinfoMsg = msg.getIfinfoHeader();
606             if (mClatInterfaceName.equals(ifname)) {
607                 updateClatInterfaceLinkState(ifinfoMsg, ifname, nlMsgType);
608                 return;
609             }
610 
611             if (ifinfoMsg.family != AF_UNSPEC || ifinfoMsg.index != mIfindex) return;
612             if ((ifinfoMsg.flags & IFF_LOOPBACK) != 0) return;
613 
614             switch (nlMsgType) {
615                 case NetlinkConstants.RTM_NEWLINK:
616                     final boolean state = (ifinfoMsg.flags & IFF_LOWER_UP) != 0;
617                     maybeLog("interfaceLinkStateChanged", "ifindex " + mIfindex
618                             + (state ? " up" : " down"));
619                     updateInterfaceLinkStateChanged(state);
620                     break;
621 
622                 case NetlinkConstants.RTM_DELLINK:
623                     maybeLog("interfaceRemoved", ifname);
624                     updateInterfaceRemoved();
625                     break;
626 
627                 default:
628                     Log.e(mTag, "Unknown rtnetlink link msg type " + nlMsgType);
629                     break;
630             }
631         }
632 
processRtNetlinkAddressMessage(RtNetlinkAddressMessage msg)633         private void processRtNetlinkAddressMessage(RtNetlinkAddressMessage msg) {
634             if (!mNetlinkEventParsingEnabled) return;
635 
636             final StructIfaddrMsg ifaddrMsg = msg.getIfaddrHeader();
637             if (ifaddrMsg.index != mIfindex) return;
638             final LinkAddress la = new LinkAddress(msg.getIpAddress(), ifaddrMsg.prefixLen,
639                     msg.getFlags(), ifaddrMsg.scope);
640 
641             switch (msg.getHeader().nlmsg_type) {
642                 case NetlinkConstants.RTM_NEWADDR:
643                     if (updateInterfaceAddress(la, true /* add address */)) {
644                         maybeLog("addressUpdated", mIfindex, la);
645                     }
646                     break;
647                 case NetlinkConstants.RTM_DELADDR:
648                     if (updateInterfaceAddress(la, false /* remove address */)) {
649                         maybeLog("addressRemoved", mIfindex, la);
650                     }
651                     break;
652                 default:
653                     Log.e(mTag, "Unknown rtnetlink address msg type " + msg.getHeader().nlmsg_type);
654                     return;
655             }
656         }
657 
processRtNetlinkRouteMessage(RtNetlinkRouteMessage msg)658         private void processRtNetlinkRouteMessage(RtNetlinkRouteMessage msg) {
659             if (!mNetlinkEventParsingEnabled) return;
660             if (msg.getInterfaceIndex() != mIfindex) return;
661             // Ignore the unsupported route protocol and non-global unicast routes.
662             if (!isSupportedRouteProtocol(msg)
663                     || !isGlobalUnicastRoute(msg)
664                     // don't support source routing
665                     || (msg.getRtMsgHeader().srcLen != 0)
666                     // don't support cloned routes
667                     || ((msg.getRtMsgHeader().flags & RTM_F_CLONED) != 0)) {
668                 return;
669             }
670 
671             final RouteInfo route = new RouteInfo(msg.getDestination(), msg.getGateway(),
672                     mInterfaceName, msg.getRtMsgHeader().type);
673             switch (msg.getHeader().nlmsg_type) {
674                 case NetlinkConstants.RTM_NEWROUTE:
675                     if (updateInterfaceRoute(route, true /* add route */)) {
676                         maybeLog("routeUpdated", route);
677                     }
678                     break;
679                 case NetlinkConstants.RTM_DELROUTE:
680                     if (updateInterfaceRoute(route, false /* remove route */)) {
681                         maybeLog("routeRemoved", route);
682                     }
683                     break;
684                 default:
685                     Log.e(mTag, "Unknown rtnetlink route msg type " + msg.getHeader().nlmsg_type);
686                     break;
687             }
688         }
689 
690         @Override
processNetlinkMessage(NetlinkMessage nlMsg, long whenMs)691         protected void processNetlinkMessage(NetlinkMessage nlMsg, long whenMs) {
692             if (nlMsg instanceof NduseroptMessage) {
693                 processNduseroptMessage((NduseroptMessage) nlMsg, whenMs);
694             } else if (nlMsg instanceof RtNetlinkLinkMessage) {
695                 processRtNetlinkLinkMessage((RtNetlinkLinkMessage) nlMsg);
696             } else if (nlMsg instanceof RtNetlinkAddressMessage) {
697                 processRtNetlinkAddressMessage((RtNetlinkAddressMessage) nlMsg);
698             } else if (nlMsg instanceof RtNetlinkRouteMessage) {
699                 processRtNetlinkRouteMessage((RtNetlinkRouteMessage) nlMsg);
700             } else {
701                 Log.e(mTag, "Unknown netlink message: " + nlMsg);
702             }
703         }
704     }
705 
706     /**
707      * Tracks DNS server updates received from Netlink.
708      *
709      * The network may announce an arbitrary number of DNS servers in Router Advertisements at any
710      * time. Each announcement has a lifetime; when the lifetime expires, the servers should not be
711      * used any more. In this way, the network can gracefully migrate clients from one set of DNS
712      * servers to another. Announcements can both raise and lower the lifetime, and an announcement
713      * can expire servers by announcing them with a lifetime of zero.
714      *
715      * Typically the system will only use a small number (2 or 3; {@code NUM_CURRENT_SERVERS}) of
716      * DNS servers at any given time. These are referred to as the current servers. In case all the
717      * current servers expire, the class also keeps track of a larger (but limited) number of
718      * servers that are promoted to current servers when the current ones expire. In order to
719      * minimize updates to the rest of the system (and potentially expensive cache flushes) this
720      * class attempts to keep the list of current servers constant where possible. More
721      * specifically, the list of current servers is only updated if a new server is learned and
722      * there are not yet {@code NUM_CURRENT_SERVERS} current servers, or if one or more of the
723      * current servers expires or is pushed out of the set. Therefore, the current servers will not
724      * necessarily be the ones with the highest lifetime, but the ones learned first.
725      *
726      * This is by design: if instead the class always preferred the servers with the highest
727      * lifetime, a (misconfigured?) network where two or more routers announce more than
728      * {@code NUM_CURRENT_SERVERS} unique servers would cause persistent oscillations.
729      *
730      * TODO: Currently servers are only expired when a new DNS update is received.
731      * Update them using timers, or possibly on every notification received by NetlinkTracker.
732      *
733      * Threading model: run by NetlinkTracker. Methods are synchronized(this) just in case netlink
734      * notifications are sent by multiple threads. If future threads use alarms to expire, those
735      * alarms must also be synchronized(this).
736      *
737      */
738     private static class DnsServerRepository {
739 
740         /** How many DNS servers we will use. 3 is suggested by RFC 6106. */
741         static final int NUM_CURRENT_SERVERS = 3;
742 
743         /** How many DNS servers we'll keep track of, in total. */
744         static final int NUM_SERVERS = 12;
745 
746         /** Stores up to {@code NUM_CURRENT_SERVERS} DNS servers we're currently using. */
747         private Set<InetAddress> mCurrentServers;
748 
749         public static final String TAG = "DnsServerRepository";
750 
751         /**
752          * Stores all the DNS servers we know about, for use when the current servers expire.
753          * Always sorted in order of decreasing expiry. The elements in this list are also the
754          * values of mIndex, and may be elements in mCurrentServers.
755          */
756         private ArrayList<DnsServerEntry> mAllServers;
757 
758         /**
759          * Indexes the servers so we can update their lifetimes more quickly in the common case
760          * where servers are not being added, but only being refreshed.
761          */
762         private HashMap<InetAddress, DnsServerEntry> mIndex;
763 
764         /**
765          * Minimum (non-zero) RDNSS lifetime to accept.
766          */
767         private final int mMinLifetime;
768 
DnsServerRepository(int minLifetime)769         DnsServerRepository(int minLifetime) {
770             mCurrentServers = new HashSet<>();
771             mAllServers = new ArrayList<>(NUM_SERVERS);
772             mIndex = new HashMap<>(NUM_SERVERS);
773             mMinLifetime = minLifetime;
774         }
775 
776         /** Sets the DNS servers of the provided LinkProperties object to the current servers. */
setDnsServersOn(LinkProperties lp)777         public synchronized void setDnsServersOn(LinkProperties lp) {
778             lp.setDnsServers(mCurrentServers);
779         }
780 
781         /**
782          * Notifies the class of new DNS server information.
783          * @param lifetime the time in seconds that the DNS servers are valid.
784          * @param addresses the string representations of the IP addresses of DNS servers to use.
785          */
addServers(long lifetime, String[] addresses)786         public synchronized boolean addServers(long lifetime, String[] addresses) {
787             // If the servers are below the minimum lifetime, don't change anything.
788             if (lifetime != 0 && lifetime < mMinLifetime) return false;
789 
790             // The lifetime is actually an unsigned 32-bit number, but Java doesn't have unsigned.
791             // Technically 0xffffffff (the maximum) is special and means "forever", but 2^32 seconds
792             // (136 years) is close enough.
793             long now = System.currentTimeMillis();
794             long expiry = now + 1000 * lifetime;
795 
796             // Go through the list of servers. For each one, update the entry if one exists, and
797             // create one if it doesn't.
798             for (String addressString : addresses) {
799                 InetAddress address;
800                 try {
801                     address = InetAddresses.parseNumericAddress(addressString);
802                 } catch (IllegalArgumentException ex) {
803                     continue;
804                 }
805 
806                 if (!updateExistingEntry(address, expiry)) {
807                     // There was no entry for this server. Create one, unless it's already expired
808                     // (i.e., if the lifetime is zero; it cannot be < 0 because it's unsigned).
809                     if (expiry > now) {
810                         DnsServerEntry entry = new DnsServerEntry(address, expiry);
811                         mAllServers.add(entry);
812                         mIndex.put(address, entry);
813                     }
814                 }
815             }
816 
817             // Sort the servers by expiry.
818             Collections.sort(mAllServers);
819 
820             // Prune excess entries and update the current server list.
821             return updateCurrentServers();
822         }
823 
updateExistingEntry(InetAddress address, long expiry)824         private synchronized boolean updateExistingEntry(InetAddress address, long expiry) {
825             DnsServerEntry existing = mIndex.get(address);
826             if (existing != null) {
827                 existing.expiry = expiry;
828                 return true;
829             }
830             return false;
831         }
832 
updateCurrentServers()833         private synchronized boolean updateCurrentServers() {
834             long now = System.currentTimeMillis();
835             boolean changed = false;
836 
837             // Prune excess or expired entries.
838             for (int i = mAllServers.size() - 1; i >= 0; i--) {
839                 if (i >= NUM_SERVERS || mAllServers.get(i).expiry <= now) {
840                     DnsServerEntry removed = mAllServers.remove(i);
841                     mIndex.remove(removed.address);
842                     changed |= mCurrentServers.remove(removed.address);
843                 } else {
844                     break;
845                 }
846             }
847 
848             // Add servers to the current set, in order of decreasing lifetime, until it has enough.
849             // Prefer existing servers over new servers in order to minimize updates to the rest of
850             // the system and avoid persistent oscillations.
851             for (DnsServerEntry entry : mAllServers) {
852                 if (mCurrentServers.size() < NUM_CURRENT_SERVERS) {
853                     changed |= mCurrentServers.add(entry.address);
854                 } else {
855                     break;
856                 }
857             }
858             return changed;
859         }
860     }
861 
862     /**
863      * Represents a DNS server entry with an expiry time.
864      *
865      * Implements Comparable so DNS server entries can be sorted by lifetime, longest-lived first.
866      * The ordering of entries with the same lifetime is unspecified, because given two servers with
867      * identical lifetimes, we don't care which one we use, and only comparing the lifetime is much
868      * faster than comparing the IP address as well.
869      *
870      * Note: this class has a natural ordering that is inconsistent with equals.
871      */
872     private static class DnsServerEntry implements Comparable<DnsServerEntry> {
873         /** The IP address of the DNS server. */
874         public final InetAddress address;
875         /** The time until which the DNS server may be used. A Java millisecond time as might be
876          * returned by currentTimeMillis(). */
877         public long expiry;
878 
DnsServerEntry(InetAddress address, long expiry)879         DnsServerEntry(InetAddress address, long expiry) throws IllegalArgumentException {
880             this.address = address;
881             this.expiry = expiry;
882         }
883 
compareTo(DnsServerEntry other)884         public int compareTo(DnsServerEntry other) {
885             return Long.compare(other.expiry, this.expiry);
886         }
887     }
888 }
889