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