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