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