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