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