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