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.system.OsConstants.*; 20 21 import android.os.SystemClock; 22 import android.net.LinkAddress; 23 import android.net.LinkProperties; 24 import android.net.NetworkUtils; 25 import android.net.apf.ApfGenerator; 26 import android.net.apf.ApfGenerator.IllegalInstructionException; 27 import android.net.apf.ApfGenerator.Register; 28 import android.net.ip.IpManager; 29 import android.net.metrics.ApfProgramEvent; 30 import android.net.metrics.ApfStats; 31 import android.net.metrics.IpConnectivityLog; 32 import android.net.metrics.RaEvent; 33 import android.system.ErrnoException; 34 import android.system.Os; 35 import android.system.PacketSocketAddress; 36 import android.text.format.DateUtils; 37 import android.util.Log; 38 import android.util.Pair; 39 40 import com.android.internal.annotations.GuardedBy; 41 import com.android.internal.annotations.VisibleForTesting; 42 import com.android.internal.util.HexDump; 43 import com.android.internal.util.IndentingPrintWriter; 44 45 import java.io.FileDescriptor; 46 import java.io.IOException; 47 import java.lang.Thread; 48 import java.net.Inet4Address; 49 import java.net.Inet6Address; 50 import java.net.InetAddress; 51 import java.net.NetworkInterface; 52 import java.net.SocketException; 53 import java.net.UnknownHostException; 54 import java.nio.ByteBuffer; 55 import java.nio.BufferUnderflowException; 56 import java.util.ArrayList; 57 import java.util.Arrays; 58 59 import libcore.io.IoBridge; 60 61 /** 62 * For networks that support packet filtering via APF programs, {@code ApfFilter} 63 * listens for IPv6 ICMPv6 router advertisements (RAs) and generates APF programs to 64 * filter out redundant duplicate ones. 65 * 66 * Threading model: 67 * A collection of RAs we've received is kept in mRas. Generating APF programs uses mRas to 68 * know what RAs to filter for, thus generating APF programs is dependent on mRas. 69 * mRas can be accessed by multiple threads: 70 * - ReceiveThread, which listens for RAs and adds them to mRas, and generates APF programs. 71 * - callers of: 72 * - setMulticastFilter(), which can cause an APF program to be generated. 73 * - dump(), which dumps mRas among other things. 74 * - shutdown(), which clears mRas. 75 * So access to mRas is synchronized. 76 * 77 * @hide 78 */ 79 public class ApfFilter { 80 81 // Enums describing the outcome of receiving an RA packet. 82 private static enum ProcessRaResult { 83 MATCH, // Received RA matched a known RA 84 DROPPED, // Received RA ignored due to MAX_RAS 85 PARSE_ERROR, // Received RA could not be parsed 86 ZERO_LIFETIME, // Received RA had 0 lifetime 87 UPDATE_NEW_RA, // APF program updated for new RA 88 UPDATE_EXPIRY // APF program updated for expiry 89 } 90 91 // Thread to listen for RAs. 92 @VisibleForTesting 93 class ReceiveThread extends Thread { 94 private final byte[] mPacket = new byte[1514]; 95 private final FileDescriptor mSocket; 96 private final long mStart = SystemClock.elapsedRealtime(); 97 private final ApfStats mStats = new ApfStats(); 98 99 private volatile boolean mStopped; 100 ReceiveThread(FileDescriptor socket)101 public ReceiveThread(FileDescriptor socket) { 102 mSocket = socket; 103 } 104 halt()105 public void halt() { 106 mStopped = true; 107 try { 108 // Interrupts the read() call the thread is blocked in. 109 IoBridge.closeAndSignalBlockedThreads(mSocket); 110 } catch (IOException ignored) {} 111 } 112 113 @Override run()114 public void run() { 115 log("begin monitoring"); 116 while (!mStopped) { 117 try { 118 int length = Os.read(mSocket, mPacket, 0, mPacket.length); 119 updateStats(processRa(mPacket, length)); 120 } catch (IOException|ErrnoException e) { 121 if (!mStopped) { 122 Log.e(TAG, "Read error", e); 123 } 124 } 125 } 126 logStats(); 127 } 128 updateStats(ProcessRaResult result)129 private void updateStats(ProcessRaResult result) { 130 mStats.receivedRas++; 131 switch(result) { 132 case MATCH: 133 mStats.matchingRas++; 134 return; 135 case DROPPED: 136 mStats.droppedRas++; 137 return; 138 case PARSE_ERROR: 139 mStats.parseErrors++; 140 return; 141 case ZERO_LIFETIME: 142 mStats.zeroLifetimeRas++; 143 return; 144 case UPDATE_EXPIRY: 145 mStats.matchingRas++; 146 mStats.programUpdates++; 147 return; 148 case UPDATE_NEW_RA: 149 mStats.programUpdates++; 150 return; 151 } 152 } 153 logStats()154 private void logStats() { 155 final long nowMs = SystemClock.elapsedRealtime(); 156 synchronized (this) { 157 mStats.durationMs = nowMs - mStart; 158 mStats.maxProgramSize = mApfCapabilities.maximumApfProgramSize; 159 mStats.programUpdatesAll = mNumProgramUpdates; 160 mStats.programUpdatesAllowingMulticast = mNumProgramUpdatesAllowingMulticast; 161 mMetricsLog.log(mStats); 162 logApfProgramEventLocked(nowMs / DateUtils.SECOND_IN_MILLIS); 163 } 164 } 165 } 166 167 private static final String TAG = "ApfFilter"; 168 private static final boolean DBG = true; 169 private static final boolean VDBG = false; 170 171 private static final int ETH_HEADER_LEN = 14; 172 private static final int ETH_DEST_ADDR_OFFSET = 0; 173 private static final int ETH_ETHERTYPE_OFFSET = 12; 174 private static final byte[] ETH_BROADCAST_MAC_ADDRESS = 175 {(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff }; 176 // TODO: Make these offsets relative to end of link-layer header; don't include ETH_HEADER_LEN. 177 private static final int IPV4_FRAGMENT_OFFSET_OFFSET = ETH_HEADER_LEN + 6; 178 // Endianness is not an issue for this constant because the APF interpreter always operates in 179 // network byte order. 180 private static final int IPV4_FRAGMENT_OFFSET_MASK = 0x1fff; 181 private static final int IPV4_PROTOCOL_OFFSET = ETH_HEADER_LEN + 9; 182 private static final int IPV4_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 16; 183 private static final int IPV4_ANY_HOST_ADDRESS = 0; 184 private static final int IPV4_BROADCAST_ADDRESS = -1; // 255.255.255.255 185 186 private static final int IPV6_NEXT_HEADER_OFFSET = ETH_HEADER_LEN + 6; 187 private static final int IPV6_SRC_ADDR_OFFSET = ETH_HEADER_LEN + 8; 188 private static final int IPV6_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 24; 189 private static final int IPV6_HEADER_LEN = 40; 190 // The IPv6 all nodes address ff02::1 191 private static final byte[] IPV6_ALL_NODES_ADDRESS = 192 { (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }; 193 194 private static final int ICMP6_TYPE_OFFSET = ETH_HEADER_LEN + IPV6_HEADER_LEN; 195 private static final int ICMP6_ROUTER_SOLICITATION = 133; 196 private static final int ICMP6_ROUTER_ADVERTISEMENT = 134; 197 private static final int ICMP6_NEIGHBOR_SOLICITATION = 135; 198 private static final int ICMP6_NEIGHBOR_ANNOUNCEMENT = 136; 199 200 // NOTE: this must be added to the IPv4 header length in IPV4_HEADER_SIZE_MEMORY_SLOT 201 private static final int UDP_DESTINATION_PORT_OFFSET = ETH_HEADER_LEN + 2; 202 private static final int UDP_HEADER_LEN = 8; 203 204 private static final int DHCP_CLIENT_PORT = 68; 205 // NOTE: this must be added to the IPv4 header length in IPV4_HEADER_SIZE_MEMORY_SLOT 206 private static final int DHCP_CLIENT_MAC_OFFSET = ETH_HEADER_LEN + UDP_HEADER_LEN + 28; 207 208 private static final int ARP_HEADER_OFFSET = ETH_HEADER_LEN; 209 private static final int ARP_OPCODE_OFFSET = ARP_HEADER_OFFSET + 6; 210 private static final short ARP_OPCODE_REQUEST = 1; 211 private static final short ARP_OPCODE_REPLY = 2; 212 private static final byte[] ARP_IPV4_HEADER = { 213 0, 1, // Hardware type: Ethernet (1) 214 8, 0, // Protocol type: IP (0x0800) 215 6, // Hardware size: 6 216 4, // Protocol size: 4 217 }; 218 private static final int ARP_TARGET_IP_ADDRESS_OFFSET = ETH_HEADER_LEN + 24; 219 // Do not log ApfProgramEvents whose actual lifetimes was less than this. 220 private static final int APF_PROGRAM_EVENT_LIFETIME_THRESHOLD = 2; 221 222 private final ApfCapabilities mApfCapabilities; 223 private final IpManager.Callback mIpManagerCallback; 224 private final NetworkInterface mNetworkInterface; 225 private final IpConnectivityLog mMetricsLog; 226 @VisibleForTesting 227 byte[] mHardwareAddress; 228 @VisibleForTesting 229 ReceiveThread mReceiveThread; 230 @GuardedBy("this") 231 private long mUniqueCounter; 232 @GuardedBy("this") 233 private boolean mMulticastFilter; 234 // Our IPv4 address, if we have just one, otherwise null. 235 @GuardedBy("this") 236 private byte[] mIPv4Address; 237 // The subnet prefix length of our IPv4 network. Only valid if mIPv4Address is not null. 238 @GuardedBy("this") 239 private int mIPv4PrefixLength; 240 241 @VisibleForTesting ApfFilter(ApfCapabilities apfCapabilities, NetworkInterface networkInterface, IpManager.Callback ipManagerCallback, boolean multicastFilter, IpConnectivityLog log)242 ApfFilter(ApfCapabilities apfCapabilities, NetworkInterface networkInterface, 243 IpManager.Callback ipManagerCallback, boolean multicastFilter, IpConnectivityLog log) { 244 mApfCapabilities = apfCapabilities; 245 mIpManagerCallback = ipManagerCallback; 246 mNetworkInterface = networkInterface; 247 mMulticastFilter = multicastFilter; 248 mMetricsLog = log; 249 250 // TODO: ApfFilter should not generate programs until IpManager sends provisioning success. 251 maybeStartFilter(); 252 } 253 log(String s)254 private void log(String s) { 255 Log.d(TAG, "(" + mNetworkInterface.getName() + "): " + s); 256 } 257 258 @GuardedBy("this") getUniqueNumberLocked()259 private long getUniqueNumberLocked() { 260 return mUniqueCounter++; 261 } 262 263 /** 264 * Attempt to start listening for RAs and, if RAs are received, generating and installing 265 * filters to ignore useless RAs. 266 */ 267 @VisibleForTesting maybeStartFilter()268 void maybeStartFilter() { 269 FileDescriptor socket; 270 try { 271 mHardwareAddress = mNetworkInterface.getHardwareAddress(); 272 synchronized(this) { 273 // Install basic filters 274 installNewProgramLocked(); 275 } 276 socket = Os.socket(AF_PACKET, SOCK_RAW, ETH_P_IPV6); 277 PacketSocketAddress addr = new PacketSocketAddress((short) ETH_P_IPV6, 278 mNetworkInterface.getIndex()); 279 Os.bind(socket, addr); 280 NetworkUtils.attachRaFilter(socket, mApfCapabilities.apfPacketFormat); 281 } catch(SocketException|ErrnoException e) { 282 Log.e(TAG, "Error starting filter", e); 283 return; 284 } 285 mReceiveThread = new ReceiveThread(socket); 286 mReceiveThread.start(); 287 } 288 289 // Returns seconds since device boot. 290 @VisibleForTesting currentTimeSeconds()291 protected long currentTimeSeconds() { 292 return SystemClock.elapsedRealtime() / DateUtils.SECOND_IN_MILLIS; 293 } 294 295 public static class InvalidRaException extends Exception { InvalidRaException(String m)296 public InvalidRaException(String m) { 297 super(m); 298 } 299 } 300 301 // A class to hold information about an RA. 302 @VisibleForTesting 303 class Ra { 304 // From RFC4861: 305 private static final int ICMP6_RA_HEADER_LEN = 16; 306 private static final int ICMP6_RA_CHECKSUM_OFFSET = 307 ETH_HEADER_LEN + IPV6_HEADER_LEN + 2; 308 private static final int ICMP6_RA_CHECKSUM_LEN = 2; 309 private static final int ICMP6_RA_OPTION_OFFSET = 310 ETH_HEADER_LEN + IPV6_HEADER_LEN + ICMP6_RA_HEADER_LEN; 311 private static final int ICMP6_RA_ROUTER_LIFETIME_OFFSET = 312 ETH_HEADER_LEN + IPV6_HEADER_LEN + 6; 313 private static final int ICMP6_RA_ROUTER_LIFETIME_LEN = 2; 314 // Prefix information option. 315 private static final int ICMP6_PREFIX_OPTION_TYPE = 3; 316 private static final int ICMP6_PREFIX_OPTION_LEN = 32; 317 private static final int ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET = 4; 318 private static final int ICMP6_PREFIX_OPTION_VALID_LIFETIME_LEN = 4; 319 private static final int ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET = 8; 320 private static final int ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_LEN = 4; 321 322 // From RFC6106: Recursive DNS Server option 323 private static final int ICMP6_RDNSS_OPTION_TYPE = 25; 324 // From RFC6106: DNS Search List option 325 private static final int ICMP6_DNSSL_OPTION_TYPE = 31; 326 327 // From RFC4191: Route Information option 328 private static final int ICMP6_ROUTE_INFO_OPTION_TYPE = 24; 329 // Above three options all have the same format: 330 private static final int ICMP6_4_BYTE_LIFETIME_OFFSET = 4; 331 private static final int ICMP6_4_BYTE_LIFETIME_LEN = 4; 332 333 // Note: mPacket's position() cannot be assumed to be reset. 334 private final ByteBuffer mPacket; 335 // List of binary ranges that include the whole packet except the lifetimes. 336 // Pairs consist of offset and length. 337 private final ArrayList<Pair<Integer, Integer>> mNonLifetimes = 338 new ArrayList<Pair<Integer, Integer>>(); 339 // Minimum lifetime in packet 340 long mMinLifetime; 341 // When the packet was last captured, in seconds since Unix Epoch 342 long mLastSeen; 343 344 // For debugging only. Offsets into the packet where PIOs are. 345 private final ArrayList<Integer> mPrefixOptionOffsets = new ArrayList<>(); 346 347 // For debugging only. Offsets into the packet where RDNSS options are. 348 private final ArrayList<Integer> mRdnssOptionOffsets = new ArrayList<>(); 349 350 // For debugging only. How many times this RA was seen. 351 int seenCount = 0; 352 353 // For debugging only. Returns the hex representation of the last matching packet. getLastMatchingPacket()354 String getLastMatchingPacket() { 355 return HexDump.toHexString(mPacket.array(), 0, mPacket.capacity(), 356 false /* lowercase */); 357 } 358 359 // For debugging only. Returns the string representation of the IPv6 address starting at 360 // position pos in the packet. IPv6AddresstoString(int pos)361 private String IPv6AddresstoString(int pos) { 362 try { 363 byte[] array = mPacket.array(); 364 // Can't just call copyOfRange() and see if it throws, because if it reads past the 365 // end it pads with zeros instead of throwing. 366 if (pos < 0 || pos + 16 > array.length || pos + 16 < pos) { 367 return "???"; 368 } 369 byte[] addressBytes = Arrays.copyOfRange(array, pos, pos + 16); 370 InetAddress address = (Inet6Address) InetAddress.getByAddress(addressBytes); 371 return address.getHostAddress(); 372 } catch (UnsupportedOperationException e) { 373 // array() failed. Cannot happen, mPacket is array-backed and read-write. 374 return "???"; 375 } catch (ClassCastException|UnknownHostException e) { 376 // Cannot happen. 377 return "???"; 378 } 379 } 380 381 // Can't be static because it's in a non-static inner class. 382 // TODO: Make this static once RA is its own class. prefixOptionToString(StringBuffer sb, int offset)383 private void prefixOptionToString(StringBuffer sb, int offset) { 384 String prefix = IPv6AddresstoString(offset + 16); 385 int length = getUint8(mPacket, offset + 2); 386 long valid = getUint32(mPacket, offset + 4); 387 long preferred = getUint32(mPacket, offset + 8); 388 sb.append(String.format("%s/%d %ds/%ds ", prefix, length, valid, preferred)); 389 } 390 rdnssOptionToString(StringBuffer sb, int offset)391 private void rdnssOptionToString(StringBuffer sb, int offset) { 392 int optLen = getUint8(mPacket, offset + 1) * 8; 393 if (optLen < 24) return; // Malformed or empty. 394 long lifetime = getUint32(mPacket, offset + 4); 395 int numServers = (optLen - 8) / 16; 396 sb.append("DNS ").append(lifetime).append("s"); 397 for (int server = 0; server < numServers; server++) { 398 sb.append(" ").append(IPv6AddresstoString(offset + 8 + 16 * server)); 399 } 400 } 401 toString()402 public String toString() { 403 try { 404 StringBuffer sb = new StringBuffer(); 405 sb.append(String.format("RA %s -> %s %ds ", 406 IPv6AddresstoString(IPV6_SRC_ADDR_OFFSET), 407 IPv6AddresstoString(IPV6_DEST_ADDR_OFFSET), 408 getUint16(mPacket, ICMP6_RA_ROUTER_LIFETIME_OFFSET))); 409 for (int i: mPrefixOptionOffsets) { 410 prefixOptionToString(sb, i); 411 } 412 for (int i: mRdnssOptionOffsets) { 413 rdnssOptionToString(sb, i); 414 } 415 return sb.toString(); 416 } catch (BufferUnderflowException|IndexOutOfBoundsException e) { 417 return "<Malformed RA>"; 418 } 419 } 420 421 /** 422 * Add a binary range of the packet that does not include a lifetime to mNonLifetimes. 423 * Assumes mPacket.position() is as far as we've parsed the packet. 424 * @param lastNonLifetimeStart offset within packet of where the last binary range of 425 * data not including a lifetime. 426 * @param lifetimeOffset offset from mPacket.position() to the next lifetime data. 427 * @param lifetimeLength length of the next lifetime data. 428 * @return offset within packet of where the next binary range of data not including 429 * a lifetime. This can be passed into the next invocation of this function 430 * via {@code lastNonLifetimeStart}. 431 */ addNonLifetime(int lastNonLifetimeStart, int lifetimeOffset, int lifetimeLength)432 private int addNonLifetime(int lastNonLifetimeStart, int lifetimeOffset, 433 int lifetimeLength) { 434 lifetimeOffset += mPacket.position(); 435 mNonLifetimes.add(new Pair<Integer, Integer>(lastNonLifetimeStart, 436 lifetimeOffset - lastNonLifetimeStart)); 437 return lifetimeOffset + lifetimeLength; 438 } 439 addNonLifetimeU32(int lastNonLifetimeStart)440 private int addNonLifetimeU32(int lastNonLifetimeStart) { 441 return addNonLifetime(lastNonLifetimeStart, 442 ICMP6_4_BYTE_LIFETIME_OFFSET, ICMP6_4_BYTE_LIFETIME_LEN); 443 } 444 445 // Note that this parses RA and may throw IllegalArgumentException (from 446 // Buffer.position(int) or due to an invalid-length option) or IndexOutOfBoundsException 447 // (from ByteBuffer.get(int) ) if parsing encounters something non-compliant with 448 // specifications. Ra(byte[] packet, int length)449 Ra(byte[] packet, int length) throws InvalidRaException { 450 if (length < ICMP6_RA_OPTION_OFFSET) { 451 throw new InvalidRaException("Not an ICMP6 router advertisement"); 452 } 453 454 mPacket = ByteBuffer.wrap(Arrays.copyOf(packet, length)); 455 mLastSeen = currentTimeSeconds(); 456 457 // Sanity check packet in case a packet arrives before we attach RA filter 458 // to our packet socket. b/29586253 459 if (getUint16(mPacket, ETH_ETHERTYPE_OFFSET) != ETH_P_IPV6 || 460 getUint8(mPacket, IPV6_NEXT_HEADER_OFFSET) != IPPROTO_ICMPV6 || 461 getUint8(mPacket, ICMP6_TYPE_OFFSET) != ICMP6_ROUTER_ADVERTISEMENT) { 462 throw new InvalidRaException("Not an ICMP6 router advertisement"); 463 } 464 465 466 RaEvent.Builder builder = new RaEvent.Builder(); 467 468 // Ignore the checksum. 469 int lastNonLifetimeStart = addNonLifetime(0, 470 ICMP6_RA_CHECKSUM_OFFSET, 471 ICMP6_RA_CHECKSUM_LEN); 472 473 // Parse router lifetime 474 lastNonLifetimeStart = addNonLifetime(lastNonLifetimeStart, 475 ICMP6_RA_ROUTER_LIFETIME_OFFSET, 476 ICMP6_RA_ROUTER_LIFETIME_LEN); 477 builder.updateRouterLifetime(getUint16(mPacket, ICMP6_RA_ROUTER_LIFETIME_OFFSET)); 478 479 // Ensures that the RA is not truncated. 480 mPacket.position(ICMP6_RA_OPTION_OFFSET); 481 while (mPacket.hasRemaining()) { 482 final int position = mPacket.position(); 483 final int optionType = getUint8(mPacket, position); 484 final int optionLength = getUint8(mPacket, position + 1) * 8; 485 long lifetime; 486 switch (optionType) { 487 case ICMP6_PREFIX_OPTION_TYPE: 488 // Parse valid lifetime 489 lastNonLifetimeStart = addNonLifetime(lastNonLifetimeStart, 490 ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET, 491 ICMP6_PREFIX_OPTION_VALID_LIFETIME_LEN); 492 lifetime = getUint32(mPacket, 493 position + ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET); 494 builder.updatePrefixValidLifetime(lifetime); 495 // Parse preferred lifetime 496 lastNonLifetimeStart = addNonLifetime(lastNonLifetimeStart, 497 ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET, 498 ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_LEN); 499 lifetime = getUint32(mPacket, 500 position + ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET); 501 builder.updatePrefixPreferredLifetime(lifetime); 502 mPrefixOptionOffsets.add(position); 503 break; 504 // These three options have the same lifetime offset and size, and 505 // are processed with the same specialized addNonLifetimeU32: 506 case ICMP6_RDNSS_OPTION_TYPE: 507 mRdnssOptionOffsets.add(position); 508 lastNonLifetimeStart = addNonLifetimeU32(lastNonLifetimeStart); 509 lifetime = getUint32(mPacket, position + ICMP6_4_BYTE_LIFETIME_OFFSET); 510 builder.updateRdnssLifetime(lifetime); 511 break; 512 case ICMP6_ROUTE_INFO_OPTION_TYPE: 513 lastNonLifetimeStart = addNonLifetimeU32(lastNonLifetimeStart); 514 lifetime = getUint32(mPacket, position + ICMP6_4_BYTE_LIFETIME_OFFSET); 515 builder.updateRouteInfoLifetime(lifetime); 516 break; 517 case ICMP6_DNSSL_OPTION_TYPE: 518 lastNonLifetimeStart = addNonLifetimeU32(lastNonLifetimeStart); 519 lifetime = getUint32(mPacket, position + ICMP6_4_BYTE_LIFETIME_OFFSET); 520 builder.updateDnsslLifetime(lifetime); 521 break; 522 default: 523 // RFC4861 section 4.2 dictates we ignore unknown options for fowards 524 // compatibility. 525 break; 526 } 527 if (optionLength <= 0) { 528 throw new InvalidRaException(String.format( 529 "Invalid option length opt=%d len=%d", optionType, optionLength)); 530 } 531 mPacket.position(position + optionLength); 532 } 533 // Mark non-lifetime bytes since last lifetime. 534 addNonLifetime(lastNonLifetimeStart, 0, 0); 535 mMinLifetime = minLifetime(packet, length); 536 mMetricsLog.log(builder.build()); 537 } 538 539 // Ignoring lifetimes (which may change) does {@code packet} match this RA? matches(byte[] packet, int length)540 boolean matches(byte[] packet, int length) { 541 if (length != mPacket.capacity()) return false; 542 byte[] referencePacket = mPacket.array(); 543 for (Pair<Integer, Integer> nonLifetime : mNonLifetimes) { 544 for (int i = nonLifetime.first; i < (nonLifetime.first + nonLifetime.second); i++) { 545 if (packet[i] != referencePacket[i]) return false; 546 } 547 } 548 return true; 549 } 550 551 // What is the minimum of all lifetimes within {@code packet} in seconds? 552 // Precondition: matches(packet, length) already returned true. minLifetime(byte[] packet, int length)553 long minLifetime(byte[] packet, int length) { 554 long minLifetime = Long.MAX_VALUE; 555 // Wrap packet in ByteBuffer so we can read big-endian values easily 556 ByteBuffer byteBuffer = ByteBuffer.wrap(packet); 557 for (int i = 0; (i + 1) < mNonLifetimes.size(); i++) { 558 int offset = mNonLifetimes.get(i).first + mNonLifetimes.get(i).second; 559 560 // The checksum is in mNonLifetimes, but it's not a lifetime. 561 if (offset == ICMP6_RA_CHECKSUM_OFFSET) { 562 continue; 563 } 564 565 final int lifetimeLength = mNonLifetimes.get(i+1).first - offset; 566 final long optionLifetime; 567 switch (lifetimeLength) { 568 case 2: 569 optionLifetime = getUint16(byteBuffer, offset); 570 break; 571 case 4: 572 optionLifetime = getUint32(byteBuffer, offset); 573 break; 574 default: 575 throw new IllegalStateException("bogus lifetime size " + lifetimeLength); 576 } 577 minLifetime = Math.min(minLifetime, optionLifetime); 578 } 579 return minLifetime; 580 } 581 582 // How many seconds does this RA's have to live, taking into account the fact 583 // that we might have seen it a while ago. currentLifetime()584 long currentLifetime() { 585 return mMinLifetime - (currentTimeSeconds() - mLastSeen); 586 } 587 isExpired()588 boolean isExpired() { 589 // TODO: We may want to handle 0 lifetime RAs differently, if they are common. We'll 590 // have to calculte the filter lifetime specially as a fraction of 0 is still 0. 591 return currentLifetime() <= 0; 592 } 593 594 // Append a filter for this RA to {@code gen}. Jump to DROP_LABEL if it should be dropped. 595 // Jump to the next filter if packet doesn't match this RA. 596 @GuardedBy("ApfFilter.this") generateFilterLocked(ApfGenerator gen)597 long generateFilterLocked(ApfGenerator gen) throws IllegalInstructionException { 598 String nextFilterLabel = "Ra" + getUniqueNumberLocked(); 599 // Skip if packet is not the right size 600 gen.addLoadFromMemory(Register.R0, gen.PACKET_SIZE_MEMORY_SLOT); 601 gen.addJumpIfR0NotEquals(mPacket.capacity(), nextFilterLabel); 602 int filterLifetime = (int)(currentLifetime() / FRACTION_OF_LIFETIME_TO_FILTER); 603 // Skip filter if expired 604 gen.addLoadFromMemory(Register.R0, gen.FILTER_AGE_MEMORY_SLOT); 605 gen.addJumpIfR0GreaterThan(filterLifetime, nextFilterLabel); 606 for (int i = 0; i < mNonLifetimes.size(); i++) { 607 // Generate code to match the packet bytes 608 Pair<Integer, Integer> nonLifetime = mNonLifetimes.get(i); 609 // Don't generate JNEBS instruction for 0 bytes as it always fails the 610 // ASSERT_FORWARD_IN_PROGRAM(pc + cmp_imm - 1) check where cmp_imm is 611 // the number of bytes to compare. nonLifetime is zero between the 612 // valid and preferred lifetimes in the prefix option. 613 if (nonLifetime.second != 0) { 614 gen.addLoadImmediate(Register.R0, nonLifetime.first); 615 gen.addJumpIfBytesNotEqual(Register.R0, 616 Arrays.copyOfRange(mPacket.array(), nonLifetime.first, 617 nonLifetime.first + nonLifetime.second), 618 nextFilterLabel); 619 } 620 // Generate code to test the lifetimes haven't gone down too far 621 if ((i + 1) < mNonLifetimes.size()) { 622 Pair<Integer, Integer> nextNonLifetime = mNonLifetimes.get(i + 1); 623 int offset = nonLifetime.first + nonLifetime.second; 624 // Skip the checksum. 625 if (offset == ICMP6_RA_CHECKSUM_OFFSET) { 626 continue; 627 } 628 int length = nextNonLifetime.first - offset; 629 switch (length) { 630 case 4: gen.addLoad32(Register.R0, offset); break; 631 case 2: gen.addLoad16(Register.R0, offset); break; 632 default: throw new IllegalStateException("bogus lifetime size " + length); 633 } 634 gen.addJumpIfR0LessThan(filterLifetime, nextFilterLabel); 635 } 636 } 637 gen.addJump(gen.DROP_LABEL); 638 gen.defineLabel(nextFilterLabel); 639 return filterLifetime; 640 } 641 } 642 643 // Maximum number of RAs to filter for. 644 private static final int MAX_RAS = 10; 645 646 @GuardedBy("this") 647 private ArrayList<Ra> mRas = new ArrayList<Ra>(); 648 649 // There is always some marginal benefit to updating the installed APF program when an RA is 650 // seen because we can extend the program's lifetime slightly, but there is some cost to 651 // updating the program, so don't bother unless the program is going to expire soon. This 652 // constant defines "soon" in seconds. 653 private static final long MAX_PROGRAM_LIFETIME_WORTH_REFRESHING = 30; 654 // We don't want to filter an RA for it's whole lifetime as it'll be expired by the time we ever 655 // see a refresh. Using half the lifetime might be a good idea except for the fact that 656 // packets may be dropped, so let's use 6. 657 private static final int FRACTION_OF_LIFETIME_TO_FILTER = 6; 658 659 // When did we last install a filter program? In seconds since Unix Epoch. 660 @GuardedBy("this") 661 private long mLastTimeInstalledProgram; 662 // How long should the last installed filter program live for? In seconds. 663 @GuardedBy("this") 664 private long mLastInstalledProgramMinLifetime; 665 @GuardedBy("this") 666 private ApfProgramEvent mLastInstallEvent; 667 668 // For debugging only. The last program installed. 669 @GuardedBy("this") 670 private byte[] mLastInstalledProgram; 671 672 // How many times the program was updated since we started. 673 @GuardedBy("this") 674 private int mNumProgramUpdates = 0; 675 // How many times the program was updated since we started for allowing multicast traffic. 676 @GuardedBy("this") 677 private int mNumProgramUpdatesAllowingMulticast = 0; 678 679 /** 680 * Generate filter code to process ARP packets. Execution of this code ends in either the 681 * DROP_LABEL or PASS_LABEL and does not fall off the end. 682 * Preconditions: 683 * - Packet being filtered is ARP 684 */ 685 @GuardedBy("this") generateArpFilterLocked(ApfGenerator gen)686 private void generateArpFilterLocked(ApfGenerator gen) throws IllegalInstructionException { 687 // Here's a basic summary of what the ARP filter program does: 688 // 689 // if not ARP IPv4 690 // pass 691 // if not ARP IPv4 reply or request 692 // pass 693 // if unicast ARP reply 694 // pass 695 // if interface has no IPv4 address 696 // if target ip is 0.0.0.0 697 // drop 698 // else 699 // if target ip is not the interface ip 700 // drop 701 // pass 702 703 final String checkTargetIPv4 = "checkTargetIPv4"; 704 705 // Pass if not ARP IPv4. 706 gen.addLoadImmediate(Register.R0, ARP_HEADER_OFFSET); 707 gen.addJumpIfBytesNotEqual(Register.R0, ARP_IPV4_HEADER, gen.PASS_LABEL); 708 709 // Pass if unknown ARP opcode. 710 gen.addLoad16(Register.R0, ARP_OPCODE_OFFSET); 711 gen.addJumpIfR0Equals(ARP_OPCODE_REQUEST, checkTargetIPv4); // Skip to unicast check 712 gen.addJumpIfR0NotEquals(ARP_OPCODE_REPLY, gen.PASS_LABEL); 713 714 // Pass if unicast reply. 715 gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET); 716 gen.addJumpIfBytesNotEqual(Register.R0, ETH_BROADCAST_MAC_ADDRESS, gen.PASS_LABEL); 717 718 // Either a unicast request, a unicast reply, or a broadcast reply. 719 gen.defineLabel(checkTargetIPv4); 720 if (mIPv4Address == null) { 721 // When there is no IPv4 address, drop GARP replies (b/29404209). 722 gen.addLoad32(Register.R0, ARP_TARGET_IP_ADDRESS_OFFSET); 723 gen.addJumpIfR0Equals(IPV4_ANY_HOST_ADDRESS, gen.DROP_LABEL); 724 } else { 725 // When there is an IPv4 address, drop unicast/broadcast requests 726 // and broadcast replies with a different target IPv4 address. 727 gen.addLoadImmediate(Register.R0, ARP_TARGET_IP_ADDRESS_OFFSET); 728 gen.addJumpIfBytesNotEqual(Register.R0, mIPv4Address, gen.DROP_LABEL); 729 } 730 731 gen.addJump(gen.PASS_LABEL); 732 } 733 734 /** 735 * Generate filter code to process IPv4 packets. Execution of this code ends in either the 736 * DROP_LABEL or PASS_LABEL and does not fall off the end. 737 * Preconditions: 738 * - Packet being filtered is IPv4 739 */ 740 @GuardedBy("this") generateIPv4FilterLocked(ApfGenerator gen)741 private void generateIPv4FilterLocked(ApfGenerator gen) throws IllegalInstructionException { 742 // Here's a basic summary of what the IPv4 filter program does: 743 // 744 // if filtering multicast (i.e. multicast lock not held): 745 // if it's DHCP destined to our MAC: 746 // pass 747 // if it's L2 broadcast: 748 // drop 749 // if it's IPv4 multicast: 750 // drop 751 // if it's IPv4 broadcast: 752 // drop 753 // pass 754 755 if (mMulticastFilter) { 756 final String skipDhcpv4Filter = "skip_dhcp_v4_filter"; 757 758 // Pass DHCP addressed to us. 759 // Check it's UDP. 760 gen.addLoad8(Register.R0, IPV4_PROTOCOL_OFFSET); 761 gen.addJumpIfR0NotEquals(IPPROTO_UDP, skipDhcpv4Filter); 762 // Check it's not a fragment. This matches the BPF filter installed by the DHCP client. 763 gen.addLoad16(Register.R0, IPV4_FRAGMENT_OFFSET_OFFSET); 764 gen.addJumpIfR0AnyBitsSet(IPV4_FRAGMENT_OFFSET_MASK, skipDhcpv4Filter); 765 // Check it's addressed to DHCP client port. 766 gen.addLoadFromMemory(Register.R1, gen.IPV4_HEADER_SIZE_MEMORY_SLOT); 767 gen.addLoad16Indexed(Register.R0, UDP_DESTINATION_PORT_OFFSET); 768 gen.addJumpIfR0NotEquals(DHCP_CLIENT_PORT, skipDhcpv4Filter); 769 // Check it's DHCP to our MAC address. 770 gen.addLoadImmediate(Register.R0, DHCP_CLIENT_MAC_OFFSET); 771 // NOTE: Relies on R1 containing IPv4 header offset. 772 gen.addAddR1(); 773 gen.addJumpIfBytesNotEqual(Register.R0, mHardwareAddress, skipDhcpv4Filter); 774 gen.addJump(gen.PASS_LABEL); 775 776 // Drop all multicasts/broadcasts. 777 gen.defineLabel(skipDhcpv4Filter); 778 779 // If IPv4 destination address is in multicast range, drop. 780 gen.addLoad8(Register.R0, IPV4_DEST_ADDR_OFFSET); 781 gen.addAnd(0xf0); 782 gen.addJumpIfR0Equals(0xe0, gen.DROP_LABEL); 783 784 // If IPv4 broadcast packet, drop regardless of L2 (b/30231088). 785 gen.addLoad32(Register.R0, IPV4_DEST_ADDR_OFFSET); 786 gen.addJumpIfR0Equals(IPV4_BROADCAST_ADDRESS, gen.DROP_LABEL); 787 if (mIPv4Address != null && mIPv4PrefixLength < 31) { 788 int broadcastAddr = ipv4BroadcastAddress(mIPv4Address, mIPv4PrefixLength); 789 gen.addJumpIfR0Equals(broadcastAddr, gen.DROP_LABEL); 790 } 791 792 // If L2 broadcast packet, drop. 793 gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET); 794 gen.addJumpIfBytesNotEqual(Register.R0, ETH_BROADCAST_MAC_ADDRESS, gen.PASS_LABEL); 795 gen.addJump(gen.DROP_LABEL); 796 } 797 798 // Otherwise, pass 799 gen.addJump(gen.PASS_LABEL); 800 } 801 802 803 /** 804 * Generate filter code to process IPv6 packets. Execution of this code ends in either the 805 * DROP_LABEL or PASS_LABEL, or falls off the end for ICMPv6 packets. 806 * Preconditions: 807 * - Packet being filtered is IPv6 808 */ 809 @GuardedBy("this") generateIPv6FilterLocked(ApfGenerator gen)810 private void generateIPv6FilterLocked(ApfGenerator gen) throws IllegalInstructionException { 811 // Here's a basic summary of what the IPv6 filter program does: 812 // 813 // if it's not ICMPv6: 814 // if it's multicast and we're dropping multicast: 815 // drop 816 // pass 817 // if it's ICMPv6 RS to any: 818 // drop 819 // if it's ICMPv6 NA to ff02::1: 820 // drop 821 822 gen.addLoad8(Register.R0, IPV6_NEXT_HEADER_OFFSET); 823 824 // Drop multicast if the multicast filter is enabled. 825 if (mMulticastFilter) { 826 // Don't touch ICMPv6 multicast here, we deal with it in more detail later. 827 String skipIpv6MulticastFilterLabel = "skipIPv6MulticastFilter"; 828 gen.addJumpIfR0Equals(IPPROTO_ICMPV6, skipIpv6MulticastFilterLabel); 829 830 // Drop all other packets sent to ff00::/8. 831 gen.addLoad8(Register.R0, IPV6_DEST_ADDR_OFFSET); 832 gen.addJumpIfR0Equals(0xff, gen.DROP_LABEL); 833 // Not multicast and not ICMPv6. Pass. 834 gen.addJump(gen.PASS_LABEL); 835 gen.defineLabel(skipIpv6MulticastFilterLabel); 836 } else { 837 // If not ICMPv6, pass. 838 gen.addJumpIfR0NotEquals(IPPROTO_ICMPV6, gen.PASS_LABEL); 839 } 840 841 // Add unsolicited multicast neighbor announcements filter 842 String skipUnsolicitedMulticastNALabel = "skipUnsolicitedMulticastNA"; 843 gen.addLoad8(Register.R0, ICMP6_TYPE_OFFSET); 844 // Drop all router solicitations (b/32833400) 845 gen.addJumpIfR0Equals(ICMP6_ROUTER_SOLICITATION, gen.DROP_LABEL); 846 // If not neighbor announcements, skip filter. 847 gen.addJumpIfR0NotEquals(ICMP6_NEIGHBOR_ANNOUNCEMENT, skipUnsolicitedMulticastNALabel); 848 // If to ff02::1, drop. 849 // TODO: Drop only if they don't contain the address of on-link neighbours. 850 gen.addLoadImmediate(Register.R0, IPV6_DEST_ADDR_OFFSET); 851 gen.addJumpIfBytesNotEqual(Register.R0, IPV6_ALL_NODES_ADDRESS, 852 skipUnsolicitedMulticastNALabel); 853 gen.addJump(gen.DROP_LABEL); 854 gen.defineLabel(skipUnsolicitedMulticastNALabel); 855 } 856 857 /** 858 * Begin generating an APF program to: 859 * <ul> 860 * <li>Drop ARP requests not for us, if mIPv4Address is set, 861 * <li>Drop IPv4 broadcast packets, except DHCP destined to our MAC, 862 * <li>Drop IPv4 multicast packets, if mMulticastFilter, 863 * <li>Pass all other IPv4 packets, 864 * <li>Drop all broadcast non-IP non-ARP packets. 865 * <li>Pass all non-ICMPv6 IPv6 packets, 866 * <li>Pass all non-IPv4 and non-IPv6 packets, 867 * <li>Drop IPv6 ICMPv6 NAs to ff02::1. 868 * <li>Drop IPv6 ICMPv6 RSs. 869 * <li>Let execution continue off the end of the program for IPv6 ICMPv6 packets. This allows 870 * insertion of RA filters here, or if there aren't any, just passes the packets. 871 * </ul> 872 */ 873 @GuardedBy("this") beginProgramLocked()874 private ApfGenerator beginProgramLocked() throws IllegalInstructionException { 875 ApfGenerator gen = new ApfGenerator(); 876 // This is guaranteed to return true because of the check in maybeCreate. 877 gen.setApfVersion(mApfCapabilities.apfVersionSupported); 878 879 // Here's a basic summary of what the initial program does: 880 // 881 // if it's ARP: 882 // insert ARP filter to drop or pass these appropriately 883 // if it's IPv4: 884 // insert IPv4 filter to drop or pass these appropriately 885 // if it's not IPv6: 886 // if it's broadcast: 887 // drop 888 // pass 889 // insert IPv6 filter to drop, pass, or fall off the end for ICMPv6 packets 890 891 // Add ARP filters: 892 String skipArpFiltersLabel = "skipArpFilters"; 893 gen.addLoad16(Register.R0, ETH_ETHERTYPE_OFFSET); 894 gen.addJumpIfR0NotEquals(ETH_P_ARP, skipArpFiltersLabel); 895 generateArpFilterLocked(gen); 896 gen.defineLabel(skipArpFiltersLabel); 897 898 // Add IPv4 filters: 899 String skipIPv4FiltersLabel = "skipIPv4Filters"; 900 // NOTE: Relies on R0 containing ethertype. This is safe because if we got here, we did not 901 // execute the ARP filter, since that filter does not fall through, but either drops or 902 // passes. 903 gen.addJumpIfR0NotEquals(ETH_P_IP, skipIPv4FiltersLabel); 904 generateIPv4FilterLocked(gen); 905 gen.defineLabel(skipIPv4FiltersLabel); 906 907 // Check for IPv6: 908 // NOTE: Relies on R0 containing ethertype. This is safe because if we got here, we did not 909 // execute the ARP or IPv4 filters, since those filters do not fall through, but either 910 // drop or pass. 911 String ipv6FilterLabel = "IPv6Filters"; 912 gen.addJumpIfR0Equals(ETH_P_IPV6, ipv6FilterLabel); 913 914 // Drop non-IP non-ARP broadcasts, pass the rest 915 gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET); 916 gen.addJumpIfBytesNotEqual(Register.R0, ETH_BROADCAST_MAC_ADDRESS, gen.PASS_LABEL); 917 gen.addJump(gen.DROP_LABEL); 918 919 // Add IPv6 filters: 920 gen.defineLabel(ipv6FilterLabel); 921 generateIPv6FilterLocked(gen); 922 return gen; 923 } 924 925 /** 926 * Generate and install a new filter program. 927 */ 928 @GuardedBy("this") 929 @VisibleForTesting installNewProgramLocked()930 void installNewProgramLocked() { 931 purgeExpiredRasLocked(); 932 ArrayList<Ra> rasToFilter = new ArrayList<>(); 933 final byte[] program; 934 long programMinLifetime = Long.MAX_VALUE; 935 try { 936 // Step 1: Determine how many RA filters we can fit in the program. 937 ApfGenerator gen = beginProgramLocked(); 938 for (Ra ra : mRas) { 939 ra.generateFilterLocked(gen); 940 // Stop if we get too big. 941 if (gen.programLengthOverEstimate() > mApfCapabilities.maximumApfProgramSize) break; 942 rasToFilter.add(ra); 943 } 944 // Step 2: Actually generate the program 945 gen = beginProgramLocked(); 946 for (Ra ra : rasToFilter) { 947 programMinLifetime = Math.min(programMinLifetime, ra.generateFilterLocked(gen)); 948 } 949 // Execution will reach the end of the program if no filters match, which will pass the 950 // packet to the AP. 951 program = gen.generate(); 952 } catch (IllegalInstructionException|IllegalStateException e) { 953 Log.e(TAG, "Failed to generate APF program.", e); 954 return; 955 } 956 final long now = currentTimeSeconds(); 957 mLastTimeInstalledProgram = now; 958 mLastInstalledProgramMinLifetime = programMinLifetime; 959 mLastInstalledProgram = program; 960 mNumProgramUpdates++; 961 962 if (VDBG) { 963 hexDump("Installing filter: ", program, program.length); 964 } 965 mIpManagerCallback.installPacketFilter(program); 966 logApfProgramEventLocked(now); 967 mLastInstallEvent = new ApfProgramEvent(); 968 mLastInstallEvent.lifetime = programMinLifetime; 969 mLastInstallEvent.filteredRas = rasToFilter.size(); 970 mLastInstallEvent.currentRas = mRas.size(); 971 mLastInstallEvent.programLength = program.length; 972 mLastInstallEvent.flags = ApfProgramEvent.flagsFor(mIPv4Address != null, mMulticastFilter); 973 } 974 logApfProgramEventLocked(long now)975 private void logApfProgramEventLocked(long now) { 976 if (mLastInstallEvent == null) { 977 return; 978 } 979 ApfProgramEvent ev = mLastInstallEvent; 980 mLastInstallEvent = null; 981 ev.actualLifetime = now - mLastTimeInstalledProgram; 982 if (ev.actualLifetime < APF_PROGRAM_EVENT_LIFETIME_THRESHOLD) { 983 return; 984 } 985 mMetricsLog.log(ev); 986 } 987 988 /** 989 * Returns {@code true} if a new program should be installed because the current one dies soon. 990 */ shouldInstallnewProgram()991 private boolean shouldInstallnewProgram() { 992 long expiry = mLastTimeInstalledProgram + mLastInstalledProgramMinLifetime; 993 return expiry < currentTimeSeconds() + MAX_PROGRAM_LIFETIME_WORTH_REFRESHING; 994 } 995 hexDump(String msg, byte[] packet, int length)996 private void hexDump(String msg, byte[] packet, int length) { 997 log(msg + HexDump.toHexString(packet, 0, length, false /* lowercase */)); 998 } 999 1000 @GuardedBy("this") purgeExpiredRasLocked()1001 private void purgeExpiredRasLocked() { 1002 for (int i = 0; i < mRas.size();) { 1003 if (mRas.get(i).isExpired()) { 1004 log("Expiring " + mRas.get(i)); 1005 mRas.remove(i); 1006 } else { 1007 i++; 1008 } 1009 } 1010 } 1011 1012 /** 1013 * Process an RA packet, updating the list of known RAs and installing a new APF program 1014 * if the current APF program should be updated. 1015 * @return a ProcessRaResult enum describing what action was performed. 1016 */ 1017 @VisibleForTesting processRa(byte[] packet, int length)1018 synchronized ProcessRaResult processRa(byte[] packet, int length) { 1019 if (VDBG) hexDump("Read packet = ", packet, length); 1020 1021 // Have we seen this RA before? 1022 for (int i = 0; i < mRas.size(); i++) { 1023 Ra ra = mRas.get(i); 1024 if (ra.matches(packet, length)) { 1025 if (VDBG) log("matched RA " + ra); 1026 // Update lifetimes. 1027 ra.mLastSeen = currentTimeSeconds(); 1028 ra.mMinLifetime = ra.minLifetime(packet, length); 1029 ra.seenCount++; 1030 1031 // Keep mRas in LRU order so as to prioritize generating filters for recently seen 1032 // RAs. LRU prioritizes this because RA filters are generated in order from mRas 1033 // until the filter program exceeds the maximum filter program size allowed by the 1034 // chipset, so RAs appearing earlier in mRas are more likely to make it into the 1035 // filter program. 1036 // TODO: consider sorting the RAs in order of increasing expiry time as well. 1037 // Swap to front of array. 1038 mRas.add(0, mRas.remove(i)); 1039 1040 // If the current program doesn't expire for a while, don't update. 1041 if (shouldInstallnewProgram()) { 1042 installNewProgramLocked(); 1043 return ProcessRaResult.UPDATE_EXPIRY; 1044 } 1045 return ProcessRaResult.MATCH; 1046 } 1047 } 1048 purgeExpiredRasLocked(); 1049 // TODO: figure out how to proceed when we've received more then MAX_RAS RAs. 1050 if (mRas.size() >= MAX_RAS) { 1051 return ProcessRaResult.DROPPED; 1052 } 1053 final Ra ra; 1054 try { 1055 ra = new Ra(packet, length); 1056 } catch (Exception e) { 1057 Log.e(TAG, "Error parsing RA", e); 1058 return ProcessRaResult.PARSE_ERROR; 1059 } 1060 // Ignore 0 lifetime RAs. 1061 if (ra.isExpired()) { 1062 return ProcessRaResult.ZERO_LIFETIME; 1063 } 1064 log("Adding " + ra); 1065 mRas.add(ra); 1066 installNewProgramLocked(); 1067 return ProcessRaResult.UPDATE_NEW_RA; 1068 } 1069 1070 /** 1071 * Create an {@link ApfFilter} if {@code apfCapabilities} indicates support for packet 1072 * filtering using APF programs. 1073 */ maybeCreate(ApfCapabilities apfCapabilities, NetworkInterface networkInterface, IpManager.Callback ipManagerCallback, boolean multicastFilter)1074 public static ApfFilter maybeCreate(ApfCapabilities apfCapabilities, 1075 NetworkInterface networkInterface, IpManager.Callback ipManagerCallback, 1076 boolean multicastFilter) { 1077 if (apfCapabilities == null || networkInterface == null) return null; 1078 if (apfCapabilities.apfVersionSupported == 0) return null; 1079 if (apfCapabilities.maximumApfProgramSize < 512) { 1080 Log.e(TAG, "Unacceptably small APF limit: " + apfCapabilities.maximumApfProgramSize); 1081 return null; 1082 } 1083 // For now only support generating programs for Ethernet frames. If this restriction is 1084 // lifted: 1085 // 1. the program generator will need its offsets adjusted. 1086 // 2. the packet filter attached to our packet socket will need its offset adjusted. 1087 if (apfCapabilities.apfPacketFormat != ARPHRD_ETHER) return null; 1088 if (!new ApfGenerator().setApfVersion(apfCapabilities.apfVersionSupported)) { 1089 Log.e(TAG, "Unsupported APF version: " + apfCapabilities.apfVersionSupported); 1090 return null; 1091 } 1092 return new ApfFilter(apfCapabilities, networkInterface, ipManagerCallback, 1093 multicastFilter, new IpConnectivityLog()); 1094 } 1095 shutdown()1096 public synchronized void shutdown() { 1097 if (mReceiveThread != null) { 1098 log("shutting down"); 1099 mReceiveThread.halt(); // Also closes socket. 1100 mReceiveThread = null; 1101 } 1102 mRas.clear(); 1103 } 1104 setMulticastFilter(boolean isEnabled)1105 public synchronized void setMulticastFilter(boolean isEnabled) { 1106 if (mMulticastFilter == isEnabled) { 1107 return; 1108 } 1109 mMulticastFilter = isEnabled; 1110 if (!isEnabled) { 1111 mNumProgramUpdatesAllowingMulticast++; 1112 } 1113 installNewProgramLocked(); 1114 } 1115 1116 /** Find the single IPv4 LinkAddress if there is one, otherwise return null. */ findIPv4LinkAddress(LinkProperties lp)1117 private static LinkAddress findIPv4LinkAddress(LinkProperties lp) { 1118 LinkAddress ipv4Address = null; 1119 for (LinkAddress address : lp.getLinkAddresses()) { 1120 if (!(address.getAddress() instanceof Inet4Address)) { 1121 continue; 1122 } 1123 if (ipv4Address != null && !ipv4Address.isSameAddressAs(address)) { 1124 // More than one IPv4 address, abort. 1125 return null; 1126 } 1127 ipv4Address = address; 1128 } 1129 return ipv4Address; 1130 } 1131 setLinkProperties(LinkProperties lp)1132 public synchronized void setLinkProperties(LinkProperties lp) { 1133 // NOTE: Do not keep a copy of LinkProperties as it would further duplicate state. 1134 final LinkAddress ipv4Address = findIPv4LinkAddress(lp); 1135 final byte[] addr = (ipv4Address != null) ? ipv4Address.getAddress().getAddress() : null; 1136 final int prefix = (ipv4Address != null) ? ipv4Address.getPrefixLength() : 0; 1137 if ((prefix == mIPv4PrefixLength) && Arrays.equals(addr, mIPv4Address)) { 1138 return; 1139 } 1140 mIPv4Address = addr; 1141 mIPv4PrefixLength = prefix; 1142 installNewProgramLocked(); 1143 } 1144 dump(IndentingPrintWriter pw)1145 public synchronized void dump(IndentingPrintWriter pw) { 1146 pw.println("Capabilities: " + mApfCapabilities); 1147 pw.println("Receive thread: " + (mReceiveThread != null ? "RUNNING" : "STOPPED")); 1148 pw.println("Multicast: " + (mMulticastFilter ? "DROP" : "ALLOW")); 1149 try { 1150 pw.println("IPv4 address: " + InetAddress.getByAddress(mIPv4Address).getHostAddress()); 1151 } catch (UnknownHostException|NullPointerException e) {} 1152 1153 if (mLastTimeInstalledProgram == 0) { 1154 pw.println("No program installed."); 1155 return; 1156 } 1157 pw.println("Program updates: " + mNumProgramUpdates); 1158 pw.println(String.format( 1159 "Last program length %d, installed %ds ago, lifetime %ds", 1160 mLastInstalledProgram.length, currentTimeSeconds() - mLastTimeInstalledProgram, 1161 mLastInstalledProgramMinLifetime)); 1162 1163 pw.println("RA filters:"); 1164 pw.increaseIndent(); 1165 for (Ra ra: mRas) { 1166 pw.println(ra); 1167 pw.increaseIndent(); 1168 pw.println(String.format( 1169 "Seen: %d, last %ds ago", ra.seenCount, currentTimeSeconds() - ra.mLastSeen)); 1170 if (DBG) { 1171 pw.println("Last match:"); 1172 pw.increaseIndent(); 1173 pw.println(ra.getLastMatchingPacket()); 1174 pw.decreaseIndent(); 1175 } 1176 pw.decreaseIndent(); 1177 } 1178 pw.decreaseIndent(); 1179 1180 if (DBG) { 1181 pw.println("Last program:"); 1182 pw.increaseIndent(); 1183 pw.println(HexDump.toHexString(mLastInstalledProgram, false /* lowercase */)); 1184 pw.decreaseIndent(); 1185 } 1186 } 1187 uint8(byte b)1188 private static int uint8(byte b) { 1189 return b & 0xff; 1190 } 1191 uint16(short s)1192 private static int uint16(short s) { 1193 return s & 0xffff; 1194 } 1195 uint32(int i)1196 private static long uint32(int i) { 1197 return i & 0xffffffffL; 1198 } 1199 getUint8(ByteBuffer buffer, int position)1200 private static int getUint8(ByteBuffer buffer, int position) { 1201 return uint8(buffer.get(position)); 1202 } 1203 getUint16(ByteBuffer buffer, int position)1204 private static int getUint16(ByteBuffer buffer, int position) { 1205 return uint16(buffer.getShort(position)); 1206 } 1207 getUint32(ByteBuffer buffer, int position)1208 private static long getUint32(ByteBuffer buffer, int position) { 1209 return uint32(buffer.getInt(position)); 1210 } 1211 1212 // TODO: move to android.net.NetworkUtils 1213 @VisibleForTesting ipv4BroadcastAddress(byte[] addrBytes, int prefixLength)1214 public static int ipv4BroadcastAddress(byte[] addrBytes, int prefixLength) { 1215 return bytesToInt(addrBytes) | (int) (uint32(-1) >>> prefixLength); 1216 } 1217 1218 @VisibleForTesting bytesToInt(byte[] addrBytes)1219 public static int bytesToInt(byte[] addrBytes) { 1220 return (uint8(addrBytes[0]) << 24) 1221 + (uint8(addrBytes[1]) << 16) 1222 + (uint8(addrBytes[2]) << 8) 1223 + (uint8(addrBytes[3])); 1224 } 1225 } 1226