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