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