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.apf; 18 19 import static android.net.util.SocketUtils.makePacketSocketAddress; 20 import static android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY; 21 import static android.system.OsConstants.AF_PACKET; 22 import static android.system.OsConstants.ARPHRD_ETHER; 23 import static android.system.OsConstants.ETH_P_ARP; 24 import static android.system.OsConstants.ETH_P_IP; 25 import static android.system.OsConstants.ETH_P_IPV6; 26 import static android.system.OsConstants.IPPROTO_ICMPV6; 27 import static android.system.OsConstants.IPPROTO_TCP; 28 import static android.system.OsConstants.IPPROTO_UDP; 29 import static android.system.OsConstants.SOCK_RAW; 30 31 import static com.android.net.module.util.NetworkStackConstants.ETHER_BROADCAST; 32 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ECHO_REQUEST_TYPE; 33 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_NEIGHBOR_ADVERTISEMENT; 34 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ROUTER_ADVERTISEMENT; 35 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ROUTER_SOLICITATION; 36 import static com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_LEN; 37 import static com.android.networkstack.util.NetworkStackUtils.APF_USE_RA_LIFETIME_CALCULATION_FIX_VERSION; 38 39 import android.content.BroadcastReceiver; 40 import android.content.Context; 41 import android.content.Intent; 42 import android.content.IntentFilter; 43 import android.net.LinkAddress; 44 import android.net.LinkProperties; 45 import android.net.NattKeepalivePacketDataParcelable; 46 import android.net.TcpKeepalivePacketDataParcelable; 47 import android.net.apf.ApfGenerator.IllegalInstructionException; 48 import android.net.apf.ApfGenerator.Register; 49 import android.net.ip.IpClient.IpClientCallbacksWrapper; 50 import android.net.metrics.ApfProgramEvent; 51 import android.net.metrics.ApfStats; 52 import android.net.metrics.IpConnectivityLog; 53 import android.net.metrics.RaEvent; 54 import android.os.PowerManager; 55 import android.os.SystemClock; 56 import android.system.ErrnoException; 57 import android.system.Os; 58 import android.text.format.DateUtils; 59 import android.util.Log; 60 import android.util.SparseArray; 61 62 import androidx.annotation.Nullable; 63 64 import com.android.internal.annotations.GuardedBy; 65 import com.android.internal.annotations.VisibleForTesting; 66 import com.android.internal.util.HexDump; 67 import com.android.internal.util.IndentingPrintWriter; 68 import com.android.net.module.util.CollectionUtils; 69 import com.android.net.module.util.ConnectivityUtils; 70 import com.android.net.module.util.DeviceConfigUtils; 71 import com.android.net.module.util.InterfaceParams; 72 import com.android.net.module.util.SocketUtils; 73 import com.android.networkstack.util.NetworkStackUtils; 74 75 import java.io.ByteArrayOutputStream; 76 import java.io.FileDescriptor; 77 import java.io.IOException; 78 import java.net.Inet4Address; 79 import java.net.Inet6Address; 80 import java.net.InetAddress; 81 import java.net.SocketAddress; 82 import java.net.SocketException; 83 import java.net.UnknownHostException; 84 import java.nio.BufferUnderflowException; 85 import java.nio.ByteBuffer; 86 import java.nio.ByteOrder; 87 import java.nio.charset.StandardCharsets; 88 import java.util.ArrayList; 89 import java.util.Arrays; 90 import java.util.List; 91 92 /** 93 * For networks that support packet filtering via APF programs, {@code ApfFilter} 94 * listens for IPv6 ICMPv6 router advertisements (RAs) and generates APF programs to 95 * filter out redundant duplicate ones. 96 * 97 * Threading model: 98 * A collection of RAs we've received is kept in mRas. Generating APF programs uses mRas to 99 * know what RAs to filter for, thus generating APF programs is dependent on mRas. 100 * mRas can be accessed by multiple threads: 101 * - ReceiveThread, which listens for RAs and adds them to mRas, and generates APF programs. 102 * - callers of: 103 * - setMulticastFilter(), which can cause an APF program to be generated. 104 * - dump(), which dumps mRas among other things. 105 * - shutdown(), which clears mRas. 106 * So access to mRas is synchronized. 107 * 108 * @hide 109 */ 110 public class ApfFilter { 111 112 // Helper class for specifying functional filter parameters. 113 public static class ApfConfiguration { 114 public ApfCapabilities apfCapabilities; 115 public boolean multicastFilter; 116 public boolean ieee802_3Filter; 117 public int[] ethTypeBlackList; 118 public int minRdnssLifetimeSec; 119 } 120 121 // Enums describing the outcome of receiving an RA packet. 122 private static enum ProcessRaResult { 123 MATCH, // Received RA matched a known RA 124 DROPPED, // Received RA ignored due to MAX_RAS 125 PARSE_ERROR, // Received RA could not be parsed 126 ZERO_LIFETIME, // Received RA had 0 lifetime 127 UPDATE_NEW_RA, // APF program updated for new RA 128 UPDATE_EXPIRY // APF program updated for expiry 129 } 130 131 /** 132 * APF packet counters. 133 * 134 * Packet counters are 32bit big-endian values, and allocated near the end of the APF data 135 * buffer, using negative byte offsets, where -4 is equivalent to maximumApfProgramSize - 4, 136 * the last writable 32bit word. 137 */ 138 @VisibleForTesting 139 public static enum Counter { 140 RESERVED_OOB, // Points to offset 0 from the end of the buffer (out-of-bounds) 141 TOTAL_PACKETS, 142 PASSED_ARP, 143 PASSED_DHCP, 144 PASSED_IPV4, 145 PASSED_IPV6_NON_ICMP, 146 PASSED_IPV4_UNICAST, 147 PASSED_IPV6_ICMP, 148 PASSED_IPV6_UNICAST_NON_ICMP, 149 PASSED_ARP_NON_IPV4, 150 PASSED_ARP_UNKNOWN, 151 PASSED_ARP_UNICAST_REPLY, 152 PASSED_NON_IP_UNICAST, 153 PASSED_MDNS, 154 DROPPED_ETH_BROADCAST, 155 DROPPED_RA, 156 DROPPED_GARP_REPLY, 157 DROPPED_ARP_OTHER_HOST, 158 DROPPED_IPV4_L2_BROADCAST, 159 DROPPED_IPV4_BROADCAST_ADDR, 160 DROPPED_IPV4_BROADCAST_NET, 161 DROPPED_IPV4_MULTICAST, 162 DROPPED_IPV6_ROUTER_SOLICITATION, 163 DROPPED_IPV6_MULTICAST_NA, 164 DROPPED_IPV6_MULTICAST, 165 DROPPED_IPV6_MULTICAST_PING, 166 DROPPED_IPV6_NON_ICMP_MULTICAST, 167 DROPPED_802_3_FRAME, 168 DROPPED_ETHERTYPE_BLACKLISTED, 169 DROPPED_ARP_REPLY_SPA_NO_HOST, 170 DROPPED_IPV4_KEEPALIVE_ACK, 171 DROPPED_IPV6_KEEPALIVE_ACK, 172 DROPPED_IPV4_NATT_KEEPALIVE, 173 DROPPED_MDNS; 174 175 // Returns the negative byte offset from the end of the APF data segment for 176 // a given counter. offset()177 public int offset() { 178 return - this.ordinal() * 4; // Currently, all counters are 32bit long. 179 } 180 181 // Returns the total size of the data segment in bytes. totalSize()182 public static int totalSize() { 183 return (Counter.class.getEnumConstants().length - 1) * 4; 184 } 185 } 186 187 /** 188 * When APFv4 is supported, loads R1 with the offset of the specified counter. 189 */ maybeSetupCounter(ApfGenerator gen, Counter c)190 private void maybeSetupCounter(ApfGenerator gen, Counter c) { 191 if (mApfCapabilities.hasDataAccess()) { 192 gen.addLoadImmediate(Register.R1, c.offset()); 193 } 194 } 195 196 // When APFv4 is supported, these point to the trampolines generated by emitEpilogue(). 197 // Otherwise, they're just aliases for PASS_LABEL and DROP_LABEL. 198 private final String mCountAndPassLabel; 199 private final String mCountAndDropLabel; 200 201 // Thread to listen for RAs. 202 @VisibleForTesting 203 public class ReceiveThread extends Thread { 204 private final byte[] mPacket = new byte[1514]; 205 private final FileDescriptor mSocket; 206 private final long mStart = SystemClock.elapsedRealtime(); 207 208 private int mReceivedRas = 0; 209 private int mMatchingRas = 0; 210 private int mDroppedRas = 0; 211 private int mParseErrors = 0; 212 private int mZeroLifetimeRas = 0; 213 private int mProgramUpdates = 0; 214 215 private volatile boolean mStopped; 216 ReceiveThread(FileDescriptor socket)217 public ReceiveThread(FileDescriptor socket) { 218 mSocket = socket; 219 } 220 halt()221 public void halt() { 222 mStopped = true; 223 // Interrupts the read() call the thread is blocked in. 224 SocketUtils.closeSocketQuietly(mSocket); 225 } 226 227 @Override run()228 public void run() { 229 log("begin monitoring"); 230 while (!mStopped) { 231 try { 232 int length = Os.read(mSocket, mPacket, 0, mPacket.length); 233 updateStats(processRa(mPacket, length)); 234 } catch (IOException|ErrnoException e) { 235 if (!mStopped) { 236 Log.e(TAG, "Read error", e); 237 } 238 } 239 } 240 logStats(); 241 } 242 updateStats(ProcessRaResult result)243 private void updateStats(ProcessRaResult result) { 244 mReceivedRas++; 245 switch(result) { 246 case MATCH: 247 mMatchingRas++; 248 return; 249 case DROPPED: 250 mDroppedRas++; 251 return; 252 case PARSE_ERROR: 253 mParseErrors++; 254 return; 255 case ZERO_LIFETIME: 256 mZeroLifetimeRas++; 257 return; 258 case UPDATE_EXPIRY: 259 mMatchingRas++; 260 mProgramUpdates++; 261 return; 262 case UPDATE_NEW_RA: 263 mProgramUpdates++; 264 return; 265 } 266 } 267 logStats()268 private void logStats() { 269 final long nowMs = SystemClock.elapsedRealtime(); 270 synchronized (this) { 271 final ApfStats stats = new ApfStats.Builder() 272 .setReceivedRas(mReceivedRas) 273 .setMatchingRas(mMatchingRas) 274 .setDroppedRas(mDroppedRas) 275 .setParseErrors(mParseErrors) 276 .setZeroLifetimeRas(mZeroLifetimeRas) 277 .setProgramUpdates(mProgramUpdates) 278 .setDurationMs(nowMs - mStart) 279 .setMaxProgramSize(mApfCapabilities.maximumApfProgramSize) 280 .setProgramUpdatesAll(mNumProgramUpdates) 281 .setProgramUpdatesAllowingMulticast(mNumProgramUpdatesAllowingMulticast) 282 .build(); 283 mMetricsLog.log(stats); 284 logApfProgramEventLocked(nowMs / DateUtils.SECOND_IN_MILLIS); 285 } 286 } 287 } 288 289 private static final String TAG = "ApfFilter"; 290 private static final boolean DBG = true; 291 private static final boolean VDBG = false; 292 293 private static final int ETH_HEADER_LEN = 14; 294 private static final int ETH_DEST_ADDR_OFFSET = 0; 295 private static final int ETH_ETHERTYPE_OFFSET = 12; 296 private static final int ETH_TYPE_MIN = 0x0600; 297 private static final int ETH_TYPE_MAX = 0xFFFF; 298 // TODO: Make these offsets relative to end of link-layer header; don't include ETH_HEADER_LEN. 299 private static final int IPV4_TOTAL_LENGTH_OFFSET = ETH_HEADER_LEN + 2; 300 private static final int IPV4_FRAGMENT_OFFSET_OFFSET = ETH_HEADER_LEN + 6; 301 // Endianness is not an issue for this constant because the APF interpreter always operates in 302 // network byte order. 303 private static final int IPV4_FRAGMENT_OFFSET_MASK = 0x1fff; 304 private static final int IPV4_PROTOCOL_OFFSET = ETH_HEADER_LEN + 9; 305 private static final int IPV4_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 16; 306 private static final int IPV4_ANY_HOST_ADDRESS = 0; 307 private static final int IPV4_BROADCAST_ADDRESS = -1; // 255.255.255.255 308 private static final int IPV4_HEADER_LEN = 20; // Without options 309 310 // Traffic class and Flow label are not byte aligned. Luckily we 311 // don't care about either value so we'll consider bytes 1-3 of the 312 // IPv6 header as don't care. 313 private static final int IPV6_FLOW_LABEL_OFFSET = ETH_HEADER_LEN + 1; 314 private static final int IPV6_FLOW_LABEL_LEN = 3; 315 private static final int IPV6_NEXT_HEADER_OFFSET = ETH_HEADER_LEN + 6; 316 private static final int IPV6_SRC_ADDR_OFFSET = ETH_HEADER_LEN + 8; 317 private static final int IPV6_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 24; 318 private static final int IPV6_HEADER_LEN = 40; 319 // The IPv6 all nodes address ff02::1 320 private static final byte[] IPV6_ALL_NODES_ADDRESS = 321 { (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; 322 323 private static final int ICMP6_TYPE_OFFSET = ETH_HEADER_LEN + IPV6_HEADER_LEN; 324 325 // NOTE: this must be added to the IPv4 header length in IPV4_HEADER_SIZE_MEMORY_SLOT 326 private static final int UDP_DESTINATION_PORT_OFFSET = ETH_HEADER_LEN + 2; 327 private static final int UDP_HEADER_LEN = 8; 328 329 private static final int TCP_HEADER_SIZE_OFFSET = 12; 330 331 private static final int DHCP_CLIENT_PORT = 68; 332 // NOTE: this must be added to the IPv4 header length in IPV4_HEADER_SIZE_MEMORY_SLOT 333 private static final int DHCP_CLIENT_MAC_OFFSET = ETH_HEADER_LEN + UDP_HEADER_LEN + 28; 334 335 private static final int ARP_HEADER_OFFSET = ETH_HEADER_LEN; 336 private static final byte[] ARP_IPV4_HEADER = { 337 0, 1, // Hardware type: Ethernet (1) 338 8, 0, // Protocol type: IP (0x0800) 339 6, // Hardware size: 6 340 4, // Protocol size: 4 341 }; 342 private static final int ARP_OPCODE_OFFSET = ARP_HEADER_OFFSET + 6; 343 // Opcode: ARP request (0x0001), ARP reply (0x0002) 344 private static final short ARP_OPCODE_REQUEST = 1; 345 private static final short ARP_OPCODE_REPLY = 2; 346 private static final int ARP_SOURCE_IP_ADDRESS_OFFSET = ARP_HEADER_OFFSET + 14; 347 private static final int ARP_TARGET_IP_ADDRESS_OFFSET = ARP_HEADER_OFFSET + 24; 348 // Do not log ApfProgramEvents whose actual lifetimes was less than this. 349 private static final int APF_PROGRAM_EVENT_LIFETIME_THRESHOLD = 2; 350 // Limit on the Black List size to cap on program usage for this 351 // TODO: Select a proper max length 352 private static final int APF_MAX_ETH_TYPE_BLACK_LIST_LEN = 20; 353 354 private static final byte[] ETH_MULTICAST_MDNS_V4_MAC_ADDRESS = 355 {(byte) 0x01, (byte) 0x00, (byte) 0x5e, (byte) 0x00, (byte) 0x00, (byte) 0xfb}; 356 private static final byte[] ETH_MULTICAST_MDNS_V6_MAC_ADDRESS = 357 {(byte) 0x33, (byte) 0x33, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xfb}; 358 private static final int MDNS_PORT = 5353; 359 private static final int DNS_HEADER_LEN = 12; 360 private static final int DNS_QDCOUNT_OFFSET = 4; 361 // NOTE: this must be added to the IPv4 header length in IPV4_HEADER_SIZE_MEMORY_SLOT, or the 362 // IPv6 header length. 363 private static final int MDNS_QDCOUNT_OFFSET = 364 ETH_HEADER_LEN + UDP_HEADER_LEN + DNS_QDCOUNT_OFFSET; 365 private static final int MDNS_QNAME_OFFSET = 366 ETH_HEADER_LEN + UDP_HEADER_LEN + DNS_HEADER_LEN; 367 368 369 370 private final ApfCapabilities mApfCapabilities; 371 private final IpClientCallbacksWrapper mIpClientCallback; 372 private final InterfaceParams mInterfaceParams; 373 private final IpConnectivityLog mMetricsLog; 374 375 @VisibleForTesting 376 public byte[] mHardwareAddress; 377 @VisibleForTesting 378 public ReceiveThread mReceiveThread; 379 @GuardedBy("this") 380 private long mUniqueCounter; 381 @GuardedBy("this") 382 private boolean mMulticastFilter; 383 @GuardedBy("this") 384 private boolean mInDozeMode; 385 private final boolean mDrop802_3Frames; 386 private final int[] mEthTypeBlackList; 387 388 // Ignore non-zero RDNSS lifetimes below this value. 389 private final int mMinRdnssLifetimeSec; 390 391 // Flag to use the RA lifetime calculation fix in aosp/2276160. 392 private final boolean mUseLifetimeCalculationFix; 393 394 // Detects doze mode state transitions. 395 private final BroadcastReceiver mDeviceIdleReceiver = new BroadcastReceiver() { 396 @Override 397 public void onReceive(Context context, Intent intent) { 398 String action = intent.getAction(); 399 if (action.equals(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED)) { 400 PowerManager powerManager = 401 (PowerManager) context.getSystemService(Context.POWER_SERVICE); 402 final boolean deviceIdle = powerManager.isDeviceIdleMode(); 403 setDozeMode(deviceIdle); 404 } 405 } 406 }; 407 private final Context mContext; 408 409 // Our IPv4 address, if we have just one, otherwise null. 410 @GuardedBy("this") 411 private byte[] mIPv4Address; 412 // The subnet prefix length of our IPv4 network. Only valid if mIPv4Address is not null. 413 @GuardedBy("this") 414 private int mIPv4PrefixLength; 415 416 /** 417 * Dependencies for the ApfFilter. Useful to be mocked in tests. 418 */ 419 public static class Dependencies { 420 /** 421 * Return whether a feature guarded by a feature flag is enabled. 422 * @see NetworkStackUtils#isFeatureEnabled(Context, String, String) 423 */ isFeatureEnabled(final Context context, final String name, boolean defaultEnabled)424 public boolean isFeatureEnabled(final Context context, final String name, 425 boolean defaultEnabled) { 426 return DeviceConfigUtils.isFeatureEnabled(context, NAMESPACE_CONNECTIVITY, name, 427 defaultEnabled); 428 } 429 } 430 ApfFilter(Context context, ApfConfiguration config, InterfaceParams ifParams, IpClientCallbacksWrapper ipClientCallback, IpConnectivityLog log)431 public ApfFilter(Context context, ApfConfiguration config, InterfaceParams ifParams, 432 IpClientCallbacksWrapper ipClientCallback, IpConnectivityLog log) { 433 this(context, config, ifParams, ipClientCallback, log, new Dependencies()); 434 } 435 436 @VisibleForTesting ApfFilter(Context context, ApfConfiguration config, InterfaceParams ifParams, IpClientCallbacksWrapper ipClientCallback, IpConnectivityLog log, Dependencies deps)437 public ApfFilter(Context context, ApfConfiguration config, InterfaceParams ifParams, 438 IpClientCallbacksWrapper ipClientCallback, IpConnectivityLog log, Dependencies deps) { 439 mApfCapabilities = config.apfCapabilities; 440 mIpClientCallback = ipClientCallback; 441 mInterfaceParams = ifParams; 442 mMulticastFilter = config.multicastFilter; 443 mDrop802_3Frames = config.ieee802_3Filter; 444 mMinRdnssLifetimeSec = config.minRdnssLifetimeSec; 445 mUseLifetimeCalculationFix = deps.isFeatureEnabled(context, 446 APF_USE_RA_LIFETIME_CALCULATION_FIX_VERSION, true /* defaultEnabled */); 447 mContext = context; 448 449 if (mApfCapabilities.hasDataAccess()) { 450 mCountAndPassLabel = "countAndPass"; 451 mCountAndDropLabel = "countAndDrop"; 452 } else { 453 // APFv4 unsupported: turn jumps to the counter trampolines to immediately PASS or DROP, 454 // preserving the original pre-APFv4 behavior. 455 mCountAndPassLabel = ApfGenerator.PASS_LABEL; 456 mCountAndDropLabel = ApfGenerator.DROP_LABEL; 457 } 458 459 // Now fill the black list from the passed array 460 mEthTypeBlackList = filterEthTypeBlackList(config.ethTypeBlackList); 461 462 mMetricsLog = log; 463 464 // TODO: ApfFilter should not generate programs until IpClient sends provisioning success. 465 maybeStartFilter(); 466 467 // Listen for doze-mode transition changes to enable/disable the IPv6 multicast filter. 468 mContext.registerReceiver(mDeviceIdleReceiver, 469 new IntentFilter(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED)); 470 } 471 setDataSnapshot(byte[] data)472 public synchronized void setDataSnapshot(byte[] data) { 473 mDataSnapshot = data; 474 } 475 log(String s)476 private void log(String s) { 477 Log.d(TAG, "(" + mInterfaceParams.name + "): " + s); 478 } 479 480 @GuardedBy("this") getUniqueNumberLocked()481 private long getUniqueNumberLocked() { 482 return mUniqueCounter++; 483 } 484 485 @GuardedBy("this") filterEthTypeBlackList(int[] ethTypeBlackList)486 private static int[] filterEthTypeBlackList(int[] ethTypeBlackList) { 487 ArrayList<Integer> bl = new ArrayList<Integer>(); 488 489 for (int p : ethTypeBlackList) { 490 // Check if the protocol is a valid ether type 491 if ((p < ETH_TYPE_MIN) || (p > ETH_TYPE_MAX)) { 492 continue; 493 } 494 495 // Check if the protocol is not repeated in the passed array 496 if (bl.contains(p)) { 497 continue; 498 } 499 500 // Check if list reach its max size 501 if (bl.size() == APF_MAX_ETH_TYPE_BLACK_LIST_LEN) { 502 Log.w(TAG, "Passed EthType Black List size too large (" + bl.size() + 503 ") using top " + APF_MAX_ETH_TYPE_BLACK_LIST_LEN + " protocols"); 504 break; 505 } 506 507 // Now add the protocol to the list 508 bl.add(p); 509 } 510 511 return bl.stream().mapToInt(Integer::intValue).toArray(); 512 } 513 514 /** 515 * Attempt to start listening for RAs and, if RAs are received, generating and installing 516 * filters to ignore useless RAs. 517 */ 518 @VisibleForTesting maybeStartFilter()519 public void maybeStartFilter() { 520 FileDescriptor socket; 521 try { 522 mHardwareAddress = mInterfaceParams.macAddr.toByteArray(); 523 synchronized(this) { 524 // Clear the APF memory to reset all counters upon connecting to the first AP 525 // in an SSID. This is limited to APFv4 devices because this large write triggers 526 // a crash on some older devices (b/78905546). 527 if (mApfCapabilities.hasDataAccess()) { 528 byte[] zeroes = new byte[mApfCapabilities.maximumApfProgramSize]; 529 mIpClientCallback.installPacketFilter(zeroes); 530 } 531 532 // Install basic filters 533 installNewProgramLocked(); 534 } 535 socket = Os.socket(AF_PACKET, SOCK_RAW, ETH_P_IPV6); 536 SocketAddress addr = makePacketSocketAddress(ETH_P_IPV6, mInterfaceParams.index); 537 Os.bind(socket, addr); 538 NetworkStackUtils.attachRaFilter(socket, mApfCapabilities.apfPacketFormat); 539 } catch(SocketException|ErrnoException e) { 540 Log.e(TAG, "Error starting filter", e); 541 return; 542 } 543 mReceiveThread = new ReceiveThread(socket); 544 mReceiveThread.start(); 545 } 546 547 // Returns seconds since device boot. 548 @VisibleForTesting currentTimeSeconds()549 protected long currentTimeSeconds() { 550 return SystemClock.elapsedRealtime() / DateUtils.SECOND_IN_MILLIS; 551 } 552 553 public static class InvalidRaException extends Exception { InvalidRaException(String m)554 public InvalidRaException(String m) { 555 super(m); 556 } 557 } 558 559 /** 560 * Class to keep track of a section in a packet. 561 */ 562 private static class PacketSection { 563 public enum Type { 564 MATCH, // A field that should be matched (e.g., the router IP address). 565 IGNORE, // An ignored field such as the checksum of the flow label. Not matched. 566 LIFETIME, // A lifetime. Not matched, and generally counts toward minimum RA lifetime. 567 } 568 569 /** The type of section. */ 570 public final Type type; 571 /** Offset into the packet at which this section begins. */ 572 public final int start; 573 /** Length of this section in bytes. */ 574 public final int length; 575 /** If this is a lifetime, the ICMP option that defined it. 0 for router lifetime. */ 576 public final int option; 577 /** If this is a lifetime, the lifetime value. */ 578 public final long lifetime; 579 PacketSection(int start, int length, Type type, int option, long lifetime)580 PacketSection(int start, int length, Type type, int option, long lifetime) { 581 this.start = start; 582 this.length = length; 583 this.type = type; 584 this.option = option; 585 this.lifetime = lifetime; 586 } 587 toString()588 public String toString() { 589 if (type == Type.LIFETIME) { 590 return String.format("%s: (%d, %d) %d %d", type, start, length, option, lifetime); 591 } else { 592 return String.format("%s: (%d, %d)", type, start, length); 593 } 594 } 595 } 596 597 // A class to hold information about an RA. 598 @VisibleForTesting 599 public class Ra { 600 // From RFC4861: 601 private static final int ICMP6_RA_HEADER_LEN = 16; 602 private static final int ICMP6_RA_CHECKSUM_OFFSET = 603 ETH_HEADER_LEN + IPV6_HEADER_LEN + 2; 604 private static final int ICMP6_RA_CHECKSUM_LEN = 2; 605 private static final int ICMP6_RA_OPTION_OFFSET = 606 ETH_HEADER_LEN + IPV6_HEADER_LEN + ICMP6_RA_HEADER_LEN; 607 private static final int ICMP6_RA_ROUTER_LIFETIME_OFFSET = 608 ETH_HEADER_LEN + IPV6_HEADER_LEN + 6; 609 private static final int ICMP6_RA_ROUTER_LIFETIME_LEN = 2; 610 // Prefix information option. 611 private static final int ICMP6_PREFIX_OPTION_TYPE = 3; 612 private static final int ICMP6_PREFIX_OPTION_LEN = 32; 613 private static final int ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET = 4; 614 private static final int ICMP6_PREFIX_OPTION_VALID_LIFETIME_LEN = 4; 615 private static final int ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET = 8; 616 private static final int ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_LEN = 4; 617 618 // From RFC6106: Recursive DNS Server option 619 private static final int ICMP6_RDNSS_OPTION_TYPE = 25; 620 // From RFC6106: DNS Search List option 621 private static final int ICMP6_DNSSL_OPTION_TYPE = 31; 622 623 // From RFC4191: Route Information option 624 private static final int ICMP6_ROUTE_INFO_OPTION_TYPE = 24; 625 // Above three options all have the same format: 626 private static final int ICMP6_4_BYTE_LIFETIME_OFFSET = 4; 627 private static final int ICMP6_4_BYTE_LIFETIME_LEN = 4; 628 629 // Note: mPacket's position() cannot be assumed to be reset. 630 private final ByteBuffer mPacket; 631 632 // List of sections in the packet. 633 private final ArrayList<PacketSection> mPacketSections = new ArrayList<>(); 634 635 // Minimum lifetime in packet 636 long mMinLifetime; 637 // When the packet was last captured, in seconds since Unix Epoch 638 long mLastSeen; 639 640 // For debugging only. Offsets into the packet where PIOs are. 641 private final ArrayList<Integer> mPrefixOptionOffsets = new ArrayList<>(); 642 643 // For debugging only. Offsets into the packet where RDNSS options are. 644 private final ArrayList<Integer> mRdnssOptionOffsets = new ArrayList<>(); 645 646 // For debugging only. Offsets into the packet where RIO options are. 647 private final ArrayList<Integer> mRioOptionOffsets = new ArrayList<>(); 648 649 // For debugging only. How many times this RA was seen. 650 int seenCount = 0; 651 652 // For debugging only. Returns the hex representation of the last matching packet. getLastMatchingPacket()653 String getLastMatchingPacket() { 654 return HexDump.toHexString(mPacket.array(), 0, mPacket.capacity(), 655 false /* lowercase */); 656 } 657 658 // For debugging only. Returns the string representation of the IPv6 address starting at 659 // position pos in the packet. IPv6AddresstoString(int pos)660 private String IPv6AddresstoString(int pos) { 661 try { 662 byte[] array = mPacket.array(); 663 // Can't just call copyOfRange() and see if it throws, because if it reads past the 664 // end it pads with zeros instead of throwing. 665 if (pos < 0 || pos + 16 > array.length || pos + 16 < pos) { 666 return "???"; 667 } 668 byte[] addressBytes = Arrays.copyOfRange(array, pos, pos + 16); 669 InetAddress address = (Inet6Address) InetAddress.getByAddress(addressBytes); 670 return address.getHostAddress(); 671 } catch (UnsupportedOperationException e) { 672 // array() failed. Cannot happen, mPacket is array-backed and read-write. 673 return "???"; 674 } catch (ClassCastException|UnknownHostException e) { 675 // Cannot happen. 676 return "???"; 677 } 678 } 679 680 // Can't be static because it's in a non-static inner class. 681 // TODO: Make this static once RA is its own class. prefixOptionToString(StringBuffer sb, int offset)682 private void prefixOptionToString(StringBuffer sb, int offset) { 683 String prefix = IPv6AddresstoString(offset + 16); 684 int length = getUint8(mPacket, offset + 2); 685 long valid = getUint32(mPacket, offset + 4); 686 long preferred = getUint32(mPacket, offset + 8); 687 sb.append(String.format("%s/%d %ds/%ds ", prefix, length, valid, preferred)); 688 } 689 rdnssOptionToString(StringBuffer sb, int offset)690 private void rdnssOptionToString(StringBuffer sb, int offset) { 691 int optLen = getUint8(mPacket, offset + 1) * 8; 692 if (optLen < 24) return; // Malformed or empty. 693 long lifetime = getUint32(mPacket, offset + 4); 694 int numServers = (optLen - 8) / 16; 695 sb.append("DNS ").append(lifetime).append("s"); 696 for (int server = 0; server < numServers; server++) { 697 sb.append(" ").append(IPv6AddresstoString(offset + 8 + 16 * server)); 698 } 699 sb.append(" "); 700 } 701 rioOptionToString(StringBuffer sb, int offset)702 private void rioOptionToString(StringBuffer sb, int offset) { 703 int optLen = getUint8(mPacket, offset + 1) * 8; 704 if (optLen < 8 || optLen > 24) return; // Malformed or empty. 705 int prefixLen = getUint8(mPacket, offset + 2); 706 long lifetime = getUint32(mPacket, offset + 4); 707 708 // This read is variable length because the prefix can be 0, 8 or 16 bytes long. 709 // We can't use any of the ByteBuffer#get methods here because they all start reading 710 // from the buffer's current position. 711 byte[] prefix = new byte[IPV6_ADDR_LEN]; 712 System.arraycopy(mPacket.array(), offset + 8, prefix, 0, optLen - 8); 713 sb.append("RIO ").append(lifetime).append("s "); 714 try { 715 InetAddress address = (Inet6Address) InetAddress.getByAddress(prefix); 716 sb.append(address.getHostAddress()); 717 } catch (UnknownHostException impossible) { 718 sb.append("???"); 719 } 720 sb.append("/").append(prefixLen).append(" "); 721 } 722 toString()723 public String toString() { 724 try { 725 StringBuffer sb = new StringBuffer(); 726 sb.append(String.format("RA %s -> %s %ds ", 727 IPv6AddresstoString(IPV6_SRC_ADDR_OFFSET), 728 IPv6AddresstoString(IPV6_DEST_ADDR_OFFSET), 729 getUint16(mPacket, ICMP6_RA_ROUTER_LIFETIME_OFFSET))); 730 for (int i: mPrefixOptionOffsets) { 731 prefixOptionToString(sb, i); 732 } 733 for (int i: mRdnssOptionOffsets) { 734 rdnssOptionToString(sb, i); 735 } 736 for (int i: mRioOptionOffsets) { 737 rioOptionToString(sb, i); 738 } 739 return sb.toString(); 740 } catch (BufferUnderflowException|IndexOutOfBoundsException e) { 741 return "<Malformed RA>"; 742 } 743 } 744 745 /** 746 * Add a packet section that should be matched, starting from the current position. 747 * @param length the length of the section 748 */ addMatchSection(int length)749 private void addMatchSection(int length) { 750 // Don't generate JNEBS instruction for 0 bytes as they will fail the 751 // ASSERT_FORWARD_IN_PROGRAM(pc + cmp_imm - 1) check (where cmp_imm is 752 // the number of bytes to compare) and immediately pass the packet. 753 // The code does not attempt to generate such matches, but add a safety 754 // check to prevent doing so in the presence of bugs or malformed or 755 // truncated packets. 756 if (length == 0) return; 757 mPacketSections.add( 758 new PacketSection(mPacket.position(), length, PacketSection.Type.MATCH, 0, 0)); 759 mPacket.position(mPacket.position() + length); 760 } 761 762 /** 763 * Add a packet section that should be matched, starting from the current position. 764 * @param end the offset in the packet before which the section ends 765 */ addMatchUntil(int end)766 private void addMatchUntil(int end) { 767 addMatchSection(end - mPacket.position()); 768 } 769 770 /** 771 * Add a packet section that should be ignored, starting from the current position. 772 * @param length the length of the section in bytes 773 */ addIgnoreSection(int length)774 private void addIgnoreSection(int length) { 775 mPacketSections.add( 776 new PacketSection(mPacket.position(), length, PacketSection.Type.IGNORE, 0, 0)); 777 mPacket.position(mPacket.position() + length); 778 } 779 780 /** 781 * Add a packet section that represents a lifetime, starting from the current position. 782 * @param length the length of the section in bytes 783 * @param optionType the RA option containing this lifetime, or 0 for router lifetime 784 * @param lifetime the lifetime 785 */ addLifetimeSection(int length, int optionType, long lifetime)786 private void addLifetimeSection(int length, int optionType, long lifetime) { 787 mPacketSections.add( 788 new PacketSection(mPacket.position(), length, PacketSection.Type.LIFETIME, 789 optionType, lifetime)); 790 mPacket.position(mPacket.position() + length); 791 } 792 793 /** 794 * Adds packet sections for an RA option with a 4-byte lifetime 4 bytes into the option 795 * @param optionType the RA option that is being added 796 * @param optionLength the length of the option in bytes 797 */ add4ByteLifetimeOption(int optionType, int optionLength)798 private long add4ByteLifetimeOption(int optionType, int optionLength) { 799 addMatchSection(ICMP6_4_BYTE_LIFETIME_OFFSET); 800 final long lifetime = getUint32(mPacket, mPacket.position()); 801 addLifetimeSection(ICMP6_4_BYTE_LIFETIME_LEN, optionType, lifetime); 802 addMatchSection(optionLength - ICMP6_4_BYTE_LIFETIME_OFFSET 803 - ICMP6_4_BYTE_LIFETIME_LEN); 804 return lifetime; 805 } 806 807 // http://b/66928272 http://b/65056012 808 // DnsServerRepository ignores RDNSS servers with lifetimes that are too low. Ignore these 809 // lifetimes for the purpose of filter lifetime calculations. shouldIgnoreLifetime(int optionType, long lifetime)810 private boolean shouldIgnoreLifetime(int optionType, long lifetime) { 811 return optionType == ICMP6_RDNSS_OPTION_TYPE 812 && lifetime != 0 && lifetime < mMinRdnssLifetimeSec; 813 } 814 isRelevantLifetime(PacketSection section)815 private boolean isRelevantLifetime(PacketSection section) { 816 return section.type == PacketSection.Type.LIFETIME 817 && !shouldIgnoreLifetime(section.option, section.lifetime); 818 } 819 820 // Note that this parses RA and may throw InvalidRaException (from 821 // Buffer.position(int) or due to an invalid-length option) or IndexOutOfBoundsException 822 // (from ByteBuffer.get(int) ) if parsing encounters something non-compliant with 823 // specifications. 824 @VisibleForTesting Ra(byte[] packet, int length)825 public Ra(byte[] packet, int length) throws InvalidRaException { 826 if (length < ICMP6_RA_OPTION_OFFSET) { 827 throw new InvalidRaException("Not an ICMP6 router advertisement: too short"); 828 } 829 830 mPacket = ByteBuffer.wrap(Arrays.copyOf(packet, length)); 831 mLastSeen = currentTimeSeconds(); 832 833 // Check packet in case a packet arrives before we attach RA filter 834 // to our packet socket. b/29586253 835 if (getUint16(mPacket, ETH_ETHERTYPE_OFFSET) != ETH_P_IPV6 || 836 getUint8(mPacket, IPV6_NEXT_HEADER_OFFSET) != IPPROTO_ICMPV6 || 837 getUint8(mPacket, ICMP6_TYPE_OFFSET) != ICMPV6_ROUTER_ADVERTISEMENT) { 838 throw new InvalidRaException("Not an ICMP6 router advertisement"); 839 } 840 841 842 RaEvent.Builder builder = new RaEvent.Builder(); 843 844 // Ignore the flow label and low 4 bits of traffic class. 845 addMatchUntil(IPV6_FLOW_LABEL_OFFSET); 846 addIgnoreSection(IPV6_FLOW_LABEL_LEN); 847 848 // Ignore checksum. 849 addMatchUntil(ICMP6_RA_CHECKSUM_OFFSET); 850 addIgnoreSection(ICMP6_RA_CHECKSUM_LEN); 851 852 // Parse router lifetime 853 addMatchUntil(ICMP6_RA_ROUTER_LIFETIME_OFFSET); 854 final long routerLifetime = getUint16(mPacket, ICMP6_RA_ROUTER_LIFETIME_OFFSET); 855 addLifetimeSection(ICMP6_RA_ROUTER_LIFETIME_LEN, 0, routerLifetime); 856 builder.updateRouterLifetime(routerLifetime); 857 858 // Add remaining fields (reachable time and retransmission timer) to match section. 859 addMatchUntil(ICMP6_RA_OPTION_OFFSET); 860 861 while (mPacket.hasRemaining()) { 862 final int position = mPacket.position(); 863 final int optionType = getUint8(mPacket, position); 864 final int optionLength = getUint8(mPacket, position + 1) * 8; 865 long lifetime; 866 switch (optionType) { 867 case ICMP6_PREFIX_OPTION_TYPE: 868 mPrefixOptionOffsets.add(position); 869 870 // Parse valid lifetime 871 addMatchSection(ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET); 872 lifetime = getUint32(mPacket, mPacket.position()); 873 addLifetimeSection(ICMP6_PREFIX_OPTION_VALID_LIFETIME_LEN, 874 ICMP6_PREFIX_OPTION_TYPE, lifetime); 875 builder.updatePrefixValidLifetime(lifetime); 876 877 // Parse preferred lifetime 878 lifetime = getUint32(mPacket, mPacket.position()); 879 addLifetimeSection(ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_LEN, 880 ICMP6_PREFIX_OPTION_TYPE, lifetime); 881 builder.updatePrefixPreferredLifetime(lifetime); 882 883 addMatchSection(4); // Reserved bytes 884 addMatchSection(IPV6_ADDR_LEN); // The prefix itself 885 break; 886 // These three options have the same lifetime offset and size, and 887 // are processed with the same specialized add4ByteLifetimeOption: 888 case ICMP6_RDNSS_OPTION_TYPE: 889 mRdnssOptionOffsets.add(position); 890 lifetime = add4ByteLifetimeOption(optionType, optionLength); 891 builder.updateRdnssLifetime(lifetime); 892 break; 893 case ICMP6_ROUTE_INFO_OPTION_TYPE: 894 mRioOptionOffsets.add(position); 895 lifetime = add4ByteLifetimeOption(optionType, optionLength); 896 builder.updateRouteInfoLifetime(lifetime); 897 break; 898 case ICMP6_DNSSL_OPTION_TYPE: 899 lifetime = add4ByteLifetimeOption(optionType, optionLength); 900 builder.updateDnsslLifetime(lifetime); 901 break; 902 default: 903 // RFC4861 section 4.2 dictates we ignore unknown options for forwards 904 // compatibility. 905 mPacket.position(position + optionLength); 906 break; 907 } 908 if (optionLength <= 0) { 909 throw new InvalidRaException(String.format( 910 "Invalid option length opt=%d len=%d", optionType, optionLength)); 911 } 912 } 913 mMinLifetime = minLifetime(); 914 mMetricsLog.log(builder.build()); 915 } 916 917 // Considering only the MATCH sections, does {@code packet} match this RA? matches(byte[] packet, int length)918 boolean matches(byte[] packet, int length) { 919 if (length != mPacket.capacity()) return false; 920 byte[] referencePacket = mPacket.array(); 921 for (PacketSection section : mPacketSections) { 922 if (section.type != PacketSection.Type.MATCH) continue; 923 for (int i = section.start; i < (section.start + section.length); i++) { 924 if (packet[i] != referencePacket[i]) return false; 925 } 926 } 927 return true; 928 } 929 930 // What is the minimum of all lifetimes within {@code packet} in seconds? 931 // Precondition: matches(packet, length) already returned true. minLifetime()932 long minLifetime() { 933 long minLifetime = Long.MAX_VALUE; 934 for (PacketSection section : mPacketSections) { 935 if (isRelevantLifetime(section)) { 936 minLifetime = Math.min(minLifetime, section.lifetime); 937 } 938 } 939 return minLifetime; 940 } 941 942 // How many seconds does this RA's have to live, taking into account the fact 943 // that we might have seen it a while ago. currentLifetime()944 long currentLifetime() { 945 return mMinLifetime - (currentTimeSeconds() - mLastSeen); 946 } 947 isExpired()948 boolean isExpired() { 949 // TODO: We may want to handle 0 lifetime RAs differently, if they are common. We'll 950 // have to calculate the filter lifetime specially as a fraction of 0 is still 0. 951 return currentLifetime() <= 0; 952 } 953 954 // Filter for a fraction of the lifetime and adjust for the age of the RA. 955 @GuardedBy("ApfFilter.this") filterLifetime()956 int filterLifetime() { 957 // Use a flag from device config to toggle on/off the use of lifetime calculation fix 958 // in aosp/2276160. The old buggy behavior drops more RAs in some circumstances which 959 // probably use less battery. We can change it immediately if any OEM complains about 960 // additional battery usage after the fix. 961 if (mUseLifetimeCalculationFix) { 962 return (int) (mMinLifetime / FRACTION_OF_LIFETIME_TO_FILTER) 963 - (int) (mProgramBaseTime - mLastSeen); 964 } else { 965 // The old buggy formula, always filter a fraction of the remaining lifetime. 966 return (int) (currentLifetime() / FRACTION_OF_LIFETIME_TO_FILTER); 967 } 968 } 969 970 @GuardedBy("ApfFilter.this") shouldFilter()971 boolean shouldFilter() { 972 return filterLifetime() > 0; 973 } 974 975 // Append a filter for this RA to {@code gen}. Jump to DROP_LABEL if it should be dropped. 976 // Jump to the next filter if packet doesn't match this RA. 977 // Return Long.MAX_VALUE if we don't install any filter program for this RA. As the return 978 // value of this function is used to calculate the program min lifetime (which corresponds 979 // to the smallest generated filter lifetime). Returning Long.MAX_VALUE in the case no 980 // filter gets generated makes sure the program lifetime stays unaffected. 981 @GuardedBy("ApfFilter.this") generateFilterLocked(ApfGenerator gen)982 long generateFilterLocked(ApfGenerator gen) throws IllegalInstructionException { 983 String nextFilterLabel = "Ra" + getUniqueNumberLocked(); 984 // Skip if packet is not the right size 985 gen.addLoadFromMemory(Register.R0, gen.PACKET_SIZE_MEMORY_SLOT); 986 gen.addJumpIfR0NotEquals(mPacket.capacity(), nextFilterLabel); 987 // Skip filter if expired 988 gen.addLoadFromMemory(Register.R0, gen.FILTER_AGE_MEMORY_SLOT); 989 gen.addJumpIfR0GreaterThan(filterLifetime(), nextFilterLabel); 990 for (PacketSection section : mPacketSections) { 991 // Generate code to match the packet bytes. 992 if (section.type == PacketSection.Type.MATCH) { 993 gen.addLoadImmediate(Register.R0, section.start); 994 gen.addJumpIfBytesNotEqual(Register.R0, 995 Arrays.copyOfRange(mPacket.array(), section.start, 996 section.start + section.length), 997 nextFilterLabel); 998 } 999 1000 // Generate code to test the lifetimes haven't gone down too far. 1001 // The packet is accepted if any non-ignored lifetime is lower than filterLifetime. 1002 if (isRelevantLifetime(section)) { 1003 switch (section.length) { 1004 case 4: gen.addLoad32(Register.R0, section.start); break; 1005 case 2: gen.addLoad16(Register.R0, section.start); break; 1006 default: 1007 throw new IllegalStateException( 1008 "bogus lifetime size " + section.length); 1009 } 1010 gen.addJumpIfR0LessThan(filterLifetime(), nextFilterLabel); 1011 } 1012 } 1013 maybeSetupCounter(gen, Counter.DROPPED_RA); 1014 gen.addJump(mCountAndDropLabel); 1015 gen.defineLabel(nextFilterLabel); 1016 return filterLifetime(); 1017 } 1018 } 1019 1020 // TODO: Refactor these subclasses to avoid so much repetition. 1021 private abstract static class KeepalivePacket { 1022 // Note that the offset starts from IP header. 1023 // These must be added ether header length when generating program. 1024 static final int IP_HEADER_OFFSET = 0; 1025 static final int IPV4_SRC_ADDR_OFFSET = IP_HEADER_OFFSET + 12; 1026 1027 // Append a filter for this keepalive ack to {@code gen}. 1028 // Jump to drop if it matches the keepalive ack. 1029 // Jump to the next filter if packet doesn't match the keepalive ack. generateFilterLocked(ApfGenerator gen)1030 abstract void generateFilterLocked(ApfGenerator gen) throws IllegalInstructionException; 1031 } 1032 1033 // A class to hold NAT-T keepalive ack information. 1034 private class NattKeepaliveResponse extends KeepalivePacket { 1035 static final int UDP_LENGTH_OFFSET = 4; 1036 static final int UDP_HEADER_LEN = 8; 1037 1038 protected class NattKeepaliveResponseData { 1039 public final byte[] srcAddress; 1040 public final int srcPort; 1041 public final byte[] dstAddress; 1042 public final int dstPort; 1043 NattKeepaliveResponseData(final NattKeepalivePacketDataParcelable sentKeepalivePacket)1044 NattKeepaliveResponseData(final NattKeepalivePacketDataParcelable sentKeepalivePacket) { 1045 srcAddress = sentKeepalivePacket.dstAddress; 1046 srcPort = sentKeepalivePacket.dstPort; 1047 dstAddress = sentKeepalivePacket.srcAddress; 1048 dstPort = sentKeepalivePacket.srcPort; 1049 } 1050 } 1051 1052 protected final NattKeepaliveResponseData mPacket; 1053 protected final byte[] mSrcDstAddr; 1054 protected final byte[] mPortFingerprint; 1055 // NAT-T keepalive packet 1056 protected final byte[] mPayload = {(byte) 0xff}; 1057 NattKeepaliveResponse(final NattKeepalivePacketDataParcelable sentKeepalivePacket)1058 NattKeepaliveResponse(final NattKeepalivePacketDataParcelable sentKeepalivePacket) { 1059 mPacket = new NattKeepaliveResponseData(sentKeepalivePacket); 1060 mSrcDstAddr = concatArrays(mPacket.srcAddress, mPacket.dstAddress); 1061 mPortFingerprint = generatePortFingerprint(mPacket.srcPort, mPacket.dstPort); 1062 } 1063 generatePortFingerprint(int srcPort, int dstPort)1064 byte[] generatePortFingerprint(int srcPort, int dstPort) { 1065 final ByteBuffer fp = ByteBuffer.allocate(4); 1066 fp.order(ByteOrder.BIG_ENDIAN); 1067 fp.putShort((short) srcPort); 1068 fp.putShort((short) dstPort); 1069 return fp.array(); 1070 } 1071 1072 @Override generateFilterLocked(ApfGenerator gen)1073 void generateFilterLocked(ApfGenerator gen) throws IllegalInstructionException { 1074 final String nextFilterLabel = "natt_keepalive_filter" + getUniqueNumberLocked(); 1075 1076 gen.addLoadImmediate(Register.R0, ETH_HEADER_LEN + IPV4_SRC_ADDR_OFFSET); 1077 gen.addJumpIfBytesNotEqual(Register.R0, mSrcDstAddr, nextFilterLabel); 1078 1079 // A NAT-T keepalive packet contains 1 byte payload with the value 0xff 1080 // Check payload length is 1 1081 gen.addLoadFromMemory(Register.R0, gen.IPV4_HEADER_SIZE_MEMORY_SLOT); 1082 gen.addAdd(UDP_HEADER_LEN); 1083 gen.addSwap(); 1084 gen.addLoad16(Register.R0, IPV4_TOTAL_LENGTH_OFFSET); 1085 gen.addNeg(Register.R1); 1086 gen.addAddR1(); 1087 gen.addJumpIfR0NotEquals(1, nextFilterLabel); 1088 1089 // Check that the ports match 1090 gen.addLoadFromMemory(Register.R0, gen.IPV4_HEADER_SIZE_MEMORY_SLOT); 1091 gen.addAdd(ETH_HEADER_LEN); 1092 gen.addJumpIfBytesNotEqual(Register.R0, mPortFingerprint, nextFilterLabel); 1093 1094 // Payload offset = R0 + UDP header length 1095 gen.addAdd(UDP_HEADER_LEN); 1096 gen.addJumpIfBytesNotEqual(Register.R0, mPayload, nextFilterLabel); 1097 1098 maybeSetupCounter(gen, Counter.DROPPED_IPV4_NATT_KEEPALIVE); 1099 gen.addJump(mCountAndDropLabel); 1100 gen.defineLabel(nextFilterLabel); 1101 } 1102 toString()1103 public String toString() { 1104 try { 1105 return String.format("%s -> %s", 1106 ConnectivityUtils.addressAndPortToString( 1107 InetAddress.getByAddress(mPacket.srcAddress), mPacket.srcPort), 1108 ConnectivityUtils.addressAndPortToString( 1109 InetAddress.getByAddress(mPacket.dstAddress), mPacket.dstPort)); 1110 } catch (UnknownHostException e) { 1111 return "Unknown host"; 1112 } 1113 } 1114 } 1115 1116 // A class to hold TCP keepalive ack information. 1117 private abstract static class TcpKeepaliveAck extends KeepalivePacket { 1118 protected static class TcpKeepaliveAckData { 1119 public final byte[] srcAddress; 1120 public final int srcPort; 1121 public final byte[] dstAddress; 1122 public final int dstPort; 1123 public final int seq; 1124 public final int ack; 1125 1126 // Create the characteristics of the ack packet from the sent keepalive packet. TcpKeepaliveAckData(final TcpKeepalivePacketDataParcelable sentKeepalivePacket)1127 TcpKeepaliveAckData(final TcpKeepalivePacketDataParcelable sentKeepalivePacket) { 1128 srcAddress = sentKeepalivePacket.dstAddress; 1129 srcPort = sentKeepalivePacket.dstPort; 1130 dstAddress = sentKeepalivePacket.srcAddress; 1131 dstPort = sentKeepalivePacket.srcPort; 1132 seq = sentKeepalivePacket.ack; 1133 ack = sentKeepalivePacket.seq + 1; 1134 } 1135 } 1136 1137 protected final TcpKeepaliveAckData mPacket; 1138 protected final byte[] mSrcDstAddr; 1139 protected final byte[] mPortSeqAckFingerprint; 1140 TcpKeepaliveAck(final TcpKeepaliveAckData packet, final byte[] srcDstAddr)1141 TcpKeepaliveAck(final TcpKeepaliveAckData packet, final byte[] srcDstAddr) { 1142 mPacket = packet; 1143 mSrcDstAddr = srcDstAddr; 1144 mPortSeqAckFingerprint = generatePortSeqAckFingerprint(mPacket.srcPort, 1145 mPacket.dstPort, mPacket.seq, mPacket.ack); 1146 } 1147 generatePortSeqAckFingerprint(int srcPort, int dstPort, int seq, int ack)1148 static byte[] generatePortSeqAckFingerprint(int srcPort, int dstPort, int seq, int ack) { 1149 final ByteBuffer fp = ByteBuffer.allocate(12); 1150 fp.order(ByteOrder.BIG_ENDIAN); 1151 fp.putShort((short) srcPort); 1152 fp.putShort((short) dstPort); 1153 fp.putInt(seq); 1154 fp.putInt(ack); 1155 return fp.array(); 1156 } 1157 toString()1158 public String toString() { 1159 try { 1160 return String.format("%s -> %s , seq=%d, ack=%d", 1161 ConnectivityUtils.addressAndPortToString( 1162 InetAddress.getByAddress(mPacket.srcAddress), mPacket.srcPort), 1163 ConnectivityUtils.addressAndPortToString( 1164 InetAddress.getByAddress(mPacket.dstAddress), mPacket.dstPort), 1165 Integer.toUnsignedLong(mPacket.seq), 1166 Integer.toUnsignedLong(mPacket.ack)); 1167 } catch (UnknownHostException e) { 1168 return "Unknown host"; 1169 } 1170 } 1171 1172 // Append a filter for this keepalive ack to {@code gen}. 1173 // Jump to drop if it matches the keepalive ack. 1174 // Jump to the next filter if packet doesn't match the keepalive ack. generateFilterLocked(ApfGenerator gen)1175 abstract void generateFilterLocked(ApfGenerator gen) throws IllegalInstructionException; 1176 } 1177 1178 private class TcpKeepaliveAckV4 extends TcpKeepaliveAck { 1179 TcpKeepaliveAckV4(final TcpKeepalivePacketDataParcelable sentKeepalivePacket)1180 TcpKeepaliveAckV4(final TcpKeepalivePacketDataParcelable sentKeepalivePacket) { 1181 this(new TcpKeepaliveAckData(sentKeepalivePacket)); 1182 } TcpKeepaliveAckV4(final TcpKeepaliveAckData packet)1183 TcpKeepaliveAckV4(final TcpKeepaliveAckData packet) { 1184 super(packet, concatArrays(packet.srcAddress, packet.dstAddress) /* srcDstAddr */); 1185 } 1186 1187 @Override generateFilterLocked(ApfGenerator gen)1188 void generateFilterLocked(ApfGenerator gen) throws IllegalInstructionException { 1189 final String nextFilterLabel = "keepalive_ack" + getUniqueNumberLocked(); 1190 1191 gen.addLoadImmediate(Register.R0, ETH_HEADER_LEN + IPV4_SRC_ADDR_OFFSET); 1192 gen.addJumpIfBytesNotEqual(Register.R0, mSrcDstAddr, nextFilterLabel); 1193 1194 // Skip to the next filter if it's not zero-sized : 1195 // TCP_HEADER_SIZE + IPV4_HEADER_SIZE - ipv4_total_length == 0 1196 // Load the IP header size into R1 1197 gen.addLoadFromMemory(Register.R1, gen.IPV4_HEADER_SIZE_MEMORY_SLOT); 1198 // Load the TCP header size into R0 (it's indexed by R1) 1199 gen.addLoad8Indexed(Register.R0, ETH_HEADER_LEN + TCP_HEADER_SIZE_OFFSET); 1200 // Size offset is in the top nibble, but it must be multiplied by 4, and the two 1201 // top bits of the low nibble are guaranteed to be zeroes. Right-shift R0 by 2. 1202 gen.addRightShift(2); 1203 // R0 += R1 -> R0 contains TCP + IP headers length 1204 gen.addAddR1(); 1205 // Load IPv4 total length 1206 gen.addLoad16(Register.R1, IPV4_TOTAL_LENGTH_OFFSET); 1207 gen.addNeg(Register.R0); 1208 gen.addAddR1(); 1209 gen.addJumpIfR0NotEquals(0, nextFilterLabel); 1210 // Add IPv4 header length 1211 gen.addLoadFromMemory(Register.R1, gen.IPV4_HEADER_SIZE_MEMORY_SLOT); 1212 gen.addLoadImmediate(Register.R0, ETH_HEADER_LEN); 1213 gen.addAddR1(); 1214 gen.addJumpIfBytesNotEqual(Register.R0, mPortSeqAckFingerprint, nextFilterLabel); 1215 1216 maybeSetupCounter(gen, Counter.DROPPED_IPV4_KEEPALIVE_ACK); 1217 gen.addJump(mCountAndDropLabel); 1218 gen.defineLabel(nextFilterLabel); 1219 } 1220 } 1221 1222 private class TcpKeepaliveAckV6 extends TcpKeepaliveAck { TcpKeepaliveAckV6(final TcpKeepalivePacketDataParcelable sentKeepalivePacket)1223 TcpKeepaliveAckV6(final TcpKeepalivePacketDataParcelable sentKeepalivePacket) { 1224 this(new TcpKeepaliveAckData(sentKeepalivePacket)); 1225 } TcpKeepaliveAckV6(final TcpKeepaliveAckData packet)1226 TcpKeepaliveAckV6(final TcpKeepaliveAckData packet) { 1227 super(packet, concatArrays(packet.srcAddress, packet.dstAddress) /* srcDstAddr */); 1228 } 1229 1230 @Override generateFilterLocked(ApfGenerator gen)1231 void generateFilterLocked(ApfGenerator gen) throws IllegalInstructionException { 1232 throw new UnsupportedOperationException("IPv6 TCP Keepalive is not supported yet"); 1233 } 1234 } 1235 1236 // Maximum number of RAs to filter for. 1237 private static final int MAX_RAS = 10; 1238 1239 @GuardedBy("this") 1240 private ArrayList<Ra> mRas = new ArrayList<>(); 1241 @GuardedBy("this") 1242 private SparseArray<KeepalivePacket> mKeepalivePackets = new SparseArray<>(); 1243 @GuardedBy("this") 1244 private final List<String[]> mMdnsAllowList = new ArrayList<>(); 1245 1246 // There is always some marginal benefit to updating the installed APF program when an RA is 1247 // seen because we can extend the program's lifetime slightly, but there is some cost to 1248 // updating the program, so don't bother unless the program is going to expire soon. This 1249 // constant defines "soon" in seconds. 1250 private static final long MAX_PROGRAM_LIFETIME_WORTH_REFRESHING = 30; 1251 // We don't want to filter an RA for it's whole lifetime as it'll be expired by the time we ever 1252 // see a refresh. Using half the lifetime might be a good idea except for the fact that 1253 // packets may be dropped, so let's use 6. 1254 private static final int FRACTION_OF_LIFETIME_TO_FILTER = 6; 1255 1256 // The base time for this filter program. In seconds since Unix Epoch. 1257 // This is the time when the APF program was generated. All filters in the program should use 1258 // this base time as their current time for consistency purposes. 1259 @GuardedBy("this") 1260 private long mProgramBaseTime; 1261 // When did we last install a filter program? In seconds since Unix Epoch. 1262 @GuardedBy("this") 1263 private long mLastTimeInstalledProgram; 1264 // How long should the last installed filter program live for? In seconds. 1265 @GuardedBy("this") 1266 private long mLastInstalledProgramMinLifetime; 1267 @GuardedBy("this") 1268 private ApfProgramEvent.Builder mLastInstallEvent; 1269 1270 // For debugging only. The last program installed. 1271 @GuardedBy("this") 1272 private byte[] mLastInstalledProgram; 1273 1274 /** 1275 * For debugging only. Contains the latest APF buffer snapshot captured from the firmware. 1276 * 1277 * A typical size for this buffer is 4KB. It is present only if the WiFi HAL supports 1278 * IWifiStaIface#readApfPacketFilterData(), and the APF interpreter advertised support for 1279 * the opcodes to access the data buffer (LDDW and STDW). 1280 */ 1281 @GuardedBy("this") @Nullable 1282 private byte[] mDataSnapshot; 1283 1284 // How many times the program was updated since we started. 1285 @GuardedBy("this") 1286 private int mNumProgramUpdates = 0; 1287 // How many times the program was updated since we started for allowing multicast traffic. 1288 @GuardedBy("this") 1289 private int mNumProgramUpdatesAllowingMulticast = 0; 1290 1291 /** 1292 * Generate filter code to process ARP packets. Execution of this code ends in either the 1293 * DROP_LABEL or PASS_LABEL and does not fall off the end. 1294 * Preconditions: 1295 * - Packet being filtered is ARP 1296 */ 1297 @GuardedBy("this") generateArpFilterLocked(ApfGenerator gen)1298 private void generateArpFilterLocked(ApfGenerator gen) throws IllegalInstructionException { 1299 // Here's a basic summary of what the ARP filter program does: 1300 // 1301 // if not ARP IPv4 1302 // pass 1303 // if not ARP IPv4 reply or request 1304 // pass 1305 // if ARP reply source ip is 0.0.0.0 1306 // drop 1307 // if unicast ARP reply 1308 // pass 1309 // if interface has no IPv4 address 1310 // if target ip is 0.0.0.0 1311 // drop 1312 // else 1313 // if target ip is not the interface ip 1314 // drop 1315 // pass 1316 1317 final String checkTargetIPv4 = "checkTargetIPv4"; 1318 1319 // Pass if not ARP IPv4. 1320 gen.addLoadImmediate(Register.R0, ARP_HEADER_OFFSET); 1321 maybeSetupCounter(gen, Counter.PASSED_ARP_NON_IPV4); 1322 gen.addJumpIfBytesNotEqual(Register.R0, ARP_IPV4_HEADER, mCountAndPassLabel); 1323 1324 // Pass if unknown ARP opcode. 1325 gen.addLoad16(Register.R0, ARP_OPCODE_OFFSET); 1326 gen.addJumpIfR0Equals(ARP_OPCODE_REQUEST, checkTargetIPv4); // Skip to unicast check 1327 maybeSetupCounter(gen, Counter.PASSED_ARP_UNKNOWN); 1328 gen.addJumpIfR0NotEquals(ARP_OPCODE_REPLY, mCountAndPassLabel); 1329 1330 // Drop if ARP reply source IP is 0.0.0.0 1331 gen.addLoad32(Register.R0, ARP_SOURCE_IP_ADDRESS_OFFSET); 1332 maybeSetupCounter(gen, Counter.DROPPED_ARP_REPLY_SPA_NO_HOST); 1333 gen.addJumpIfR0Equals(IPV4_ANY_HOST_ADDRESS, mCountAndDropLabel); 1334 1335 // Pass if unicast reply. 1336 gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET); 1337 maybeSetupCounter(gen, Counter.PASSED_ARP_UNICAST_REPLY); 1338 gen.addJumpIfBytesNotEqual(Register.R0, ETHER_BROADCAST, mCountAndPassLabel); 1339 1340 // Either a unicast request, a unicast reply, or a broadcast reply. 1341 gen.defineLabel(checkTargetIPv4); 1342 if (mIPv4Address == null) { 1343 // When there is no IPv4 address, drop GARP replies (b/29404209). 1344 gen.addLoad32(Register.R0, ARP_TARGET_IP_ADDRESS_OFFSET); 1345 maybeSetupCounter(gen, Counter.DROPPED_GARP_REPLY); 1346 gen.addJumpIfR0Equals(IPV4_ANY_HOST_ADDRESS, mCountAndDropLabel); 1347 } else { 1348 // When there is an IPv4 address, drop unicast/broadcast requests 1349 // and broadcast replies with a different target IPv4 address. 1350 gen.addLoadImmediate(Register.R0, ARP_TARGET_IP_ADDRESS_OFFSET); 1351 maybeSetupCounter(gen, Counter.DROPPED_ARP_OTHER_HOST); 1352 gen.addJumpIfBytesNotEqual(Register.R0, mIPv4Address, mCountAndDropLabel); 1353 } 1354 1355 maybeSetupCounter(gen, Counter.PASSED_ARP); 1356 gen.addJump(mCountAndPassLabel); 1357 } 1358 1359 /** 1360 * Generate filter code to process IPv4 packets. Execution of this code ends in either the 1361 * DROP_LABEL or PASS_LABEL and does not fall off the end. 1362 * Preconditions: 1363 * - Packet being filtered is IPv4 1364 */ 1365 @GuardedBy("this") generateIPv4FilterLocked(ApfGenerator gen)1366 private void generateIPv4FilterLocked(ApfGenerator gen) throws IllegalInstructionException { 1367 // Here's a basic summary of what the IPv4 filter program does: 1368 // 1369 // if filtering multicast (i.e. multicast lock not held): 1370 // if it's DHCP destined to our MAC: 1371 // pass 1372 // if it's L2 broadcast: 1373 // drop 1374 // if it's IPv4 multicast: 1375 // drop 1376 // if it's IPv4 broadcast: 1377 // drop 1378 // if keepalive ack 1379 // drop 1380 // pass 1381 1382 if (mMulticastFilter) { 1383 final String skipDhcpv4Filter = "skip_dhcp_v4_filter"; 1384 1385 // Pass DHCP addressed to us. 1386 // Check it's UDP. 1387 gen.addLoad8(Register.R0, IPV4_PROTOCOL_OFFSET); 1388 gen.addJumpIfR0NotEquals(IPPROTO_UDP, skipDhcpv4Filter); 1389 // Check it's not a fragment. This matches the BPF filter installed by the DHCP client. 1390 gen.addLoad16(Register.R0, IPV4_FRAGMENT_OFFSET_OFFSET); 1391 gen.addJumpIfR0AnyBitsSet(IPV4_FRAGMENT_OFFSET_MASK, skipDhcpv4Filter); 1392 // Check it's addressed to DHCP client port. 1393 gen.addLoadFromMemory(Register.R1, gen.IPV4_HEADER_SIZE_MEMORY_SLOT); 1394 gen.addLoad16Indexed(Register.R0, UDP_DESTINATION_PORT_OFFSET); 1395 gen.addJumpIfR0NotEquals(DHCP_CLIENT_PORT, skipDhcpv4Filter); 1396 // Check it's DHCP to our MAC address. 1397 gen.addLoadImmediate(Register.R0, DHCP_CLIENT_MAC_OFFSET); 1398 // NOTE: Relies on R1 containing IPv4 header offset. 1399 gen.addAddR1(); 1400 gen.addJumpIfBytesNotEqual(Register.R0, mHardwareAddress, skipDhcpv4Filter); 1401 maybeSetupCounter(gen, Counter.PASSED_DHCP); 1402 gen.addJump(mCountAndPassLabel); 1403 1404 // Drop all multicasts/broadcasts. 1405 gen.defineLabel(skipDhcpv4Filter); 1406 1407 // If IPv4 destination address is in multicast range, drop. 1408 gen.addLoad8(Register.R0, IPV4_DEST_ADDR_OFFSET); 1409 gen.addAnd(0xf0); 1410 maybeSetupCounter(gen, Counter.DROPPED_IPV4_MULTICAST); 1411 gen.addJumpIfR0Equals(0xe0, mCountAndDropLabel); 1412 1413 // If IPv4 broadcast packet, drop regardless of L2 (b/30231088). 1414 maybeSetupCounter(gen, Counter.DROPPED_IPV4_BROADCAST_ADDR); 1415 gen.addLoad32(Register.R0, IPV4_DEST_ADDR_OFFSET); 1416 gen.addJumpIfR0Equals(IPV4_BROADCAST_ADDRESS, mCountAndDropLabel); 1417 if (mIPv4Address != null && mIPv4PrefixLength < 31) { 1418 maybeSetupCounter(gen, Counter.DROPPED_IPV4_BROADCAST_NET); 1419 int broadcastAddr = ipv4BroadcastAddress(mIPv4Address, mIPv4PrefixLength); 1420 gen.addJumpIfR0Equals(broadcastAddr, mCountAndDropLabel); 1421 } 1422 1423 // If any TCP keepalive filter matches, drop 1424 generateV4KeepaliveFilters(gen); 1425 1426 // If any NAT-T keepalive filter matches, drop 1427 generateV4NattKeepaliveFilters(gen); 1428 1429 // Otherwise, this is an IPv4 unicast, pass 1430 // If L2 broadcast packet, drop. 1431 // TODO: can we invert this condition to fall through to the common pass case below? 1432 maybeSetupCounter(gen, Counter.PASSED_IPV4_UNICAST); 1433 gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET); 1434 gen.addJumpIfBytesNotEqual(Register.R0, ETHER_BROADCAST, mCountAndPassLabel); 1435 maybeSetupCounter(gen, Counter.DROPPED_IPV4_L2_BROADCAST); 1436 gen.addJump(mCountAndDropLabel); 1437 } else { 1438 generateV4KeepaliveFilters(gen); 1439 generateV4NattKeepaliveFilters(gen); 1440 } 1441 1442 // Otherwise, pass 1443 maybeSetupCounter(gen, Counter.PASSED_IPV4); 1444 gen.addJump(mCountAndPassLabel); 1445 } 1446 generateKeepaliveFilters(ApfGenerator gen, Class<?> filterType, int proto, int offset, String label)1447 private void generateKeepaliveFilters(ApfGenerator gen, Class<?> filterType, int proto, 1448 int offset, String label) throws IllegalInstructionException { 1449 final boolean haveKeepaliveResponses = CollectionUtils.any(mKeepalivePackets, 1450 ack -> filterType.isInstance(ack)); 1451 1452 // If no keepalive packets of this type 1453 if (!haveKeepaliveResponses) return; 1454 1455 // If not the right proto, skip keepalive filters 1456 gen.addLoad8(Register.R0, offset); 1457 gen.addJumpIfR0NotEquals(proto, label); 1458 1459 // Drop Keepalive responses 1460 for (int i = 0; i < mKeepalivePackets.size(); ++i) { 1461 final KeepalivePacket response = mKeepalivePackets.valueAt(i); 1462 if (filterType.isInstance(response)) response.generateFilterLocked(gen); 1463 } 1464 1465 gen.defineLabel(label); 1466 } 1467 generateV4KeepaliveFilters(ApfGenerator gen)1468 private void generateV4KeepaliveFilters(ApfGenerator gen) throws IllegalInstructionException { 1469 generateKeepaliveFilters(gen, TcpKeepaliveAckV4.class, IPPROTO_TCP, IPV4_PROTOCOL_OFFSET, 1470 "skip_v4_keepalive_filter"); 1471 } 1472 generateV4NattKeepaliveFilters(ApfGenerator gen)1473 private void generateV4NattKeepaliveFilters(ApfGenerator gen) 1474 throws IllegalInstructionException { 1475 generateKeepaliveFilters(gen, NattKeepaliveResponse.class, 1476 IPPROTO_UDP, IPV4_PROTOCOL_OFFSET, "skip_v4_nattkeepalive_filter"); 1477 } 1478 1479 /** 1480 * Generate filter code to process IPv6 packets. Execution of this code ends in either the 1481 * DROP_LABEL or PASS_LABEL, or falls off the end for ICMPv6 packets. 1482 * Preconditions: 1483 * - Packet being filtered is IPv6 1484 */ 1485 @GuardedBy("this") generateIPv6FilterLocked(ApfGenerator gen)1486 private void generateIPv6FilterLocked(ApfGenerator gen) throws IllegalInstructionException { 1487 // Here's a basic summary of what the IPv6 filter program does: 1488 // 1489 // if we're dropping multicast 1490 // if it's not IPCMv6 or it's ICMPv6 but we're in doze mode: 1491 // if it's multicast: 1492 // drop 1493 // pass 1494 // if it's ICMPv6 RS to any: 1495 // drop 1496 // if it's ICMPv6 NA to anything in ff02::/120 1497 // drop 1498 // if keepalive ack 1499 // drop 1500 1501 gen.addLoad8(Register.R0, IPV6_NEXT_HEADER_OFFSET); 1502 1503 // Drop multicast if the multicast filter is enabled. 1504 if (mMulticastFilter) { 1505 final String skipIPv6MulticastFilterLabel = "skipIPv6MulticastFilter"; 1506 final String dropAllIPv6MulticastsLabel = "dropAllIPv6Multicast"; 1507 1508 // While in doze mode, drop ICMPv6 multicast pings, let the others pass. 1509 // While awake, let all ICMPv6 multicasts through. 1510 if (mInDozeMode) { 1511 // Not ICMPv6? -> Proceed to multicast filtering 1512 gen.addJumpIfR0NotEquals(IPPROTO_ICMPV6, dropAllIPv6MulticastsLabel); 1513 1514 // ICMPv6 but not ECHO? -> Skip the multicast filter. 1515 // (ICMPv6 ECHO requests will go through the multicast filter below). 1516 gen.addLoad8(Register.R0, ICMP6_TYPE_OFFSET); 1517 gen.addJumpIfR0NotEquals(ICMPV6_ECHO_REQUEST_TYPE, skipIPv6MulticastFilterLabel); 1518 } else { 1519 gen.addJumpIfR0Equals(IPPROTO_ICMPV6, skipIPv6MulticastFilterLabel); 1520 } 1521 1522 // Drop all other packets sent to ff00::/8 (multicast prefix). 1523 gen.defineLabel(dropAllIPv6MulticastsLabel); 1524 maybeSetupCounter(gen, Counter.DROPPED_IPV6_NON_ICMP_MULTICAST); 1525 gen.addLoad8(Register.R0, IPV6_DEST_ADDR_OFFSET); 1526 gen.addJumpIfR0Equals(0xff, mCountAndDropLabel); 1527 // If any keepalive filter matches, drop 1528 generateV6KeepaliveFilters(gen); 1529 // Not multicast. Pass. 1530 maybeSetupCounter(gen, Counter.PASSED_IPV6_UNICAST_NON_ICMP); 1531 gen.addJump(mCountAndPassLabel); 1532 gen.defineLabel(skipIPv6MulticastFilterLabel); 1533 } else { 1534 generateV6KeepaliveFilters(gen); 1535 // If not ICMPv6, pass. 1536 maybeSetupCounter(gen, Counter.PASSED_IPV6_NON_ICMP); 1537 gen.addJumpIfR0NotEquals(IPPROTO_ICMPV6, mCountAndPassLabel); 1538 } 1539 1540 // If we got this far, the packet is ICMPv6. Drop some specific types. 1541 1542 // Add unsolicited multicast neighbor announcements filter 1543 String skipUnsolicitedMulticastNALabel = "skipUnsolicitedMulticastNA"; 1544 gen.addLoad8(Register.R0, ICMP6_TYPE_OFFSET); 1545 // Drop all router solicitations (b/32833400) 1546 maybeSetupCounter(gen, Counter.DROPPED_IPV6_ROUTER_SOLICITATION); 1547 gen.addJumpIfR0Equals(ICMPV6_ROUTER_SOLICITATION, mCountAndDropLabel); 1548 // If not neighbor announcements, skip filter. 1549 gen.addJumpIfR0NotEquals(ICMPV6_NEIGHBOR_ADVERTISEMENT, skipUnsolicitedMulticastNALabel); 1550 // Drop all multicast NA to ff02::/120. 1551 // This is a way to cover ff02::1 and ff02::2 with a single JNEBS. 1552 // TODO: Drop only if they don't contain the address of on-link neighbours. 1553 final byte[] unsolicitedNaDropPrefix = Arrays.copyOf(IPV6_ALL_NODES_ADDRESS, 15); 1554 gen.addLoadImmediate(Register.R0, IPV6_DEST_ADDR_OFFSET); 1555 gen.addJumpIfBytesNotEqual(Register.R0, unsolicitedNaDropPrefix, 1556 skipUnsolicitedMulticastNALabel); 1557 1558 maybeSetupCounter(gen, Counter.DROPPED_IPV6_MULTICAST_NA); 1559 gen.addJump(mCountAndDropLabel); 1560 gen.defineLabel(skipUnsolicitedMulticastNALabel); 1561 } 1562 1563 /** Encodes qname in TLV pattern. */ 1564 @VisibleForTesting encodeQname(String[] labels)1565 public static byte[] encodeQname(String[] labels) { 1566 final ByteArrayOutputStream out = new ByteArrayOutputStream(); 1567 for (String label : labels) { 1568 byte[] labelBytes = label.getBytes(StandardCharsets.UTF_8); 1569 out.write(labelBytes.length); 1570 out.write(labelBytes, 0, labelBytes.length); 1571 } 1572 out.write(0); 1573 return out.toByteArray(); 1574 } 1575 1576 /** 1577 * Generate filter code to process mDNS packets. Execution of this code ends in * DROP_LABEL 1578 * or PASS_LABEL if the packet is mDNS packets. Otherwise, skip this check. 1579 */ 1580 @GuardedBy("this") generateMdnsFilterLocked(ApfGenerator gen)1581 private void generateMdnsFilterLocked(ApfGenerator gen) 1582 throws IllegalInstructionException { 1583 final String skipMdnsv4Filter = "skip_mdns_v4_filter"; 1584 final String skipMdnsFilter = "skip_mdns_filter"; 1585 final String checkMdnsUdpPort = "check_mdns_udp_port"; 1586 final String mDnsAcceptPacket = "mdns_accept_packet"; 1587 final String mDnsDropPacket = "mdns_drop_packet"; 1588 1589 // Only turn on the filter if multicast filter is on and the qname allowlist is non-empty. 1590 if (!mMulticastFilter || mMdnsAllowList.isEmpty()) { 1591 return; 1592 } 1593 1594 // Here's a basic summary of what the mDNS filter program does: 1595 // 1596 // if it is a multicast mDNS packet 1597 // if QDCOUNT > 1 and the first QNAME is in the allowlist 1598 // pass 1599 // else: 1600 // drop 1601 // 1602 // A packet is considered as a multicast mDNS packet if it matches all the following 1603 // conditions 1604 // 1. its destination MAC address matches 01:00:5E:00:00:FB or 33:33:00:00:00:FB, for 1605 // v4 and v6 respectively. 1606 // 2. it is an IPv4/IPv6 packet 1607 // 3. it is a UDP packet with port 5353 1608 1609 // Check it's L2 mDNS multicast address. 1610 gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET); 1611 gen.addJumpIfBytesNotEqual(Register.R0, ETH_MULTICAST_MDNS_V4_MAC_ADDRESS, 1612 skipMdnsv4Filter); 1613 1614 // Checks it's IPv4. 1615 gen.addLoad16(Register.R0, ETH_ETHERTYPE_OFFSET); 1616 gen.addJumpIfR0NotEquals(ETH_P_IP, skipMdnsFilter); 1617 1618 // Checks it's UDP. 1619 gen.addLoad8(Register.R0, IPV4_PROTOCOL_OFFSET); 1620 gen.addJumpIfR0NotEquals(IPPROTO_UDP, skipMdnsFilter); 1621 // Set R1 to IPv4 header. 1622 gen.addLoadFromMemory(Register.R1, gen.IPV4_HEADER_SIZE_MEMORY_SLOT); 1623 gen.addJump(checkMdnsUdpPort); 1624 1625 gen.defineLabel(skipMdnsv4Filter); 1626 1627 // Checks it's L2 mDNS multicast address. 1628 // Relies on R0 containing the ethernet destination mac address offset. 1629 gen.addJumpIfBytesNotEqual(Register.R0, ETH_MULTICAST_MDNS_V6_MAC_ADDRESS, 1630 skipMdnsFilter); 1631 1632 // Checks it's IPv6. 1633 gen.addLoad16(Register.R0, ETH_ETHERTYPE_OFFSET); 1634 gen.addJumpIfR0NotEquals(ETH_P_IPV6, skipMdnsFilter); 1635 1636 // Checks it's UDP. 1637 gen.addLoad8(Register.R0, IPV6_NEXT_HEADER_OFFSET); 1638 gen.addJumpIfR0NotEquals(IPPROTO_UDP, skipMdnsFilter); 1639 1640 // Set R1 to IPv6 header. 1641 gen.addLoadImmediate(Register.R1, IPV6_HEADER_LEN); 1642 1643 // Checks it's mDNS UDP port 1644 gen.defineLabel(checkMdnsUdpPort); 1645 gen.addLoad16Indexed(Register.R0, UDP_DESTINATION_PORT_OFFSET); 1646 gen.addJumpIfR0NotEquals(MDNS_PORT, skipMdnsFilter); 1647 1648 // Only do the QNAME check if the QDCOUNT is more than 0. 1649 // If there is more than one query (QDCOUNT > 1), we only matches the first QNAME. 1650 gen.addLoad16Indexed(Register.R0, MDNS_QDCOUNT_OFFSET); 1651 gen.addJumpIfR0Equals(0, mDnsDropPacket); 1652 1653 // Load offset for the first QNAME. 1654 gen.addLoadImmediate(Register.R0, MDNS_QNAME_OFFSET); 1655 gen.addAddR1(); 1656 1657 // Check first QNAME against allowlist 1658 for (int i = 0; i < mMdnsAllowList.size(); ++i) { 1659 final String mDnsNextAllowedQnameCheck = "mdns_next_allowed_qname_check" + i; 1660 final byte[] encodedQname = encodeQname(mMdnsAllowList.get(i)); 1661 gen.addJumpIfBytesNotEqual(Register.R0, encodedQname, mDnsNextAllowedQnameCheck); 1662 // QNAME matched 1663 gen.addJump(mDnsAcceptPacket); 1664 // QNAME not matched 1665 gen.defineLabel(mDnsNextAllowedQnameCheck); 1666 } 1667 // If QNAME doesn't match any entries in allowlist, drop the packet. 1668 gen.defineLabel(mDnsDropPacket); 1669 maybeSetupCounter(gen, Counter.DROPPED_MDNS); 1670 gen.addJump(mCountAndDropLabel); 1671 1672 gen.defineLabel(mDnsAcceptPacket); 1673 maybeSetupCounter(gen, Counter.PASSED_MDNS); 1674 gen.addJump(mCountAndPassLabel); 1675 1676 1677 gen.defineLabel(skipMdnsFilter); 1678 } 1679 1680 generateV6KeepaliveFilters(ApfGenerator gen)1681 private void generateV6KeepaliveFilters(ApfGenerator gen) throws IllegalInstructionException { 1682 generateKeepaliveFilters(gen, TcpKeepaliveAckV6.class, IPPROTO_TCP, IPV6_NEXT_HEADER_OFFSET, 1683 "skip_v6_keepalive_filter"); 1684 } 1685 1686 /** 1687 * Begin generating an APF program to: 1688 * <ul> 1689 * <li>Drop/Pass 802.3 frames (based on policy) 1690 * <li>Drop packets with EtherType within the Black List 1691 * <li>Drop ARP requests not for us, if mIPv4Address is set, 1692 * <li>Drop IPv4 broadcast packets, except DHCP destined to our MAC, 1693 * <li>Drop IPv4 multicast packets, if mMulticastFilter, 1694 * <li>Pass all other IPv4 packets, 1695 * <li>Drop all broadcast non-IP non-ARP packets. 1696 * <li>Pass all non-ICMPv6 IPv6 packets, 1697 * <li>Pass all non-IPv4 and non-IPv6 packets, 1698 * <li>Drop IPv6 ICMPv6 NAs to anything in ff02::/120. 1699 * <li>Drop IPv6 ICMPv6 RSs. 1700 * <li>Filter IPv4 packets (see generateIPv4FilterLocked()) 1701 * <li>Filter IPv6 packets (see generateIPv6FilterLocked()) 1702 * <li>Let execution continue off the end of the program for IPv6 ICMPv6 packets. This allows 1703 * insertion of RA filters here, or if there aren't any, just passes the packets. 1704 * </ul> 1705 */ 1706 @GuardedBy("this") emitPrologueLocked()1707 private ApfGenerator emitPrologueLocked() throws IllegalInstructionException { 1708 // This is guaranteed to succeed because of the check in maybeCreate. 1709 ApfGenerator gen = new ApfGenerator(mApfCapabilities.apfVersionSupported); 1710 1711 if (mApfCapabilities.hasDataAccess()) { 1712 // Increment TOTAL_PACKETS 1713 maybeSetupCounter(gen, Counter.TOTAL_PACKETS); 1714 gen.addLoadData(Register.R0, 0); // load counter 1715 gen.addAdd(1); 1716 gen.addStoreData(Register.R0, 0); // write-back counter 1717 } 1718 1719 // Here's a basic summary of what the initial program does: 1720 // 1721 // if it's a 802.3 Frame (ethtype < 0x0600): 1722 // drop or pass based on configurations 1723 // if it has a ether-type that belongs to the black list 1724 // drop 1725 // if it's ARP: 1726 // insert ARP filter to drop or pass these appropriately 1727 // if it's IPv4: 1728 // insert IPv4 filter to drop or pass these appropriately 1729 // if it's not IPv6: 1730 // if it's broadcast: 1731 // drop 1732 // pass 1733 // insert IPv6 filter to drop, pass, or fall off the end for ICMPv6 packets 1734 1735 gen.addLoad16(Register.R0, ETH_ETHERTYPE_OFFSET); 1736 1737 if (mDrop802_3Frames) { 1738 // drop 802.3 frames (ethtype < 0x0600) 1739 maybeSetupCounter(gen, Counter.DROPPED_802_3_FRAME); 1740 gen.addJumpIfR0LessThan(ETH_TYPE_MIN, mCountAndDropLabel); 1741 } 1742 1743 // Handle ether-type black list 1744 maybeSetupCounter(gen, Counter.DROPPED_ETHERTYPE_BLACKLISTED); 1745 for (int p : mEthTypeBlackList) { 1746 gen.addJumpIfR0Equals(p, mCountAndDropLabel); 1747 } 1748 1749 // Add ARP filters: 1750 String skipArpFiltersLabel = "skipArpFilters"; 1751 gen.addJumpIfR0NotEquals(ETH_P_ARP, skipArpFiltersLabel); 1752 generateArpFilterLocked(gen); 1753 gen.defineLabel(skipArpFiltersLabel); 1754 1755 // Add mDNS filter: 1756 generateMdnsFilterLocked(gen); 1757 gen.addLoad16(Register.R0, ETH_ETHERTYPE_OFFSET); 1758 1759 // Add IPv4 filters: 1760 String skipIPv4FiltersLabel = "skipIPv4Filters"; 1761 gen.addJumpIfR0NotEquals(ETH_P_IP, skipIPv4FiltersLabel); 1762 generateIPv4FilterLocked(gen); 1763 gen.defineLabel(skipIPv4FiltersLabel); 1764 1765 // Check for IPv6: 1766 // NOTE: Relies on R0 containing ethertype. This is safe because if we got here, we did 1767 // not execute the IPv4 filter, since this filter do not fall through, but either drop or 1768 // pass. 1769 String ipv6FilterLabel = "IPv6Filters"; 1770 gen.addJumpIfR0Equals(ETH_P_IPV6, ipv6FilterLabel); 1771 1772 // Drop non-IP non-ARP broadcasts, pass the rest 1773 gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET); 1774 maybeSetupCounter(gen, Counter.PASSED_NON_IP_UNICAST); 1775 gen.addJumpIfBytesNotEqual(Register.R0, ETHER_BROADCAST, mCountAndPassLabel); 1776 maybeSetupCounter(gen, Counter.DROPPED_ETH_BROADCAST); 1777 gen.addJump(mCountAndDropLabel); 1778 1779 // Add IPv6 filters: 1780 gen.defineLabel(ipv6FilterLabel); 1781 generateIPv6FilterLocked(gen); 1782 return gen; 1783 } 1784 1785 /** 1786 * Append packet counting epilogue to the APF program. 1787 * 1788 * Currently, the epilogue consists of two trampolines which count passed and dropped packets 1789 * before jumping to the actual PASS and DROP labels. 1790 */ 1791 @GuardedBy("this") emitEpilogue(ApfGenerator gen)1792 private void emitEpilogue(ApfGenerator gen) throws IllegalInstructionException { 1793 // If APFv4 is unsupported, no epilogue is necessary: if execution reached this far, it 1794 // will just fall-through to the PASS label. 1795 if (!mApfCapabilities.hasDataAccess()) return; 1796 1797 // Execution will reach the bottom of the program if none of the filters match, 1798 // which will pass the packet to the application processor. 1799 maybeSetupCounter(gen, Counter.PASSED_IPV6_ICMP); 1800 1801 // Append the count & pass trampoline, which increments the counter at the data address 1802 // pointed to by R1, then jumps to the pass label. This saves a few bytes over inserting 1803 // the entire sequence inline for every counter. 1804 gen.defineLabel(mCountAndPassLabel); 1805 gen.addLoadData(Register.R0, 0); // R0 = *(R1 + 0) 1806 gen.addAdd(1); // R0++ 1807 gen.addStoreData(Register.R0, 0); // *(R1 + 0) = R0 1808 gen.addJump(gen.PASS_LABEL); 1809 1810 // Same as above for the count & drop trampoline. 1811 gen.defineLabel(mCountAndDropLabel); 1812 gen.addLoadData(Register.R0, 0); // R0 = *(R1 + 0) 1813 gen.addAdd(1); // R0++ 1814 gen.addStoreData(Register.R0, 0); // *(R1 + 0) = R0 1815 gen.addJump(gen.DROP_LABEL); 1816 } 1817 1818 /** 1819 * Generate and install a new filter program. 1820 */ 1821 @GuardedBy("this") 1822 @VisibleForTesting installNewProgramLocked()1823 public void installNewProgramLocked() { 1824 purgeExpiredRasLocked(); 1825 ArrayList<Ra> rasToFilter = new ArrayList<>(); 1826 final byte[] program; 1827 long programMinLifetime = Long.MAX_VALUE; 1828 long maximumApfProgramSize = mApfCapabilities.maximumApfProgramSize; 1829 if (mApfCapabilities.hasDataAccess()) { 1830 // Reserve space for the counters. 1831 maximumApfProgramSize -= Counter.totalSize(); 1832 } 1833 1834 mProgramBaseTime = currentTimeSeconds(); 1835 try { 1836 // Step 1: Determine how many RA filters we can fit in the program. 1837 ApfGenerator gen = emitPrologueLocked(); 1838 1839 // The epilogue normally goes after the RA filters, but add it early to include its 1840 // length when estimating the total. 1841 emitEpilogue(gen); 1842 1843 // Can't fit the program even without any RA filters? 1844 if (gen.programLengthOverEstimate() > maximumApfProgramSize) { 1845 Log.e(TAG, "Program exceeds maximum size " + maximumApfProgramSize); 1846 return; 1847 } 1848 1849 for (Ra ra : mRas) { 1850 if (!ra.shouldFilter()) continue; 1851 ra.generateFilterLocked(gen); 1852 // Stop if we get too big. 1853 if (gen.programLengthOverEstimate() > maximumApfProgramSize) { 1854 if (VDBG) Log.d(TAG, "Past maximum program size, skipping RAs"); 1855 break; 1856 } 1857 1858 rasToFilter.add(ra); 1859 } 1860 1861 // Step 2: Actually generate the program 1862 gen = emitPrologueLocked(); 1863 for (Ra ra : rasToFilter) { 1864 programMinLifetime = Math.min(programMinLifetime, ra.generateFilterLocked(gen)); 1865 } 1866 emitEpilogue(gen); 1867 program = gen.generate(); 1868 } catch (IllegalInstructionException|IllegalStateException e) { 1869 Log.e(TAG, "Failed to generate APF program.", e); 1870 return; 1871 } 1872 mIpClientCallback.installPacketFilter(program); 1873 mLastTimeInstalledProgram = mProgramBaseTime; 1874 mLastInstalledProgramMinLifetime = programMinLifetime; 1875 mLastInstalledProgram = program; 1876 mNumProgramUpdates++; 1877 1878 if (VDBG) { 1879 hexDump("Installing filter: ", program, program.length); 1880 } 1881 logApfProgramEventLocked(mProgramBaseTime); 1882 mLastInstallEvent = new ApfProgramEvent.Builder() 1883 .setLifetime(programMinLifetime) 1884 .setFilteredRas(rasToFilter.size()) 1885 .setCurrentRas(mRas.size()) 1886 .setProgramLength(program.length) 1887 .setFlags(mIPv4Address != null, mMulticastFilter); 1888 } 1889 1890 @GuardedBy("this") logApfProgramEventLocked(long now)1891 private void logApfProgramEventLocked(long now) { 1892 if (mLastInstallEvent == null) { 1893 return; 1894 } 1895 ApfProgramEvent.Builder ev = mLastInstallEvent; 1896 mLastInstallEvent = null; 1897 final long actualLifetime = now - mLastTimeInstalledProgram; 1898 ev.setActualLifetime(actualLifetime); 1899 if (actualLifetime < APF_PROGRAM_EVENT_LIFETIME_THRESHOLD) { 1900 return; 1901 } 1902 mMetricsLog.log(ev.build()); 1903 } 1904 1905 /** 1906 * Returns {@code true} if a new program should be installed because the current one dies soon. 1907 */ shouldInstallnewProgram()1908 private boolean shouldInstallnewProgram() { 1909 long expiry = mLastTimeInstalledProgram + mLastInstalledProgramMinLifetime; 1910 return expiry < currentTimeSeconds() + MAX_PROGRAM_LIFETIME_WORTH_REFRESHING; 1911 } 1912 hexDump(String msg, byte[] packet, int length)1913 private void hexDump(String msg, byte[] packet, int length) { 1914 log(msg + HexDump.toHexString(packet, 0, length, false /* lowercase */)); 1915 } 1916 1917 @GuardedBy("this") purgeExpiredRasLocked()1918 private void purgeExpiredRasLocked() { 1919 for (int i = 0; i < mRas.size();) { 1920 if (mRas.get(i).isExpired()) { 1921 log("Expiring " + mRas.get(i)); 1922 mRas.remove(i); 1923 } else { 1924 i++; 1925 } 1926 } 1927 } 1928 1929 /** 1930 * Process an RA packet, updating the list of known RAs and installing a new APF program 1931 * if the current APF program should be updated. 1932 * @return a ProcessRaResult enum describing what action was performed. 1933 */ 1934 @VisibleForTesting processRa(byte[] packet, int length)1935 public synchronized ProcessRaResult processRa(byte[] packet, int length) { 1936 if (VDBG) hexDump("Read packet = ", packet, length); 1937 1938 // Have we seen this RA before? 1939 for (int i = 0; i < mRas.size(); i++) { 1940 Ra ra = mRas.get(i); 1941 if (ra.matches(packet, length)) { 1942 if (VDBG) log("matched RA " + ra); 1943 // Update lifetimes. 1944 ra.mLastSeen = currentTimeSeconds(); 1945 ra.seenCount++; 1946 1947 // Keep mRas in LRU order so as to prioritize generating filters for recently seen 1948 // RAs. LRU prioritizes this because RA filters are generated in order from mRas 1949 // until the filter program exceeds the maximum filter program size allowed by the 1950 // chipset, so RAs appearing earlier in mRas are more likely to make it into the 1951 // filter program. 1952 // TODO: consider sorting the RAs in order of increasing expiry time as well. 1953 // Swap to front of array. 1954 mRas.add(0, mRas.remove(i)); 1955 1956 // If the current program doesn't expire for a while, don't update. 1957 if (shouldInstallnewProgram()) { 1958 installNewProgramLocked(); 1959 return ProcessRaResult.UPDATE_EXPIRY; 1960 } 1961 return ProcessRaResult.MATCH; 1962 } 1963 } 1964 purgeExpiredRasLocked(); 1965 // TODO: figure out how to proceed when we've received more then MAX_RAS RAs. 1966 if (mRas.size() >= MAX_RAS) { 1967 return ProcessRaResult.DROPPED; 1968 } 1969 final Ra ra; 1970 try { 1971 ra = new Ra(packet, length); 1972 } catch (Exception e) { 1973 Log.e(TAG, "Error parsing RA", e); 1974 return ProcessRaResult.PARSE_ERROR; 1975 } 1976 // Ignore 0 lifetime RAs. 1977 if (ra.isExpired()) { 1978 return ProcessRaResult.ZERO_LIFETIME; 1979 } 1980 log("Adding " + ra); 1981 mRas.add(ra); 1982 installNewProgramLocked(); 1983 return ProcessRaResult.UPDATE_NEW_RA; 1984 } 1985 1986 /** 1987 * Create an {@link ApfFilter} if {@code apfCapabilities} indicates support for packet 1988 * filtering using APF programs. 1989 */ maybeCreate(Context context, ApfConfiguration config, InterfaceParams ifParams, IpClientCallbacksWrapper ipClientCallback)1990 public static ApfFilter maybeCreate(Context context, ApfConfiguration config, 1991 InterfaceParams ifParams, IpClientCallbacksWrapper ipClientCallback) { 1992 if (context == null || config == null || ifParams == null) return null; 1993 ApfCapabilities apfCapabilities = config.apfCapabilities; 1994 if (apfCapabilities == null) return null; 1995 if (apfCapabilities.apfVersionSupported == 0) return null; 1996 if (apfCapabilities.maximumApfProgramSize < 512) { 1997 Log.e(TAG, "Unacceptably small APF limit: " + apfCapabilities.maximumApfProgramSize); 1998 return null; 1999 } 2000 // For now only support generating programs for Ethernet frames. If this restriction is 2001 // lifted: 2002 // 1. the program generator will need its offsets adjusted. 2003 // 2. the packet filter attached to our packet socket will need its offset adjusted. 2004 if (apfCapabilities.apfPacketFormat != ARPHRD_ETHER) return null; 2005 if (!ApfGenerator.supportsVersion(apfCapabilities.apfVersionSupported)) { 2006 Log.e(TAG, "Unsupported APF version: " + apfCapabilities.apfVersionSupported); 2007 return null; 2008 } 2009 2010 return new ApfFilter(context, config, ifParams, ipClientCallback, new IpConnectivityLog()); 2011 } 2012 shutdown()2013 public synchronized void shutdown() { 2014 if (mReceiveThread != null) { 2015 log("shutting down"); 2016 mReceiveThread.halt(); // Also closes socket. 2017 mReceiveThread = null; 2018 } 2019 mRas.clear(); 2020 mContext.unregisterReceiver(mDeviceIdleReceiver); 2021 } 2022 setMulticastFilter(boolean isEnabled)2023 public synchronized void setMulticastFilter(boolean isEnabled) { 2024 if (mMulticastFilter == isEnabled) return; 2025 mMulticastFilter = isEnabled; 2026 if (!isEnabled) { 2027 mNumProgramUpdatesAllowingMulticast++; 2028 } 2029 installNewProgramLocked(); 2030 } 2031 2032 /** Adds qname to the mDNS allowlist */ addToMdnsAllowList(String[] labels)2033 public synchronized void addToMdnsAllowList(String[] labels) { 2034 mMdnsAllowList.add(labels); 2035 if (mMulticastFilter) { 2036 installNewProgramLocked(); 2037 } 2038 } 2039 2040 /** Removes qname from the mDNS allowlist */ removeFromAllowList(String[] labels)2041 public synchronized void removeFromAllowList(String[] labels) { 2042 mMdnsAllowList.removeIf(e -> Arrays.equals(labels, e)); 2043 if (mMulticastFilter) { 2044 installNewProgramLocked(); 2045 } 2046 } 2047 2048 @VisibleForTesting setDozeMode(boolean isEnabled)2049 public synchronized void setDozeMode(boolean isEnabled) { 2050 if (mInDozeMode == isEnabled) return; 2051 mInDozeMode = isEnabled; 2052 installNewProgramLocked(); 2053 } 2054 2055 /** Find the single IPv4 LinkAddress if there is one, otherwise return null. */ findIPv4LinkAddress(LinkProperties lp)2056 private static LinkAddress findIPv4LinkAddress(LinkProperties lp) { 2057 LinkAddress ipv4Address = null; 2058 for (LinkAddress address : lp.getLinkAddresses()) { 2059 if (!(address.getAddress() instanceof Inet4Address)) { 2060 continue; 2061 } 2062 if (ipv4Address != null && !ipv4Address.isSameAddressAs(address)) { 2063 // More than one IPv4 address, abort. 2064 return null; 2065 } 2066 ipv4Address = address; 2067 } 2068 return ipv4Address; 2069 } 2070 setLinkProperties(LinkProperties lp)2071 public synchronized void setLinkProperties(LinkProperties lp) { 2072 // NOTE: Do not keep a copy of LinkProperties as it would further duplicate state. 2073 final LinkAddress ipv4Address = findIPv4LinkAddress(lp); 2074 final byte[] addr = (ipv4Address != null) ? ipv4Address.getAddress().getAddress() : null; 2075 final int prefix = (ipv4Address != null) ? ipv4Address.getPrefixLength() : 0; 2076 if ((prefix == mIPv4PrefixLength) && Arrays.equals(addr, mIPv4Address)) { 2077 return; 2078 } 2079 mIPv4Address = addr; 2080 mIPv4PrefixLength = prefix; 2081 installNewProgramLocked(); 2082 } 2083 2084 /** 2085 * Add TCP keepalive ack packet filter. 2086 * This will add a filter to drop acks to the keepalive packet passed as an argument. 2087 * 2088 * @param slot The index used to access the filter. 2089 * @param sentKeepalivePacket The attributes of the sent keepalive packet. 2090 */ addTcpKeepalivePacketFilter(final int slot, final TcpKeepalivePacketDataParcelable sentKeepalivePacket)2091 public synchronized void addTcpKeepalivePacketFilter(final int slot, 2092 final TcpKeepalivePacketDataParcelable sentKeepalivePacket) { 2093 log("Adding keepalive ack(" + slot + ")"); 2094 if (null != mKeepalivePackets.get(slot)) { 2095 throw new IllegalArgumentException("Keepalive slot " + slot + " is occupied"); 2096 } 2097 final int ipVersion = sentKeepalivePacket.srcAddress.length == 4 ? 4 : 6; 2098 mKeepalivePackets.put(slot, (ipVersion == 4) 2099 ? new TcpKeepaliveAckV4(sentKeepalivePacket) 2100 : new TcpKeepaliveAckV6(sentKeepalivePacket)); 2101 installNewProgramLocked(); 2102 } 2103 2104 /** 2105 * Add NAT-T keepalive packet filter. 2106 * This will add a filter to drop NAT-T keepalive packet which is passed as an argument. 2107 * 2108 * @param slot The index used to access the filter. 2109 * @param sentKeepalivePacket The attributes of the sent keepalive packet. 2110 */ addNattKeepalivePacketFilter(final int slot, final NattKeepalivePacketDataParcelable sentKeepalivePacket)2111 public synchronized void addNattKeepalivePacketFilter(final int slot, 2112 final NattKeepalivePacketDataParcelable sentKeepalivePacket) { 2113 log("Adding NAT-T keepalive packet(" + slot + ")"); 2114 if (null != mKeepalivePackets.get(slot)) { 2115 throw new IllegalArgumentException("NAT-T Keepalive slot " + slot + " is occupied"); 2116 } 2117 if (sentKeepalivePacket.srcAddress.length != 4) { 2118 throw new IllegalArgumentException("NAT-T keepalive is only supported on IPv4"); 2119 } 2120 mKeepalivePackets.put(slot, new NattKeepaliveResponse(sentKeepalivePacket)); 2121 installNewProgramLocked(); 2122 } 2123 2124 /** 2125 * Remove keepalive packet filter. 2126 * 2127 * @param slot The index used to access the filter. 2128 */ removeKeepalivePacketFilter(int slot)2129 public synchronized void removeKeepalivePacketFilter(int slot) { 2130 log("Removing keepalive packet(" + slot + ")"); 2131 mKeepalivePackets.remove(slot); 2132 installNewProgramLocked(); 2133 } 2134 counterValue(byte[] data, Counter counter)2135 static public long counterValue(byte[] data, Counter counter) 2136 throws ArrayIndexOutOfBoundsException { 2137 // Follow the same wrap-around addressing scheme of the interpreter. 2138 int offset = counter.offset(); 2139 if (offset < 0) { 2140 offset = data.length + offset; 2141 } 2142 2143 // Decode 32bit big-endian integer into a long so we can count up beyond 2^31. 2144 long value = 0; 2145 for (int i = 0; i < 4; i++) { 2146 value = value << 8 | (data[offset] & 0xFF); 2147 offset++; 2148 } 2149 return value; 2150 } 2151 dump(IndentingPrintWriter pw)2152 public synchronized void dump(IndentingPrintWriter pw) { 2153 pw.println("Capabilities: " + mApfCapabilities); 2154 pw.println("Receive thread: " + (mReceiveThread != null ? "RUNNING" : "STOPPED")); 2155 pw.println("Multicast: " + (mMulticastFilter ? "DROP" : "ALLOW")); 2156 pw.println("Minimum RDNSS lifetime: " + mMinRdnssLifetimeSec); 2157 try { 2158 pw.println("IPv4 address: " + InetAddress.getByAddress(mIPv4Address).getHostAddress()); 2159 } catch (UnknownHostException|NullPointerException e) {} 2160 2161 if (mLastTimeInstalledProgram == 0) { 2162 pw.println("No program installed."); 2163 return; 2164 } 2165 pw.println("Program updates: " + mNumProgramUpdates); 2166 pw.println(String.format( 2167 "Last program length %d, installed %ds ago, lifetime %ds", 2168 mLastInstalledProgram.length, currentTimeSeconds() - mLastTimeInstalledProgram, 2169 mLastInstalledProgramMinLifetime)); 2170 2171 pw.print("Denylisted Ethertypes:"); 2172 for (int p : mEthTypeBlackList) { 2173 pw.print(String.format(" %04x", p)); 2174 } 2175 pw.println(); 2176 pw.println("RA filters:"); 2177 pw.increaseIndent(); 2178 for (Ra ra: mRas) { 2179 pw.println(ra); 2180 pw.increaseIndent(); 2181 pw.println(String.format( 2182 "Seen: %d, last %ds ago", ra.seenCount, currentTimeSeconds() - ra.mLastSeen)); 2183 if (DBG) { 2184 pw.println("Last match:"); 2185 pw.increaseIndent(); 2186 pw.println(ra.getLastMatchingPacket()); 2187 pw.decreaseIndent(); 2188 } 2189 pw.decreaseIndent(); 2190 } 2191 pw.decreaseIndent(); 2192 2193 pw.println("TCP Keepalive filters:"); 2194 pw.increaseIndent(); 2195 for (int i = 0; i < mKeepalivePackets.size(); ++i) { 2196 final KeepalivePacket keepalivePacket = mKeepalivePackets.valueAt(i); 2197 if (keepalivePacket instanceof TcpKeepaliveAck) { 2198 pw.print("Slot "); 2199 pw.print(mKeepalivePackets.keyAt(i)); 2200 pw.print(": "); 2201 pw.println(keepalivePacket); 2202 } 2203 } 2204 pw.decreaseIndent(); 2205 2206 pw.println("NAT-T Keepalive filters:"); 2207 pw.increaseIndent(); 2208 for (int i = 0; i < mKeepalivePackets.size(); ++i) { 2209 final KeepalivePacket keepalivePacket = mKeepalivePackets.valueAt(i); 2210 if (keepalivePacket instanceof NattKeepaliveResponse) { 2211 pw.print("Slot "); 2212 pw.print(mKeepalivePackets.keyAt(i)); 2213 pw.print(": "); 2214 pw.println(keepalivePacket); 2215 } 2216 } 2217 pw.decreaseIndent(); 2218 2219 if (DBG) { 2220 pw.println("Last program:"); 2221 pw.increaseIndent(); 2222 pw.println(HexDump.toHexString(mLastInstalledProgram, false /* lowercase */)); 2223 pw.decreaseIndent(); 2224 } 2225 2226 pw.println("APF packet counters: "); 2227 pw.increaseIndent(); 2228 if (!mApfCapabilities.hasDataAccess()) { 2229 pw.println("APF counters not supported"); 2230 } else if (mDataSnapshot == null) { 2231 pw.println("No last snapshot."); 2232 } else { 2233 try { 2234 Counter[] counters = Counter.class.getEnumConstants(); 2235 for (Counter c : Arrays.asList(counters).subList(1, counters.length)) { 2236 long value = counterValue(mDataSnapshot, c); 2237 // Only print non-zero counters 2238 if (value != 0) { 2239 pw.println(c.toString() + ": " + value); 2240 } 2241 } 2242 } catch (ArrayIndexOutOfBoundsException e) { 2243 pw.println("Uh-oh: " + e); 2244 } 2245 if (VDBG) { 2246 pw.println("Raw data dump: "); 2247 pw.println(HexDump.dumpHexString(mDataSnapshot)); 2248 } 2249 } 2250 pw.decreaseIndent(); 2251 } 2252 2253 // TODO: move to android.net.NetworkUtils 2254 @VisibleForTesting ipv4BroadcastAddress(byte[] addrBytes, int prefixLength)2255 public static int ipv4BroadcastAddress(byte[] addrBytes, int prefixLength) { 2256 return bytesToBEInt(addrBytes) | (int) (Integer.toUnsignedLong(-1) >>> prefixLength); 2257 } 2258 uint8(byte b)2259 private static int uint8(byte b) { 2260 return b & 0xff; 2261 } 2262 getUint16(ByteBuffer buffer, int position)2263 private static int getUint16(ByteBuffer buffer, int position) { 2264 return buffer.getShort(position) & 0xffff; 2265 } 2266 getUint32(ByteBuffer buffer, int position)2267 private static long getUint32(ByteBuffer buffer, int position) { 2268 return Integer.toUnsignedLong(buffer.getInt(position)); 2269 } 2270 getUint8(ByteBuffer buffer, int position)2271 private static int getUint8(ByteBuffer buffer, int position) { 2272 return uint8(buffer.get(position)); 2273 } 2274 bytesToBEInt(byte[] bytes)2275 private static int bytesToBEInt(byte[] bytes) { 2276 return (uint8(bytes[0]) << 24) 2277 + (uint8(bytes[1]) << 16) 2278 + (uint8(bytes[2]) << 8) 2279 + (uint8(bytes[3])); 2280 } 2281 concatArrays(final byte[]... arr)2282 private static byte[] concatArrays(final byte[]... arr) { 2283 int size = 0; 2284 for (byte[] a : arr) { 2285 size += a.length; 2286 } 2287 final byte[] result = new byte[size]; 2288 int offset = 0; 2289 for (byte[] a : arr) { 2290 System.arraycopy(a, 0, result, offset, a.length); 2291 offset += a.length; 2292 } 2293 return result; 2294 } 2295 } 2296