1 /* 2 * Copyright (C) 2016 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 com.android.internal.util.MessageUtils; 20 import com.android.internal.util.WakeupMessage; 21 22 import android.content.Context; 23 import android.net.DhcpResults; 24 import android.net.INetd; 25 import android.net.InterfaceConfiguration; 26 import android.net.IpPrefix; 27 import android.net.LinkAddress; 28 import android.net.LinkProperties.ProvisioningChange; 29 import android.net.LinkProperties; 30 import android.net.ProxyInfo; 31 import android.net.RouteInfo; 32 import android.net.StaticIpConfiguration; 33 import android.net.apf.ApfCapabilities; 34 import android.net.apf.ApfFilter; 35 import android.net.dhcp.DhcpClient; 36 import android.net.metrics.IpConnectivityLog; 37 import android.net.metrics.IpManagerEvent; 38 import android.net.util.MultinetworkPolicyTracker; 39 import android.net.util.NetdService; 40 import android.net.util.NetworkConstants; 41 import android.net.util.SharedLog; 42 import android.os.INetworkManagementService; 43 import android.os.Message; 44 import android.os.RemoteException; 45 import android.os.ServiceManager; 46 import android.os.ServiceSpecificException; 47 import android.os.SystemClock; 48 import android.system.OsConstants; 49 import android.text.TextUtils; 50 import android.util.LocalLog; 51 import android.util.Log; 52 import android.util.SparseArray; 53 54 import com.android.internal.annotations.VisibleForTesting; 55 import com.android.internal.R; 56 import com.android.internal.util.IndentingPrintWriter; 57 import com.android.internal.util.IState; 58 import com.android.internal.util.Preconditions; 59 import com.android.internal.util.State; 60 import com.android.internal.util.StateMachine; 61 import com.android.server.net.NetlinkTracker; 62 63 import java.io.FileDescriptor; 64 import java.io.PrintWriter; 65 import java.net.Inet4Address; 66 import java.net.Inet6Address; 67 import java.net.InetAddress; 68 import java.net.NetworkInterface; 69 import java.net.SocketException; 70 import java.util.ArrayList; 71 import java.util.Collection; 72 import java.util.HashSet; 73 import java.util.Objects; 74 import java.util.List; 75 import java.util.Set; 76 import java.util.StringJoiner; 77 import java.util.function.Predicate; 78 import java.util.stream.Collectors; 79 80 81 /** 82 * IpManager 83 * 84 * This class provides the interface to IP-layer provisioning and maintenance 85 * functionality that can be used by transport layers like Wi-Fi, Ethernet, 86 * et cetera. 87 * 88 * [ Lifetime ] 89 * IpManager is designed to be instantiated as soon as the interface name is 90 * known and can be as long-lived as the class containing it (i.e. declaring 91 * it "private final" is okay). 92 * 93 * @hide 94 */ 95 public class IpManager extends StateMachine { 96 private static final boolean DBG = false; 97 private static final boolean VDBG = false; 98 99 // For message logging. 100 private static final Class[] sMessageClasses = { IpManager.class, DhcpClient.class }; 101 private static final SparseArray<String> sWhatToString = 102 MessageUtils.findMessageNames(sMessageClasses); 103 104 /** 105 * Callbacks for handling IpManager events. 106 */ 107 public static class Callback { 108 // In order to receive onPreDhcpAction(), call #withPreDhcpAction() 109 // when constructing a ProvisioningConfiguration. 110 // 111 // Implementations of onPreDhcpAction() must call 112 // IpManager#completedPreDhcpAction() to indicate that DHCP is clear 113 // to proceed. onPreDhcpAction()114 public void onPreDhcpAction() {} onPostDhcpAction()115 public void onPostDhcpAction() {} 116 117 // This is purely advisory and not an indication of provisioning 118 // success or failure. This is only here for callers that want to 119 // expose DHCPv4 results to other APIs (e.g., WifiInfo#setInetAddress). 120 // DHCPv4 or static IPv4 configuration failure or success can be 121 // determined by whether or not the passed-in DhcpResults object is 122 // null or not. onNewDhcpResults(DhcpResults dhcpResults)123 public void onNewDhcpResults(DhcpResults dhcpResults) {} 124 onProvisioningSuccess(LinkProperties newLp)125 public void onProvisioningSuccess(LinkProperties newLp) {} onProvisioningFailure(LinkProperties newLp)126 public void onProvisioningFailure(LinkProperties newLp) {} 127 128 // Invoked on LinkProperties changes. onLinkPropertiesChange(LinkProperties newLp)129 public void onLinkPropertiesChange(LinkProperties newLp) {} 130 131 // Called when the internal IpReachabilityMonitor (if enabled) has 132 // detected the loss of a critical number of required neighbors. onReachabilityLost(String logMsg)133 public void onReachabilityLost(String logMsg) {} 134 135 // Called when the IpManager state machine terminates. onQuit()136 public void onQuit() {} 137 138 // Install an APF program to filter incoming packets. installPacketFilter(byte[] filter)139 public void installPacketFilter(byte[] filter) {} 140 141 // If multicast filtering cannot be accomplished with APF, this function will be called to 142 // actuate multicast filtering using another means. setFallbackMulticastFilter(boolean enabled)143 public void setFallbackMulticastFilter(boolean enabled) {} 144 145 // Enabled/disable Neighbor Discover offload functionality. This is 146 // called, for example, whenever 464xlat is being started or stopped. setNeighborDiscoveryOffload(boolean enable)147 public void setNeighborDiscoveryOffload(boolean enable) {} 148 } 149 150 public static class WaitForProvisioningCallback extends Callback { 151 private LinkProperties mCallbackLinkProperties; 152 waitForProvisioning()153 public LinkProperties waitForProvisioning() { 154 synchronized (this) { 155 try { 156 wait(); 157 } catch (InterruptedException e) {} 158 return mCallbackLinkProperties; 159 } 160 } 161 162 @Override onProvisioningSuccess(LinkProperties newLp)163 public void onProvisioningSuccess(LinkProperties newLp) { 164 synchronized (this) { 165 mCallbackLinkProperties = newLp; 166 notify(); 167 } 168 } 169 170 @Override onProvisioningFailure(LinkProperties newLp)171 public void onProvisioningFailure(LinkProperties newLp) { 172 synchronized (this) { 173 mCallbackLinkProperties = null; 174 notify(); 175 } 176 } 177 } 178 179 // Use a wrapper class to log in order to ensure complete and detailed 180 // logging. This method is lighter weight than annotations/reflection 181 // and has the following benefits: 182 // 183 // - No invoked method can be forgotten. 184 // Any new method added to IpManager.Callback must be overridden 185 // here or it will never be called. 186 // 187 // - No invoking call site can be forgotten. 188 // Centralized logging in this way means call sites don't need to 189 // remember to log, and therefore no call site can be forgotten. 190 // 191 // - No variation in log format among call sites. 192 // Encourages logging of any available arguments, and all call sites 193 // are necessarily logged identically. 194 // 195 // TODO: Find an lighter weight approach. 196 private class LoggingCallbackWrapper extends Callback { 197 private static final String PREFIX = "INVOKE "; 198 private Callback mCallback; 199 LoggingCallbackWrapper(Callback callback)200 public LoggingCallbackWrapper(Callback callback) { 201 mCallback = callback; 202 } 203 log(String msg)204 private void log(String msg) { 205 mLog.log(PREFIX + msg); 206 } 207 208 @Override onPreDhcpAction()209 public void onPreDhcpAction() { 210 mCallback.onPreDhcpAction(); 211 log("onPreDhcpAction()"); 212 } 213 @Override onPostDhcpAction()214 public void onPostDhcpAction() { 215 mCallback.onPostDhcpAction(); 216 log("onPostDhcpAction()"); 217 } 218 @Override onNewDhcpResults(DhcpResults dhcpResults)219 public void onNewDhcpResults(DhcpResults dhcpResults) { 220 mCallback.onNewDhcpResults(dhcpResults); 221 log("onNewDhcpResults({" + dhcpResults + "})"); 222 } 223 @Override onProvisioningSuccess(LinkProperties newLp)224 public void onProvisioningSuccess(LinkProperties newLp) { 225 mCallback.onProvisioningSuccess(newLp); 226 log("onProvisioningSuccess({" + newLp + "})"); 227 } 228 @Override onProvisioningFailure(LinkProperties newLp)229 public void onProvisioningFailure(LinkProperties newLp) { 230 mCallback.onProvisioningFailure(newLp); 231 log("onProvisioningFailure({" + newLp + "})"); 232 } 233 @Override onLinkPropertiesChange(LinkProperties newLp)234 public void onLinkPropertiesChange(LinkProperties newLp) { 235 mCallback.onLinkPropertiesChange(newLp); 236 log("onLinkPropertiesChange({" + newLp + "})"); 237 } 238 @Override onReachabilityLost(String logMsg)239 public void onReachabilityLost(String logMsg) { 240 mCallback.onReachabilityLost(logMsg); 241 log("onReachabilityLost(" + logMsg + ")"); 242 } 243 @Override onQuit()244 public void onQuit() { 245 mCallback.onQuit(); 246 log("onQuit()"); 247 } 248 @Override installPacketFilter(byte[] filter)249 public void installPacketFilter(byte[] filter) { 250 mCallback.installPacketFilter(filter); 251 log("installPacketFilter(byte[" + filter.length + "])"); 252 } 253 @Override setFallbackMulticastFilter(boolean enabled)254 public void setFallbackMulticastFilter(boolean enabled) { 255 mCallback.setFallbackMulticastFilter(enabled); 256 log("setFallbackMulticastFilter(" + enabled + ")"); 257 } 258 @Override setNeighborDiscoveryOffload(boolean enable)259 public void setNeighborDiscoveryOffload(boolean enable) { 260 mCallback.setNeighborDiscoveryOffload(enable); 261 log("setNeighborDiscoveryOffload(" + enable + ")"); 262 } 263 } 264 265 /** 266 * This class encapsulates parameters to be passed to 267 * IpManager#startProvisioning(). A defensive copy is made by IpManager 268 * and the values specified herein are in force until IpManager#stop() 269 * is called. 270 * 271 * Example use: 272 * 273 * final ProvisioningConfiguration config = 274 * mIpManager.buildProvisioningConfiguration() 275 * .withPreDhcpAction() 276 * .withProvisioningTimeoutMs(36 * 1000) 277 * .build(); 278 * mIpManager.startProvisioning(config); 279 * ... 280 * mIpManager.stop(); 281 * 282 * The specified provisioning configuration will only be active until 283 * IpManager#stop() is called. Future calls to IpManager#startProvisioning() 284 * must specify the configuration again. 285 */ 286 public static class ProvisioningConfiguration { 287 // TODO: Delete this default timeout once those callers that care are 288 // fixed to pass in their preferred timeout. 289 // 290 // We pick 36 seconds so we can send DHCP requests at 291 // 292 // t=0, t=2, t=6, t=14, t=30 293 // 294 // allowing for 10% jitter. 295 private static final int DEFAULT_TIMEOUT_MS = 36 * 1000; 296 297 public static class Builder { 298 private ProvisioningConfiguration mConfig = new ProvisioningConfiguration(); 299 withoutIPv4()300 public Builder withoutIPv4() { 301 mConfig.mEnableIPv4 = false; 302 return this; 303 } 304 withoutIPv6()305 public Builder withoutIPv6() { 306 mConfig.mEnableIPv6 = false; 307 return this; 308 } 309 withoutIpReachabilityMonitor()310 public Builder withoutIpReachabilityMonitor() { 311 mConfig.mUsingIpReachabilityMonitor = false; 312 return this; 313 } 314 withPreDhcpAction()315 public Builder withPreDhcpAction() { 316 mConfig.mRequestedPreDhcpActionMs = DEFAULT_TIMEOUT_MS; 317 return this; 318 } 319 withPreDhcpAction(int dhcpActionTimeoutMs)320 public Builder withPreDhcpAction(int dhcpActionTimeoutMs) { 321 mConfig.mRequestedPreDhcpActionMs = dhcpActionTimeoutMs; 322 return this; 323 } 324 withInitialConfiguration(InitialConfiguration initialConfig)325 public Builder withInitialConfiguration(InitialConfiguration initialConfig) { 326 mConfig.mInitialConfig = initialConfig; 327 return this; 328 } 329 withStaticConfiguration(StaticIpConfiguration staticConfig)330 public Builder withStaticConfiguration(StaticIpConfiguration staticConfig) { 331 mConfig.mStaticIpConfig = staticConfig; 332 return this; 333 } 334 withApfCapabilities(ApfCapabilities apfCapabilities)335 public Builder withApfCapabilities(ApfCapabilities apfCapabilities) { 336 mConfig.mApfCapabilities = apfCapabilities; 337 return this; 338 } 339 withProvisioningTimeoutMs(int timeoutMs)340 public Builder withProvisioningTimeoutMs(int timeoutMs) { 341 mConfig.mProvisioningTimeoutMs = timeoutMs; 342 return this; 343 } 344 withIPv6AddrGenModeEUI64()345 public Builder withIPv6AddrGenModeEUI64() { 346 mConfig.mIPv6AddrGenMode = INetd.IPV6_ADDR_GEN_MODE_EUI64; 347 return this; 348 } 349 withIPv6AddrGenModeStablePrivacy()350 public Builder withIPv6AddrGenModeStablePrivacy() { 351 mConfig.mIPv6AddrGenMode = INetd.IPV6_ADDR_GEN_MODE_STABLE_PRIVACY; 352 return this; 353 } 354 build()355 public ProvisioningConfiguration build() { 356 return new ProvisioningConfiguration(mConfig); 357 } 358 } 359 360 /* package */ boolean mEnableIPv4 = true; 361 /* package */ boolean mEnableIPv6 = true; 362 /* package */ boolean mUsingIpReachabilityMonitor = true; 363 /* package */ int mRequestedPreDhcpActionMs; 364 /* package */ InitialConfiguration mInitialConfig; 365 /* package */ StaticIpConfiguration mStaticIpConfig; 366 /* package */ ApfCapabilities mApfCapabilities; 367 /* package */ int mProvisioningTimeoutMs = DEFAULT_TIMEOUT_MS; 368 /* package */ int mIPv6AddrGenMode = INetd.IPV6_ADDR_GEN_MODE_STABLE_PRIVACY; 369 ProvisioningConfiguration()370 public ProvisioningConfiguration() {} // used by Builder 371 ProvisioningConfiguration(ProvisioningConfiguration other)372 public ProvisioningConfiguration(ProvisioningConfiguration other) { 373 mEnableIPv4 = other.mEnableIPv4; 374 mEnableIPv6 = other.mEnableIPv6; 375 mUsingIpReachabilityMonitor = other.mUsingIpReachabilityMonitor; 376 mRequestedPreDhcpActionMs = other.mRequestedPreDhcpActionMs; 377 mInitialConfig = InitialConfiguration.copy(other.mInitialConfig); 378 mStaticIpConfig = other.mStaticIpConfig; 379 mApfCapabilities = other.mApfCapabilities; 380 mProvisioningTimeoutMs = other.mProvisioningTimeoutMs; 381 } 382 383 @Override toString()384 public String toString() { 385 return new StringJoiner(", ", getClass().getSimpleName() + "{", "}") 386 .add("mEnableIPv4: " + mEnableIPv4) 387 .add("mEnableIPv6: " + mEnableIPv6) 388 .add("mUsingIpReachabilityMonitor: " + mUsingIpReachabilityMonitor) 389 .add("mRequestedPreDhcpActionMs: " + mRequestedPreDhcpActionMs) 390 .add("mInitialConfig: " + mInitialConfig) 391 .add("mStaticIpConfig: " + mStaticIpConfig) 392 .add("mApfCapabilities: " + mApfCapabilities) 393 .add("mProvisioningTimeoutMs: " + mProvisioningTimeoutMs) 394 .add("mIPv6AddrGenMode: " + mIPv6AddrGenMode) 395 .toString(); 396 } 397 isValid()398 public boolean isValid() { 399 return (mInitialConfig == null) || mInitialConfig.isValid(); 400 } 401 } 402 403 public static class InitialConfiguration { 404 public final Set<LinkAddress> ipAddresses = new HashSet<>(); 405 public final Set<IpPrefix> directlyConnectedRoutes = new HashSet<>(); 406 public final Set<InetAddress> dnsServers = new HashSet<>(); 407 public Inet4Address gateway; // WiFi legacy behavior with static ipv4 config 408 copy(InitialConfiguration config)409 public static InitialConfiguration copy(InitialConfiguration config) { 410 if (config == null) { 411 return null; 412 } 413 InitialConfiguration configCopy = new InitialConfiguration(); 414 configCopy.ipAddresses.addAll(config.ipAddresses); 415 configCopy.directlyConnectedRoutes.addAll(config.directlyConnectedRoutes); 416 configCopy.dnsServers.addAll(config.dnsServers); 417 return configCopy; 418 } 419 420 @Override toString()421 public String toString() { 422 return String.format( 423 "InitialConfiguration(IPs: {%s}, prefixes: {%s}, DNS: {%s}, v4 gateway: %s)", 424 join(", ", ipAddresses), join(", ", directlyConnectedRoutes), 425 join(", ", dnsServers), gateway); 426 } 427 isValid()428 public boolean isValid() { 429 if (ipAddresses.isEmpty()) { 430 return false; 431 } 432 433 // For every IP address, there must be at least one prefix containing that address. 434 for (LinkAddress addr : ipAddresses) { 435 if (!any(directlyConnectedRoutes, (p) -> p.contains(addr.getAddress()))) { 436 return false; 437 } 438 } 439 // For every dns server, there must be at least one prefix containing that address. 440 for (InetAddress addr : dnsServers) { 441 if (!any(directlyConnectedRoutes, (p) -> p.contains(addr))) { 442 return false; 443 } 444 } 445 // All IPv6 LinkAddresses have an RFC7421-suitable prefix length 446 // (read: compliant with RFC4291#section2.5.4). 447 if (any(ipAddresses, not(InitialConfiguration::isPrefixLengthCompliant))) { 448 return false; 449 } 450 // If directlyConnectedRoutes contains an IPv6 default route 451 // then ipAddresses MUST contain at least one non-ULA GUA. 452 if (any(directlyConnectedRoutes, InitialConfiguration::isIPv6DefaultRoute) 453 && all(ipAddresses, not(InitialConfiguration::isIPv6GUA))) { 454 return false; 455 } 456 // The prefix length of routes in directlyConnectedRoutes be within reasonable 457 // bounds for IPv6: /48-/64 just as we’d accept in RIOs. 458 if (any(directlyConnectedRoutes, not(InitialConfiguration::isPrefixLengthCompliant))) { 459 return false; 460 } 461 // There no more than one IPv4 address 462 if (ipAddresses.stream().filter(Inet4Address.class::isInstance).count() > 1) { 463 return false; 464 } 465 466 return true; 467 } 468 469 /** 470 * @return true if the given list of addressess and routes satisfies provisioning for this 471 * InitialConfiguration. LinkAddresses and RouteInfo objects are not compared with equality 472 * because addresses and routes seen by Netlink will contain additional fields like flags, 473 * interfaces, and so on. If this InitialConfiguration has no IP address specified, the 474 * provisioning check always fails. 475 * 476 * If the given list of routes is null, only addresses are taken into considerations. 477 */ isProvisionedBy(List<LinkAddress> addresses, List<RouteInfo> routes)478 public boolean isProvisionedBy(List<LinkAddress> addresses, List<RouteInfo> routes) { 479 if (ipAddresses.isEmpty()) { 480 return false; 481 } 482 483 for (LinkAddress addr : ipAddresses) { 484 if (!any(addresses, (addrSeen) -> addr.isSameAddressAs(addrSeen))) { 485 return false; 486 } 487 } 488 489 if (routes != null) { 490 for (IpPrefix prefix : directlyConnectedRoutes) { 491 if (!any(routes, (routeSeen) -> isDirectlyConnectedRoute(routeSeen, prefix))) { 492 return false; 493 } 494 } 495 } 496 497 return true; 498 } 499 isDirectlyConnectedRoute(RouteInfo route, IpPrefix prefix)500 private static boolean isDirectlyConnectedRoute(RouteInfo route, IpPrefix prefix) { 501 return !route.hasGateway() && prefix.equals(route.getDestination()); 502 } 503 isPrefixLengthCompliant(LinkAddress addr)504 private static boolean isPrefixLengthCompliant(LinkAddress addr) { 505 return addr.isIPv4() || isCompliantIPv6PrefixLength(addr.getPrefixLength()); 506 } 507 isPrefixLengthCompliant(IpPrefix prefix)508 private static boolean isPrefixLengthCompliant(IpPrefix prefix) { 509 return prefix.isIPv4() || isCompliantIPv6PrefixLength(prefix.getPrefixLength()); 510 } 511 isCompliantIPv6PrefixLength(int prefixLength)512 private static boolean isCompliantIPv6PrefixLength(int prefixLength) { 513 return (NetworkConstants.RFC6177_MIN_PREFIX_LENGTH <= prefixLength) 514 && (prefixLength <= NetworkConstants.RFC7421_PREFIX_LENGTH); 515 } 516 isIPv6DefaultRoute(IpPrefix prefix)517 private static boolean isIPv6DefaultRoute(IpPrefix prefix) { 518 return prefix.getAddress().equals(Inet6Address.ANY); 519 } 520 isIPv6GUA(LinkAddress addr)521 private static boolean isIPv6GUA(LinkAddress addr) { 522 return addr.isIPv6() && addr.isGlobalPreferred(); 523 } 524 } 525 526 public static final String DUMP_ARG = "ipmanager"; 527 public static final String DUMP_ARG_CONFIRM = "confirm"; 528 529 private static final int CMD_STOP = 1; 530 private static final int CMD_START = 2; 531 private static final int CMD_CONFIRM = 3; 532 private static final int EVENT_PRE_DHCP_ACTION_COMPLETE = 4; 533 // Sent by NetlinkTracker to communicate netlink events. 534 private static final int EVENT_NETLINK_LINKPROPERTIES_CHANGED = 5; 535 private static final int CMD_UPDATE_TCP_BUFFER_SIZES = 6; 536 private static final int CMD_UPDATE_HTTP_PROXY = 7; 537 private static final int CMD_SET_MULTICAST_FILTER = 8; 538 private static final int EVENT_PROVISIONING_TIMEOUT = 9; 539 private static final int EVENT_DHCPACTION_TIMEOUT = 10; 540 541 private static final int MAX_LOG_RECORDS = 500; 542 private static final int MAX_PACKET_RECORDS = 100; 543 544 private static final boolean NO_CALLBACKS = false; 545 private static final boolean SEND_CALLBACKS = true; 546 547 // This must match the interface prefix in clatd.c. 548 // TODO: Revert this hack once IpManager and Nat464Xlat work in concert. 549 private static final String CLAT_PREFIX = "v4-"; 550 551 private final State mStoppedState = new StoppedState(); 552 private final State mStoppingState = new StoppingState(); 553 private final State mStartedState = new StartedState(); 554 private final State mRunningState = new RunningState(); 555 556 private final String mTag; 557 private final Context mContext; 558 private final String mInterfaceName; 559 private final String mClatInterfaceName; 560 @VisibleForTesting 561 protected final Callback mCallback; 562 private final INetworkManagementService mNwService; 563 private final NetlinkTracker mNetlinkTracker; 564 private final WakeupMessage mProvisioningTimeoutAlarm; 565 private final WakeupMessage mDhcpActionTimeoutAlarm; 566 private final MultinetworkPolicyTracker mMultinetworkPolicyTracker; 567 private final SharedLog mLog; 568 private final LocalLog mConnectivityPacketLog; 569 private final MessageHandlingLogger mMsgStateLogger; 570 private final IpConnectivityLog mMetricsLog = new IpConnectivityLog(); 571 private final INetd mNetd; 572 573 private NetworkInterface mNetworkInterface; 574 575 /** 576 * Non-final member variables accessed only from within our StateMachine. 577 */ 578 private LinkProperties mLinkProperties; 579 private ProvisioningConfiguration mConfiguration; 580 private IpReachabilityMonitor mIpReachabilityMonitor; 581 private DhcpClient mDhcpClient; 582 private DhcpResults mDhcpResults; 583 private String mTcpBufferSizes; 584 private ProxyInfo mHttpProxy; 585 private ApfFilter mApfFilter; 586 private boolean mMulticastFiltering; 587 private long mStartTimeMillis; 588 IpManager(Context context, String ifName, Callback callback)589 public IpManager(Context context, String ifName, Callback callback) { 590 this(context, ifName, callback, INetworkManagementService.Stub.asInterface( 591 ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE)), 592 NetdService.getInstance()); 593 } 594 595 /** 596 * An expanded constructor, useful for dependency injection. 597 * TODO: migrate all test users to mock IpManager directly and remove this ctor. 598 */ IpManager(Context context, String ifName, Callback callback, INetworkManagementService nwService)599 public IpManager(Context context, String ifName, Callback callback, 600 INetworkManagementService nwService) { 601 this(context, ifName, callback, nwService, NetdService.getInstance()); 602 } 603 604 @VisibleForTesting IpManager(Context context, String ifName, Callback callback, INetworkManagementService nwService, INetd netd)605 IpManager(Context context, String ifName, Callback callback, 606 INetworkManagementService nwService, INetd netd) { 607 super(IpManager.class.getSimpleName() + "." + ifName); 608 mTag = getName(); 609 610 mContext = context; 611 mInterfaceName = ifName; 612 mClatInterfaceName = CLAT_PREFIX + ifName; 613 mCallback = new LoggingCallbackWrapper(callback); 614 mNwService = nwService; 615 mNetd = netd; 616 617 mLog = new SharedLog(MAX_LOG_RECORDS, mTag); 618 mConnectivityPacketLog = new LocalLog(MAX_PACKET_RECORDS); 619 mMsgStateLogger = new MessageHandlingLogger(); 620 621 mNetlinkTracker = new NetlinkTracker( 622 mInterfaceName, 623 new NetlinkTracker.Callback() { 624 @Override 625 public void update() { 626 sendMessage(EVENT_NETLINK_LINKPROPERTIES_CHANGED); 627 } 628 }) { 629 @Override 630 public void interfaceAdded(String iface) { 631 super.interfaceAdded(iface); 632 if (mClatInterfaceName.equals(iface)) { 633 mCallback.setNeighborDiscoveryOffload(false); 634 } else if (!mInterfaceName.equals(iface)) { 635 return; 636 } 637 638 final String msg = "interfaceAdded(" + iface +")"; 639 logMsg(msg); 640 } 641 642 @Override 643 public void interfaceRemoved(String iface) { 644 super.interfaceRemoved(iface); 645 // TODO: Also observe mInterfaceName going down and take some 646 // kind of appropriate action. 647 if (mClatInterfaceName.equals(iface)) { 648 // TODO: consider sending a message to the IpManager main 649 // StateMachine thread, in case "NDO enabled" state becomes 650 // tied to more things that 464xlat operation. 651 mCallback.setNeighborDiscoveryOffload(true); 652 } else if (!mInterfaceName.equals(iface)) { 653 return; 654 } 655 656 final String msg = "interfaceRemoved(" + iface +")"; 657 logMsg(msg); 658 } 659 660 private void logMsg(String msg) { 661 Log.d(mTag, msg); 662 getHandler().post(() -> { mLog.log("OBSERVED " + msg); }); 663 } 664 }; 665 666 mLinkProperties = new LinkProperties(); 667 mLinkProperties.setInterfaceName(mInterfaceName); 668 669 mMultinetworkPolicyTracker = new MultinetworkPolicyTracker(mContext, getHandler(), 670 () -> { mLog.log("OBSERVED AvoidBadWifi changed"); }); 671 672 mProvisioningTimeoutAlarm = new WakeupMessage(mContext, getHandler(), 673 mTag + ".EVENT_PROVISIONING_TIMEOUT", EVENT_PROVISIONING_TIMEOUT); 674 mDhcpActionTimeoutAlarm = new WakeupMessage(mContext, getHandler(), 675 mTag + ".EVENT_DHCPACTION_TIMEOUT", EVENT_DHCPACTION_TIMEOUT); 676 677 // Anything the StateMachine may access must have been instantiated 678 // before this point. 679 configureAndStartStateMachine(); 680 681 // Anything that may send messages to the StateMachine must only be 682 // configured to do so after the StateMachine has started (above). 683 startStateMachineUpdaters(); 684 } 685 configureAndStartStateMachine()686 private void configureAndStartStateMachine() { 687 addState(mStoppedState); 688 addState(mStartedState); 689 addState(mRunningState, mStartedState); 690 addState(mStoppingState); 691 692 setInitialState(mStoppedState); 693 694 super.start(); 695 } 696 startStateMachineUpdaters()697 private void startStateMachineUpdaters() { 698 try { 699 mNwService.registerObserver(mNetlinkTracker); 700 } catch (RemoteException e) { 701 logError("Couldn't register NetlinkTracker: %s", e); 702 } 703 704 mMultinetworkPolicyTracker.start(); 705 } 706 707 @Override onQuitting()708 protected void onQuitting() { 709 mCallback.onQuit(); 710 } 711 712 // Shut down this IpManager instance altogether. shutdown()713 public void shutdown() { 714 stop(); 715 mMultinetworkPolicyTracker.shutdown(); 716 quit(); 717 } 718 buildProvisioningConfiguration()719 public static ProvisioningConfiguration.Builder buildProvisioningConfiguration() { 720 return new ProvisioningConfiguration.Builder(); 721 } 722 startProvisioning(ProvisioningConfiguration req)723 public void startProvisioning(ProvisioningConfiguration req) { 724 if (!req.isValid()) { 725 doImmediateProvisioningFailure(IpManagerEvent.ERROR_INVALID_PROVISIONING); 726 return; 727 } 728 729 getNetworkInterface(); 730 731 mCallback.setNeighborDiscoveryOffload(true); 732 sendMessage(CMD_START, new ProvisioningConfiguration(req)); 733 } 734 735 // TODO: Delete this. startProvisioning(StaticIpConfiguration staticIpConfig)736 public void startProvisioning(StaticIpConfiguration staticIpConfig) { 737 startProvisioning(buildProvisioningConfiguration() 738 .withStaticConfiguration(staticIpConfig) 739 .build()); 740 } 741 startProvisioning()742 public void startProvisioning() { 743 startProvisioning(new ProvisioningConfiguration()); 744 } 745 stop()746 public void stop() { 747 sendMessage(CMD_STOP); 748 } 749 confirmConfiguration()750 public void confirmConfiguration() { 751 sendMessage(CMD_CONFIRM); 752 } 753 completedPreDhcpAction()754 public void completedPreDhcpAction() { 755 sendMessage(EVENT_PRE_DHCP_ACTION_COMPLETE); 756 } 757 758 /** 759 * Set the TCP buffer sizes to use. 760 * 761 * This may be called, repeatedly, at any time before or after a call to 762 * #startProvisioning(). The setting is cleared upon calling #stop(). 763 */ setTcpBufferSizes(String tcpBufferSizes)764 public void setTcpBufferSizes(String tcpBufferSizes) { 765 sendMessage(CMD_UPDATE_TCP_BUFFER_SIZES, tcpBufferSizes); 766 } 767 768 /** 769 * Set the HTTP Proxy configuration to use. 770 * 771 * This may be called, repeatedly, at any time before or after a call to 772 * #startProvisioning(). The setting is cleared upon calling #stop(). 773 */ setHttpProxy(ProxyInfo proxyInfo)774 public void setHttpProxy(ProxyInfo proxyInfo) { 775 sendMessage(CMD_UPDATE_HTTP_PROXY, proxyInfo); 776 } 777 778 /** 779 * Enable or disable the multicast filter. Attempts to use APF to accomplish the filtering, 780 * if not, Callback.setFallbackMulticastFilter() is called. 781 */ setMulticastFilter(boolean enabled)782 public void setMulticastFilter(boolean enabled) { 783 sendMessage(CMD_SET_MULTICAST_FILTER, enabled); 784 } 785 dump(FileDescriptor fd, PrintWriter writer, String[] args)786 public void dump(FileDescriptor fd, PrintWriter writer, String[] args) { 787 if (args != null && args.length > 0 && DUMP_ARG_CONFIRM.equals(args[0])) { 788 // Execute confirmConfiguration() and take no further action. 789 confirmConfiguration(); 790 return; 791 } 792 793 // Thread-unsafe access to mApfFilter but just used for debugging. 794 final ApfFilter apfFilter = mApfFilter; 795 final ProvisioningConfiguration provisioningConfig = mConfiguration; 796 final ApfCapabilities apfCapabilities = (provisioningConfig != null) 797 ? provisioningConfig.mApfCapabilities : null; 798 799 IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); 800 pw.println(mTag + " APF dump:"); 801 pw.increaseIndent(); 802 if (apfFilter != null) { 803 apfFilter.dump(pw); 804 } else { 805 pw.print("No active ApfFilter; "); 806 if (provisioningConfig == null) { 807 pw.println("IpManager not yet started."); 808 } else if (apfCapabilities == null || apfCapabilities.apfVersionSupported == 0) { 809 pw.println("Hardware does not support APF."); 810 } else { 811 pw.println("ApfFilter not yet started, APF capabilities: " + apfCapabilities); 812 } 813 } 814 pw.decreaseIndent(); 815 816 pw.println(); 817 pw.println(mTag + " current ProvisioningConfiguration:"); 818 pw.increaseIndent(); 819 pw.println(Objects.toString(provisioningConfig, "N/A")); 820 pw.decreaseIndent(); 821 822 pw.println(); 823 pw.println(mTag + " StateMachine dump:"); 824 pw.increaseIndent(); 825 mLog.dump(fd, pw, args); 826 pw.decreaseIndent(); 827 828 pw.println(); 829 pw.println(mTag + " connectivity packet log:"); 830 pw.println(); 831 pw.println("Debug with python and scapy via:"); 832 pw.println("shell$ python"); 833 pw.println(">>> from scapy import all as scapy"); 834 pw.println(">>> scapy.Ether(\"<paste_hex_string>\".decode(\"hex\")).show2()"); 835 pw.println(); 836 837 pw.increaseIndent(); 838 mConnectivityPacketLog.readOnlyLocalLog().dump(fd, pw, args); 839 pw.decreaseIndent(); 840 } 841 842 843 /** 844 * Internals. 845 */ 846 847 @Override getWhatToString(int what)848 protected String getWhatToString(int what) { 849 return sWhatToString.get(what, "UNKNOWN: " + Integer.toString(what)); 850 } 851 852 @Override getLogRecString(Message msg)853 protected String getLogRecString(Message msg) { 854 final String logLine = String.format( 855 "%s/%d %d %d %s [%s]", 856 mInterfaceName, mNetworkInterface == null ? -1 : mNetworkInterface.getIndex(), 857 msg.arg1, msg.arg2, Objects.toString(msg.obj), mMsgStateLogger); 858 859 final String richerLogLine = getWhatToString(msg.what) + " " + logLine; 860 mLog.log(richerLogLine); 861 if (VDBG) { 862 Log.d(mTag, richerLogLine); 863 } 864 865 mMsgStateLogger.reset(); 866 return logLine; 867 } 868 869 @Override recordLogRec(Message msg)870 protected boolean recordLogRec(Message msg) { 871 // Don't log EVENT_NETLINK_LINKPROPERTIES_CHANGED. They can be noisy, 872 // and we already log any LinkProperties change that results in an 873 // invocation of IpManager.Callback#onLinkPropertiesChange(). 874 final boolean shouldLog = (msg.what != EVENT_NETLINK_LINKPROPERTIES_CHANGED); 875 if (!shouldLog) { 876 mMsgStateLogger.reset(); 877 } 878 return shouldLog; 879 } 880 logError(String fmt, Object... args)881 private void logError(String fmt, Object... args) { 882 final String msg = "ERROR " + String.format(fmt, args); 883 Log.e(mTag, msg); 884 mLog.log(msg); 885 } 886 getNetworkInterface()887 private void getNetworkInterface() { 888 try { 889 mNetworkInterface = NetworkInterface.getByName(mInterfaceName); 890 } catch (SocketException | NullPointerException e) { 891 // TODO: throw new IllegalStateException. 892 logError("Failed to get interface object: %s", e); 893 } 894 } 895 896 // This needs to be called with care to ensure that our LinkProperties 897 // are in sync with the actual LinkProperties of the interface. For example, 898 // we should only call this if we know for sure that there are no IP addresses 899 // assigned to the interface, etc. resetLinkProperties()900 private void resetLinkProperties() { 901 mNetlinkTracker.clearLinkProperties(); 902 mConfiguration = null; 903 mDhcpResults = null; 904 mTcpBufferSizes = ""; 905 mHttpProxy = null; 906 907 mLinkProperties = new LinkProperties(); 908 mLinkProperties.setInterfaceName(mInterfaceName); 909 } 910 recordMetric(final int type)911 private void recordMetric(final int type) { 912 if (mStartTimeMillis <= 0) { Log.wtf(mTag, "Start time undefined!"); } 913 final long duration = SystemClock.elapsedRealtime() - mStartTimeMillis; 914 mMetricsLog.log(mInterfaceName, new IpManagerEvent(type, duration)); 915 } 916 917 // For now: use WifiStateMachine's historical notion of provisioned. 918 @VisibleForTesting isProvisioned(LinkProperties lp, InitialConfiguration config)919 static boolean isProvisioned(LinkProperties lp, InitialConfiguration config) { 920 // For historical reasons, we should connect even if all we have is 921 // an IPv4 address and nothing else. 922 if (lp.hasIPv4Address() || lp.isProvisioned()) { 923 return true; 924 } 925 if (config == null) { 926 return false; 927 } 928 929 // When an InitialConfiguration is specified, ignore any difference with previous 930 // properties and instead check if properties observed match the desired properties. 931 return config.isProvisionedBy(lp.getLinkAddresses(), lp.getRoutes()); 932 } 933 934 // TODO: Investigate folding all this into the existing static function 935 // LinkProperties.compareProvisioning() or some other single function that 936 // takes two LinkProperties objects and returns a ProvisioningChange 937 // object that is a correct and complete assessment of what changed, taking 938 // account of the asymmetries described in the comments in this function. 939 // Then switch to using it everywhere (IpReachabilityMonitor, etc.). compareProvisioning(LinkProperties oldLp, LinkProperties newLp)940 private ProvisioningChange compareProvisioning(LinkProperties oldLp, LinkProperties newLp) { 941 ProvisioningChange delta; 942 InitialConfiguration config = mConfiguration != null ? mConfiguration.mInitialConfig : null; 943 final boolean wasProvisioned = isProvisioned(oldLp, config); 944 final boolean isProvisioned = isProvisioned(newLp, config); 945 946 if (!wasProvisioned && isProvisioned) { 947 delta = ProvisioningChange.GAINED_PROVISIONING; 948 } else if (wasProvisioned && isProvisioned) { 949 delta = ProvisioningChange.STILL_PROVISIONED; 950 } else if (!wasProvisioned && !isProvisioned) { 951 delta = ProvisioningChange.STILL_NOT_PROVISIONED; 952 } else { 953 // (wasProvisioned && !isProvisioned) 954 // 955 // Note that this is true even if we lose a configuration element 956 // (e.g., a default gateway) that would not be required to advance 957 // into provisioned state. This is intended: if we have a default 958 // router and we lose it, that's a sure sign of a problem, but if 959 // we connect to a network with no IPv4 DNS servers, we consider 960 // that to be a network without DNS servers and connect anyway. 961 // 962 // See the comment below. 963 delta = ProvisioningChange.LOST_PROVISIONING; 964 } 965 966 final boolean lostIPv6 = oldLp.isIPv6Provisioned() && !newLp.isIPv6Provisioned(); 967 final boolean lostIPv4Address = oldLp.hasIPv4Address() && !newLp.hasIPv4Address(); 968 final boolean lostIPv6Router = oldLp.hasIPv6DefaultRoute() && !newLp.hasIPv6DefaultRoute(); 969 970 // If bad wifi avoidance is disabled, then ignore IPv6 loss of 971 // provisioning. Otherwise, when a hotspot that loses Internet 972 // access sends out a 0-lifetime RA to its clients, the clients 973 // will disconnect and then reconnect, avoiding the bad hotspot, 974 // instead of getting stuck on the bad hotspot. http://b/31827713 . 975 // 976 // This is incorrect because if the hotspot then regains Internet 977 // access with a different prefix, TCP connections on the 978 // deprecated addresses will remain stuck. 979 // 980 // Note that we can still be disconnected by IpReachabilityMonitor 981 // if the IPv6 default gateway (but not the IPv6 DNS servers; see 982 // accompanying code in IpReachabilityMonitor) is unreachable. 983 final boolean ignoreIPv6ProvisioningLoss = !mMultinetworkPolicyTracker.getAvoidBadWifi(); 984 985 // Additionally: 986 // 987 // Partial configurations (e.g., only an IPv4 address with no DNS 988 // servers and no default route) are accepted as long as DHCPv4 989 // succeeds. On such a network, isProvisioned() will always return 990 // false, because the configuration is not complete, but we want to 991 // connect anyway. It might be a disconnected network such as a 992 // Chromecast or a wireless printer, for example. 993 // 994 // Because on such a network isProvisioned() will always return false, 995 // delta will never be LOST_PROVISIONING. So check for loss of 996 // provisioning here too. 997 if (lostIPv4Address || (lostIPv6 && !ignoreIPv6ProvisioningLoss)) { 998 delta = ProvisioningChange.LOST_PROVISIONING; 999 } 1000 1001 // Additionally: 1002 // 1003 // If the previous link properties had a global IPv6 address and an 1004 // IPv6 default route then also consider the loss of that default route 1005 // to be a loss of provisioning. See b/27962810. 1006 if (oldLp.hasGlobalIPv6Address() && (lostIPv6Router && !ignoreIPv6ProvisioningLoss)) { 1007 delta = ProvisioningChange.LOST_PROVISIONING; 1008 } 1009 1010 return delta; 1011 } 1012 dispatchCallback(ProvisioningChange delta, LinkProperties newLp)1013 private void dispatchCallback(ProvisioningChange delta, LinkProperties newLp) { 1014 switch (delta) { 1015 case GAINED_PROVISIONING: 1016 if (VDBG) { Log.d(mTag, "onProvisioningSuccess()"); } 1017 recordMetric(IpManagerEvent.PROVISIONING_OK); 1018 mCallback.onProvisioningSuccess(newLp); 1019 break; 1020 1021 case LOST_PROVISIONING: 1022 if (VDBG) { Log.d(mTag, "onProvisioningFailure()"); } 1023 recordMetric(IpManagerEvent.PROVISIONING_FAIL); 1024 mCallback.onProvisioningFailure(newLp); 1025 break; 1026 1027 default: 1028 if (VDBG) { Log.d(mTag, "onLinkPropertiesChange()"); } 1029 mCallback.onLinkPropertiesChange(newLp); 1030 break; 1031 } 1032 } 1033 1034 // Updates all IpManager-related state concerned with LinkProperties. 1035 // Returns a ProvisioningChange for possibly notifying other interested 1036 // parties that are not fronted by IpManager. setLinkProperties(LinkProperties newLp)1037 private ProvisioningChange setLinkProperties(LinkProperties newLp) { 1038 if (mApfFilter != null) { 1039 mApfFilter.setLinkProperties(newLp); 1040 } 1041 if (mIpReachabilityMonitor != null) { 1042 mIpReachabilityMonitor.updateLinkProperties(newLp); 1043 } 1044 1045 ProvisioningChange delta = compareProvisioning(mLinkProperties, newLp); 1046 mLinkProperties = new LinkProperties(newLp); 1047 1048 if (delta == ProvisioningChange.GAINED_PROVISIONING) { 1049 // TODO: Add a proper ProvisionedState and cancel the alarm in 1050 // its enter() method. 1051 mProvisioningTimeoutAlarm.cancel(); 1052 } 1053 1054 return delta; 1055 } 1056 assembleLinkProperties()1057 private LinkProperties assembleLinkProperties() { 1058 // [1] Create a new LinkProperties object to populate. 1059 LinkProperties newLp = new LinkProperties(); 1060 newLp.setInterfaceName(mInterfaceName); 1061 1062 // [2] Pull in data from netlink: 1063 // - IPv4 addresses 1064 // - IPv6 addresses 1065 // - IPv6 routes 1066 // - IPv6 DNS servers 1067 // 1068 // N.B.: this is fundamentally race-prone and should be fixed by 1069 // changing NetlinkTracker from a hybrid edge/level model to an 1070 // edge-only model, or by giving IpManager its own netlink socket(s) 1071 // so as to track all required information directly. 1072 LinkProperties netlinkLinkProperties = mNetlinkTracker.getLinkProperties(); 1073 newLp.setLinkAddresses(netlinkLinkProperties.getLinkAddresses()); 1074 for (RouteInfo route : netlinkLinkProperties.getRoutes()) { 1075 newLp.addRoute(route); 1076 } 1077 addAllReachableDnsServers(newLp, netlinkLinkProperties.getDnsServers()); 1078 1079 // [3] Add in data from DHCPv4, if available. 1080 // 1081 // mDhcpResults is never shared with any other owner so we don't have 1082 // to worry about concurrent modification. 1083 if (mDhcpResults != null) { 1084 for (RouteInfo route : mDhcpResults.getRoutes(mInterfaceName)) { 1085 newLp.addRoute(route); 1086 } 1087 addAllReachableDnsServers(newLp, mDhcpResults.dnsServers); 1088 newLp.setDomains(mDhcpResults.domains); 1089 1090 if (mDhcpResults.mtu != 0) { 1091 newLp.setMtu(mDhcpResults.mtu); 1092 } 1093 } 1094 1095 // [4] Add in TCP buffer sizes and HTTP Proxy config, if available. 1096 if (!TextUtils.isEmpty(mTcpBufferSizes)) { 1097 newLp.setTcpBufferSizes(mTcpBufferSizes); 1098 } 1099 if (mHttpProxy != null) { 1100 newLp.setHttpProxy(mHttpProxy); 1101 } 1102 1103 // [5] Add data from InitialConfiguration 1104 if (mConfiguration != null && mConfiguration.mInitialConfig != null) { 1105 InitialConfiguration config = mConfiguration.mInitialConfig; 1106 // Add InitialConfiguration routes and dns server addresses once all addresses 1107 // specified in the InitialConfiguration have been observed with Netlink. 1108 if (config.isProvisionedBy(newLp.getLinkAddresses(), null)) { 1109 for (IpPrefix prefix : config.directlyConnectedRoutes) { 1110 newLp.addRoute(new RouteInfo(prefix, null, mInterfaceName)); 1111 } 1112 } 1113 addAllReachableDnsServers(newLp, config.dnsServers); 1114 } 1115 final LinkProperties oldLp = mLinkProperties; 1116 if (VDBG) { 1117 Log.d(mTag, String.format("Netlink-seen LPs: %s, new LPs: %s; old LPs: %s", 1118 netlinkLinkProperties, newLp, oldLp)); 1119 } 1120 1121 // TODO: also learn via netlink routes specified by an InitialConfiguration and specified 1122 // from a static IP v4 config instead of manually patching them in in steps [3] and [5]. 1123 return newLp; 1124 } 1125 addAllReachableDnsServers( LinkProperties lp, Iterable<InetAddress> dnses)1126 private static void addAllReachableDnsServers( 1127 LinkProperties lp, Iterable<InetAddress> dnses) { 1128 // TODO: Investigate deleting this reachability check. We should be 1129 // able to pass everything down to netd and let netd do evaluation 1130 // and RFC6724-style sorting. 1131 for (InetAddress dns : dnses) { 1132 if (!dns.isAnyLocalAddress() && lp.isReachable(dns)) { 1133 lp.addDnsServer(dns); 1134 } 1135 } 1136 } 1137 1138 // Returns false if we have lost provisioning, true otherwise. handleLinkPropertiesUpdate(boolean sendCallbacks)1139 private boolean handleLinkPropertiesUpdate(boolean sendCallbacks) { 1140 final LinkProperties newLp = assembleLinkProperties(); 1141 if (Objects.equals(newLp, mLinkProperties)) { 1142 return true; 1143 } 1144 final ProvisioningChange delta = setLinkProperties(newLp); 1145 if (sendCallbacks) { 1146 dispatchCallback(delta, newLp); 1147 } 1148 return (delta != ProvisioningChange.LOST_PROVISIONING); 1149 } 1150 setIPv4Address(LinkAddress address)1151 private boolean setIPv4Address(LinkAddress address) { 1152 final InterfaceConfiguration ifcg = new InterfaceConfiguration(); 1153 ifcg.setLinkAddress(address); 1154 try { 1155 mNwService.setInterfaceConfig(mInterfaceName, ifcg); 1156 if (VDBG) Log.d(mTag, "IPv4 configuration succeeded"); 1157 } catch (IllegalStateException | RemoteException e) { 1158 logError("IPv4 configuration failed: %s", e); 1159 return false; 1160 } 1161 return true; 1162 } 1163 clearIPv4Address()1164 private void clearIPv4Address() { 1165 try { 1166 final InterfaceConfiguration ifcg = new InterfaceConfiguration(); 1167 ifcg.setLinkAddress(new LinkAddress("0.0.0.0/0")); 1168 mNwService.setInterfaceConfig(mInterfaceName, ifcg); 1169 } catch (IllegalStateException | RemoteException e) { 1170 logError("Failed to clear IPv4 address on interface %s: %s", mInterfaceName, e); 1171 } 1172 } 1173 handleIPv4Success(DhcpResults dhcpResults)1174 private void handleIPv4Success(DhcpResults dhcpResults) { 1175 mDhcpResults = new DhcpResults(dhcpResults); 1176 final LinkProperties newLp = assembleLinkProperties(); 1177 final ProvisioningChange delta = setLinkProperties(newLp); 1178 1179 if (VDBG) { 1180 Log.d(mTag, "onNewDhcpResults(" + Objects.toString(dhcpResults) + ")"); 1181 } 1182 mCallback.onNewDhcpResults(dhcpResults); 1183 dispatchCallback(delta, newLp); 1184 } 1185 handleIPv4Failure()1186 private void handleIPv4Failure() { 1187 // TODO: Investigate deleting this clearIPv4Address() call. 1188 // 1189 // DhcpClient will send us CMD_CLEAR_LINKADDRESS in all circumstances 1190 // that could trigger a call to this function. If we missed handling 1191 // that message in StartedState for some reason we would still clear 1192 // any addresses upon entry to StoppedState. 1193 clearIPv4Address(); 1194 mDhcpResults = null; 1195 if (VDBG) { Log.d(mTag, "onNewDhcpResults(null)"); } 1196 mCallback.onNewDhcpResults(null); 1197 1198 handleProvisioningFailure(); 1199 } 1200 handleProvisioningFailure()1201 private void handleProvisioningFailure() { 1202 final LinkProperties newLp = assembleLinkProperties(); 1203 ProvisioningChange delta = setLinkProperties(newLp); 1204 // If we've gotten here and we're still not provisioned treat that as 1205 // a total loss of provisioning. 1206 // 1207 // Either (a) static IP configuration failed or (b) DHCPv4 failed AND 1208 // there was no usable IPv6 obtained before a non-zero provisioning 1209 // timeout expired. 1210 // 1211 // Regardless: GAME OVER. 1212 if (delta == ProvisioningChange.STILL_NOT_PROVISIONED) { 1213 delta = ProvisioningChange.LOST_PROVISIONING; 1214 } 1215 1216 dispatchCallback(delta, newLp); 1217 if (delta == ProvisioningChange.LOST_PROVISIONING) { 1218 transitionTo(mStoppingState); 1219 } 1220 } 1221 doImmediateProvisioningFailure(int failureType)1222 private void doImmediateProvisioningFailure(int failureType) { 1223 logError("onProvisioningFailure(): %s", failureType); 1224 recordMetric(failureType); 1225 mCallback.onProvisioningFailure(new LinkProperties(mLinkProperties)); 1226 } 1227 startIPv4()1228 private boolean startIPv4() { 1229 // If we have a StaticIpConfiguration attempt to apply it and 1230 // handle the result accordingly. 1231 if (mConfiguration.mStaticIpConfig != null) { 1232 if (setIPv4Address(mConfiguration.mStaticIpConfig.ipAddress)) { 1233 handleIPv4Success(new DhcpResults(mConfiguration.mStaticIpConfig)); 1234 } else { 1235 return false; 1236 } 1237 } else { 1238 // Start DHCPv4. 1239 mDhcpClient = DhcpClient.makeDhcpClient(mContext, IpManager.this, mInterfaceName); 1240 mDhcpClient.registerForPreDhcpNotification(); 1241 mDhcpClient.sendMessage(DhcpClient.CMD_START_DHCP); 1242 } 1243 1244 return true; 1245 } 1246 setIPv6AddrGenModeIfSupported()1247 private void setIPv6AddrGenModeIfSupported() throws RemoteException { 1248 try { 1249 mNwService.setIPv6AddrGenMode(mInterfaceName, mConfiguration.mIPv6AddrGenMode); 1250 } catch (ServiceSpecificException e) { 1251 if (e.errorCode != OsConstants.EOPNOTSUPP) { 1252 logError("Unable to set IPv6 addrgen mode: %s", e); 1253 } 1254 } 1255 } 1256 startIPv6()1257 private boolean startIPv6() { 1258 // Set privacy extensions. 1259 try { 1260 mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true); 1261 1262 setIPv6AddrGenModeIfSupported(); 1263 mNwService.enableIpv6(mInterfaceName); 1264 } catch (IllegalStateException | RemoteException | ServiceSpecificException e) { 1265 logError("Unable to change interface settings: %s", e); 1266 return false; 1267 } 1268 1269 return true; 1270 } 1271 applyInitialConfig(InitialConfiguration config)1272 private boolean applyInitialConfig(InitialConfiguration config) { 1273 if (mNetd == null) { 1274 logError("tried to add %s to %s but INetd was null", config, mInterfaceName); 1275 return false; 1276 } 1277 1278 // TODO: also support specifying a static IPv4 configuration in InitialConfiguration. 1279 for (LinkAddress addr : findAll(config.ipAddresses, LinkAddress::isIPv6)) { 1280 try { 1281 mNetd.interfaceAddAddress( 1282 mInterfaceName, addr.getAddress().getHostAddress(), addr.getPrefixLength()); 1283 } catch (ServiceSpecificException | RemoteException e) { 1284 logError("failed to add %s to %s: %s", addr, mInterfaceName, e); 1285 return false; 1286 } 1287 } 1288 1289 return true; 1290 } 1291 startIpReachabilityMonitor()1292 private boolean startIpReachabilityMonitor() { 1293 try { 1294 mIpReachabilityMonitor = new IpReachabilityMonitor( 1295 mContext, 1296 mInterfaceName, 1297 mLog, 1298 new IpReachabilityMonitor.Callback() { 1299 @Override 1300 public void notifyLost(InetAddress ip, String logMsg) { 1301 mCallback.onReachabilityLost(logMsg); 1302 } 1303 }, 1304 mMultinetworkPolicyTracker); 1305 } catch (IllegalArgumentException iae) { 1306 // Failed to start IpReachabilityMonitor. Log it and call 1307 // onProvisioningFailure() immediately. 1308 // 1309 // See http://b/31038971. 1310 logError("IpReachabilityMonitor failure: %s", iae); 1311 mIpReachabilityMonitor = null; 1312 } 1313 1314 return (mIpReachabilityMonitor != null); 1315 } 1316 stopAllIP()1317 private void stopAllIP() { 1318 // We don't need to worry about routes, just addresses, because: 1319 // - disableIpv6() will clear autoconf IPv6 routes as well, and 1320 // - we don't get IPv4 routes from netlink 1321 // so we neither react to nor need to wait for changes in either. 1322 1323 try { 1324 mNwService.disableIpv6(mInterfaceName); 1325 } catch (Exception e) { 1326 logError("Failed to disable IPv6: %s", e); 1327 } 1328 1329 try { 1330 mNwService.clearInterfaceAddresses(mInterfaceName); 1331 } catch (Exception e) { 1332 logError("Failed to clear addresses: %s", e); 1333 } 1334 } 1335 1336 class StoppedState extends State { 1337 @Override enter()1338 public void enter() { 1339 stopAllIP(); 1340 1341 resetLinkProperties(); 1342 if (mStartTimeMillis > 0) { 1343 recordMetric(IpManagerEvent.COMPLETE_LIFECYCLE); 1344 mStartTimeMillis = 0; 1345 } 1346 } 1347 1348 @Override processMessage(Message msg)1349 public boolean processMessage(Message msg) { 1350 switch (msg.what) { 1351 case CMD_STOP: 1352 break; 1353 1354 case CMD_START: 1355 mConfiguration = (ProvisioningConfiguration) msg.obj; 1356 transitionTo(mStartedState); 1357 break; 1358 1359 case EVENT_NETLINK_LINKPROPERTIES_CHANGED: 1360 handleLinkPropertiesUpdate(NO_CALLBACKS); 1361 break; 1362 1363 case CMD_UPDATE_TCP_BUFFER_SIZES: 1364 mTcpBufferSizes = (String) msg.obj; 1365 handleLinkPropertiesUpdate(NO_CALLBACKS); 1366 break; 1367 1368 case CMD_UPDATE_HTTP_PROXY: 1369 mHttpProxy = (ProxyInfo) msg.obj; 1370 handleLinkPropertiesUpdate(NO_CALLBACKS); 1371 break; 1372 1373 case CMD_SET_MULTICAST_FILTER: 1374 mMulticastFiltering = (boolean) msg.obj; 1375 break; 1376 1377 case DhcpClient.CMD_ON_QUIT: 1378 // Everything is already stopped. 1379 logError("Unexpected CMD_ON_QUIT (already stopped)."); 1380 break; 1381 1382 default: 1383 return NOT_HANDLED; 1384 } 1385 1386 mMsgStateLogger.handled(this, getCurrentState()); 1387 return HANDLED; 1388 } 1389 } 1390 1391 class StoppingState extends State { 1392 @Override enter()1393 public void enter() { 1394 if (mDhcpClient == null) { 1395 // There's no DHCPv4 for which to wait; proceed to stopped. 1396 transitionTo(mStoppedState); 1397 } 1398 } 1399 1400 @Override processMessage(Message msg)1401 public boolean processMessage(Message msg) { 1402 switch (msg.what) { 1403 case CMD_STOP: 1404 break; 1405 1406 case DhcpClient.CMD_CLEAR_LINKADDRESS: 1407 clearIPv4Address(); 1408 break; 1409 1410 case DhcpClient.CMD_ON_QUIT: 1411 mDhcpClient = null; 1412 transitionTo(mStoppedState); 1413 break; 1414 1415 default: 1416 deferMessage(msg); 1417 } 1418 1419 mMsgStateLogger.handled(this, getCurrentState()); 1420 return HANDLED; 1421 } 1422 } 1423 1424 class StartedState extends State { 1425 @Override enter()1426 public void enter() { 1427 mStartTimeMillis = SystemClock.elapsedRealtime(); 1428 1429 if (mConfiguration.mProvisioningTimeoutMs > 0) { 1430 final long alarmTime = SystemClock.elapsedRealtime() + 1431 mConfiguration.mProvisioningTimeoutMs; 1432 mProvisioningTimeoutAlarm.schedule(alarmTime); 1433 } 1434 1435 if (readyToProceed()) { 1436 transitionTo(mRunningState); 1437 } else { 1438 // Clear all IPv4 and IPv6 before proceeding to RunningState. 1439 // Clean up any leftover state from an abnormal exit from 1440 // tethering or during an IpManager restart. 1441 stopAllIP(); 1442 } 1443 } 1444 1445 @Override exit()1446 public void exit() { 1447 mProvisioningTimeoutAlarm.cancel(); 1448 } 1449 1450 @Override processMessage(Message msg)1451 public boolean processMessage(Message msg) { 1452 switch (msg.what) { 1453 case CMD_STOP: 1454 transitionTo(mStoppingState); 1455 break; 1456 1457 case EVENT_NETLINK_LINKPROPERTIES_CHANGED: 1458 handleLinkPropertiesUpdate(NO_CALLBACKS); 1459 if (readyToProceed()) { 1460 transitionTo(mRunningState); 1461 } 1462 break; 1463 1464 case EVENT_PROVISIONING_TIMEOUT: 1465 handleProvisioningFailure(); 1466 break; 1467 1468 default: 1469 // It's safe to process messages out of order because the 1470 // only message that can both 1471 // a) be received at this time and 1472 // b) affect provisioning state 1473 // is EVENT_NETLINK_LINKPROPERTIES_CHANGED (handled above). 1474 deferMessage(msg); 1475 } 1476 1477 mMsgStateLogger.handled(this, getCurrentState()); 1478 return HANDLED; 1479 } 1480 readyToProceed()1481 boolean readyToProceed() { 1482 return (!mLinkProperties.hasIPv4Address() && 1483 !mLinkProperties.hasGlobalIPv6Address()); 1484 } 1485 } 1486 1487 class RunningState extends State { 1488 private ConnectivityPacketTracker mPacketTracker; 1489 private boolean mDhcpActionInFlight; 1490 1491 @Override enter()1492 public void enter() { 1493 // Get the Configuration for ApfFilter from Context 1494 boolean filter802_3Frames = 1495 mContext.getResources().getBoolean(R.bool.config_apfDrop802_3Frames); 1496 1497 mApfFilter = ApfFilter.maybeCreate(mConfiguration.mApfCapabilities, mNetworkInterface, 1498 mCallback, mMulticastFiltering, filter802_3Frames); 1499 // TODO: investigate the effects of any multicast filtering racing/interfering with the 1500 // rest of this IP configuration startup. 1501 if (mApfFilter == null) { 1502 mCallback.setFallbackMulticastFilter(mMulticastFiltering); 1503 } 1504 1505 mPacketTracker = createPacketTracker(); 1506 if (mPacketTracker != null) mPacketTracker.start(); 1507 1508 if (mConfiguration.mEnableIPv6 && !startIPv6()) { 1509 doImmediateProvisioningFailure(IpManagerEvent.ERROR_STARTING_IPV6); 1510 transitionTo(mStoppingState); 1511 return; 1512 } 1513 1514 if (mConfiguration.mEnableIPv4 && !startIPv4()) { 1515 doImmediateProvisioningFailure(IpManagerEvent.ERROR_STARTING_IPV4); 1516 transitionTo(mStoppingState); 1517 return; 1518 } 1519 1520 InitialConfiguration config = mConfiguration.mInitialConfig; 1521 if ((config != null) && !applyInitialConfig(config)) { 1522 // TODO introduce a new IpManagerEvent constant to distinguish this error case. 1523 doImmediateProvisioningFailure(IpManagerEvent.ERROR_INVALID_PROVISIONING); 1524 transitionTo(mStoppingState); 1525 return; 1526 } 1527 1528 if (mConfiguration.mUsingIpReachabilityMonitor && !startIpReachabilityMonitor()) { 1529 doImmediateProvisioningFailure( 1530 IpManagerEvent.ERROR_STARTING_IPREACHABILITYMONITOR); 1531 transitionTo(mStoppingState); 1532 return; 1533 } 1534 } 1535 1536 @Override exit()1537 public void exit() { 1538 stopDhcpAction(); 1539 1540 if (mIpReachabilityMonitor != null) { 1541 mIpReachabilityMonitor.stop(); 1542 mIpReachabilityMonitor = null; 1543 } 1544 1545 if (mDhcpClient != null) { 1546 mDhcpClient.sendMessage(DhcpClient.CMD_STOP_DHCP); 1547 mDhcpClient.doQuit(); 1548 } 1549 1550 if (mPacketTracker != null) { 1551 mPacketTracker.stop(); 1552 mPacketTracker = null; 1553 } 1554 1555 if (mApfFilter != null) { 1556 mApfFilter.shutdown(); 1557 mApfFilter = null; 1558 } 1559 1560 resetLinkProperties(); 1561 } 1562 createPacketTracker()1563 private ConnectivityPacketTracker createPacketTracker() { 1564 try { 1565 return new ConnectivityPacketTracker(mNetworkInterface, mConnectivityPacketLog); 1566 } catch (IllegalArgumentException e) { 1567 return null; 1568 } 1569 } 1570 ensureDhcpAction()1571 private void ensureDhcpAction() { 1572 if (!mDhcpActionInFlight) { 1573 mCallback.onPreDhcpAction(); 1574 mDhcpActionInFlight = true; 1575 final long alarmTime = SystemClock.elapsedRealtime() + 1576 mConfiguration.mRequestedPreDhcpActionMs; 1577 mDhcpActionTimeoutAlarm.schedule(alarmTime); 1578 } 1579 } 1580 stopDhcpAction()1581 private void stopDhcpAction() { 1582 mDhcpActionTimeoutAlarm.cancel(); 1583 if (mDhcpActionInFlight) { 1584 mCallback.onPostDhcpAction(); 1585 mDhcpActionInFlight = false; 1586 } 1587 } 1588 1589 @Override processMessage(Message msg)1590 public boolean processMessage(Message msg) { 1591 switch (msg.what) { 1592 case CMD_STOP: 1593 transitionTo(mStoppingState); 1594 break; 1595 1596 case CMD_START: 1597 logError("ALERT: START received in StartedState. Please fix caller."); 1598 break; 1599 1600 case CMD_CONFIRM: 1601 // TODO: Possibly introduce a second type of confirmation 1602 // that both probes (a) on-link neighbors and (b) does 1603 // a DHCPv4 RENEW. We used to do this on Wi-Fi framework 1604 // roams. 1605 if (mIpReachabilityMonitor != null) { 1606 mIpReachabilityMonitor.probeAll(); 1607 } 1608 break; 1609 1610 case EVENT_PRE_DHCP_ACTION_COMPLETE: 1611 // It's possible to reach here if, for example, someone 1612 // calls completedPreDhcpAction() after provisioning with 1613 // a static IP configuration. 1614 if (mDhcpClient != null) { 1615 mDhcpClient.sendMessage(DhcpClient.CMD_PRE_DHCP_ACTION_COMPLETE); 1616 } 1617 break; 1618 1619 case EVENT_NETLINK_LINKPROPERTIES_CHANGED: 1620 if (!handleLinkPropertiesUpdate(SEND_CALLBACKS)) { 1621 transitionTo(mStoppingState); 1622 } 1623 break; 1624 1625 case CMD_UPDATE_TCP_BUFFER_SIZES: 1626 mTcpBufferSizes = (String) msg.obj; 1627 // This cannot possibly change provisioning state. 1628 handleLinkPropertiesUpdate(SEND_CALLBACKS); 1629 break; 1630 1631 case CMD_UPDATE_HTTP_PROXY: 1632 mHttpProxy = (ProxyInfo) msg.obj; 1633 // This cannot possibly change provisioning state. 1634 handleLinkPropertiesUpdate(SEND_CALLBACKS); 1635 break; 1636 1637 case CMD_SET_MULTICAST_FILTER: { 1638 mMulticastFiltering = (boolean) msg.obj; 1639 if (mApfFilter != null) { 1640 mApfFilter.setMulticastFilter(mMulticastFiltering); 1641 } else { 1642 mCallback.setFallbackMulticastFilter(mMulticastFiltering); 1643 } 1644 break; 1645 } 1646 1647 case EVENT_DHCPACTION_TIMEOUT: 1648 stopDhcpAction(); 1649 break; 1650 1651 case DhcpClient.CMD_PRE_DHCP_ACTION: 1652 if (mConfiguration.mRequestedPreDhcpActionMs > 0) { 1653 ensureDhcpAction(); 1654 } else { 1655 sendMessage(EVENT_PRE_DHCP_ACTION_COMPLETE); 1656 } 1657 break; 1658 1659 case DhcpClient.CMD_CLEAR_LINKADDRESS: 1660 clearIPv4Address(); 1661 break; 1662 1663 case DhcpClient.CMD_CONFIGURE_LINKADDRESS: { 1664 final LinkAddress ipAddress = (LinkAddress) msg.obj; 1665 if (setIPv4Address(ipAddress)) { 1666 mDhcpClient.sendMessage(DhcpClient.EVENT_LINKADDRESS_CONFIGURED); 1667 } else { 1668 logError("Failed to set IPv4 address."); 1669 dispatchCallback(ProvisioningChange.LOST_PROVISIONING, 1670 new LinkProperties(mLinkProperties)); 1671 transitionTo(mStoppingState); 1672 } 1673 break; 1674 } 1675 1676 // This message is only received when: 1677 // 1678 // a) initial address acquisition succeeds, 1679 // b) renew succeeds or is NAK'd, 1680 // c) rebind succeeds or is NAK'd, or 1681 // c) the lease expires, 1682 // 1683 // but never when initial address acquisition fails. The latter 1684 // condition is now governed by the provisioning timeout. 1685 case DhcpClient.CMD_POST_DHCP_ACTION: 1686 stopDhcpAction(); 1687 1688 switch (msg.arg1) { 1689 case DhcpClient.DHCP_SUCCESS: 1690 handleIPv4Success((DhcpResults) msg.obj); 1691 break; 1692 case DhcpClient.DHCP_FAILURE: 1693 handleIPv4Failure(); 1694 break; 1695 default: 1696 logError("Unknown CMD_POST_DHCP_ACTION status: %s", msg.arg1); 1697 } 1698 break; 1699 1700 case DhcpClient.CMD_ON_QUIT: 1701 // DHCPv4 quit early for some reason. 1702 logError("Unexpected CMD_ON_QUIT."); 1703 mDhcpClient = null; 1704 break; 1705 1706 default: 1707 return NOT_HANDLED; 1708 } 1709 1710 mMsgStateLogger.handled(this, getCurrentState()); 1711 return HANDLED; 1712 } 1713 } 1714 1715 private static class MessageHandlingLogger { 1716 public String processedInState; 1717 public String receivedInState; 1718 reset()1719 public void reset() { 1720 processedInState = null; 1721 receivedInState = null; 1722 } 1723 handled(State processedIn, IState receivedIn)1724 public void handled(State processedIn, IState receivedIn) { 1725 processedInState = processedIn.getClass().getSimpleName(); 1726 receivedInState = receivedIn.getName(); 1727 } 1728 toString()1729 public String toString() { 1730 return String.format("rcvd_in=%s, proc_in=%s", 1731 receivedInState, processedInState); 1732 } 1733 } 1734 1735 // TODO: extract out into CollectionUtils. any(Iterable<T> coll, Predicate<T> fn)1736 static <T> boolean any(Iterable<T> coll, Predicate<T> fn) { 1737 for (T t : coll) { 1738 if (fn.test(t)) { 1739 return true; 1740 } 1741 } 1742 return false; 1743 } 1744 all(Iterable<T> coll, Predicate<T> fn)1745 static <T> boolean all(Iterable<T> coll, Predicate<T> fn) { 1746 return !any(coll, not(fn)); 1747 } 1748 not(Predicate<T> fn)1749 static <T> Predicate<T> not(Predicate<T> fn) { 1750 return (t) -> !fn.test(t); 1751 } 1752 join(String delimiter, Collection<T> coll)1753 static <T> String join(String delimiter, Collection<T> coll) { 1754 return coll.stream().map(Object::toString).collect(Collectors.joining(delimiter)); 1755 } 1756 find(Iterable<T> coll, Predicate<T> fn)1757 static <T> T find(Iterable<T> coll, Predicate<T> fn) { 1758 for (T t: coll) { 1759 if (fn.test(t)) { 1760 return t; 1761 } 1762 } 1763 return null; 1764 } 1765 findAll(Collection<T> coll, Predicate<T> fn)1766 static <T> List<T> findAll(Collection<T> coll, Predicate<T> fn) { 1767 return coll.stream().filter(fn).collect(Collectors.toList()); 1768 } 1769 } 1770