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