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