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