1 /* 2 * Copyright (C) 2018 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 com.android.server.ethernet; 18 19 import static android.net.EthernetManager.ETHERNET_STATE_DISABLED; 20 import static android.net.EthernetManager.ETHERNET_STATE_ENABLED; 21 import static android.net.TestNetworkManager.TEST_TAP_PREFIX; 22 23 import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE; 24 25 import android.annotation.NonNull; 26 import android.annotation.Nullable; 27 import android.content.Context; 28 import android.net.ConnectivityResources; 29 import android.net.EthernetManager; 30 import android.net.IEthernetServiceListener; 31 import android.net.INetd; 32 import android.net.INetworkInterfaceOutcomeReceiver; 33 import android.net.ITetheredInterfaceCallback; 34 import android.net.InterfaceConfigurationParcel; 35 import android.net.IpConfiguration; 36 import android.net.IpConfiguration.IpAssignment; 37 import android.net.IpConfiguration.ProxySettings; 38 import android.net.LinkAddress; 39 import android.net.NetworkCapabilities; 40 import android.net.StaticIpConfiguration; 41 import android.os.ConditionVariable; 42 import android.os.Handler; 43 import android.os.RemoteCallbackList; 44 import android.os.RemoteException; 45 import android.os.ServiceSpecificException; 46 import android.text.TextUtils; 47 import android.util.ArrayMap; 48 import android.util.Log; 49 50 import com.android.internal.annotations.VisibleForTesting; 51 import com.android.internal.util.IndentingPrintWriter; 52 import com.android.net.module.util.BaseNetdUnsolicitedEventListener; 53 import com.android.net.module.util.NetdUtils; 54 import com.android.net.module.util.PermissionUtils; 55 56 import java.io.FileDescriptor; 57 import java.net.InetAddress; 58 import java.util.ArrayList; 59 import java.util.Iterator; 60 import java.util.List; 61 import java.util.Objects; 62 import java.util.concurrent.ConcurrentHashMap; 63 64 /** 65 * Tracks Ethernet interfaces and manages interface configurations. 66 * 67 * <p>Interfaces may have different {@link android.net.NetworkCapabilities}. This mapping is defined 68 * in {@code config_ethernet_interfaces}. Notably, some interfaces could be marked as restricted by 69 * not specifying {@link android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED} flag. 70 * Interfaces could have associated {@link android.net.IpConfiguration}. 71 * Ethernet Interfaces may be present at boot time or appear after boot (e.g., for Ethernet adapters 72 * connected over USB). This class supports multiple interfaces. When an interface appears on the 73 * system (or is present at boot time) this class will start tracking it and bring it up. Only 74 * interfaces whose names match the {@code config_ethernet_iface_regex} regular expression are 75 * tracked. 76 * 77 * <p>All public or package private methods must be thread-safe unless stated otherwise. 78 */ 79 @VisibleForTesting(visibility = PACKAGE) 80 public class EthernetTracker { 81 private static final int INTERFACE_MODE_CLIENT = 1; 82 private static final int INTERFACE_MODE_SERVER = 2; 83 84 private static final String TAG = EthernetTracker.class.getSimpleName(); 85 private static final boolean DBG = EthernetNetworkFactory.DBG; 86 87 private static final String TEST_IFACE_REGEXP = TEST_TAP_PREFIX + "\\d+"; 88 89 /** 90 * Interface names we track. This is a product-dependent regular expression, plus, 91 * if setIncludeTestInterfaces is true, any test interfaces. 92 */ 93 private volatile String mIfaceMatch; 94 95 /** 96 * Track test interfaces if true, don't track otherwise. 97 */ 98 private boolean mIncludeTestInterfaces = false; 99 100 /** Mapping between {iface name | mac address} -> {NetworkCapabilities} */ 101 private final ConcurrentHashMap<String, NetworkCapabilities> mNetworkCapabilities = 102 new ConcurrentHashMap<>(); 103 private final ConcurrentHashMap<String, IpConfiguration> mIpConfigurations = 104 new ConcurrentHashMap<>(); 105 106 private final Context mContext; 107 private final INetd mNetd; 108 private final Handler mHandler; 109 private final EthernetNetworkFactory mFactory; 110 private final EthernetConfigStore mConfigStore; 111 private final Dependencies mDeps; 112 113 private final RemoteCallbackList<IEthernetServiceListener> mListeners = 114 new RemoteCallbackList<>(); 115 private final TetheredInterfaceRequestList mTetheredInterfaceRequests = 116 new TetheredInterfaceRequestList(); 117 118 // Used only on the handler thread 119 private String mDefaultInterface; 120 private int mDefaultInterfaceMode = INTERFACE_MODE_CLIENT; 121 // Tracks whether clients were notified that the tethered interface is available 122 private boolean mTetheredInterfaceWasAvailable = false; 123 private volatile IpConfiguration mIpConfigForDefaultInterface; 124 125 private int mEthernetState = ETHERNET_STATE_ENABLED; 126 127 private class TetheredInterfaceRequestList extends 128 RemoteCallbackList<ITetheredInterfaceCallback> { 129 @Override onCallbackDied(ITetheredInterfaceCallback cb, Object cookie)130 public void onCallbackDied(ITetheredInterfaceCallback cb, Object cookie) { 131 mHandler.post(EthernetTracker.this::maybeUntetherDefaultInterface); 132 } 133 } 134 135 public static class Dependencies { getInterfaceRegexFromResource(Context context)136 public String getInterfaceRegexFromResource(Context context) { 137 final ConnectivityResources resources = new ConnectivityResources(context); 138 return resources.get().getString( 139 com.android.connectivity.resources.R.string.config_ethernet_iface_regex); 140 } 141 getInterfaceConfigFromResource(Context context)142 public String[] getInterfaceConfigFromResource(Context context) { 143 final ConnectivityResources resources = new ConnectivityResources(context); 144 return resources.get().getStringArray( 145 com.android.connectivity.resources.R.array.config_ethernet_interfaces); 146 } 147 } 148 EthernetTracker(@onNull final Context context, @NonNull final Handler handler, @NonNull final EthernetNetworkFactory factory, @NonNull final INetd netd)149 EthernetTracker(@NonNull final Context context, @NonNull final Handler handler, 150 @NonNull final EthernetNetworkFactory factory, @NonNull final INetd netd) { 151 this(context, handler, factory, netd, new Dependencies()); 152 } 153 154 @VisibleForTesting EthernetTracker(@onNull final Context context, @NonNull final Handler handler, @NonNull final EthernetNetworkFactory factory, @NonNull final INetd netd, @NonNull final Dependencies deps)155 EthernetTracker(@NonNull final Context context, @NonNull final Handler handler, 156 @NonNull final EthernetNetworkFactory factory, @NonNull final INetd netd, 157 @NonNull final Dependencies deps) { 158 mContext = context; 159 mHandler = handler; 160 mFactory = factory; 161 mNetd = netd; 162 mDeps = deps; 163 164 // Interface match regex. 165 updateIfaceMatchRegexp(); 166 167 // Read default Ethernet interface configuration from resources 168 final String[] interfaceConfigs = mDeps.getInterfaceConfigFromResource(context); 169 for (String strConfig : interfaceConfigs) { 170 parseEthernetConfig(strConfig); 171 } 172 173 mConfigStore = new EthernetConfigStore(); 174 } 175 start()176 void start() { 177 mFactory.register(); 178 mConfigStore.read(); 179 180 // Default interface is just the first one we want to track. 181 mIpConfigForDefaultInterface = mConfigStore.getIpConfigurationForDefaultInterface(); 182 final ArrayMap<String, IpConfiguration> configs = mConfigStore.getIpConfigurations(); 183 for (int i = 0; i < configs.size(); i++) { 184 mIpConfigurations.put(configs.keyAt(i), configs.valueAt(i)); 185 } 186 187 try { 188 PermissionUtils.enforceNetworkStackPermission(mContext); 189 mNetd.registerUnsolicitedEventListener(new InterfaceObserver()); 190 } catch (RemoteException | ServiceSpecificException e) { 191 Log.e(TAG, "Could not register InterfaceObserver " + e); 192 } 193 194 mHandler.post(this::trackAvailableInterfaces); 195 } 196 updateIpConfiguration(String iface, IpConfiguration ipConfiguration)197 void updateIpConfiguration(String iface, IpConfiguration ipConfiguration) { 198 if (DBG) { 199 Log.i(TAG, "updateIpConfiguration, iface: " + iface + ", cfg: " + ipConfiguration); 200 } 201 writeIpConfiguration(iface, ipConfiguration); 202 mHandler.post(() -> { 203 mFactory.updateInterface(iface, ipConfiguration, null, null); 204 broadcastInterfaceStateChange(iface); 205 }); 206 } 207 writeIpConfiguration(@onNull final String iface, @NonNull final IpConfiguration ipConfig)208 private void writeIpConfiguration(@NonNull final String iface, 209 @NonNull final IpConfiguration ipConfig) { 210 mConfigStore.write(iface, ipConfig); 211 mIpConfigurations.put(iface, ipConfig); 212 } 213 getIpConfigurationForCallback(String iface, int state)214 private IpConfiguration getIpConfigurationForCallback(String iface, int state) { 215 return (state == EthernetManager.STATE_ABSENT) ? null : getOrCreateIpConfiguration(iface); 216 } 217 ensureRunningOnEthernetServiceThread()218 private void ensureRunningOnEthernetServiceThread() { 219 if (mHandler.getLooper().getThread() != Thread.currentThread()) { 220 throw new IllegalStateException( 221 "Not running on EthernetService thread: " 222 + Thread.currentThread().getName()); 223 } 224 } 225 226 /** 227 * Broadcast the link state or IpConfiguration change of existing Ethernet interfaces to all 228 * listeners. 229 */ broadcastInterfaceStateChange(@onNull String iface)230 protected void broadcastInterfaceStateChange(@NonNull String iface) { 231 ensureRunningOnEthernetServiceThread(); 232 final int state = getInterfaceState(iface); 233 final int role = getInterfaceRole(iface); 234 final IpConfiguration config = getIpConfigurationForCallback(iface, state); 235 final int n = mListeners.beginBroadcast(); 236 for (int i = 0; i < n; i++) { 237 try { 238 mListeners.getBroadcastItem(i).onInterfaceStateChanged(iface, state, role, config); 239 } catch (RemoteException e) { 240 // Do nothing here. 241 } 242 } 243 mListeners.finishBroadcast(); 244 } 245 246 /** 247 * Unicast the interface state or IpConfiguration change of existing Ethernet interfaces to a 248 * specific listener. 249 */ unicastInterfaceStateChange(@onNull IEthernetServiceListener listener, @NonNull String iface)250 protected void unicastInterfaceStateChange(@NonNull IEthernetServiceListener listener, 251 @NonNull String iface) { 252 ensureRunningOnEthernetServiceThread(); 253 final int state = mFactory.getInterfaceState(iface); 254 final int role = getInterfaceRole(iface); 255 final IpConfiguration config = getIpConfigurationForCallback(iface, state); 256 try { 257 listener.onInterfaceStateChanged(iface, state, role, config); 258 } catch (RemoteException e) { 259 // Do nothing here. 260 } 261 } 262 263 @VisibleForTesting(visibility = PACKAGE) updateConfiguration(@onNull final String iface, @Nullable final IpConfiguration ipConfig, @Nullable final NetworkCapabilities capabilities, @Nullable final INetworkInterfaceOutcomeReceiver listener)264 protected void updateConfiguration(@NonNull final String iface, 265 @Nullable final IpConfiguration ipConfig, 266 @Nullable final NetworkCapabilities capabilities, 267 @Nullable final INetworkInterfaceOutcomeReceiver listener) { 268 if (DBG) { 269 Log.i(TAG, "updateConfiguration, iface: " + iface + ", capabilities: " + capabilities 270 + ", ipConfig: " + ipConfig); 271 } 272 273 final IpConfiguration localIpConfig = ipConfig == null 274 ? null : new IpConfiguration(ipConfig); 275 if (ipConfig != null) { 276 writeIpConfiguration(iface, localIpConfig); 277 } 278 279 if (null != capabilities) { 280 mNetworkCapabilities.put(iface, capabilities); 281 } 282 mHandler.post(() -> { 283 mFactory.updateInterface(iface, localIpConfig, capabilities, listener); 284 broadcastInterfaceStateChange(iface); 285 }); 286 } 287 288 @VisibleForTesting(visibility = PACKAGE) connectNetwork(@onNull final String iface, @Nullable final INetworkInterfaceOutcomeReceiver listener)289 protected void connectNetwork(@NonNull final String iface, 290 @Nullable final INetworkInterfaceOutcomeReceiver listener) { 291 mHandler.post(() -> updateInterfaceState(iface, true, listener)); 292 } 293 294 @VisibleForTesting(visibility = PACKAGE) disconnectNetwork(@onNull final String iface, @Nullable final INetworkInterfaceOutcomeReceiver listener)295 protected void disconnectNetwork(@NonNull final String iface, 296 @Nullable final INetworkInterfaceOutcomeReceiver listener) { 297 mHandler.post(() -> updateInterfaceState(iface, false, listener)); 298 } 299 getIpConfiguration(String iface)300 IpConfiguration getIpConfiguration(String iface) { 301 return mIpConfigurations.get(iface); 302 } 303 304 @VisibleForTesting(visibility = PACKAGE) isTrackingInterface(String iface)305 protected boolean isTrackingInterface(String iface) { 306 return mFactory.hasInterface(iface); 307 } 308 getInterfaces(boolean includeRestricted)309 String[] getInterfaces(boolean includeRestricted) { 310 return mFactory.getAvailableInterfaces(includeRestricted); 311 } 312 getInterfaceList()313 List<String> getInterfaceList() { 314 final List<String> interfaceList = new ArrayList<String>(); 315 final String[] ifaces; 316 try { 317 ifaces = mNetd.interfaceGetList(); 318 } catch (RemoteException e) { 319 Log.e(TAG, "Could not get list of interfaces " + e); 320 return interfaceList; 321 } 322 final String ifaceMatch = mIfaceMatch; 323 for (String iface : ifaces) { 324 if (iface.matches(ifaceMatch)) interfaceList.add(iface); 325 } 326 return interfaceList; 327 } 328 329 /** 330 * Returns true if given interface was configured as restricted (doesn't have 331 * NET_CAPABILITY_NOT_RESTRICTED) capability. Otherwise, returns false. 332 */ isRestrictedInterface(String iface)333 boolean isRestrictedInterface(String iface) { 334 final NetworkCapabilities nc = mNetworkCapabilities.get(iface); 335 return nc != null && !nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); 336 } 337 addListener(IEthernetServiceListener listener, boolean canUseRestrictedNetworks)338 void addListener(IEthernetServiceListener listener, boolean canUseRestrictedNetworks) { 339 mHandler.post(() -> { 340 if (!mListeners.register(listener, new ListenerInfo(canUseRestrictedNetworks))) { 341 // Remote process has already died 342 return; 343 } 344 for (String iface : getInterfaces(canUseRestrictedNetworks)) { 345 unicastInterfaceStateChange(listener, iface); 346 } 347 348 unicastEthernetStateChange(listener, mEthernetState); 349 }); 350 } 351 removeListener(IEthernetServiceListener listener)352 void removeListener(IEthernetServiceListener listener) { 353 mHandler.post(() -> mListeners.unregister(listener)); 354 } 355 setIncludeTestInterfaces(boolean include)356 public void setIncludeTestInterfaces(boolean include) { 357 mHandler.post(() -> { 358 mIncludeTestInterfaces = include; 359 updateIfaceMatchRegexp(); 360 if (!include) { 361 removeTestData(); 362 } 363 mHandler.post(() -> trackAvailableInterfaces()); 364 }); 365 } 366 removeTestData()367 private void removeTestData() { 368 removeTestIpData(); 369 removeTestCapabilityData(); 370 } 371 removeTestIpData()372 private void removeTestIpData() { 373 final Iterator<String> iterator = mIpConfigurations.keySet().iterator(); 374 while (iterator.hasNext()) { 375 final String iface = iterator.next(); 376 if (iface.matches(TEST_IFACE_REGEXP)) { 377 mConfigStore.write(iface, null); 378 iterator.remove(); 379 } 380 } 381 } 382 removeTestCapabilityData()383 private void removeTestCapabilityData() { 384 mNetworkCapabilities.keySet().removeIf(iface -> iface.matches(TEST_IFACE_REGEXP)); 385 } 386 requestTetheredInterface(ITetheredInterfaceCallback callback)387 public void requestTetheredInterface(ITetheredInterfaceCallback callback) { 388 mHandler.post(() -> { 389 if (!mTetheredInterfaceRequests.register(callback)) { 390 // Remote process has already died 391 return; 392 } 393 if (mDefaultInterfaceMode == INTERFACE_MODE_SERVER) { 394 if (mTetheredInterfaceWasAvailable) { 395 notifyTetheredInterfaceAvailable(callback, mDefaultInterface); 396 } 397 return; 398 } 399 400 setDefaultInterfaceMode(INTERFACE_MODE_SERVER); 401 }); 402 } 403 releaseTetheredInterface(ITetheredInterfaceCallback callback)404 public void releaseTetheredInterface(ITetheredInterfaceCallback callback) { 405 mHandler.post(() -> { 406 mTetheredInterfaceRequests.unregister(callback); 407 maybeUntetherDefaultInterface(); 408 }); 409 } 410 notifyTetheredInterfaceAvailable(ITetheredInterfaceCallback cb, String iface)411 private void notifyTetheredInterfaceAvailable(ITetheredInterfaceCallback cb, String iface) { 412 try { 413 cb.onAvailable(iface); 414 } catch (RemoteException e) { 415 Log.e(TAG, "Error sending tethered interface available callback", e); 416 } 417 } 418 notifyTetheredInterfaceUnavailable(ITetheredInterfaceCallback cb)419 private void notifyTetheredInterfaceUnavailable(ITetheredInterfaceCallback cb) { 420 try { 421 cb.onUnavailable(); 422 } catch (RemoteException e) { 423 Log.e(TAG, "Error sending tethered interface available callback", e); 424 } 425 } 426 maybeUntetherDefaultInterface()427 private void maybeUntetherDefaultInterface() { 428 if (mTetheredInterfaceRequests.getRegisteredCallbackCount() > 0) return; 429 if (mDefaultInterfaceMode == INTERFACE_MODE_CLIENT) return; 430 setDefaultInterfaceMode(INTERFACE_MODE_CLIENT); 431 } 432 setDefaultInterfaceMode(int mode)433 private void setDefaultInterfaceMode(int mode) { 434 Log.d(TAG, "Setting default interface mode to " + mode); 435 mDefaultInterfaceMode = mode; 436 if (mDefaultInterface != null) { 437 removeInterface(mDefaultInterface); 438 addInterface(mDefaultInterface); 439 // when this broadcast is sent, any calls to notifyTetheredInterfaceAvailable or 440 // notifyTetheredInterfaceUnavailable have already happened 441 broadcastInterfaceStateChange(mDefaultInterface); 442 } 443 } 444 getInterfaceState(final String iface)445 private int getInterfaceState(final String iface) { 446 if (mFactory.hasInterface(iface)) { 447 return mFactory.getInterfaceState(iface); 448 } 449 if (getInterfaceMode(iface) == INTERFACE_MODE_SERVER) { 450 // server mode interfaces are not tracked by the factory. 451 // TODO(b/234743836): interface state for server mode interfaces is not tracked 452 // properly; just return link up. 453 return EthernetManager.STATE_LINK_UP; 454 } 455 return EthernetManager.STATE_ABSENT; 456 } 457 getInterfaceRole(final String iface)458 private int getInterfaceRole(final String iface) { 459 if (mFactory.hasInterface(iface)) { 460 // only client mode interfaces are tracked by the factory. 461 return EthernetManager.ROLE_CLIENT; 462 } 463 if (getInterfaceMode(iface) == INTERFACE_MODE_SERVER) { 464 return EthernetManager.ROLE_SERVER; 465 } 466 return EthernetManager.ROLE_NONE; 467 } 468 getInterfaceMode(final String iface)469 private int getInterfaceMode(final String iface) { 470 if (iface.equals(mDefaultInterface)) { 471 return mDefaultInterfaceMode; 472 } 473 return INTERFACE_MODE_CLIENT; 474 } 475 removeInterface(String iface)476 private void removeInterface(String iface) { 477 mFactory.removeInterface(iface); 478 maybeUpdateServerModeInterfaceState(iface, false); 479 } 480 stopTrackingInterface(String iface)481 private void stopTrackingInterface(String iface) { 482 removeInterface(iface); 483 if (iface.equals(mDefaultInterface)) { 484 mDefaultInterface = null; 485 } 486 broadcastInterfaceStateChange(iface); 487 } 488 addInterface(String iface)489 private void addInterface(String iface) { 490 InterfaceConfigurationParcel config = null; 491 // Bring up the interface so we get link status indications. 492 try { 493 PermissionUtils.enforceNetworkStackPermission(mContext); 494 NetdUtils.setInterfaceUp(mNetd, iface); 495 config = NetdUtils.getInterfaceConfigParcel(mNetd, iface); 496 } catch (IllegalStateException e) { 497 // Either the system is crashing or the interface has disappeared. Just ignore the 498 // error; we haven't modified any state because we only do that if our calls succeed. 499 Log.e(TAG, "Error upping interface " + iface, e); 500 } 501 502 if (config == null) { 503 Log.e(TAG, "Null interface config parcelable for " + iface + ". Bailing out."); 504 return; 505 } 506 507 final String hwAddress = config.hwAddr; 508 509 NetworkCapabilities nc = mNetworkCapabilities.get(iface); 510 if (nc == null) { 511 // Try to resolve using mac address 512 nc = mNetworkCapabilities.get(hwAddress); 513 if (nc == null) { 514 final boolean isTestIface = iface.matches(TEST_IFACE_REGEXP); 515 nc = createDefaultNetworkCapabilities(isTestIface); 516 } 517 } 518 519 final int mode = getInterfaceMode(iface); 520 if (mode == INTERFACE_MODE_CLIENT) { 521 IpConfiguration ipConfiguration = getOrCreateIpConfiguration(iface); 522 Log.d(TAG, "Tracking interface in client mode: " + iface); 523 mFactory.addInterface(iface, hwAddress, ipConfiguration, nc); 524 } else { 525 maybeUpdateServerModeInterfaceState(iface, true); 526 } 527 528 // Note: if the interface already has link (e.g., if we crashed and got 529 // restarted while it was running), we need to fake a link up notification so we 530 // start configuring it. 531 if (NetdUtils.hasFlag(config, "running")) { 532 updateInterfaceState(iface, true); 533 } 534 } 535 updateInterfaceState(String iface, boolean up)536 private void updateInterfaceState(String iface, boolean up) { 537 updateInterfaceState(iface, up, null /* listener */); 538 } 539 updateInterfaceState(@onNull final String iface, final boolean up, @Nullable final INetworkInterfaceOutcomeReceiver listener)540 private void updateInterfaceState(@NonNull final String iface, final boolean up, 541 @Nullable final INetworkInterfaceOutcomeReceiver listener) { 542 final int mode = getInterfaceMode(iface); 543 final boolean factoryLinkStateUpdated = (mode == INTERFACE_MODE_CLIENT) 544 && mFactory.updateInterfaceLinkState(iface, up, listener); 545 546 if (factoryLinkStateUpdated) { 547 broadcastInterfaceStateChange(iface); 548 } 549 } 550 maybeUpdateServerModeInterfaceState(String iface, boolean available)551 private void maybeUpdateServerModeInterfaceState(String iface, boolean available) { 552 if (available == mTetheredInterfaceWasAvailable || !iface.equals(mDefaultInterface)) return; 553 554 Log.d(TAG, (available ? "Tracking" : "No longer tracking") 555 + " interface in server mode: " + iface); 556 557 final int pendingCbs = mTetheredInterfaceRequests.beginBroadcast(); 558 for (int i = 0; i < pendingCbs; i++) { 559 ITetheredInterfaceCallback item = mTetheredInterfaceRequests.getBroadcastItem(i); 560 if (available) { 561 notifyTetheredInterfaceAvailable(item, iface); 562 } else { 563 notifyTetheredInterfaceUnavailable(item); 564 } 565 } 566 mTetheredInterfaceRequests.finishBroadcast(); 567 mTetheredInterfaceWasAvailable = available; 568 } 569 maybeTrackInterface(String iface)570 private void maybeTrackInterface(String iface) { 571 if (!iface.matches(mIfaceMatch)) { 572 return; 573 } 574 575 // If we don't already track this interface, and if this interface matches 576 // our regex, start tracking it. 577 if (mFactory.hasInterface(iface) || iface.equals(mDefaultInterface)) { 578 if (DBG) Log.w(TAG, "Ignoring already-tracked interface " + iface); 579 return; 580 } 581 if (DBG) Log.i(TAG, "maybeTrackInterface: " + iface); 582 583 // TODO: avoid making an interface default if it has configured NetworkCapabilities. 584 if (mDefaultInterface == null) { 585 mDefaultInterface = iface; 586 } 587 588 if (mIpConfigForDefaultInterface != null) { 589 updateIpConfiguration(iface, mIpConfigForDefaultInterface); 590 mIpConfigForDefaultInterface = null; 591 } 592 593 addInterface(iface); 594 595 broadcastInterfaceStateChange(iface); 596 } 597 trackAvailableInterfaces()598 private void trackAvailableInterfaces() { 599 try { 600 final String[] ifaces = mNetd.interfaceGetList(); 601 for (String iface : ifaces) { 602 maybeTrackInterface(iface); 603 } 604 } catch (RemoteException | ServiceSpecificException e) { 605 Log.e(TAG, "Could not get list of interfaces " + e); 606 } 607 } 608 609 @VisibleForTesting 610 class InterfaceObserver extends BaseNetdUnsolicitedEventListener { 611 612 @Override onInterfaceLinkStateChanged(String iface, boolean up)613 public void onInterfaceLinkStateChanged(String iface, boolean up) { 614 if (DBG) { 615 Log.i(TAG, "interfaceLinkStateChanged, iface: " + iface + ", up: " + up); 616 } 617 mHandler.post(() -> { 618 if (mEthernetState == ETHERNET_STATE_DISABLED) return; 619 updateInterfaceState(iface, up); 620 }); 621 } 622 623 @Override onInterfaceAdded(String iface)624 public void onInterfaceAdded(String iface) { 625 if (DBG) { 626 Log.i(TAG, "onInterfaceAdded, iface: " + iface); 627 } 628 mHandler.post(() -> { 629 if (mEthernetState == ETHERNET_STATE_DISABLED) return; 630 maybeTrackInterface(iface); 631 }); 632 } 633 634 @Override onInterfaceRemoved(String iface)635 public void onInterfaceRemoved(String iface) { 636 if (DBG) { 637 Log.i(TAG, "onInterfaceRemoved, iface: " + iface); 638 } 639 mHandler.post(() -> { 640 if (mEthernetState == ETHERNET_STATE_DISABLED) return; 641 stopTrackingInterface(iface); 642 }); 643 } 644 } 645 646 private static class ListenerInfo { 647 648 boolean canUseRestrictedNetworks = false; 649 ListenerInfo(boolean canUseRestrictedNetworks)650 ListenerInfo(boolean canUseRestrictedNetworks) { 651 this.canUseRestrictedNetworks = canUseRestrictedNetworks; 652 } 653 } 654 655 /** 656 * Parses an Ethernet interface configuration 657 * 658 * @param configString represents an Ethernet configuration in the following format: {@code 659 * <interface name|mac address>;[Network Capabilities];[IP config];[Override Transport]} 660 */ parseEthernetConfig(String configString)661 private void parseEthernetConfig(String configString) { 662 final EthernetTrackerConfig config = createEthernetTrackerConfig(configString); 663 NetworkCapabilities nc = createNetworkCapabilities( 664 !TextUtils.isEmpty(config.mCapabilities) /* clear default capabilities */, 665 config.mCapabilities, config.mTransport).build(); 666 mNetworkCapabilities.put(config.mIface, nc); 667 668 if (null != config.mIpConfig) { 669 IpConfiguration ipConfig = parseStaticIpConfiguration(config.mIpConfig); 670 mIpConfigurations.put(config.mIface, ipConfig); 671 } 672 } 673 674 @VisibleForTesting createEthernetTrackerConfig(@onNull final String configString)675 static EthernetTrackerConfig createEthernetTrackerConfig(@NonNull final String configString) { 676 Objects.requireNonNull(configString, "EthernetTrackerConfig requires non-null config"); 677 return new EthernetTrackerConfig(configString.split(";", /* limit of tokens */ 4)); 678 } 679 createDefaultNetworkCapabilities(boolean isTestIface)680 private static NetworkCapabilities createDefaultNetworkCapabilities(boolean isTestIface) { 681 NetworkCapabilities.Builder builder = createNetworkCapabilities( 682 false /* clear default capabilities */, null, null) 683 .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) 684 .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED) 685 .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING) 686 .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED) 687 .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED) 688 .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); 689 690 if (isTestIface) { 691 builder.addTransportType(NetworkCapabilities.TRANSPORT_TEST); 692 } else { 693 builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); 694 } 695 696 return builder.build(); 697 } 698 699 /** 700 * Parses a static list of network capabilities 701 * 702 * @param clearDefaultCapabilities Indicates whether or not to clear any default capabilities 703 * @param commaSeparatedCapabilities A comma separated string list of integer encoded 704 * NetworkCapability.NET_CAPABILITY_* values 705 * @param overrideTransport A string representing a single integer encoded override transport 706 * type. Must be one of the NetworkCapability.TRANSPORT_* 707 * values. TRANSPORT_VPN is not supported. Errors with input 708 * will cause the override to be ignored. 709 */ 710 @VisibleForTesting createNetworkCapabilities( boolean clearDefaultCapabilities, @Nullable String commaSeparatedCapabilities, @Nullable String overrideTransport)711 static NetworkCapabilities.Builder createNetworkCapabilities( 712 boolean clearDefaultCapabilities, @Nullable String commaSeparatedCapabilities, 713 @Nullable String overrideTransport) { 714 715 final NetworkCapabilities.Builder builder = clearDefaultCapabilities 716 ? NetworkCapabilities.Builder.withoutDefaultCapabilities() 717 : new NetworkCapabilities.Builder(); 718 719 // Determine the transport type. If someone has tried to define an override transport then 720 // attempt to add it. Since we can only have one override, all errors with it will 721 // gracefully default back to TRANSPORT_ETHERNET and warn the user. VPN is not allowed as an 722 // override type. Wifi Aware and LoWPAN are currently unsupported as well. 723 int transport = NetworkCapabilities.TRANSPORT_ETHERNET; 724 if (!TextUtils.isEmpty(overrideTransport)) { 725 try { 726 int parsedTransport = Integer.valueOf(overrideTransport); 727 if (parsedTransport == NetworkCapabilities.TRANSPORT_VPN 728 || parsedTransport == NetworkCapabilities.TRANSPORT_WIFI_AWARE 729 || parsedTransport == NetworkCapabilities.TRANSPORT_LOWPAN) { 730 Log.e(TAG, "Override transport '" + parsedTransport + "' is not supported. " 731 + "Defaulting to TRANSPORT_ETHERNET"); 732 } else { 733 transport = parsedTransport; 734 } 735 } catch (NumberFormatException nfe) { 736 Log.e(TAG, "Override transport type '" + overrideTransport + "' " 737 + "could not be parsed. Defaulting to TRANSPORT_ETHERNET"); 738 } 739 } 740 741 // Apply the transport. If the user supplied a valid number that is not a valid transport 742 // then adding will throw an exception. Default back to TRANSPORT_ETHERNET if that happens 743 try { 744 builder.addTransportType(transport); 745 } catch (IllegalArgumentException iae) { 746 Log.e(TAG, transport + " is not a valid NetworkCapability.TRANSPORT_* value. " 747 + "Defaulting to TRANSPORT_ETHERNET"); 748 builder.addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET); 749 } 750 751 builder.setLinkUpstreamBandwidthKbps(100 * 1000); 752 builder.setLinkDownstreamBandwidthKbps(100 * 1000); 753 754 if (!TextUtils.isEmpty(commaSeparatedCapabilities)) { 755 for (String strNetworkCapability : commaSeparatedCapabilities.split(",")) { 756 if (!TextUtils.isEmpty(strNetworkCapability)) { 757 try { 758 builder.addCapability(Integer.valueOf(strNetworkCapability)); 759 } catch (NumberFormatException nfe) { 760 Log.e(TAG, "Capability '" + strNetworkCapability + "' could not be parsed"); 761 } catch (IllegalArgumentException iae) { 762 Log.e(TAG, strNetworkCapability + " is not a valid " 763 + "NetworkCapability.NET_CAPABILITY_* value"); 764 } 765 } 766 } 767 } 768 // Ethernet networks have no way to update the following capabilities, so they always 769 // have them. 770 builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING); 771 builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED); 772 builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED); 773 774 return builder; 775 } 776 777 /** 778 * Parses static IP configuration. 779 * 780 * @param staticIpConfig represents static IP configuration in the following format: {@code 781 * ip=<ip-address/mask> gateway=<ip-address> dns=<comma-sep-ip-addresses> 782 * domains=<comma-sep-domains>} 783 */ 784 @VisibleForTesting parseStaticIpConfiguration(String staticIpConfig)785 static IpConfiguration parseStaticIpConfiguration(String staticIpConfig) { 786 final StaticIpConfiguration.Builder staticIpConfigBuilder = 787 new StaticIpConfiguration.Builder(); 788 789 for (String keyValueAsString : staticIpConfig.trim().split(" ")) { 790 if (TextUtils.isEmpty(keyValueAsString)) continue; 791 792 String[] pair = keyValueAsString.split("="); 793 if (pair.length != 2) { 794 throw new IllegalArgumentException("Unexpected token: " + keyValueAsString 795 + " in " + staticIpConfig); 796 } 797 798 String key = pair[0]; 799 String value = pair[1]; 800 801 switch (key) { 802 case "ip": 803 staticIpConfigBuilder.setIpAddress(new LinkAddress(value)); 804 break; 805 case "domains": 806 staticIpConfigBuilder.setDomains(value); 807 break; 808 case "gateway": 809 staticIpConfigBuilder.setGateway(InetAddress.parseNumericAddress(value)); 810 break; 811 case "dns": { 812 ArrayList<InetAddress> dnsAddresses = new ArrayList<>(); 813 for (String address: value.split(",")) { 814 dnsAddresses.add(InetAddress.parseNumericAddress(address)); 815 } 816 staticIpConfigBuilder.setDnsServers(dnsAddresses); 817 break; 818 } 819 default : { 820 throw new IllegalArgumentException("Unexpected key: " + key 821 + " in " + staticIpConfig); 822 } 823 } 824 } 825 return createIpConfiguration(staticIpConfigBuilder.build()); 826 } 827 createIpConfiguration( @onNull final StaticIpConfiguration staticIpConfig)828 private static IpConfiguration createIpConfiguration( 829 @NonNull final StaticIpConfiguration staticIpConfig) { 830 return new IpConfiguration.Builder().setStaticIpConfiguration(staticIpConfig).build(); 831 } 832 getOrCreateIpConfiguration(String iface)833 private IpConfiguration getOrCreateIpConfiguration(String iface) { 834 IpConfiguration ret = mIpConfigurations.get(iface); 835 if (ret != null) return ret; 836 ret = new IpConfiguration(); 837 ret.setIpAssignment(IpAssignment.DHCP); 838 ret.setProxySettings(ProxySettings.NONE); 839 return ret; 840 } 841 updateIfaceMatchRegexp()842 private void updateIfaceMatchRegexp() { 843 final String match = mDeps.getInterfaceRegexFromResource(mContext); 844 mIfaceMatch = mIncludeTestInterfaces 845 ? "(" + match + "|" + TEST_IFACE_REGEXP + ")" 846 : match; 847 Log.d(TAG, "Interface match regexp set to '" + mIfaceMatch + "'"); 848 } 849 850 /** 851 * Validate if a given interface is valid for testing. 852 * 853 * @param iface the name of the interface to validate. 854 * @return {@code true} if test interfaces are enabled and the given {@code iface} has a test 855 * interface prefix, {@code false} otherwise. 856 */ isValidTestInterface(@onNull final String iface)857 public boolean isValidTestInterface(@NonNull final String iface) { 858 return mIncludeTestInterfaces && iface.matches(TEST_IFACE_REGEXP); 859 } 860 postAndWaitForRunnable(Runnable r)861 private void postAndWaitForRunnable(Runnable r) { 862 final ConditionVariable cv = new ConditionVariable(); 863 if (mHandler.post(() -> { 864 r.run(); 865 cv.open(); 866 })) { 867 cv.block(2000L); 868 } 869 } 870 871 @VisibleForTesting(visibility = PACKAGE) setEthernetEnabled(boolean enabled)872 protected void setEthernetEnabled(boolean enabled) { 873 mHandler.post(() -> { 874 int newState = enabled ? ETHERNET_STATE_ENABLED : ETHERNET_STATE_DISABLED; 875 if (mEthernetState == newState) return; 876 877 mEthernetState = newState; 878 879 if (enabled) { 880 trackAvailableInterfaces(); 881 } else { 882 // TODO: maybe also disable server mode interface as well. 883 untrackFactoryInterfaces(); 884 } 885 broadcastEthernetStateChange(mEthernetState); 886 }); 887 } 888 untrackFactoryInterfaces()889 private void untrackFactoryInterfaces() { 890 for (String iface : mFactory.getAvailableInterfaces(true /* includeRestricted */)) { 891 stopTrackingInterface(iface); 892 } 893 } 894 unicastEthernetStateChange(@onNull IEthernetServiceListener listener, int state)895 private void unicastEthernetStateChange(@NonNull IEthernetServiceListener listener, 896 int state) { 897 ensureRunningOnEthernetServiceThread(); 898 try { 899 listener.onEthernetStateChanged(state); 900 } catch (RemoteException e) { 901 // Do nothing here. 902 } 903 } 904 broadcastEthernetStateChange(int state)905 private void broadcastEthernetStateChange(int state) { 906 ensureRunningOnEthernetServiceThread(); 907 final int n = mListeners.beginBroadcast(); 908 for (int i = 0; i < n; i++) { 909 try { 910 mListeners.getBroadcastItem(i).onEthernetStateChanged(state); 911 } catch (RemoteException e) { 912 // Do nothing here. 913 } 914 } 915 mListeners.finishBroadcast(); 916 } 917 dump(FileDescriptor fd, IndentingPrintWriter pw, String[] args)918 void dump(FileDescriptor fd, IndentingPrintWriter pw, String[] args) { 919 postAndWaitForRunnable(() -> { 920 pw.println(getClass().getSimpleName()); 921 pw.println("Ethernet State: " 922 + (mEthernetState == ETHERNET_STATE_ENABLED ? "enabled" : "disabled")); 923 pw.println("Ethernet interface name filter: " + mIfaceMatch); 924 pw.println("Default interface: " + mDefaultInterface); 925 pw.println("Default interface mode: " + mDefaultInterfaceMode); 926 pw.println("Tethered interface requests: " 927 + mTetheredInterfaceRequests.getRegisteredCallbackCount()); 928 pw.println("Listeners: " + mListeners.getRegisteredCallbackCount()); 929 pw.println("IP Configurations:"); 930 pw.increaseIndent(); 931 for (String iface : mIpConfigurations.keySet()) { 932 pw.println(iface + ": " + mIpConfigurations.get(iface)); 933 } 934 pw.decreaseIndent(); 935 pw.println(); 936 937 pw.println("Network Capabilities:"); 938 pw.increaseIndent(); 939 for (String iface : mNetworkCapabilities.keySet()) { 940 pw.println(iface + ": " + mNetworkCapabilities.get(iface)); 941 } 942 pw.decreaseIndent(); 943 pw.println(); 944 945 mFactory.dump(fd, pw, args); 946 }); 947 } 948 949 @VisibleForTesting 950 static class EthernetTrackerConfig { 951 final String mIface; 952 final String mCapabilities; 953 final String mIpConfig; 954 final String mTransport; 955 EthernetTrackerConfig(@onNull final String[] tokens)956 EthernetTrackerConfig(@NonNull final String[] tokens) { 957 Objects.requireNonNull(tokens, "EthernetTrackerConfig requires non-null tokens"); 958 mIface = tokens[0]; 959 mCapabilities = tokens.length > 1 ? tokens[1] : null; 960 mIpConfig = tokens.length > 2 && !TextUtils.isEmpty(tokens[2]) ? tokens[2] : null; 961 mTransport = tokens.length > 3 ? tokens[3] : null; 962 } 963 } 964 } 965