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; 18 19 import static android.net.dhcp.IDhcpServer.STATUS_INVALID_ARGUMENT; 20 import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS; 21 import static android.net.dhcp.IDhcpServer.STATUS_UNKNOWN_ERROR; 22 import static android.net.util.RawPacketTracker.MAX_CAPTURE_TIME_MS; 23 import static android.net.util.RawSocketUtils.sendRawPacketDownStream; 24 25 import static com.android.net.module.util.DeviceConfigUtils.getResBooleanConfig; 26 import static com.android.net.module.util.FeatureVersions.FEATURE_IS_UID_NETWORKING_BLOCKED; 27 import static com.android.networkstack.util.NetworkStackUtils.IGNORE_TCP_INFO_FOR_BLOCKED_UIDS; 28 import static com.android.networkstack.util.NetworkStackUtils.SKIP_TCP_POLL_IN_LIGHT_DOZE; 29 import static com.android.server.util.PermissionUtil.checkDumpPermission; 30 31 import android.app.Service; 32 import android.content.Context; 33 import android.content.Intent; 34 import android.net.ConnectivityManager; 35 import android.net.IIpMemoryStore; 36 import android.net.IIpMemoryStoreCallbacks; 37 import android.net.INetd; 38 import android.net.INetworkMonitor; 39 import android.net.INetworkMonitorCallbacks; 40 import android.net.INetworkStackConnector; 41 import android.net.INetworkStackStatusCallback; 42 import android.net.LinkProperties; 43 import android.net.Network; 44 import android.net.NetworkCapabilities; 45 import android.net.PrivateDnsConfigParcel; 46 import android.net.dhcp.DhcpServer; 47 import android.net.dhcp.DhcpServingParams; 48 import android.net.dhcp.DhcpServingParamsParcel; 49 import android.net.dhcp.IDhcpServerCallbacks; 50 import android.net.ip.IIpClientCallbacks; 51 import android.net.ip.IpClient; 52 import android.net.networkstack.aidl.NetworkMonitorParameters; 53 import android.net.shared.PrivateDnsConfig; 54 import android.net.util.RawPacketTracker; 55 import android.net.util.RawSocketUtils; 56 import android.os.HandlerThread; 57 import android.os.IBinder; 58 import android.os.Looper; 59 import android.os.ParcelFileDescriptor; 60 import android.os.RemoteException; 61 import android.text.TextUtils; 62 import android.util.ArraySet; 63 64 import androidx.annotation.NonNull; 65 import androidx.annotation.Nullable; 66 import androidx.annotation.VisibleForTesting; 67 68 import com.android.internal.annotations.GuardedBy; 69 import com.android.internal.util.IndentingPrintWriter; 70 import com.android.modules.utils.BasicShellCommandHandler; 71 import com.android.net.module.util.DeviceConfigUtils; 72 import com.android.net.module.util.HandlerUtils; 73 import com.android.net.module.util.SharedLog; 74 import com.android.networkstack.NetworkStackNotifier; 75 import com.android.networkstack.R; 76 import com.android.networkstack.ipmemorystore.IpMemoryStoreService; 77 import com.android.server.connectivity.NetworkMonitor; 78 import com.android.server.util.PermissionUtil; 79 80 import java.io.FileDescriptor; 81 import java.io.PrintWriter; 82 import java.lang.ref.WeakReference; 83 import java.util.ArrayDeque; 84 import java.util.ArrayList; 85 import java.util.Collection; 86 import java.util.Collections; 87 import java.util.Comparator; 88 import java.util.HashSet; 89 import java.util.Iterator; 90 import java.util.List; 91 import java.util.ListIterator; 92 import java.util.Objects; 93 import java.util.SortedSet; 94 import java.util.TreeSet; 95 import java.util.concurrent.ExecutionException; 96 import java.util.concurrent.TimeoutException; 97 98 /** 99 * Android service used to start the network stack when bound to via an intent. 100 * 101 * <p>The service returns a binder for the system server to communicate with the network stack. 102 */ 103 public class NetworkStackService extends Service { 104 private static final String TAG = NetworkStackService.class.getSimpleName(); 105 private static NetworkStackConnector sConnector; 106 private static final RawPacketTracker sRawPacketTracker = new RawPacketTracker(); 107 108 /** 109 * Create a binder connector for the system server to communicate with the network stack. 110 */ makeConnector(Context context)111 public static synchronized IBinder makeConnector(Context context) { 112 if (sConnector == null) { 113 sConnector = new NetworkStackConnector(context); 114 } 115 return sConnector; 116 } 117 118 @NonNull 119 @Override onBind(Intent intent)120 public IBinder onBind(Intent intent) { 121 return makeConnector(this); 122 } 123 124 /** 125 * An interface for internal clients of the network stack service that can return 126 * or create inline instances of the service it manages. 127 */ 128 public interface NetworkStackServiceManager { 129 /** 130 * Get an instance of the IpMemoryStoreService. 131 */ getIpMemoryStoreService()132 IIpMemoryStore getIpMemoryStoreService(); 133 134 /** 135 * Get an instance of the NetworkNotifier. 136 */ getNotifier()137 NetworkStackNotifier getNotifier(); 138 } 139 140 /** 141 * Permission checking dependency of the connector, useful for testing. 142 */ 143 public static class PermissionChecker { 144 /** 145 * @see PermissionUtil#enforceNetworkStackCallingPermission() 146 */ enforceNetworkStackCallingPermission()147 public void enforceNetworkStackCallingPermission() { 148 PermissionUtil.enforceNetworkStackCallingPermission(); 149 } 150 } 151 152 /** 153 * Dependencies of {@link NetworkStackConnector}, useful for testing. 154 */ 155 public static class Dependencies { 156 /** @see IpMemoryStoreService */ 157 @NonNull makeIpMemoryStoreService(@onNull Context context)158 public IpMemoryStoreService makeIpMemoryStoreService(@NonNull Context context) { 159 return new IpMemoryStoreService(context); 160 } 161 162 /** @see NetworkStackNotifier */ 163 @NonNull makeNotifier(@onNull Context context, @NonNull Looper looper)164 public NetworkStackNotifier makeNotifier(@NonNull Context context, @NonNull Looper looper) { 165 return new NetworkStackNotifier(context, looper); 166 } 167 168 /** @see DhcpServer */ 169 @NonNull makeDhcpServer(@onNull Context context, @NonNull String ifName, @NonNull DhcpServingParams params, @NonNull SharedLog log)170 public DhcpServer makeDhcpServer(@NonNull Context context, @NonNull String ifName, 171 @NonNull DhcpServingParams params, @NonNull SharedLog log) { 172 return new DhcpServer(context, ifName, params, log); 173 } 174 175 /** @see NetworkMonitor */ 176 @NonNull makeNetworkMonitor(@onNull Context context, @NonNull INetworkMonitorCallbacks cb, @NonNull Network network, @NonNull SharedLog log, @NonNull NetworkStackServiceManager nsServiceManager)177 public NetworkMonitor makeNetworkMonitor(@NonNull Context context, 178 @NonNull INetworkMonitorCallbacks cb, @NonNull Network network, 179 @NonNull SharedLog log, @NonNull NetworkStackServiceManager nsServiceManager) { 180 return new NetworkMonitor(context, cb, network, log, nsServiceManager); 181 } 182 183 /** @see IpClient */ 184 @NonNull makeIpClient(@onNull Context context, @NonNull String ifName, @NonNull IIpClientCallbacks cb, @NonNull NetworkStackServiceManager nsServiceManager)185 public IpClient makeIpClient(@NonNull Context context, @NonNull String ifName, 186 @NonNull IIpClientCallbacks cb, 187 @NonNull NetworkStackServiceManager nsServiceManager) { 188 return new IpClient(context, ifName, cb, nsServiceManager); 189 } 190 } 191 192 /** 193 * Connector implementing INetworkStackConnector for clients. 194 */ 195 @VisibleForTesting 196 public static class NetworkStackConnector extends INetworkStackConnector.Stub 197 implements NetworkStackServiceManager { 198 private static final int NUM_VALIDATION_LOG_LINES = 20; 199 private final Context mContext; 200 private final PermissionChecker mPermChecker; 201 private final Dependencies mDeps; 202 private final INetd mNetd; 203 @GuardedBy("mIpClients") 204 private final ArrayList<WeakReference<IpClient>> mIpClients = new ArrayList<>(); 205 private final IpMemoryStoreService mIpMemoryStoreService; 206 private final NetworkStackNotifier mNotifier; 207 208 private static final int MAX_VALIDATION_LOGS = 10; 209 @GuardedBy("mValidationLogs") 210 private final ArrayDeque<SharedLog> mValidationLogs = new ArrayDeque<>(MAX_VALIDATION_LOGS); 211 212 private static final String DUMPSYS_ARG_VERSION = "version"; 213 214 private static final String AIDL_KEY_NETWORKSTACK = "networkstack"; 215 private static final String AIDL_KEY_IPMEMORYSTORE = "ipmemorystore"; 216 private static final String AIDL_KEY_NETD = "netd"; 217 218 private static final int VERSION_UNKNOWN = -1; 219 private static final String HASH_UNKNOWN = "unknown"; 220 221 /** 222 * Versions of the AIDL interfaces observed by the network stack, in other words versions 223 * that the framework and other modules communicating with the network stack are using. 224 * The map may hold multiple values as the interface is used by modules with different 225 * versions. 226 */ 227 @GuardedBy("mFrameworkAidlVersions") 228 private final ArraySet<AidlVersion> mAidlVersions = new ArraySet<>(); 229 230 private static final class AidlVersion implements Comparable<AidlVersion> { 231 @NonNull 232 final String mKey; 233 final int mVersion; 234 @NonNull 235 final String mHash; 236 237 private static final Comparator<AidlVersion> COMPARATOR = 238 Comparator.comparing((AidlVersion v) -> v.mKey) 239 .thenComparingInt(v -> v.mVersion) 240 .thenComparing(v -> v.mHash, String::compareTo); 241 AidlVersion(@onNull String key, int version, @NonNull String hash)242 AidlVersion(@NonNull String key, int version, @NonNull String hash) { 243 mKey = key; 244 mVersion = version; 245 mHash = hash; 246 } 247 248 @Override hashCode()249 public int hashCode() { 250 return Objects.hash(mVersion, mHash); 251 } 252 253 @Override equals(@ullable Object obj)254 public boolean equals(@Nullable Object obj) { 255 if (!(obj instanceof AidlVersion)) return false; 256 final AidlVersion other = (AidlVersion) obj; 257 return Objects.equals(mKey, other.mKey) 258 && Objects.equals(mVersion, other.mVersion) 259 && Objects.equals(mHash, other.mHash); 260 } 261 262 @NonNull 263 @Override toString()264 public String toString() { 265 // Use a format that can be easily parsed by tests for the version 266 return String.format("%s:%s:%s", mKey, mVersion, mHash); 267 } 268 269 @Override compareTo(AidlVersion o)270 public int compareTo(AidlVersion o) { 271 return COMPARATOR.compare(this, o); 272 } 273 } 274 addValidationLogs(Network network, String name)275 private SharedLog addValidationLogs(Network network, String name) { 276 final SharedLog log = new SharedLog(NUM_VALIDATION_LOG_LINES, network + " - " + name); 277 synchronized (mValidationLogs) { 278 while (mValidationLogs.size() >= MAX_VALIDATION_LOGS) { 279 mValidationLogs.removeLast(); 280 } 281 mValidationLogs.addFirst(log); 282 } 283 return log; 284 } 285 NetworkStackConnector(@onNull Context context)286 NetworkStackConnector(@NonNull Context context) { 287 this(context, new PermissionChecker(), new Dependencies()); 288 } 289 290 @VisibleForTesting NetworkStackConnector( @onNull Context context, @NonNull PermissionChecker permChecker, @NonNull Dependencies deps)291 public NetworkStackConnector( 292 @NonNull Context context, @NonNull PermissionChecker permChecker, 293 @NonNull Dependencies deps) { 294 mContext = context; 295 mPermChecker = permChecker; 296 mDeps = deps; 297 mNetd = INetd.Stub.asInterface( 298 (IBinder) context.getSystemService(Context.NETD_SERVICE)); 299 mIpMemoryStoreService = mDeps.makeIpMemoryStoreService(context); 300 final HandlerThread notifierThread = new HandlerThread( 301 NetworkStackNotifier.class.getSimpleName()); 302 notifierThread.start(); 303 mNotifier = mDeps.makeNotifier(context, notifierThread.getLooper()); 304 305 int netdVersion; 306 String netdHash; 307 try { 308 netdVersion = mNetd.getInterfaceVersion(); 309 netdHash = mNetd.getInterfaceHash(); 310 } catch (RemoteException e) { 311 mLog.e("Error obtaining INetd version", e); 312 netdVersion = VERSION_UNKNOWN; 313 netdHash = HASH_UNKNOWN; 314 } 315 updateNetdAidlVersion(netdVersion, netdHash); 316 } 317 updateNetdAidlVersion(final int version, final String hash)318 private void updateNetdAidlVersion(final int version, final String hash) { 319 synchronized (mAidlVersions) { 320 mAidlVersions.add(new AidlVersion(AIDL_KEY_NETD, version, hash)); 321 } 322 } 323 updateNetworkStackAidlVersion(final int version, final String hash)324 private void updateNetworkStackAidlVersion(final int version, final String hash) { 325 synchronized (mAidlVersions) { 326 mAidlVersions.add(new AidlVersion(AIDL_KEY_NETWORKSTACK, version, hash)); 327 } 328 } 329 updateIpMemoryStoreAidlVersion(final int version, final String hash)330 private void updateIpMemoryStoreAidlVersion(final int version, final String hash) { 331 synchronized (mAidlVersions) { 332 mAidlVersions.add(new AidlVersion(AIDL_KEY_IPMEMORYSTORE, version, hash)); 333 } 334 } 335 336 @NonNull 337 private final SharedLog mLog = new SharedLog(TAG); 338 339 @Override makeDhcpServer(@onNull String ifName, @NonNull DhcpServingParamsParcel params, @NonNull IDhcpServerCallbacks cb)340 public void makeDhcpServer(@NonNull String ifName, @NonNull DhcpServingParamsParcel params, 341 @NonNull IDhcpServerCallbacks cb) throws RemoteException { 342 mPermChecker.enforceNetworkStackCallingPermission(); 343 updateNetworkStackAidlVersion(cb.getInterfaceVersion(), cb.getInterfaceHash()); 344 final DhcpServer server; 345 try { 346 server = mDeps.makeDhcpServer( 347 mContext, 348 ifName, 349 DhcpServingParams.fromParcelableObject(params), 350 mLog.forSubComponent(ifName + ".DHCP")); 351 } catch (DhcpServingParams.InvalidParameterException e) { 352 mLog.e("Invalid DhcpServingParams", e); 353 cb.onDhcpServerCreated(STATUS_INVALID_ARGUMENT, null); 354 return; 355 } catch (Exception e) { 356 mLog.e("Unknown error starting DhcpServer", e); 357 cb.onDhcpServerCreated(STATUS_UNKNOWN_ERROR, null); 358 return; 359 } 360 cb.onDhcpServerCreated(STATUS_SUCCESS, server.makeConnector()); 361 } 362 363 @Override makeNetworkMonitor(Network network, @Nullable String name, INetworkMonitorCallbacks cb)364 public void makeNetworkMonitor(Network network, @Nullable String name, 365 INetworkMonitorCallbacks cb) throws RemoteException { 366 mPermChecker.enforceNetworkStackCallingPermission(); 367 updateNetworkStackAidlVersion(cb.getInterfaceVersion(), cb.getInterfaceHash()); 368 final SharedLog log = addValidationLogs(network, name); 369 final NetworkMonitor nm = mDeps.makeNetworkMonitor(mContext, cb, network, log, this); 370 cb.onNetworkMonitorCreated(new NetworkMonitorConnector(nm, mPermChecker)); 371 } 372 373 @Override makeIpClient(String ifName, IIpClientCallbacks cb)374 public void makeIpClient(String ifName, IIpClientCallbacks cb) throws RemoteException { 375 mPermChecker.enforceNetworkStackCallingPermission(); 376 updateNetworkStackAidlVersion(cb.getInterfaceVersion(), cb.getInterfaceHash()); 377 final IpClient ipClient = mDeps.makeIpClient( 378 mContext, ifName, cb, this); 379 380 synchronized (mIpClients) { 381 final Iterator<WeakReference<IpClient>> it = mIpClients.iterator(); 382 while (it.hasNext()) { 383 final IpClient ipc = it.next().get(); 384 if (ipc == null) { 385 it.remove(); 386 } 387 } 388 mIpClients.add(new WeakReference<>(ipClient)); 389 } 390 391 cb.onIpClientCreated(ipClient.makeConnector()); 392 } 393 394 @Override getIpMemoryStoreService()395 public IIpMemoryStore getIpMemoryStoreService() { 396 return mIpMemoryStoreService; 397 } 398 399 @Override getNotifier()400 public NetworkStackNotifier getNotifier() { 401 return mNotifier; 402 } 403 404 @Override fetchIpMemoryStore(@onNull final IIpMemoryStoreCallbacks cb)405 public void fetchIpMemoryStore(@NonNull final IIpMemoryStoreCallbacks cb) 406 throws RemoteException { 407 mPermChecker.enforceNetworkStackCallingPermission(); 408 updateIpMemoryStoreAidlVersion(cb.getInterfaceVersion(), cb.getInterfaceHash()); 409 cb.onIpMemoryStoreFetched(mIpMemoryStoreService); 410 } 411 412 @Override allowTestUid(int uid, @Nullable INetworkStackStatusCallback cb)413 public void allowTestUid(int uid, @Nullable INetworkStackStatusCallback cb) 414 throws RemoteException { 415 // setTestUid does its own permission checks 416 PermissionUtil.setTestUid(mContext, uid); 417 mLog.i("Allowing test uid " + uid); 418 if (cb != null) cb.onStatusAvailable(0); 419 } 420 421 @Override @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) dump(@onNull FileDescriptor fd, @NonNull PrintWriter fout, @Nullable String[] args)422 public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter fout, 423 @Nullable String[] args) { 424 checkDumpPermission(); 425 426 final IndentingPrintWriter pw = new IndentingPrintWriter(fout, " "); 427 pw.println("NetworkStack version:"); 428 dumpVersion(pw); 429 pw.println(); 430 431 if (args != null && args.length >= 1 && DUMPSYS_ARG_VERSION.equals(args[0])) { 432 return; 433 } 434 435 pw.println("Device Configs:"); 436 pw.increaseIndent(); 437 pw.println("SKIP_TCP_POLL_IN_LIGHT_DOZE=" 438 + DeviceConfigUtils.isNetworkStackFeatureNotChickenedOut( 439 mContext, SKIP_TCP_POLL_IN_LIGHT_DOZE)); 440 pw.println("FEATURE_IS_UID_NETWORKING_BLOCKED=" + DeviceConfigUtils.isFeatureSupported( 441 mContext, FEATURE_IS_UID_NETWORKING_BLOCKED)); 442 pw.println("IGNORE_TCP_INFO_FOR_BLOCKED_UIDS=" 443 + DeviceConfigUtils.isNetworkStackFeatureNotChickenedOut(mContext, 444 IGNORE_TCP_INFO_FOR_BLOCKED_UIDS)); 445 pw.decreaseIndent(); 446 pw.println(); 447 448 449 pw.println("NetworkStack logs:"); 450 mLog.dump(fd, pw, args); 451 452 // Dump full IpClient logs for non-GCed clients 453 pw.println(); 454 pw.println("Recently active IpClient logs:"); 455 final ArrayList<IpClient> ipClients = new ArrayList<>(); 456 final HashSet<String> dumpedIpClientIfaces = new HashSet<>(); 457 synchronized (mIpClients) { 458 for (WeakReference<IpClient> ipcRef : mIpClients) { 459 final IpClient ipc = ipcRef.get(); 460 if (ipc != null) { 461 ipClients.add(ipc); 462 } 463 } 464 } 465 466 for (IpClient ipc : ipClients) { 467 pw.println(ipc.getName()); 468 pw.increaseIndent(); 469 ipc.dump(fd, pw, args); 470 pw.decreaseIndent(); 471 dumpedIpClientIfaces.add(ipc.getInterfaceName()); 472 } 473 474 // State machine and connectivity metrics logs are kept for GCed IpClients 475 pw.println(); 476 pw.println("Other IpClient logs:"); 477 IpClient.dumpAllLogs(fout, dumpedIpClientIfaces); 478 479 pw.println(); 480 pw.println("Validation logs (most recent first):"); 481 synchronized (mValidationLogs) { 482 for (SharedLog p : mValidationLogs) { 483 pw.println(p.getTag()); 484 pw.increaseIndent(); 485 p.dump(fd, pw, args); 486 pw.decreaseIndent(); 487 } 488 } 489 490 pw.println(); 491 pw.print("useNeighborResource: "); 492 pw.println(getResBooleanConfig(mContext, 493 R.bool.config_no_sim_card_uses_neighbor_mcc, false)); 494 } 495 496 @Override handleShellCommand(@onNull ParcelFileDescriptor in, @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err, @NonNull String[] args)497 public int handleShellCommand(@NonNull ParcelFileDescriptor in, 498 @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err, 499 @NonNull String[] args) { 500 return new ShellCmd().exec(this, in.getFileDescriptor(), out.getFileDescriptor(), 501 err.getFileDescriptor(), args); 502 } 503 apfShellCommand(String iface, String cmd, @Nullable String optarg)504 private String apfShellCommand(String iface, String cmd, @Nullable String optarg) { 505 synchronized (mIpClients) { 506 // HACK: An old IpClient serving the given interface name might not have been 507 // garbage collected. Since new IpClients are always appended to the list, iterate 508 // through it in reverse order to get the most up-to-date IpClient instance. 509 // Create a ListIterator at the end of the list. 510 final ListIterator it = mIpClients.listIterator(mIpClients.size()); 511 while (it.hasPrevious()) { 512 final IpClient ipClient = ((WeakReference<IpClient>) it.previous()).get(); 513 if (ipClient != null && ipClient.getInterfaceName().equals(iface)) { 514 return ipClient.apfShellCommand(cmd, optarg); 515 } 516 } 517 } 518 throw new IllegalArgumentException("No active IpClient found for interface " + iface); 519 } 520 521 private class ShellCmd extends BasicShellCommandHandler { 522 private static final long MAX_CAPTURE_CMD_WAITING_TIMEOUT_MS = 30_000L; 523 524 @Override onCommand(String cmd)525 public int onCommand(String cmd) { 526 if (cmd == null) { 527 return handleDefaultCommands(cmd); 528 } 529 final PrintWriter pw = getOutPrintWriter(); 530 switch (cmd) { 531 case "is-uid-networking-blocked": 532 if (!DeviceConfigUtils.isFeatureSupported(mContext, 533 FEATURE_IS_UID_NETWORKING_BLOCKED)) { 534 throw new IllegalStateException("API is unsupported"); 535 } 536 537 // Usage : cmd network_stack is-uid-networking-blocked <uid> <metered> 538 // If no argument, get and display the usage help. 539 if (getRemainingArgsCount() != 2) { 540 onHelp(); 541 throw new IllegalArgumentException("Incorrect number of arguments"); 542 } 543 final int uid; 544 final boolean metered; 545 uid = Integer.parseInt(getNextArg()); 546 metered = Boolean.parseBoolean(getNextArg()); 547 final ConnectivityManager cm = 548 mContext.getSystemService(ConnectivityManager.class); 549 pw.println(cm.isUidNetworkingBlocked(uid, metered /* isNetworkMetered */)); 550 return 0; 551 case "send-raw-packet-downstream": { 552 // Usage : cmd network_stack send-raw-packet-downstream 553 // <interface> <packet-in-hex> 554 // If no argument, get and display the usage help. 555 if (getRemainingArgsCount() != 2) { 556 onHelp(); 557 throw new IllegalArgumentException("Incorrect number of arguments"); 558 } 559 final String iface = getNextArg(); 560 final String packetInHex = getNextArg(); 561 try { 562 sendRawPacketDownStream(mContext, iface, packetInHex); 563 } catch (Exception e) { 564 throw new RuntimeException(e); 565 } 566 return 0; 567 } 568 case "capture": 569 // Usage: cmd network_stack capture <cmd> 570 HandlerUtils.runWithScissorsForDump( 571 sRawPacketTracker.getHandler(), 572 () -> captureShellCommand(mContext, peekRemainingArgs()), 573 MAX_CAPTURE_CMD_WAITING_TIMEOUT_MS 574 ); 575 return 0; 576 case "apf": 577 // Usage: cmd network_stack apf <iface> <cmd> 578 final String iface = getNextArg(); 579 if (iface == null) { 580 throw new IllegalArgumentException("No <iface> specified"); 581 } 582 583 final String subcmd = getNextArg(); 584 if (subcmd == null) { 585 throw new IllegalArgumentException("No <cmd> specified"); 586 } 587 588 final String optarg = getNextArg(); 589 if (getRemainingArgsCount() != 0) { 590 throw new IllegalArgumentException("Too many arguments passed"); 591 } 592 593 final String result = apfShellCommand(iface, subcmd, optarg); 594 pw.println(result); 595 return 0; 596 597 default: 598 return handleDefaultCommands(cmd); 599 } 600 } 601 602 @Override onHelp()603 public void onHelp() { 604 PrintWriter pw = getOutPrintWriter(); 605 pw.println("NetworkStack service commands:"); 606 pw.println(" help"); 607 pw.println(" Print this help text."); 608 pw.println(" is-uid-networking-blocked <uid> <metered>"); 609 pw.println(" Get whether the networking is blocked for given uid and metered."); 610 pw.println(" <uid>: The target uid."); 611 pw.println(" <metered>: [true|false], Whether the target network is metered."); 612 pw.println(" send-raw-packet-downstream <interface> <packet-in-hex>"); 613 pw.println(" Send raw packet for testing purpose."); 614 pw.println(" <interface>: Target interface name, note that this is limited"); 615 pw.println(" to tethering downstream for security considerations."); 616 pw.println(" <packet_in_hex>: A valid hexadecimal representation of "); 617 pw.println(" a packet starting from L2 header."); 618 pw.println(" capture <cmd>"); 619 pw.println(" APF utility commands for multi-devices tests."); 620 pw.println(" start <interface>"); 621 pw.println(" start capture packets in the received buffer."); 622 pw.println(" The capture is up to 300 sec, then it will stop."); 623 pw.println(" <interface>: Target interface name, note that this is limited"); 624 pw.println(" to tethering downstream for security considerations."); 625 pw.println(" stop <interface>"); 626 pw.println(" stop capture packets and clear the received buffer."); 627 pw.println(" matched-packet-counts <interface> <pkt-hex-string>"); 628 pw.println(" the <pkt-hex-string> starts from ether header."); 629 pw.println(" Expect to do full packet match."); 630 pw.println(" apf <iface> <cmd>"); 631 pw.println(" APF utility commands for integration tests."); 632 pw.println(" <iface>: the network interface the provided command operates on."); 633 pw.println(" <cmd>: [status]"); 634 pw.println(" status"); 635 pw.println(" returns whether the APF filter is \"running\" or \"paused\"."); 636 pw.println(" pause"); 637 pw.println(" pause APF filter generation."); 638 pw.println(" resume"); 639 pw.println(" resume APF filter generation."); 640 pw.println(" install <program-hex-string>"); 641 pw.println(" install the APF program contained in <program-hex-string>."); 642 pw.println(" The filter must be paused before installing a new program."); 643 pw.println(" capabilities"); 644 pw.println(" return the reported APF capabilities."); 645 pw.println(" Format: <apfVersion>,<maxProgramSize>,<packetFormat>"); 646 pw.println(" read"); 647 pw.println(" reads and returns the current state of APF memory."); 648 } 649 captureShellCommand( @onNull Context context, @NonNull String[] args )650 private void captureShellCommand( 651 @NonNull Context context, 652 @NonNull String[] args 653 ) { 654 if (args.length < 2) { 655 throw new IllegalArgumentException("Incorrect number of arguments"); 656 } 657 658 final String cmd = args[0]; 659 final String ifaceName = args[1]; 660 try { 661 RawSocketUtils.enforceTetheredInterface(context, ifaceName); 662 } catch (ExecutionException 663 | InterruptedException 664 | TimeoutException 665 | SecurityException e) { 666 throw new RuntimeException(e.getMessage()); 667 } 668 669 final PrintWriter pw = getOutPrintWriter(); 670 switch(cmd) { 671 case "start": 672 // Usage : cmd network_stack capture start <interface> 673 if (args.length != 2) { 674 throw new IllegalArgumentException("Incorrect number of arguments"); 675 } 676 677 sRawPacketTracker.startCapture(ifaceName, MAX_CAPTURE_TIME_MS); 678 pw.println("success"); 679 break; 680 case "matched-packet-counts": 681 // Usage : cmd network_stack capture matched-packet-counts 682 // <interface> <packet-in-hex> 683 // for example, there is an usage to get matched arp reply packet count 684 // in hex string format on the wlan0 interface 685 // cmd network_stack capture matched-packet-counts wlan0 \ 686 // "00010203040501020304050608060001080006040002010203040506c0a80101" + 687 // "000102030405c0a80102" 688 if (args.length != 3) { 689 throw new IllegalArgumentException("Incorrect number of arguments"); 690 } 691 692 final String packetInHex = args[2]; 693 694 // limit the input hex string up to 3000 (1500 bytes) 695 if (packetInHex.length() > 3000) { 696 throw new IllegalArgumentException("Packet Hex String over the limit"); 697 } 698 699 final int pktCnt = 700 sRawPacketTracker.getMatchedPacketCount(ifaceName, packetInHex); 701 pw.println(pktCnt); 702 break; 703 case "stop": 704 // Usage : cmd network_stack capture stop <interface> 705 if (args.length != 2) { 706 throw new IllegalArgumentException("Incorrect number of arguments"); 707 } 708 709 sRawPacketTracker.stopCapture(ifaceName); 710 pw.println("success"); 711 break; 712 default: 713 throw new IllegalArgumentException("Invalid apf command: " + cmd); 714 } 715 } 716 } 717 718 /** 719 * Dump version information of the module and detected system version. 720 */ dumpVersion(@onNull PrintWriter fout)721 private void dumpVersion(@NonNull PrintWriter fout) { 722 fout.println("LocalInterface:" + this.VERSION + ":" + this.HASH); 723 synchronized (mAidlVersions) { 724 // Sort versions for deterministic order in output 725 for (AidlVersion version : sortVersions(mAidlVersions)) { 726 fout.println(version); 727 } 728 } 729 } 730 sortVersions(Collection<AidlVersion> versions)731 private List<AidlVersion> sortVersions(Collection<AidlVersion> versions) { 732 final List<AidlVersion> sorted = new ArrayList<>(versions); 733 Collections.sort(sorted); 734 return sorted; 735 } 736 737 /** 738 * Legacy version of dumpVersion, only used for Q, as only the interface version number 739 * was used in Q. 740 * 741 * <p>Q behavior needs to be preserved as conformance tests for Q still expect this format. 742 * Once all conformance test suites are updated to expect the new format even on Q devices, 743 * this can be removed. 744 */ dumpVersionNumberOnly(@onNull PrintWriter fout)745 private void dumpVersionNumberOnly(@NonNull PrintWriter fout) { 746 fout.println("NetworkStackConnector: " + this.VERSION); 747 final SortedSet<Integer> systemServerVersions = new TreeSet<>(); 748 int netdVersion = VERSION_UNKNOWN; 749 synchronized (mAidlVersions) { 750 for (AidlVersion version : mAidlVersions) { 751 switch (version.mKey) { 752 case AIDL_KEY_IPMEMORYSTORE: 753 case AIDL_KEY_NETWORKSTACK: 754 systemServerVersions.add(version.mVersion); 755 break; 756 case AIDL_KEY_NETD: 757 netdVersion = version.mVersion; 758 break; 759 default: 760 break; 761 } 762 } 763 } 764 // TreeSet.toString is formatted as [a, b], but Q used ArraySet.toString formatted as 765 // {a, b}. ArraySet does not have guaranteed ordering, which was not a problem in Q 766 // when only one interface number was expected (and there was no unit test relying on 767 // the ordering). 768 fout.println("SystemServer: {" + TextUtils.join(", ", systemServerVersions) + "}"); 769 fout.println("Netd: " + netdVersion); 770 } 771 772 /** 773 * Get the version of the AIDL interface. 774 */ 775 @Override getInterfaceVersion()776 public int getInterfaceVersion() { 777 return this.VERSION; 778 } 779 780 @Override getInterfaceHash()781 public String getInterfaceHash() { 782 return this.HASH; 783 } 784 } 785 786 /** 787 * Proxy for {@link NetworkMonitor} that implements {@link INetworkMonitor}. 788 */ 789 @VisibleForTesting 790 public static class NetworkMonitorConnector extends INetworkMonitor.Stub { 791 @NonNull 792 private final NetworkMonitor mNm; 793 @NonNull 794 private final PermissionChecker mPermChecker; 795 NetworkMonitorConnector(@onNull NetworkMonitor nm, @NonNull PermissionChecker permChecker)796 public NetworkMonitorConnector(@NonNull NetworkMonitor nm, 797 @NonNull PermissionChecker permChecker) { 798 mNm = nm; 799 mPermChecker = permChecker; 800 } 801 802 @Override start()803 public void start() { 804 mPermChecker.enforceNetworkStackCallingPermission(); 805 mNm.start(); 806 } 807 808 @Override launchCaptivePortalApp()809 public void launchCaptivePortalApp() { 810 mPermChecker.enforceNetworkStackCallingPermission(); 811 mNm.launchCaptivePortalApp(); 812 } 813 814 @Override notifyCaptivePortalAppFinished(int response)815 public void notifyCaptivePortalAppFinished(int response) { 816 mPermChecker.enforceNetworkStackCallingPermission(); 817 mNm.notifyCaptivePortalAppFinished(response); 818 } 819 820 @Override setAcceptPartialConnectivity()821 public void setAcceptPartialConnectivity() { 822 mPermChecker.enforceNetworkStackCallingPermission(); 823 mNm.setAcceptPartialConnectivity(); 824 } 825 826 @Override forceReevaluation(int uid)827 public void forceReevaluation(int uid) { 828 mPermChecker.enforceNetworkStackCallingPermission(); 829 mNm.forceReevaluation(uid); 830 } 831 832 @Override notifyPrivateDnsChanged(PrivateDnsConfigParcel config)833 public void notifyPrivateDnsChanged(PrivateDnsConfigParcel config) { 834 mPermChecker.enforceNetworkStackCallingPermission(); 835 mNm.notifyPrivateDnsSettingsChanged(PrivateDnsConfig.fromParcel(config)); 836 } 837 838 @Override notifyDnsResponse(int returnCode)839 public void notifyDnsResponse(int returnCode) { 840 mPermChecker.enforceNetworkStackCallingPermission(); 841 mNm.notifyDnsResponse(returnCode); 842 } 843 844 /** 845 * Send a notification to NetworkMonitor indicating that the network is now connected. 846 * @Deprecated use notifyNetworkConnectedParcel, which also passes the NetworkAgentConfig. 847 */ 848 @Override notifyNetworkConnected(LinkProperties lp, NetworkCapabilities nc)849 public void notifyNetworkConnected(LinkProperties lp, NetworkCapabilities nc) { 850 mPermChecker.enforceNetworkStackCallingPermission(); 851 mNm.notifyNetworkConnected(lp, nc); 852 } 853 854 /** 855 * Send a notification to NetworkMonitor indicating that the network is now connected. 856 */ 857 @Override notifyNetworkConnectedParcel(NetworkMonitorParameters params)858 public void notifyNetworkConnectedParcel(NetworkMonitorParameters params) { 859 mPermChecker.enforceNetworkStackCallingPermission(); 860 mNm.notifyNetworkConnectedParcel(params); 861 } 862 863 @Override notifyNetworkDisconnected()864 public void notifyNetworkDisconnected() { 865 mPermChecker.enforceNetworkStackCallingPermission(); 866 mNm.notifyNetworkDisconnected(); 867 } 868 869 @Override notifyLinkPropertiesChanged(LinkProperties lp)870 public void notifyLinkPropertiesChanged(LinkProperties lp) { 871 mPermChecker.enforceNetworkStackCallingPermission(); 872 mNm.notifyLinkPropertiesChanged(lp); 873 } 874 875 @Override notifyNetworkCapabilitiesChanged(NetworkCapabilities nc)876 public void notifyNetworkCapabilitiesChanged(NetworkCapabilities nc) { 877 mPermChecker.enforceNetworkStackCallingPermission(); 878 mNm.notifyNetworkCapabilitiesChanged(nc); 879 } 880 881 @Override getInterfaceVersion()882 public int getInterfaceVersion() { 883 return this.VERSION; 884 } 885 886 @Override getInterfaceHash()887 public String getInterfaceHash() { 888 return this.HASH; 889 } 890 } 891 } 892