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 static android.net.NetworkUtils.numericToInetAddress; 20 import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS; 21 import static android.net.util.NetworkConstants.FF; 22 import static android.net.util.NetworkConstants.RFC7421_PREFIX_LENGTH; 23 import static android.net.util.NetworkConstants.asByte; 24 25 import android.net.ConnectivityManager; 26 import android.net.INetd; 27 import android.net.INetworkStackStatusCallback; 28 import android.net.INetworkStatsService; 29 import android.net.InterfaceConfiguration; 30 import android.net.IpPrefix; 31 import android.net.LinkAddress; 32 import android.net.LinkProperties; 33 import android.net.NetworkStackClient; 34 import android.net.RouteInfo; 35 import android.net.dhcp.DhcpServerCallbacks; 36 import android.net.dhcp.DhcpServingParamsParcel; 37 import android.net.dhcp.DhcpServingParamsParcelExt; 38 import android.net.dhcp.IDhcpServer; 39 import android.net.ip.RouterAdvertisementDaemon.RaParams; 40 import android.net.util.InterfaceParams; 41 import android.net.util.InterfaceSet; 42 import android.net.util.NetdService; 43 import android.net.util.SharedLog; 44 import android.os.INetworkManagementService; 45 import android.os.Looper; 46 import android.os.Message; 47 import android.os.RemoteException; 48 import android.os.ServiceSpecificException; 49 import android.util.Log; 50 import android.util.Slog; 51 import android.util.SparseArray; 52 53 import com.android.internal.util.MessageUtils; 54 import com.android.internal.util.Protocol; 55 import com.android.internal.util.State; 56 import com.android.internal.util.StateMachine; 57 58 import java.net.Inet4Address; 59 import java.net.Inet6Address; 60 import java.net.InetAddress; 61 import java.net.UnknownHostException; 62 import java.util.ArrayList; 63 import java.util.HashSet; 64 import java.util.Objects; 65 import java.util.Random; 66 import java.util.Set; 67 68 /** 69 * Provides the interface to IP-layer serving functionality for a given network 70 * interface, e.g. for tethering or "local-only hotspot" mode. 71 * 72 * @hide 73 */ 74 public class IpServer extends StateMachine { 75 public static final int STATE_UNAVAILABLE = 0; 76 public static final int STATE_AVAILABLE = 1; 77 public static final int STATE_TETHERED = 2; 78 public static final int STATE_LOCAL_ONLY = 3; 79 getStateString(int state)80 public static String getStateString(int state) { 81 switch (state) { 82 case STATE_UNAVAILABLE: return "UNAVAILABLE"; 83 case STATE_AVAILABLE: return "AVAILABLE"; 84 case STATE_TETHERED: return "TETHERED"; 85 case STATE_LOCAL_ONLY: return "LOCAL_ONLY"; 86 } 87 return "UNKNOWN: " + state; 88 } 89 90 private static final byte DOUG_ADAMS = (byte) 42; 91 92 private static final String USB_NEAR_IFACE_ADDR = "192.168.42.129"; 93 private static final int USB_PREFIX_LENGTH = 24; 94 private static final String WIFI_HOST_IFACE_ADDR = "192.168.43.1"; 95 private static final int WIFI_HOST_IFACE_PREFIX_LENGTH = 24; 96 97 // TODO: have PanService use some visible version of this constant 98 private static final String BLUETOOTH_IFACE_ADDR = "192.168.44.1"; 99 private static final int BLUETOOTH_DHCP_PREFIX_LENGTH = 24; 100 101 // TODO: have this configurable 102 private static final int DHCP_LEASE_TIME_SECS = 3600; 103 104 private final static String TAG = "IpServer"; 105 private final static boolean DBG = false; 106 private final static boolean VDBG = false; 107 private static final Class[] messageClasses = { 108 IpServer.class 109 }; 110 private static final SparseArray<String> sMagicDecoderRing = 111 MessageUtils.findMessageNames(messageClasses); 112 113 public static class Callback { 114 /** 115 * Notify that |who| has changed its tethering state. 116 * 117 * @param who the calling instance of IpServer 118 * @param state one of STATE_* 119 * @param lastError one of ConnectivityManager.TETHER_ERROR_* 120 */ updateInterfaceState(IpServer who, int state, int lastError)121 public void updateInterfaceState(IpServer who, int state, int lastError) {} 122 123 /** 124 * Notify that |who| has new LinkProperties. 125 * 126 * @param who the calling instance of IpServer 127 * @param newLp the new LinkProperties to report 128 */ updateLinkProperties(IpServer who, LinkProperties newLp)129 public void updateLinkProperties(IpServer who, LinkProperties newLp) {} 130 } 131 132 public static class Dependencies { getRouterAdvertisementDaemon(InterfaceParams ifParams)133 public RouterAdvertisementDaemon getRouterAdvertisementDaemon(InterfaceParams ifParams) { 134 return new RouterAdvertisementDaemon(ifParams); 135 } 136 getInterfaceParams(String ifName)137 public InterfaceParams getInterfaceParams(String ifName) { 138 return InterfaceParams.getByName(ifName); 139 } 140 getNetdService()141 public INetd getNetdService() { 142 return NetdService.getInstance(); 143 } 144 145 /** 146 * Create a DhcpServer instance to be used by IpServer. 147 */ makeDhcpServer(String ifName, DhcpServingParamsParcel params, DhcpServerCallbacks cb)148 public void makeDhcpServer(String ifName, DhcpServingParamsParcel params, 149 DhcpServerCallbacks cb) { 150 NetworkStackClient.getInstance().makeDhcpServer(ifName, params, cb); 151 } 152 } 153 154 private static final int BASE_IFACE = Protocol.BASE_TETHERING + 100; 155 // request from the user that it wants to tether 156 public static final int CMD_TETHER_REQUESTED = BASE_IFACE + 2; 157 // request from the user that it wants to untether 158 public static final int CMD_TETHER_UNREQUESTED = BASE_IFACE + 3; 159 // notification that this interface is down 160 public static final int CMD_INTERFACE_DOWN = BASE_IFACE + 4; 161 // notification from the master SM that it had trouble enabling IP Forwarding 162 public static final int CMD_IP_FORWARDING_ENABLE_ERROR = BASE_IFACE + 7; 163 // notification from the master SM that it had trouble disabling IP Forwarding 164 public static final int CMD_IP_FORWARDING_DISABLE_ERROR = BASE_IFACE + 8; 165 // notification from the master SM that it had trouble starting tethering 166 public static final int CMD_START_TETHERING_ERROR = BASE_IFACE + 9; 167 // notification from the master SM that it had trouble stopping tethering 168 public static final int CMD_STOP_TETHERING_ERROR = BASE_IFACE + 10; 169 // notification from the master SM that it had trouble setting the DNS forwarders 170 public static final int CMD_SET_DNS_FORWARDERS_ERROR = BASE_IFACE + 11; 171 // the upstream connection has changed 172 public static final int CMD_TETHER_CONNECTION_CHANGED = BASE_IFACE + 12; 173 // new IPv6 tethering parameters need to be processed 174 public static final int CMD_IPV6_TETHER_UPDATE = BASE_IFACE + 13; 175 176 private final State mInitialState; 177 private final State mLocalHotspotState; 178 private final State mTetheredState; 179 private final State mUnavailableState; 180 181 private final SharedLog mLog; 182 private final INetworkManagementService mNMService; 183 private final INetd mNetd; 184 private final INetworkStatsService mStatsService; 185 private final Callback mCallback; 186 private final InterfaceController mInterfaceCtrl; 187 188 private final String mIfaceName; 189 private final int mInterfaceType; 190 private final LinkProperties mLinkProperties; 191 private final boolean mUsingLegacyDhcp; 192 193 private final Dependencies mDeps; 194 195 private int mLastError; 196 private int mServingMode; 197 private InterfaceSet mUpstreamIfaceSet; // may change over time 198 private InterfaceParams mInterfaceParams; 199 // TODO: De-duplicate this with mLinkProperties above. Currently, these link 200 // properties are those selected by the IPv6TetheringCoordinator and relayed 201 // to us. By comparison, mLinkProperties contains the addresses and directly 202 // connected routes that have been formed from these properties iff. we have 203 // succeeded in configuring them and are able to announce them within Router 204 // Advertisements (otherwise, we do not add them to mLinkProperties at all). 205 private LinkProperties mLastIPv6LinkProperties; 206 private RouterAdvertisementDaemon mRaDaemon; 207 208 // To be accessed only on the handler thread 209 private int mDhcpServerStartIndex = 0; 210 private IDhcpServer mDhcpServer; 211 private RaParams mLastRaParams; 212 IpServer( String ifaceName, Looper looper, int interfaceType, SharedLog log, INetworkManagementService nMService, INetworkStatsService statsService, Callback callback, boolean usingLegacyDhcp, Dependencies deps)213 public IpServer( 214 String ifaceName, Looper looper, int interfaceType, SharedLog log, 215 INetworkManagementService nMService, INetworkStatsService statsService, 216 Callback callback, boolean usingLegacyDhcp, Dependencies deps) { 217 super(ifaceName, looper); 218 mLog = log.forSubComponent(ifaceName); 219 mNMService = nMService; 220 mNetd = deps.getNetdService(); 221 mStatsService = statsService; 222 mCallback = callback; 223 mInterfaceCtrl = new InterfaceController(ifaceName, mNetd, mLog); 224 mIfaceName = ifaceName; 225 mInterfaceType = interfaceType; 226 mLinkProperties = new LinkProperties(); 227 mUsingLegacyDhcp = usingLegacyDhcp; 228 mDeps = deps; 229 resetLinkProperties(); 230 mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR; 231 mServingMode = STATE_AVAILABLE; 232 233 mInitialState = new InitialState(); 234 mLocalHotspotState = new LocalHotspotState(); 235 mTetheredState = new TetheredState(); 236 mUnavailableState = new UnavailableState(); 237 addState(mInitialState); 238 addState(mLocalHotspotState); 239 addState(mTetheredState); 240 addState(mUnavailableState); 241 242 setInitialState(mInitialState); 243 } 244 interfaceName()245 public String interfaceName() { return mIfaceName; } 246 interfaceType()247 public int interfaceType() { return mInterfaceType; } 248 lastError()249 public int lastError() { return mLastError; } 250 servingMode()251 public int servingMode() { return mServingMode; } 252 linkProperties()253 public LinkProperties linkProperties() { return new LinkProperties(mLinkProperties); } 254 stop()255 public void stop() { sendMessage(CMD_INTERFACE_DOWN); } 256 unwanted()257 public void unwanted() { sendMessage(CMD_TETHER_UNREQUESTED); } 258 259 /** 260 * Internals. 261 */ 262 startIPv4()263 private boolean startIPv4() { return configureIPv4(true); } 264 265 /** 266 * Convenience wrapper around INetworkStackStatusCallback to run callbacks on the IpServer 267 * handler. 268 * 269 * <p>Different instances of this class can be created for each call to IDhcpServer methods, 270 * with different implementations of the callback, to differentiate handling of success/error in 271 * each call. 272 */ 273 private abstract class OnHandlerStatusCallback extends INetworkStackStatusCallback.Stub { 274 @Override onStatusAvailable(int statusCode)275 public void onStatusAvailable(int statusCode) { 276 getHandler().post(() -> callback(statusCode)); 277 } 278 callback(int statusCode)279 public abstract void callback(int statusCode); 280 281 @Override getInterfaceVersion()282 public int getInterfaceVersion() { 283 return this.VERSION; 284 } 285 } 286 287 private class DhcpServerCallbacksImpl extends DhcpServerCallbacks { 288 private final int mStartIndex; 289 DhcpServerCallbacksImpl(int startIndex)290 private DhcpServerCallbacksImpl(int startIndex) { 291 mStartIndex = startIndex; 292 } 293 294 @Override onDhcpServerCreated(int statusCode, IDhcpServer server)295 public void onDhcpServerCreated(int statusCode, IDhcpServer server) throws RemoteException { 296 getHandler().post(() -> { 297 // We are on the handler thread: mDhcpServerStartIndex can be read safely. 298 if (mStartIndex != mDhcpServerStartIndex) { 299 // This start request is obsolete. When the |server| binder token goes out of 300 // scope, the garbage collector will finalize it, which causes the network stack 301 // process garbage collector to collect the server itself. 302 return; 303 } 304 305 if (statusCode != STATUS_SUCCESS) { 306 mLog.e("Error obtaining DHCP server: " + statusCode); 307 handleError(); 308 return; 309 } 310 311 mDhcpServer = server; 312 try { 313 mDhcpServer.start(new OnHandlerStatusCallback() { 314 @Override 315 public void callback(int startStatusCode) { 316 if (startStatusCode != STATUS_SUCCESS) { 317 mLog.e("Error starting DHCP server: " + startStatusCode); 318 handleError(); 319 } 320 } 321 }); 322 } catch (RemoteException e) { 323 e.rethrowFromSystemServer(); 324 } 325 }); 326 } 327 handleError()328 private void handleError() { 329 mLastError = ConnectivityManager.TETHER_ERROR_DHCPSERVER_ERROR; 330 transitionTo(mInitialState); 331 } 332 } 333 startDhcp(Inet4Address addr, int prefixLen)334 private boolean startDhcp(Inet4Address addr, int prefixLen) { 335 if (mUsingLegacyDhcp) { 336 return true; 337 } 338 final DhcpServingParamsParcel params; 339 params = new DhcpServingParamsParcelExt() 340 .setDefaultRouters(addr) 341 .setDhcpLeaseTimeSecs(DHCP_LEASE_TIME_SECS) 342 .setDnsServers(addr) 343 .setServerAddr(new LinkAddress(addr, prefixLen)) 344 .setMetered(true); 345 // TODO: also advertise link MTU 346 347 mDhcpServerStartIndex++; 348 mDeps.makeDhcpServer( 349 mIfaceName, params, new DhcpServerCallbacksImpl(mDhcpServerStartIndex)); 350 return true; 351 } 352 stopDhcp()353 private void stopDhcp() { 354 // Make all previous start requests obsolete so servers are not started later 355 mDhcpServerStartIndex++; 356 357 if (mDhcpServer != null) { 358 try { 359 mDhcpServer.stop(new OnHandlerStatusCallback() { 360 @Override 361 public void callback(int statusCode) { 362 if (statusCode != STATUS_SUCCESS) { 363 mLog.e("Error stopping DHCP server: " + statusCode); 364 mLastError = ConnectivityManager.TETHER_ERROR_DHCPSERVER_ERROR; 365 // Not much more we can do here 366 } 367 } 368 }); 369 mDhcpServer = null; 370 } catch (RemoteException e) { 371 e.rethrowFromSystemServer(); 372 } 373 } 374 } 375 configureDhcp(boolean enable, Inet4Address addr, int prefixLen)376 private boolean configureDhcp(boolean enable, Inet4Address addr, int prefixLen) { 377 if (enable) { 378 return startDhcp(addr, prefixLen); 379 } else { 380 stopDhcp(); 381 return true; 382 } 383 } 384 stopIPv4()385 private void stopIPv4() { 386 configureIPv4(false); 387 // NOTE: All of configureIPv4() will be refactored out of existence 388 // into calls to InterfaceController, shared with startIPv4(). 389 mInterfaceCtrl.clearIPv4Address(); 390 } 391 392 // TODO: Refactor this in terms of calls to InterfaceController. configureIPv4(boolean enabled)393 private boolean configureIPv4(boolean enabled) { 394 if (VDBG) Log.d(TAG, "configureIPv4(" + enabled + ")"); 395 396 // TODO: Replace this hard-coded information with dynamically selected 397 // config passed down to us by a higher layer IP-coordinating element. 398 String ipAsString = null; 399 int prefixLen = 0; 400 if (mInterfaceType == ConnectivityManager.TETHERING_USB) { 401 ipAsString = USB_NEAR_IFACE_ADDR; 402 prefixLen = USB_PREFIX_LENGTH; 403 } else if (mInterfaceType == ConnectivityManager.TETHERING_WIFI) { 404 ipAsString = getRandomWifiIPv4Address(); 405 prefixLen = WIFI_HOST_IFACE_PREFIX_LENGTH; 406 } else { 407 // BT configures the interface elsewhere: only start DHCP. 408 final Inet4Address srvAddr = (Inet4Address) numericToInetAddress(BLUETOOTH_IFACE_ADDR); 409 return configureDhcp(enabled, srvAddr, BLUETOOTH_DHCP_PREFIX_LENGTH); 410 } 411 412 final LinkAddress linkAddr; 413 try { 414 final InterfaceConfiguration ifcg = mNMService.getInterfaceConfig(mIfaceName); 415 if (ifcg == null) { 416 mLog.e("Received null interface config"); 417 return false; 418 } 419 420 InetAddress addr = numericToInetAddress(ipAsString); 421 linkAddr = new LinkAddress(addr, prefixLen); 422 ifcg.setLinkAddress(linkAddr); 423 if (mInterfaceType == ConnectivityManager.TETHERING_WIFI) { 424 // The WiFi stack has ownership of the interface up/down state. 425 // It is unclear whether the Bluetooth or USB stacks will manage their own 426 // state. 427 ifcg.ignoreInterfaceUpDownStatus(); 428 } else { 429 if (enabled) { 430 ifcg.setInterfaceUp(); 431 } else { 432 ifcg.setInterfaceDown(); 433 } 434 } 435 ifcg.clearFlag("running"); 436 437 // TODO: this may throw if the interface is already gone. Do proper handling and 438 // simplify the DHCP server start/stop. 439 mNMService.setInterfaceConfig(mIfaceName, ifcg); 440 441 if (!configureDhcp(enabled, (Inet4Address) addr, prefixLen)) { 442 return false; 443 } 444 } catch (Exception e) { 445 mLog.e("Error configuring interface " + e); 446 if (!enabled) { 447 try { 448 // Calling stopDhcp several times is fine 449 stopDhcp(); 450 } catch (Exception dhcpError) { 451 mLog.e("Error stopping DHCP", dhcpError); 452 } 453 } 454 return false; 455 } 456 457 // Directly-connected route. 458 final RouteInfo route = new RouteInfo(linkAddr); 459 if (enabled) { 460 mLinkProperties.addLinkAddress(linkAddr); 461 mLinkProperties.addRoute(route); 462 } else { 463 mLinkProperties.removeLinkAddress(linkAddr); 464 mLinkProperties.removeRoute(route); 465 } 466 return true; 467 } 468 getRandomWifiIPv4Address()469 private String getRandomWifiIPv4Address() { 470 try { 471 byte[] bytes = numericToInetAddress(WIFI_HOST_IFACE_ADDR).getAddress(); 472 bytes[3] = getRandomSanitizedByte(DOUG_ADAMS, asByte(0), asByte(1), FF); 473 return InetAddress.getByAddress(bytes).getHostAddress(); 474 } catch (Exception e) { 475 return WIFI_HOST_IFACE_ADDR; 476 } 477 } 478 startIPv6()479 private boolean startIPv6() { 480 mInterfaceParams = mDeps.getInterfaceParams(mIfaceName); 481 if (mInterfaceParams == null) { 482 mLog.e("Failed to find InterfaceParams"); 483 stopIPv6(); 484 return false; 485 } 486 487 mRaDaemon = mDeps.getRouterAdvertisementDaemon(mInterfaceParams); 488 if (!mRaDaemon.start()) { 489 stopIPv6(); 490 return false; 491 } 492 493 return true; 494 } 495 stopIPv6()496 private void stopIPv6() { 497 mInterfaceParams = null; 498 setRaParams(null); 499 500 if (mRaDaemon != null) { 501 mRaDaemon.stop(); 502 mRaDaemon = null; 503 } 504 } 505 506 // IPv6TetheringCoordinator sends updates with carefully curated IPv6-only 507 // LinkProperties. These have extraneous data filtered out and only the 508 // necessary prefixes included (per its prefix distribution policy). 509 // 510 // TODO: Evaluate using a data structure than is more directly suited to 511 // communicating only the relevant information. updateUpstreamIPv6LinkProperties(LinkProperties v6only)512 private void updateUpstreamIPv6LinkProperties(LinkProperties v6only) { 513 if (mRaDaemon == null) return; 514 515 // Avoid unnecessary work on spurious updates. 516 if (Objects.equals(mLastIPv6LinkProperties, v6only)) { 517 return; 518 } 519 520 RaParams params = null; 521 522 if (v6only != null) { 523 params = new RaParams(); 524 params.mtu = v6only.getMtu(); 525 params.hasDefaultRoute = v6only.hasIpv6DefaultRoute(); 526 527 if (params.hasDefaultRoute) params.hopLimit = getHopLimit(v6only.getInterfaceName()); 528 529 for (LinkAddress linkAddr : v6only.getLinkAddresses()) { 530 if (linkAddr.getPrefixLength() != RFC7421_PREFIX_LENGTH) continue; 531 532 final IpPrefix prefix = new IpPrefix( 533 linkAddr.getAddress(), linkAddr.getPrefixLength()); 534 params.prefixes.add(prefix); 535 536 final Inet6Address dnsServer = getLocalDnsIpFor(prefix); 537 if (dnsServer != null) { 538 params.dnses.add(dnsServer); 539 } 540 } 541 } 542 // If v6only is null, we pass in null to setRaParams(), which handles 543 // deprecation of any existing RA data. 544 545 setRaParams(params); 546 mLastIPv6LinkProperties = v6only; 547 } 548 configureLocalIPv6Routes( HashSet<IpPrefix> deprecatedPrefixes, HashSet<IpPrefix> newPrefixes)549 private void configureLocalIPv6Routes( 550 HashSet<IpPrefix> deprecatedPrefixes, HashSet<IpPrefix> newPrefixes) { 551 // [1] Remove the routes that are deprecated. 552 if (!deprecatedPrefixes.isEmpty()) { 553 final ArrayList<RouteInfo> toBeRemoved = 554 getLocalRoutesFor(mIfaceName, deprecatedPrefixes); 555 try { 556 final int removalFailures = mNMService.removeRoutesFromLocalNetwork(toBeRemoved); 557 if (removalFailures > 0) { 558 mLog.e(String.format("Failed to remove %d IPv6 routes from local table.", 559 removalFailures)); 560 } 561 } catch (RemoteException e) { 562 mLog.e("Failed to remove IPv6 routes from local table: " + e); 563 } 564 565 for (RouteInfo route : toBeRemoved) mLinkProperties.removeRoute(route); 566 } 567 568 // [2] Add only the routes that have not previously been added. 569 if (newPrefixes != null && !newPrefixes.isEmpty()) { 570 HashSet<IpPrefix> addedPrefixes = (HashSet) newPrefixes.clone(); 571 if (mLastRaParams != null) { 572 addedPrefixes.removeAll(mLastRaParams.prefixes); 573 } 574 575 if (!addedPrefixes.isEmpty()) { 576 final ArrayList<RouteInfo> toBeAdded = 577 getLocalRoutesFor(mIfaceName, addedPrefixes); 578 try { 579 // It's safe to call addInterfaceToLocalNetwork() even if 580 // the interface is already in the local_network. Note also 581 // that adding routes that already exist does not cause an 582 // error (EEXIST is silently ignored). 583 mNMService.addInterfaceToLocalNetwork(mIfaceName, toBeAdded); 584 } catch (Exception e) { 585 mLog.e("Failed to add IPv6 routes to local table: " + e); 586 } 587 588 for (RouteInfo route : toBeAdded) mLinkProperties.addRoute(route); 589 } 590 } 591 } 592 configureLocalIPv6Dns( HashSet<Inet6Address> deprecatedDnses, HashSet<Inet6Address> newDnses)593 private void configureLocalIPv6Dns( 594 HashSet<Inet6Address> deprecatedDnses, HashSet<Inet6Address> newDnses) { 595 // TODO: Is this really necessary? Can we not fail earlier if INetd cannot be located? 596 if (mNetd == null) { 597 if (newDnses != null) newDnses.clear(); 598 mLog.e("No netd service instance available; not setting local IPv6 addresses"); 599 return; 600 } 601 602 // [1] Remove deprecated local DNS IP addresses. 603 if (!deprecatedDnses.isEmpty()) { 604 for (Inet6Address dns : deprecatedDnses) { 605 if (!mInterfaceCtrl.removeAddress(dns, RFC7421_PREFIX_LENGTH)) { 606 mLog.e("Failed to remove local dns IP " + dns); 607 } 608 609 mLinkProperties.removeLinkAddress(new LinkAddress(dns, RFC7421_PREFIX_LENGTH)); 610 } 611 } 612 613 // [2] Add only the local DNS IP addresses that have not previously been added. 614 if (newDnses != null && !newDnses.isEmpty()) { 615 final HashSet<Inet6Address> addedDnses = (HashSet) newDnses.clone(); 616 if (mLastRaParams != null) { 617 addedDnses.removeAll(mLastRaParams.dnses); 618 } 619 620 for (Inet6Address dns : addedDnses) { 621 if (!mInterfaceCtrl.addAddress(dns, RFC7421_PREFIX_LENGTH)) { 622 mLog.e("Failed to add local dns IP " + dns); 623 newDnses.remove(dns); 624 } 625 626 mLinkProperties.addLinkAddress(new LinkAddress(dns, RFC7421_PREFIX_LENGTH)); 627 } 628 } 629 630 try { 631 mNetd.tetherApplyDnsInterfaces(); 632 } catch (ServiceSpecificException | RemoteException e) { 633 mLog.e("Failed to update local DNS caching server"); 634 if (newDnses != null) newDnses.clear(); 635 } 636 } 637 getHopLimit(String upstreamIface)638 private byte getHopLimit(String upstreamIface) { 639 try { 640 int upstreamHopLimit = Integer.parseUnsignedInt( 641 mNetd.getProcSysNet(INetd.IPV6, INetd.CONF, upstreamIface, "hop_limit")); 642 // Add one hop to account for this forwarding device 643 upstreamHopLimit++; 644 // Cap the hop limit to 255. 645 return (byte) Integer.min(upstreamHopLimit, 255); 646 } catch (Exception e) { 647 mLog.e("Failed to find upstream interface hop limit", e); 648 } 649 return RaParams.DEFAULT_HOPLIMIT; 650 } 651 setRaParams(RaParams newParams)652 private void setRaParams(RaParams newParams) { 653 if (mRaDaemon != null) { 654 final RaParams deprecatedParams = 655 RaParams.getDeprecatedRaParams(mLastRaParams, newParams); 656 657 configureLocalIPv6Routes(deprecatedParams.prefixes, 658 (newParams != null) ? newParams.prefixes : null); 659 660 configureLocalIPv6Dns(deprecatedParams.dnses, 661 (newParams != null) ? newParams.dnses : null); 662 663 mRaDaemon.buildNewRa(deprecatedParams, newParams); 664 } 665 666 mLastRaParams = newParams; 667 } 668 logMessage(State state, int what)669 private void logMessage(State state, int what) { 670 mLog.log(state.getName() + " got " + sMagicDecoderRing.get(what, Integer.toString(what))); 671 } 672 sendInterfaceState(int newInterfaceState)673 private void sendInterfaceState(int newInterfaceState) { 674 mServingMode = newInterfaceState; 675 mCallback.updateInterfaceState(this, newInterfaceState, mLastError); 676 sendLinkProperties(); 677 } 678 sendLinkProperties()679 private void sendLinkProperties() { 680 mCallback.updateLinkProperties(this, new LinkProperties(mLinkProperties)); 681 } 682 resetLinkProperties()683 private void resetLinkProperties() { 684 mLinkProperties.clear(); 685 mLinkProperties.setInterfaceName(mIfaceName); 686 } 687 688 class InitialState extends State { 689 @Override enter()690 public void enter() { 691 sendInterfaceState(STATE_AVAILABLE); 692 } 693 694 @Override processMessage(Message message)695 public boolean processMessage(Message message) { 696 logMessage(this, message.what); 697 switch (message.what) { 698 case CMD_TETHER_REQUESTED: 699 mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR; 700 switch (message.arg1) { 701 case STATE_LOCAL_ONLY: 702 transitionTo(mLocalHotspotState); 703 break; 704 case STATE_TETHERED: 705 transitionTo(mTetheredState); 706 break; 707 default: 708 mLog.e("Invalid tethering interface serving state specified."); 709 } 710 break; 711 case CMD_INTERFACE_DOWN: 712 transitionTo(mUnavailableState); 713 break; 714 case CMD_IPV6_TETHER_UPDATE: 715 updateUpstreamIPv6LinkProperties((LinkProperties) message.obj); 716 break; 717 default: 718 return NOT_HANDLED; 719 } 720 return HANDLED; 721 } 722 } 723 724 class BaseServingState extends State { 725 @Override enter()726 public void enter() { 727 if (!startIPv4()) { 728 mLastError = ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR; 729 return; 730 } 731 732 try { 733 mNMService.tetherInterface(mIfaceName); 734 } catch (Exception e) { 735 mLog.e("Error Tethering: " + e); 736 mLastError = ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR; 737 return; 738 } 739 740 if (!startIPv6()) { 741 mLog.e("Failed to startIPv6"); 742 // TODO: Make this a fatal error once Bluetooth IPv6 is sorted. 743 return; 744 } 745 } 746 747 @Override exit()748 public void exit() { 749 // Note that at this point, we're leaving the tethered state. We can fail any 750 // of these operations, but it doesn't really change that we have to try them 751 // all in sequence. 752 stopIPv6(); 753 754 try { 755 mNMService.untetherInterface(mIfaceName); 756 } catch (Exception e) { 757 mLastError = ConnectivityManager.TETHER_ERROR_UNTETHER_IFACE_ERROR; 758 mLog.e("Failed to untether interface: " + e); 759 } 760 761 stopIPv4(); 762 763 resetLinkProperties(); 764 } 765 766 @Override processMessage(Message message)767 public boolean processMessage(Message message) { 768 logMessage(this, message.what); 769 switch (message.what) { 770 case CMD_TETHER_UNREQUESTED: 771 transitionTo(mInitialState); 772 if (DBG) Log.d(TAG, "Untethered (unrequested)" + mIfaceName); 773 break; 774 case CMD_INTERFACE_DOWN: 775 transitionTo(mUnavailableState); 776 if (DBG) Log.d(TAG, "Untethered (ifdown)" + mIfaceName); 777 break; 778 case CMD_IPV6_TETHER_UPDATE: 779 updateUpstreamIPv6LinkProperties((LinkProperties) message.obj); 780 sendLinkProperties(); 781 break; 782 case CMD_IP_FORWARDING_ENABLE_ERROR: 783 case CMD_IP_FORWARDING_DISABLE_ERROR: 784 case CMD_START_TETHERING_ERROR: 785 case CMD_STOP_TETHERING_ERROR: 786 case CMD_SET_DNS_FORWARDERS_ERROR: 787 mLastError = ConnectivityManager.TETHER_ERROR_MASTER_ERROR; 788 transitionTo(mInitialState); 789 break; 790 default: 791 return false; 792 } 793 return true; 794 } 795 } 796 797 // Handling errors in BaseServingState.enter() by transitioning is 798 // problematic because transitioning during a multi-state jump yields 799 // a Log.wtf(). Ultimately, there should be only one ServingState, 800 // and forwarding and NAT rules should be handled by a coordinating 801 // functional element outside of IpServer. 802 class LocalHotspotState extends BaseServingState { 803 @Override enter()804 public void enter() { 805 super.enter(); 806 if (mLastError != ConnectivityManager.TETHER_ERROR_NO_ERROR) { 807 transitionTo(mInitialState); 808 } 809 810 if (DBG) Log.d(TAG, "Local hotspot " + mIfaceName); 811 sendInterfaceState(STATE_LOCAL_ONLY); 812 } 813 814 @Override processMessage(Message message)815 public boolean processMessage(Message message) { 816 if (super.processMessage(message)) return true; 817 818 logMessage(this, message.what); 819 switch (message.what) { 820 case CMD_TETHER_REQUESTED: 821 mLog.e("CMD_TETHER_REQUESTED while in local-only hotspot mode."); 822 break; 823 case CMD_TETHER_CONNECTION_CHANGED: 824 // Ignored in local hotspot state. 825 break; 826 default: 827 return false; 828 } 829 return true; 830 } 831 } 832 833 // Handling errors in BaseServingState.enter() by transitioning is 834 // problematic because transitioning during a multi-state jump yields 835 // a Log.wtf(). Ultimately, there should be only one ServingState, 836 // and forwarding and NAT rules should be handled by a coordinating 837 // functional element outside of IpServer. 838 class TetheredState extends BaseServingState { 839 @Override enter()840 public void enter() { 841 super.enter(); 842 if (mLastError != ConnectivityManager.TETHER_ERROR_NO_ERROR) { 843 transitionTo(mInitialState); 844 } 845 846 if (DBG) Log.d(TAG, "Tethered " + mIfaceName); 847 sendInterfaceState(STATE_TETHERED); 848 } 849 850 @Override exit()851 public void exit() { 852 cleanupUpstream(); 853 super.exit(); 854 } 855 cleanupUpstream()856 private void cleanupUpstream() { 857 if (mUpstreamIfaceSet == null) return; 858 859 for (String ifname : mUpstreamIfaceSet.ifnames) cleanupUpstreamInterface(ifname); 860 mUpstreamIfaceSet = null; 861 } 862 cleanupUpstreamInterface(String upstreamIface)863 private void cleanupUpstreamInterface(String upstreamIface) { 864 // Note that we don't care about errors here. 865 // Sometimes interfaces are gone before we get 866 // to remove their rules, which generates errors. 867 // Just do the best we can. 868 try { 869 // About to tear down NAT; gather remaining statistics. 870 mStatsService.forceUpdate(); 871 } catch (Exception e) { 872 if (VDBG) Log.e(TAG, "Exception in forceUpdate: " + e.toString()); 873 } 874 try { 875 mNMService.stopInterfaceForwarding(mIfaceName, upstreamIface); 876 } catch (Exception e) { 877 if (VDBG) Log.e(TAG, "Exception in removeInterfaceForward: " + e.toString()); 878 } 879 try { 880 mNMService.disableNat(mIfaceName, upstreamIface); 881 } catch (Exception e) { 882 if (VDBG) Log.e(TAG, "Exception in disableNat: " + e.toString()); 883 } 884 } 885 886 @Override processMessage(Message message)887 public boolean processMessage(Message message) { 888 if (super.processMessage(message)) return true; 889 890 logMessage(this, message.what); 891 switch (message.what) { 892 case CMD_TETHER_REQUESTED: 893 mLog.e("CMD_TETHER_REQUESTED while already tethering."); 894 break; 895 case CMD_TETHER_CONNECTION_CHANGED: 896 final InterfaceSet newUpstreamIfaceSet = (InterfaceSet) message.obj; 897 if (noChangeInUpstreamIfaceSet(newUpstreamIfaceSet)) { 898 if (VDBG) Log.d(TAG, "Connection changed noop - dropping"); 899 break; 900 } 901 902 if (newUpstreamIfaceSet == null) { 903 cleanupUpstream(); 904 break; 905 } 906 907 for (String removed : upstreamInterfacesRemoved(newUpstreamIfaceSet)) { 908 cleanupUpstreamInterface(removed); 909 } 910 911 final Set<String> added = upstreamInterfacesAdd(newUpstreamIfaceSet); 912 // This makes the call to cleanupUpstream() in the error 913 // path for any interface neatly cleanup all the interfaces. 914 mUpstreamIfaceSet = newUpstreamIfaceSet; 915 916 for (String ifname : added) { 917 try { 918 mNMService.enableNat(mIfaceName, ifname); 919 mNMService.startInterfaceForwarding(mIfaceName, ifname); 920 } catch (Exception e) { 921 mLog.e("Exception enabling NAT: " + e); 922 cleanupUpstream(); 923 mLastError = ConnectivityManager.TETHER_ERROR_ENABLE_NAT_ERROR; 924 transitionTo(mInitialState); 925 return true; 926 } 927 } 928 break; 929 default: 930 return false; 931 } 932 return true; 933 } 934 noChangeInUpstreamIfaceSet(InterfaceSet newIfaces)935 private boolean noChangeInUpstreamIfaceSet(InterfaceSet newIfaces) { 936 if (mUpstreamIfaceSet == null && newIfaces == null) return true; 937 if (mUpstreamIfaceSet != null && newIfaces != null) { 938 return mUpstreamIfaceSet.equals(newIfaces); 939 } 940 return false; 941 } 942 upstreamInterfacesRemoved(InterfaceSet newIfaces)943 private Set<String> upstreamInterfacesRemoved(InterfaceSet newIfaces) { 944 if (mUpstreamIfaceSet == null) return new HashSet<>(); 945 946 final HashSet<String> removed = new HashSet<>(mUpstreamIfaceSet.ifnames); 947 removed.removeAll(newIfaces.ifnames); 948 return removed; 949 } 950 upstreamInterfacesAdd(InterfaceSet newIfaces)951 private Set<String> upstreamInterfacesAdd(InterfaceSet newIfaces) { 952 final HashSet<String> added = new HashSet<>(newIfaces.ifnames); 953 if (mUpstreamIfaceSet != null) added.removeAll(mUpstreamIfaceSet.ifnames); 954 return added; 955 } 956 } 957 958 /** 959 * This state is terminal for the per interface state machine. At this 960 * point, the master state machine should have removed this interface 961 * specific state machine from its list of possible recipients of 962 * tethering requests. The state machine itself will hang around until 963 * the garbage collector finds it. 964 */ 965 class UnavailableState extends State { 966 @Override enter()967 public void enter() { 968 mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR; 969 sendInterfaceState(STATE_UNAVAILABLE); 970 } 971 } 972 973 // Accumulate routes representing "prefixes to be assigned to the local 974 // interface", for subsequent modification of local_network routing. getLocalRoutesFor( String ifname, HashSet<IpPrefix> prefixes)975 private static ArrayList<RouteInfo> getLocalRoutesFor( 976 String ifname, HashSet<IpPrefix> prefixes) { 977 final ArrayList<RouteInfo> localRoutes = new ArrayList<RouteInfo>(); 978 for (IpPrefix ipp : prefixes) { 979 localRoutes.add(new RouteInfo(ipp, null, ifname)); 980 } 981 return localRoutes; 982 } 983 984 // Given a prefix like 2001:db8::/64 return an address like 2001:db8::1. getLocalDnsIpFor(IpPrefix localPrefix)985 private static Inet6Address getLocalDnsIpFor(IpPrefix localPrefix) { 986 final byte[] dnsBytes = localPrefix.getRawAddress(); 987 dnsBytes[dnsBytes.length - 1] = getRandomSanitizedByte(DOUG_ADAMS, asByte(0), asByte(1)); 988 try { 989 return Inet6Address.getByAddress(null, dnsBytes, 0); 990 } catch (UnknownHostException e) { 991 Slog.wtf(TAG, "Failed to construct Inet6Address from: " + localPrefix); 992 return null; 993 } 994 } 995 getRandomSanitizedByte(byte dflt, byte... excluded)996 private static byte getRandomSanitizedByte(byte dflt, byte... excluded) { 997 final byte random = (byte) (new Random()).nextInt(); 998 for (int value : excluded) { 999 if (random == value) return dflt; 1000 } 1001 return random; 1002 } 1003 } 1004