1 /* 2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.net.apf; 18 19 import static android.net.apf.ApfConstants.APF_MAX_ETH_TYPE_BLACK_LIST_LEN; 20 import static android.net.apf.ApfConstants.ARP_HEADER_OFFSET; 21 import static android.net.apf.ApfConstants.ARP_IPV4_HEADER; 22 import static android.net.apf.ApfConstants.ARP_OPCODE_OFFSET; 23 import static android.net.apf.ApfConstants.ARP_OPCODE_REPLY; 24 import static android.net.apf.ApfConstants.ARP_OPCODE_REQUEST; 25 import static android.net.apf.ApfConstants.ARP_SOURCE_IP_ADDRESS_OFFSET; 26 import static android.net.apf.ApfConstants.ARP_TARGET_IP_ADDRESS_OFFSET; 27 import static android.net.apf.ApfConstants.DHCP_CLIENT_MAC_OFFSET; 28 import static android.net.apf.ApfConstants.DHCP_CLIENT_PORT; 29 import static android.net.apf.ApfConstants.DHCP_SERVER_PORT; 30 import static android.net.apf.ApfConstants.ECHO_PORT; 31 import static android.net.apf.ApfConstants.ETH_DEST_ADDR_OFFSET; 32 import static android.net.apf.ApfConstants.ETH_ETHERTYPE_OFFSET; 33 import static android.net.apf.ApfConstants.ETH_HEADER_LEN; 34 import static android.net.apf.ApfConstants.ETH_MULTICAST_MDNS_V4_MAC_ADDRESS; 35 import static android.net.apf.ApfConstants.ETH_MULTICAST_MDNS_V6_MAC_ADDRESS; 36 import static android.net.apf.ApfConstants.ETH_TYPE_MAX; 37 import static android.net.apf.ApfConstants.ETH_TYPE_MIN; 38 import static android.net.apf.ApfConstants.FIXED_ARP_REPLY_HEADER; 39 import static android.net.apf.ApfConstants.ICMP6_CHECKSUM_OFFSET; 40 import static android.net.apf.ApfConstants.ICMP6_CODE_OFFSET; 41 import static android.net.apf.ApfConstants.ICMP6_NS_OPTION_TYPE_OFFSET; 42 import static android.net.apf.ApfConstants.ICMP6_NS_TARGET_IP_OFFSET; 43 import static android.net.apf.ApfConstants.ICMP6_TYPE_OFFSET; 44 import static android.net.apf.ApfConstants.IPPROTO_HOPOPTS; 45 import static android.net.apf.ApfConstants.IPV4_ANY_HOST_ADDRESS; 46 import static android.net.apf.ApfConstants.IPV4_BROADCAST_ADDRESS; 47 import static android.net.apf.ApfConstants.IPV4_DEST_ADDR_OFFSET; 48 import static android.net.apf.ApfConstants.IPV4_FRAGMENT_MORE_FRAGS_MASK; 49 import static android.net.apf.ApfConstants.IPV4_FRAGMENT_OFFSET_MASK; 50 import static android.net.apf.ApfConstants.IPV4_FRAGMENT_OFFSET_OFFSET; 51 import static android.net.apf.ApfConstants.IPV4_PROTOCOL_OFFSET; 52 import static android.net.apf.ApfConstants.IPV4_TOTAL_LENGTH_OFFSET; 53 import static android.net.apf.ApfConstants.IPV6_ALL_NODES_ADDRESS; 54 import static android.net.apf.ApfConstants.IPV6_DEST_ADDR_OFFSET; 55 import static android.net.apf.ApfConstants.IPV6_FLOW_LABEL_LEN; 56 import static android.net.apf.ApfConstants.IPV6_FLOW_LABEL_OFFSET; 57 import static android.net.apf.ApfConstants.IPV6_HEADER_LEN; 58 import static android.net.apf.ApfConstants.IPV6_HOP_LIMIT_OFFSET; 59 import static android.net.apf.ApfConstants.IPV6_NEXT_HEADER_OFFSET; 60 import static android.net.apf.ApfConstants.IPV6_PAYLOAD_LEN_OFFSET; 61 import static android.net.apf.ApfConstants.IPV6_SOLICITED_NODES_PREFIX; 62 import static android.net.apf.ApfConstants.IPV6_SRC_ADDR_OFFSET; 63 import static android.net.apf.ApfConstants.MDNS_PORT; 64 import static android.net.apf.ApfConstants.TCP_HEADER_SIZE_OFFSET; 65 import static android.net.apf.ApfConstants.TCP_UDP_DESTINATION_PORT_OFFSET; 66 import static android.net.apf.ApfConstants.TCP_UDP_SOURCE_PORT_OFFSET; 67 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV6_NS_INVALID; 68 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV6_NS_OTHER_HOST; 69 import static android.net.apf.ApfCounterTracker.Counter.PASSED_IPV6_NS_MULTIPLE_OPTIONS; 70 import static android.net.apf.ApfCounterTracker.Counter.PASSED_IPV6_NS_NO_ADDRESS; 71 import static android.net.apf.BaseApfGenerator.MemorySlot; 72 import static android.net.apf.BaseApfGenerator.Register.R0; 73 import static android.net.apf.BaseApfGenerator.Register.R1; 74 import static android.net.util.SocketUtils.makePacketSocketAddress; 75 import static android.os.PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED; 76 import static android.os.PowerManager.ACTION_DEVICE_LIGHT_IDLE_MODE_CHANGED; 77 import static android.system.OsConstants.AF_PACKET; 78 import static android.system.OsConstants.ARPHRD_ETHER; 79 import static android.system.OsConstants.ETH_P_ARP; 80 import static android.system.OsConstants.ETH_P_IP; 81 import static android.system.OsConstants.ETH_P_IPV6; 82 import static android.system.OsConstants.IFA_F_TENTATIVE; 83 import static android.system.OsConstants.IPPROTO_ICMPV6; 84 import static android.system.OsConstants.IPPROTO_TCP; 85 import static android.system.OsConstants.IPPROTO_UDP; 86 import static android.system.OsConstants.SOCK_CLOEXEC; 87 import static android.system.OsConstants.SOCK_RAW; 88 89 import static com.android.net.module.util.NetworkStackConstants.ETHER_ADDR_LEN; 90 import static com.android.net.module.util.NetworkStackConstants.ETHER_BROADCAST; 91 import static com.android.net.module.util.NetworkStackConstants.ETHER_HEADER_LEN; 92 import static com.android.net.module.util.NetworkStackConstants.ETHER_SRC_ADDR_OFFSET; 93 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ECHO_REQUEST_TYPE; 94 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_NA_HEADER_LEN; 95 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_TLLA; 96 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_TLLA_LEN; 97 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_NEIGHBOR_ADVERTISEMENT; 98 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_NEIGHBOR_SOLICITATION; 99 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ROUTER_ADVERTISEMENT; 100 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ROUTER_SOLICITATION; 101 import static com.android.net.module.util.NetworkStackConstants.IPV4_ADDR_LEN; 102 import static com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_LEN; 103 104 import android.annotation.NonNull; 105 import android.annotation.Nullable; 106 import android.content.BroadcastReceiver; 107 import android.content.Context; 108 import android.content.Intent; 109 import android.content.IntentFilter; 110 import android.net.LinkAddress; 111 import android.net.LinkProperties; 112 import android.net.MacAddress; 113 import android.net.NattKeepalivePacketDataParcelable; 114 import android.net.TcpKeepalivePacketDataParcelable; 115 import android.net.apf.ApfCounterTracker.Counter; 116 import android.net.apf.BaseApfGenerator.IllegalInstructionException; 117 import android.net.ip.IpClient.IpClientCallbacksWrapper; 118 import android.os.PowerManager; 119 import android.os.SystemClock; 120 import android.stats.connectivity.NetworkQuirkEvent; 121 import android.system.ErrnoException; 122 import android.system.Os; 123 import android.text.format.DateUtils; 124 import android.util.ArraySet; 125 import android.util.Log; 126 import android.util.Pair; 127 import android.util.SparseArray; 128 129 import com.android.internal.annotations.GuardedBy; 130 import com.android.internal.annotations.VisibleForTesting; 131 import com.android.internal.util.HexDump; 132 import com.android.internal.util.IndentingPrintWriter; 133 import com.android.internal.util.TokenBucket; 134 import com.android.modules.utils.build.SdkLevel; 135 import com.android.net.module.util.CollectionUtils; 136 import com.android.net.module.util.ConnectivityUtils; 137 import com.android.net.module.util.InterfaceParams; 138 import com.android.net.module.util.SocketUtils; 139 import com.android.networkstack.metrics.ApfSessionInfoMetrics; 140 import com.android.networkstack.metrics.IpClientRaInfoMetrics; 141 import com.android.networkstack.metrics.NetworkQuirkMetrics; 142 import com.android.networkstack.util.NetworkStackUtils; 143 144 import java.io.FileDescriptor; 145 import java.io.IOException; 146 import java.net.Inet4Address; 147 import java.net.Inet6Address; 148 import java.net.InetAddress; 149 import java.net.SocketAddress; 150 import java.net.SocketException; 151 import java.net.UnknownHostException; 152 import java.nio.BufferUnderflowException; 153 import java.nio.ByteBuffer; 154 import java.nio.ByteOrder; 155 import java.util.ArrayList; 156 import java.util.Arrays; 157 import java.util.List; 158 import java.util.Map; 159 import java.util.Set; 160 161 /** 162 * For networks that support packet filtering via APF programs, {@code ApfFilter} 163 * listens for IPv6 ICMPv6 router advertisements (RAs) and generates APF programs to 164 * filter out redundant duplicate ones. 165 * <p> 166 * Threading model: 167 * A collection of RAs we've received is kept in mRas. Generating APF programs uses mRas to 168 * know what RAs to filter for, thus generating APF programs is dependent on mRas. 169 * mRas can be accessed by multiple threads: 170 * - ReceiveThread, which listens for RAs and adds them to mRas, and generates APF programs. 171 * - callers of: 172 * - setMulticastFilter(), which can cause an APF program to be generated. 173 * - dump(), which dumps mRas among other things. 174 * - shutdown(), which clears mRas. 175 * So access to mRas is synchronized. 176 * 177 * @hide 178 */ 179 public class ApfFilter implements AndroidPacketFilter { 180 181 // Helper class for specifying functional filter parameters. 182 public static class ApfConfiguration { 183 public ApfCapabilities apfCapabilities; 184 public int installableProgramSizeClamp = Integer.MAX_VALUE; 185 public boolean multicastFilter; 186 public boolean ieee802_3Filter; 187 public int[] ethTypeBlackList; 188 public int minRdnssLifetimeSec; 189 public int acceptRaMinLft; 190 public boolean shouldHandleLightDoze; 191 public long minMetricsSessionDurationMs; 192 public boolean hasClatInterface; 193 public boolean shouldHandleArpOffload; 194 } 195 196 /** A wrapper class of {@link SystemClock} to be mocked in unit tests. */ 197 public static class Clock { 198 /** 199 * @see SystemClock#elapsedRealtime 200 */ elapsedRealtime()201 public long elapsedRealtime() { 202 return SystemClock.elapsedRealtime(); 203 } 204 } 205 206 // Thread to listen for RAs. 207 @VisibleForTesting 208 public class ReceiveThread extends Thread { 209 private final byte[] mPacket = new byte[1514]; 210 private final FileDescriptor mSocket; 211 212 private volatile boolean mStopped; 213 ReceiveThread(FileDescriptor socket)214 public ReceiveThread(FileDescriptor socket) { 215 mSocket = socket; 216 } 217 halt()218 public void halt() { 219 mStopped = true; 220 // Interrupts the read() call the thread is blocked in. 221 SocketUtils.closeSocketQuietly(mSocket); 222 } 223 224 @Override run()225 public void run() { 226 log("begin monitoring"); 227 while (!mStopped) { 228 try { 229 int length = Os.read(mSocket, mPacket, 0, mPacket.length); 230 processRa(mPacket, length); 231 } catch (IOException|ErrnoException e) { 232 if (!mStopped) { 233 Log.e(TAG, "Read error", e); 234 } 235 } 236 } 237 } 238 } 239 240 private static final String TAG = "ApfFilter"; 241 private static final boolean DBG = true; 242 private static final boolean VDBG = false; 243 244 private final ApfCapabilities mApfCapabilities; 245 private final int mInstallableProgramSizeClamp; 246 private final IpClientCallbacksWrapper mIpClientCallback; 247 private final InterfaceParams mInterfaceParams; 248 private final TokenBucket mTokenBucket; 249 250 @VisibleForTesting 251 @NonNull 252 public byte[] mHardwareAddress; 253 @VisibleForTesting 254 public ReceiveThread mReceiveThread; 255 @GuardedBy("this") 256 private long mUniqueCounter; 257 @GuardedBy("this") 258 private boolean mMulticastFilter; 259 @GuardedBy("this") 260 private boolean mInDozeMode; 261 private final boolean mDrop802_3Frames; 262 private final int[] mEthTypeBlackList; 263 264 private final Clock mClock; 265 private final ApfCounterTracker mApfCounterTracker = new ApfCounterTracker(); 266 @GuardedBy("this") 267 private final long mSessionStartMs; 268 @GuardedBy("this") 269 private int mNumParseErrorRas = 0; 270 @GuardedBy("this") 271 private int mNumZeroLifetimeRas = 0; 272 @GuardedBy("this") 273 private int mLowestRouterLifetimeSeconds = Integer.MAX_VALUE; 274 @GuardedBy("this") 275 private long mLowestPioValidLifetimeSeconds = Long.MAX_VALUE; 276 @GuardedBy("this") 277 private long mLowestRioRouteLifetimeSeconds = Long.MAX_VALUE; 278 @GuardedBy("this") 279 private long mLowestRdnssLifetimeSeconds = Long.MAX_VALUE; 280 281 // Ignore non-zero RDNSS lifetimes below this value. 282 private final int mMinRdnssLifetimeSec; 283 284 // Minimum session time for metrics, duration less than this time will not be logged. 285 private final long mMinMetricsSessionDurationMs; 286 287 // Tracks the value of /proc/sys/ipv6/conf/$iface/accept_ra_min_lft which affects router, RIO, 288 // and PIO valid lifetimes. 289 private final int mAcceptRaMinLft; 290 private final boolean mShouldHandleLightDoze; 291 private final boolean mShouldHandleArpOffload; 292 293 private final NetworkQuirkMetrics mNetworkQuirkMetrics; 294 private final IpClientRaInfoMetrics mIpClientRaInfoMetrics; 295 private final ApfSessionInfoMetrics mApfSessionInfoMetrics; 296 isDeviceIdleModeChangedAction(Intent intent)297 private static boolean isDeviceIdleModeChangedAction(Intent intent) { 298 return ACTION_DEVICE_IDLE_MODE_CHANGED.equals(intent.getAction()); 299 } 300 isDeviceLightIdleModeChangedAction(Intent intent)301 private boolean isDeviceLightIdleModeChangedAction(Intent intent) { 302 // The ACTION_DEVICE_LIGHT_IDLE_MODE_CHANGED only exist since T. For lower platform version, 303 // the check should return false. The explicit SDK check is needed to make linter happy 304 // about accessing ACTION_DEVICE_LIGHT_IDLE_MODE_CHANGED in this function. 305 if (!SdkLevel.isAtLeastT()) { 306 return false; 307 } 308 if (!mShouldHandleLightDoze) { 309 return false; 310 } 311 return ACTION_DEVICE_LIGHT_IDLE_MODE_CHANGED.equals(intent.getAction()); 312 } 313 isDeviceLightIdleMode(@onNull PowerManager powerManager)314 private boolean isDeviceLightIdleMode(@NonNull PowerManager powerManager) { 315 // The powerManager.isDeviceLightIdleMode() only exist since T. For lower platform version, 316 // the check should return false. The explicit SDK check is needed to make linter happy 317 // about accessing powerManager.isDeviceLightIdleMode() in this function. 318 if (!SdkLevel.isAtLeastT()) { 319 return false; 320 } 321 if (!mShouldHandleLightDoze) { 322 return false; 323 } 324 325 return powerManager.isDeviceLightIdleMode(); 326 } 327 328 // Detects doze mode state transitions. 329 private final BroadcastReceiver mDeviceIdleReceiver = new BroadcastReceiver() { 330 @Override 331 public void onReceive(Context context, Intent intent) { 332 final PowerManager powerManager = context.getSystemService(PowerManager.class); 333 if (isDeviceIdleModeChangedAction(intent) 334 || isDeviceLightIdleModeChangedAction(intent)) { 335 final boolean deviceIdle = powerManager.isDeviceIdleMode() 336 || isDeviceLightIdleMode(powerManager); 337 setDozeMode(deviceIdle); 338 } 339 } 340 }; 341 342 // Our IPv4 address, if we have just one, otherwise null. 343 @GuardedBy("this") 344 private byte[] mIPv4Address; 345 // The subnet prefix length of our IPv4 network. Only valid if mIPv4Address is not null. 346 @GuardedBy("this") 347 private int mIPv4PrefixLength; 348 349 // Our IPv6 non-tentative addresses 350 @GuardedBy("this") 351 private Set<Inet6Address> mIPv6NonTentativeAddresses = new ArraySet<>(); 352 353 // Our tentative IPv6 addresses 354 @GuardedBy("this") 355 private Set<Inet6Address> mIPv6TentativeAddresses = new ArraySet<>(); 356 357 // Whether CLAT is enabled. 358 @GuardedBy("this") 359 private boolean mHasClat; 360 361 // mIsRunning is reflects the state of the ApfFilter during integration tests. ApfFilter can be 362 // paused using "adb shell cmd apf <iface> <cmd>" commands. A paused ApfFilter will not install 363 // any new programs, but otherwise operates normally. 364 private volatile boolean mIsRunning = true; 365 366 private final Dependencies mDependencies; 367 ApfFilter(Context context, ApfConfiguration config, InterfaceParams ifParams, IpClientCallbacksWrapper ipClientCallback, NetworkQuirkMetrics networkQuirkMetrics)368 public ApfFilter(Context context, ApfConfiguration config, InterfaceParams ifParams, 369 IpClientCallbacksWrapper ipClientCallback, NetworkQuirkMetrics networkQuirkMetrics) { 370 this(context, config, ifParams, ipClientCallback, networkQuirkMetrics, 371 new Dependencies(context), new Clock()); 372 } 373 374 @VisibleForTesting ApfFilter(Context context, ApfConfiguration config, InterfaceParams ifParams, IpClientCallbacksWrapper ipClientCallback, NetworkQuirkMetrics networkQuirkMetrics, Dependencies dependencies)375 public ApfFilter(Context context, ApfConfiguration config, InterfaceParams ifParams, 376 IpClientCallbacksWrapper ipClientCallback, NetworkQuirkMetrics networkQuirkMetrics, 377 Dependencies dependencies) { 378 this(context, config, ifParams, ipClientCallback, networkQuirkMetrics, dependencies, 379 new Clock()); 380 } 381 382 @VisibleForTesting ApfFilter(Context context, ApfConfiguration config, InterfaceParams ifParams, IpClientCallbacksWrapper ipClientCallback, NetworkQuirkMetrics networkQuirkMetrics, Dependencies dependencies, Clock clock)383 public ApfFilter(Context context, ApfConfiguration config, InterfaceParams ifParams, 384 IpClientCallbacksWrapper ipClientCallback, NetworkQuirkMetrics networkQuirkMetrics, 385 Dependencies dependencies, Clock clock) { 386 mApfCapabilities = config.apfCapabilities; 387 mInstallableProgramSizeClamp = config.installableProgramSizeClamp; 388 mIpClientCallback = ipClientCallback; 389 mInterfaceParams = ifParams; 390 mMulticastFilter = config.multicastFilter; 391 mDrop802_3Frames = config.ieee802_3Filter; 392 mMinRdnssLifetimeSec = config.minRdnssLifetimeSec; 393 mAcceptRaMinLft = config.acceptRaMinLft; 394 mShouldHandleLightDoze = config.shouldHandleLightDoze; 395 mShouldHandleArpOffload = config.shouldHandleArpOffload; 396 mDependencies = dependencies; 397 mNetworkQuirkMetrics = networkQuirkMetrics; 398 mIpClientRaInfoMetrics = dependencies.getIpClientRaInfoMetrics(); 399 mApfSessionInfoMetrics = dependencies.getApfSessionInfoMetrics(); 400 mClock = clock; 401 mSessionStartMs = mClock.elapsedRealtime(); 402 mMinMetricsSessionDurationMs = config.minMetricsSessionDurationMs; 403 mHasClat = config.hasClatInterface; 404 405 // Now fill the black list from the passed array 406 mEthTypeBlackList = filterEthTypeBlackList(config.ethTypeBlackList); 407 408 // TokenBucket for rate limiting filter installation. APF filtering relies on the filter 409 // always being up-to-date and APF bytecode being in sync with userspace. The TokenBucket 410 // merely prevents illconfigured / abusive networks from impacting the system, so it does 411 // not need to be very restrictive. 412 // The TokenBucket starts with its full capacity of 20 tokens (= 20 filter updates). A new 413 // token is generated every 3 seconds limiting the filter update rate to at most once every 414 // 3 seconds. 415 mTokenBucket = new TokenBucket(3_000 /* deltaMs */, 20 /* capacity */, 20 /* tokens */); 416 417 // TODO: ApfFilter should not generate programs until IpClient sends provisioning success. 418 maybeStartFilter(); 419 420 // Listen for doze-mode transition changes to enable/disable the IPv6 multicast filter. 421 mDependencies.addDeviceIdleReceiver(mDeviceIdleReceiver, mShouldHandleLightDoze); 422 423 mDependencies.onApfFilterCreated(this); 424 // mReceiveThread is created in maybeStartFilter() and halted in shutdown(). 425 mDependencies.onThreadCreated(mReceiveThread); 426 } 427 428 /** 429 * Dependencies class for testing. 430 */ 431 @VisibleForTesting 432 public static class Dependencies { 433 private final Context mContext; Dependencies(final Context context)434 public Dependencies(final Context context) { 435 mContext = context; 436 } 437 438 /** Add receiver for detecting doze mode change */ addDeviceIdleReceiver(@onNull final BroadcastReceiver receiver, boolean shouldHandleLightDoze)439 public void addDeviceIdleReceiver(@NonNull final BroadcastReceiver receiver, 440 boolean shouldHandleLightDoze) { 441 final IntentFilter intentFilter = new IntentFilter(ACTION_DEVICE_IDLE_MODE_CHANGED); 442 if (SdkLevel.isAtLeastT() && shouldHandleLightDoze) { 443 intentFilter.addAction(ACTION_DEVICE_LIGHT_IDLE_MODE_CHANGED); 444 } 445 mContext.registerReceiver(receiver, intentFilter); 446 } 447 448 /** Remove broadcast receiver. */ removeBroadcastReceiver(@onNull final BroadcastReceiver receiver)449 public void removeBroadcastReceiver(@NonNull final BroadcastReceiver receiver) { 450 mContext.unregisterReceiver(receiver); 451 } 452 453 /** 454 * Get a ApfSessionInfoMetrics instance. 455 */ getApfSessionInfoMetrics()456 public ApfSessionInfoMetrics getApfSessionInfoMetrics() { 457 return new ApfSessionInfoMetrics(); 458 } 459 460 /** 461 * Get a IpClientRaInfoMetrics instance. 462 */ getIpClientRaInfoMetrics()463 public IpClientRaInfoMetrics getIpClientRaInfoMetrics() { 464 return new IpClientRaInfoMetrics(); 465 } 466 467 /** 468 * Callback to be called when an ApfFilter instance is created. 469 * 470 * This method is designed to be overridden in test classes to collect created ApfFilter 471 * instances. 472 */ onApfFilterCreated(@onNull AndroidPacketFilter apfFilter)473 public void onApfFilterCreated(@NonNull AndroidPacketFilter apfFilter) { 474 } 475 476 /** 477 * Callback to be called when a ReceiveThread instance is created. 478 * 479 * This method is designed for overriding in test classes to collect created threads and 480 * waits for the termination. 481 */ onThreadCreated(@onNull Thread thread)482 public void onThreadCreated(@NonNull Thread thread) { 483 } 484 485 /** 486 * Loads the existing IPv6 anycast addresses from the file `/proc/net/anycast6`. 487 */ getAnycast6Addresses(@onNull String ifname)488 public List<byte[]> getAnycast6Addresses(@NonNull String ifname) { 489 final List<Inet6Address> anycast6Addresses = 490 ProcfsParsingUtils.getAnycast6Addresses(ifname); 491 final List<byte[]> addresses = new ArrayList<>(); 492 for (Inet6Address addr : anycast6Addresses) { 493 addresses.add(addr.getAddress()); 494 } 495 496 return addresses; 497 } 498 499 /** 500 * Loads the existing Ethernet multicast addresses from the file 501 * `/proc/net/dev_mcast`. 502 */ getEtherMulticastAddresses(@onNull String ifname)503 public List<byte[]> getEtherMulticastAddresses(@NonNull String ifname) { 504 final List<MacAddress> etherAddresses = 505 ProcfsParsingUtils.getEtherMulticastAddresses(ifname); 506 final List<byte[]> addresses = new ArrayList<>(); 507 for (MacAddress addr : etherAddresses) { 508 addresses.add(addr.toByteArray()); 509 } 510 511 return addresses; 512 } 513 514 /** 515 * Loads the existing ND traffic class for the specific interface from the file 516 * /proc/sys/net/ipv6/conf/{ifname}/ndisc_tclass. 517 * 518 * If the file does not exist or the interface is not found, 519 * the function returns 0..255, 0 as default ND traffic class. 520 */ getNdTrafficClass(@onNull String ifname)521 public int getNdTrafficClass(@NonNull String ifname) { 522 return ProcfsParsingUtils.getNdTrafficClass(ifname); 523 } 524 } 525 526 @Override setDataSnapshot(byte[] data)527 public synchronized String setDataSnapshot(byte[] data) { 528 mDataSnapshot = data; 529 if (mIsRunning) { 530 mApfCounterTracker.updateCountersFromData(data); 531 } 532 return mApfCounterTracker.getCounters().toString(); 533 } 534 log(String s)535 private void log(String s) { 536 Log.d(TAG, "(" + mInterfaceParams.name + "): " + s); 537 } 538 539 @GuardedBy("this") getUniqueNumberLocked()540 private long getUniqueNumberLocked() { 541 return mUniqueCounter++; 542 } 543 filterEthTypeBlackList(int[] ethTypeBlackList)544 private static int[] filterEthTypeBlackList(int[] ethTypeBlackList) { 545 ArrayList<Integer> bl = new ArrayList<>(); 546 547 for (int p : ethTypeBlackList) { 548 // Check if the protocol is a valid ether type 549 if ((p < ETH_TYPE_MIN) || (p > ETH_TYPE_MAX)) { 550 continue; 551 } 552 553 // Check if the protocol is not repeated in the passed array 554 if (bl.contains(p)) { 555 continue; 556 } 557 558 // Check if list reach its max size 559 if (bl.size() == APF_MAX_ETH_TYPE_BLACK_LIST_LEN) { 560 Log.w(TAG, "Passed EthType Black List size too large (" + bl.size() + 561 ") using top " + APF_MAX_ETH_TYPE_BLACK_LIST_LEN + " protocols"); 562 break; 563 } 564 565 // Now add the protocol to the list 566 bl.add(p); 567 } 568 569 return bl.stream().mapToInt(Integer::intValue).toArray(); 570 } 571 572 /** 573 * Attempt to start listening for RAs and, if RAs are received, generating and installing 574 * filters to ignore useless RAs. 575 */ 576 @VisibleForTesting maybeStartFilter()577 public void maybeStartFilter() { 578 FileDescriptor socket; 579 try { 580 mHardwareAddress = mInterfaceParams.macAddr.toByteArray(); 581 synchronized(this) { 582 // Clear the APF memory to reset all counters upon connecting to the first AP 583 // in an SSID. This is limited to APFv4 devices because this large write triggers 584 // a crash on some older devices (b/78905546). 585 if (mIsRunning && hasDataAccess(mApfCapabilities)) { 586 byte[] zeroes = new byte[mApfCapabilities.maximumApfProgramSize]; 587 if (!mIpClientCallback.installPacketFilter(zeroes)) { 588 sendNetworkQuirkMetrics(NetworkQuirkEvent.QE_APF_INSTALL_FAILURE); 589 } 590 } 591 592 // Install basic filters 593 installNewProgramLocked(); 594 } 595 socket = Os.socket(AF_PACKET, SOCK_RAW | SOCK_CLOEXEC, 0); 596 NetworkStackUtils.attachRaFilter(socket); 597 SocketAddress addr = makePacketSocketAddress(ETH_P_IPV6, mInterfaceParams.index); 598 Os.bind(socket, addr); 599 } catch(SocketException|ErrnoException e) { 600 Log.e(TAG, "Error starting filter", e); 601 return; 602 } 603 mReceiveThread = new ReceiveThread(socket); 604 mReceiveThread.start(); 605 } 606 607 // Returns seconds since device boot. 608 @VisibleForTesting secondsSinceBoot()609 protected int secondsSinceBoot() { 610 return (int) (mClock.elapsedRealtime() / DateUtils.SECOND_IN_MILLIS); 611 } 612 613 public static class InvalidRaException extends Exception { InvalidRaException(String m)614 public InvalidRaException(String m) { 615 super(m); 616 } 617 } 618 619 /** 620 * Class to keep track of a section in a packet. 621 */ 622 private static class PacketSection { 623 public enum Type { 624 MATCH, // A field that should be matched (e.g., the router IP address). 625 LIFETIME, // A lifetime. Not matched, and counts toward minimum RA lifetime if >= min. 626 } 627 628 /** The type of section. */ 629 public final Type type; 630 /** Offset into the packet at which this section begins. */ 631 public final int start; 632 /** Length of this section in bytes. */ 633 public final int length; 634 /** If this is a lifetime, the lifetime value. */ 635 public final long lifetime; 636 /** If this is a lifetime, the value below which the lifetime is ignored */ 637 public final int min; 638 PacketSection(int start, int length, Type type, long lifetime, int min)639 PacketSection(int start, int length, Type type, long lifetime, int min) { 640 this.start = start; 641 642 if (type == Type.LIFETIME && length != 2 && length != 4) { 643 throw new IllegalArgumentException("LIFETIME section length must be 2 or 4 bytes"); 644 } 645 this.length = length; 646 this.type = type; 647 648 if (type == Type.MATCH && (lifetime != 0 || min != 0)) { 649 throw new IllegalArgumentException("lifetime, min must be 0 for MATCH sections"); 650 } 651 this.lifetime = lifetime; 652 653 // It has already been asserted that min is 0 for MATCH sections. 654 if (min < 0) { 655 throw new IllegalArgumentException("min must be >= 0 for LIFETIME sections"); 656 } 657 this.min = min; 658 } 659 toString()660 public String toString() { 661 if (type == Type.LIFETIME) { 662 return String.format("%s: (%d, %d) %d %d", type, start, length, lifetime, min); 663 } else { 664 return String.format("%s: (%d, %d)", type, start, length); 665 } 666 } 667 } 668 669 // A class to hold information about an RA. 670 @VisibleForTesting 671 public class Ra { 672 // From RFC4861: 673 private static final int ICMP6_RA_HEADER_LEN = 16; 674 private static final int ICMP6_RA_CHECKSUM_OFFSET = 675 ETH_HEADER_LEN + IPV6_HEADER_LEN + 2; 676 private static final int ICMP6_RA_CHECKSUM_LEN = 2; 677 private static final int ICMP6_RA_OPTION_OFFSET = 678 ETH_HEADER_LEN + IPV6_HEADER_LEN + ICMP6_RA_HEADER_LEN; 679 private static final int ICMP6_RA_ROUTER_LIFETIME_OFFSET = 680 ETH_HEADER_LEN + IPV6_HEADER_LEN + 6; 681 private static final int ICMP6_RA_ROUTER_LIFETIME_LEN = 2; 682 // Prefix information option. 683 private static final int ICMP6_PREFIX_OPTION_TYPE = 3; 684 private static final int ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET = 4; 685 private static final int ICMP6_PREFIX_OPTION_VALID_LIFETIME_LEN = 4; 686 private static final int ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_LEN = 4; 687 688 // From RFC4861: source link-layer address 689 private static final int ICMP6_SOURCE_LL_ADDRESS_OPTION_TYPE = 1; 690 // From RFC4861: mtu size option 691 private static final int ICMP6_MTU_OPTION_TYPE = 5; 692 // From RFC6106: Recursive DNS Server option 693 private static final int ICMP6_RDNSS_OPTION_TYPE = 25; 694 // From RFC6106: DNS Search List option 695 private static final int ICMP6_DNSSL_OPTION_TYPE = 31; 696 // From RFC8910: Captive-Portal option 697 private static final int ICMP6_CAPTIVE_PORTAL_OPTION_TYPE = 37; 698 // From RFC8781: PREF64 option 699 private static final int ICMP6_PREF64_OPTION_TYPE = 38; 700 701 // From RFC4191: Route Information option 702 private static final int ICMP6_ROUTE_INFO_OPTION_TYPE = 24; 703 // Above three options all have the same format: 704 private static final int ICMP6_4_BYTE_LIFETIME_OFFSET = 4; 705 private static final int ICMP6_4_BYTE_LIFETIME_LEN = 4; 706 707 // Note: mPacket's position() cannot be assumed to be reset. 708 private final ByteBuffer mPacket; 709 710 // List of sections in the packet. 711 private final ArrayList<PacketSection> mPacketSections = new ArrayList<>(); 712 713 // Router lifetime in packet 714 private final int mRouterLifetime; 715 // Minimum valid lifetime of PIOs in packet, Long.MAX_VALUE means not seen. 716 private long mMinPioValidLifetime = Long.MAX_VALUE; 717 // Minimum route lifetime of RIOs in packet, Long.MAX_VALUE means not seen. 718 private long mMinRioRouteLifetime = Long.MAX_VALUE; 719 // Minimum lifetime of RDNSSs in packet, Long.MAX_VALUE means not seen. 720 private long mMinRdnssLifetime = Long.MAX_VALUE; 721 // The time in seconds in which some of the information contained in this RA expires. 722 private final int mExpirationTime; 723 // When the packet was last captured, in seconds since Unix Epoch 724 private final int mLastSeen; 725 726 // For debugging only. Offsets into the packet where PIOs are. 727 private final ArrayList<Integer> mPrefixOptionOffsets = new ArrayList<>(); 728 729 // For debugging only. Offsets into the packet where RDNSS options are. 730 private final ArrayList<Integer> mRdnssOptionOffsets = new ArrayList<>(); 731 732 // For debugging only. Offsets into the packet where RIO options are. 733 private final ArrayList<Integer> mRioOptionOffsets = new ArrayList<>(); 734 735 // For debugging only. Returns the hex representation of the last matching packet. getLastMatchingPacket()736 String getLastMatchingPacket() { 737 return HexDump.toHexString(mPacket.array(), 0, mPacket.capacity(), 738 false /* lowercase */); 739 } 740 741 // For debugging only. Returns the string representation of the IPv6 address starting at 742 // position pos in the packet. IPv6AddresstoString(int pos)743 private String IPv6AddresstoString(int pos) { 744 try { 745 byte[] array = mPacket.array(); 746 // Can't just call copyOfRange() and see if it throws, because if it reads past the 747 // end it pads with zeros instead of throwing. 748 if (pos < 0 || pos + 16 > array.length || pos + 16 < pos) { 749 return "???"; 750 } 751 byte[] addressBytes = Arrays.copyOfRange(array, pos, pos + 16); 752 InetAddress address = InetAddress.getByAddress(addressBytes); 753 return address.getHostAddress(); 754 } catch (UnsupportedOperationException e) { 755 // array() failed. Cannot happen, mPacket is array-backed and read-write. 756 return "???"; 757 } catch (ClassCastException|UnknownHostException e) { 758 // Cannot happen. 759 return "???"; 760 } 761 } 762 763 // Can't be static because it's in a non-static inner class. 764 // TODO: Make this static once RA is its own class. prefixOptionToString(StringBuffer sb, int offset)765 private void prefixOptionToString(StringBuffer sb, int offset) { 766 String prefix = IPv6AddresstoString(offset + 16); 767 int length = getUint8(mPacket, offset + 2); 768 long valid = getUint32(mPacket, offset + 4); 769 long preferred = getUint32(mPacket, offset + 8); 770 sb.append(String.format("%s/%d %ds/%ds ", prefix, length, valid, preferred)); 771 } 772 rdnssOptionToString(StringBuffer sb, int offset)773 private void rdnssOptionToString(StringBuffer sb, int offset) { 774 int optLen = getUint8(mPacket, offset + 1) * 8; 775 if (optLen < 24) return; // Malformed or empty. 776 long lifetime = getUint32(mPacket, offset + 4); 777 int numServers = (optLen - 8) / 16; 778 sb.append("DNS ").append(lifetime).append("s"); 779 for (int server = 0; server < numServers; server++) { 780 sb.append(" ").append(IPv6AddresstoString(offset + 8 + 16 * server)); 781 } 782 sb.append(" "); 783 } 784 rioOptionToString(StringBuffer sb, int offset)785 private void rioOptionToString(StringBuffer sb, int offset) { 786 int optLen = getUint8(mPacket, offset + 1) * 8; 787 if (optLen < 8 || optLen > 24) return; // Malformed or empty. 788 int prefixLen = getUint8(mPacket, offset + 2); 789 long lifetime = getUint32(mPacket, offset + 4); 790 791 // This read is variable length because the prefix can be 0, 8 or 16 bytes long. 792 // We can't use any of the ByteBuffer#get methods here because they all start reading 793 // from the buffer's current position. 794 byte[] prefix = new byte[IPV6_ADDR_LEN]; 795 System.arraycopy(mPacket.array(), offset + 8, prefix, 0, optLen - 8); 796 sb.append("RIO ").append(lifetime).append("s "); 797 try { 798 InetAddress address = InetAddress.getByAddress(prefix); 799 sb.append(address.getHostAddress()); 800 } catch (UnknownHostException impossible) { 801 sb.append("???"); 802 } 803 sb.append("/").append(prefixLen).append(" "); 804 } 805 toString()806 public String toString() { 807 try { 808 StringBuffer sb = new StringBuffer(); 809 sb.append(String.format("RA %s -> %s %ds ", 810 IPv6AddresstoString(IPV6_SRC_ADDR_OFFSET), 811 IPv6AddresstoString(IPV6_DEST_ADDR_OFFSET), 812 getUint16(mPacket, ICMP6_RA_ROUTER_LIFETIME_OFFSET))); 813 for (int i: mPrefixOptionOffsets) { 814 prefixOptionToString(sb, i); 815 } 816 for (int i: mRdnssOptionOffsets) { 817 rdnssOptionToString(sb, i); 818 } 819 for (int i: mRioOptionOffsets) { 820 rioOptionToString(sb, i); 821 } 822 return sb.toString(); 823 } catch (BufferUnderflowException|IndexOutOfBoundsException e) { 824 return "<Malformed RA>"; 825 } 826 } 827 828 /** 829 * Add a packet section that should be matched, starting from the current position. 830 * @param length the length of the section 831 */ addMatchSection(int length)832 private void addMatchSection(int length) { 833 // Don't generate JNEBS instruction for 0 bytes as they will fail the 834 // ASSERT_FORWARD_IN_PROGRAM(pc + cmp_imm - 1) check (where cmp_imm is 835 // the number of bytes to compare) and immediately pass the packet. 836 // The code does not attempt to generate such matches, but add a safety 837 // check to prevent doing so in the presence of bugs or malformed or 838 // truncated packets. 839 if (length == 0) return; 840 841 // we need to add a MATCH section 'from, length, MATCH, 0, 0' 842 int from = mPacket.position(); 843 844 // if possible try to increase the length of the previous match section 845 int lastIdx = mPacketSections.size() - 1; 846 if (lastIdx >= 0) { // there had to be a previous section 847 PacketSection prev = mPacketSections.get(lastIdx); 848 if (prev.type == PacketSection.Type.MATCH) { // of type match 849 if (prev.start + prev.length == from) { // ending where we start 850 from -= prev.length; 851 length += prev.length; 852 mPacketSections.remove(lastIdx); 853 } 854 } 855 } 856 857 mPacketSections.add(new PacketSection(from, length, PacketSection.Type.MATCH, 0, 0)); 858 mPacket.position(from + length); 859 } 860 861 /** 862 * Add a packet section that should be matched, starting from the current position. 863 * @param end the offset in the packet before which the section ends 864 */ addMatchUntil(int end)865 private void addMatchUntil(int end) { 866 addMatchSection(end - mPacket.position()); 867 } 868 869 /** 870 * Add a packet section that should be ignored, starting from the current position. 871 * @param length the length of the section in bytes 872 */ addIgnoreSection(int length)873 private void addIgnoreSection(int length) { 874 mPacket.position(mPacket.position() + length); 875 } 876 877 /** 878 * Add a packet section that represents a lifetime, starting from the current position. 879 * @param length the length of the section in bytes 880 * @param lifetime the lifetime 881 * @param min the minimum acceptable lifetime 882 */ addLifetimeSection(int length, long lifetime, int min)883 private void addLifetimeSection(int length, long lifetime, int min) { 884 mPacketSections.add( 885 new PacketSection(mPacket.position(), length, PacketSection.Type.LIFETIME, 886 lifetime, min)); 887 mPacket.position(mPacket.position() + length); 888 } 889 890 /** 891 * Adds packet sections for an RA option with a 4-byte lifetime 4 bytes into the option 892 * @param optionLength the length of the option in bytes 893 * @param min the minimum acceptable lifetime 894 */ add4ByteLifetimeOption(int optionLength, int min)895 private long add4ByteLifetimeOption(int optionLength, int min) { 896 addMatchSection(ICMP6_4_BYTE_LIFETIME_OFFSET); 897 final long lifetime = getUint32(mPacket, mPacket.position()); 898 addLifetimeSection(ICMP6_4_BYTE_LIFETIME_LEN, lifetime, min); 899 addMatchSection(optionLength - ICMP6_4_BYTE_LIFETIME_OFFSET 900 - ICMP6_4_BYTE_LIFETIME_LEN); 901 return lifetime; 902 } 903 904 /** 905 * Return the router lifetime of the RA 906 */ routerLifetime()907 public int routerLifetime() { 908 return mRouterLifetime; 909 } 910 911 /** 912 * Return the minimum valid lifetime in PIOs 913 */ minPioValidLifetime()914 public long minPioValidLifetime() { 915 return mMinPioValidLifetime; 916 } 917 918 /** 919 * Return the minimum route lifetime in RIOs 920 */ minRioRouteLifetime()921 public long minRioRouteLifetime() { 922 return mMinRioRouteLifetime; 923 } 924 925 /** 926 * Return the minimum lifetime in RDNSSs 927 */ minRdnssLifetime()928 public long minRdnssLifetime() { 929 return mMinRdnssLifetime; 930 } 931 932 // Note that this parses RA and may throw InvalidRaException (from 933 // Buffer.position(int) or due to an invalid-length option) or IndexOutOfBoundsException 934 // (from ByteBuffer.get(int) ) if parsing encounters something non-compliant with 935 // specifications. 936 @VisibleForTesting Ra(byte[] packet, int length)937 public Ra(byte[] packet, int length) throws InvalidRaException { 938 if (length < ICMP6_RA_OPTION_OFFSET) { 939 throw new InvalidRaException("Not an ICMP6 router advertisement: too short"); 940 } 941 942 mPacket = ByteBuffer.wrap(Arrays.copyOf(packet, length)); 943 mLastSeen = secondsSinceBoot(); 944 945 // Check packet in case a packet arrives before we attach RA filter 946 // to our packet socket. b/29586253 947 if (getUint16(mPacket, ETH_ETHERTYPE_OFFSET) != ETH_P_IPV6 || 948 getUint8(mPacket, IPV6_NEXT_HEADER_OFFSET) != IPPROTO_ICMPV6 || 949 getUint8(mPacket, ICMP6_TYPE_OFFSET) != ICMPV6_ROUTER_ADVERTISEMENT) { 950 throw new InvalidRaException("Not an ICMP6 router advertisement"); 951 } 952 953 // Ignore destination MAC address. 954 addIgnoreSection(6 /* Size of MAC address */); 955 956 // Ignore the flow label and low 4 bits of traffic class. 957 addMatchUntil(IPV6_FLOW_LABEL_OFFSET); 958 addIgnoreSection(IPV6_FLOW_LABEL_LEN); 959 960 // Ignore IPv6 destination address. 961 addMatchUntil(IPV6_DEST_ADDR_OFFSET); 962 addIgnoreSection(IPV6_ADDR_LEN); 963 964 // Ignore checksum. 965 addMatchUntil(ICMP6_RA_CHECKSUM_OFFSET); 966 addIgnoreSection(ICMP6_RA_CHECKSUM_LEN); 967 968 // Parse router lifetime 969 addMatchUntil(ICMP6_RA_ROUTER_LIFETIME_OFFSET); 970 mRouterLifetime = getUint16(mPacket, ICMP6_RA_ROUTER_LIFETIME_OFFSET); 971 addLifetimeSection(ICMP6_RA_ROUTER_LIFETIME_LEN, mRouterLifetime, mAcceptRaMinLft); 972 if (mRouterLifetime == 0) mNumZeroLifetimeRas++; 973 974 // Add remaining fields (reachable time and retransmission timer) to match section. 975 addMatchUntil(ICMP6_RA_OPTION_OFFSET); 976 977 while (mPacket.hasRemaining()) { 978 final int position = mPacket.position(); 979 final int optionType = getUint8(mPacket, position); 980 final int optionLength = getUint8(mPacket, position + 1) * 8; 981 if (optionLength <= 0) { 982 throw new InvalidRaException(String.format( 983 "Invalid option length opt=%d len=%d", optionType, optionLength)); 984 } 985 986 long lifetime; 987 switch (optionType) { 988 case ICMP6_PREFIX_OPTION_TYPE: 989 mPrefixOptionOffsets.add(position); 990 991 // Parse valid lifetime 992 addMatchSection(ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET); 993 lifetime = getUint32(mPacket, mPacket.position()); 994 addLifetimeSection(ICMP6_PREFIX_OPTION_VALID_LIFETIME_LEN, 995 lifetime, mAcceptRaMinLft); 996 mMinPioValidLifetime = getMinForPositiveValue( 997 mMinPioValidLifetime, lifetime); 998 if (lifetime == 0) mNumZeroLifetimeRas++; 999 1000 // Parse preferred lifetime 1001 lifetime = getUint32(mPacket, mPacket.position()); 1002 // The PIO preferred lifetime is not affected by accept_ra_min_lft and 1003 // therefore does not have a minimum. 1004 addLifetimeSection(ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_LEN, 1005 lifetime, 0 /* min lifetime */); 1006 1007 addMatchSection(4); // Reserved bytes 1008 addMatchSection(IPV6_ADDR_LEN); // The prefix itself 1009 break; 1010 // These three options have the same lifetime offset and size, and 1011 // are processed with the same specialized add4ByteLifetimeOption: 1012 case ICMP6_RDNSS_OPTION_TYPE: 1013 mRdnssOptionOffsets.add(position); 1014 lifetime = add4ByteLifetimeOption(optionLength, mMinRdnssLifetimeSec); 1015 mMinRdnssLifetime = getMinForPositiveValue(mMinRdnssLifetime, lifetime); 1016 if (lifetime == 0) mNumZeroLifetimeRas++; 1017 break; 1018 case ICMP6_ROUTE_INFO_OPTION_TYPE: 1019 mRioOptionOffsets.add(position); 1020 lifetime = add4ByteLifetimeOption(optionLength, mAcceptRaMinLft); 1021 mMinRioRouteLifetime = getMinForPositiveValue( 1022 mMinRioRouteLifetime, lifetime); 1023 if (lifetime == 0) mNumZeroLifetimeRas++; 1024 break; 1025 case ICMP6_SOURCE_LL_ADDRESS_OPTION_TYPE: 1026 case ICMP6_MTU_OPTION_TYPE: 1027 case ICMP6_PREF64_OPTION_TYPE: 1028 addMatchSection(optionLength); 1029 break; 1030 case ICMP6_CAPTIVE_PORTAL_OPTION_TYPE: // unlikely to ever change. 1031 case ICMP6_DNSSL_OPTION_TYPE: // currently unsupported in userspace. 1032 default: 1033 // RFC4861 section 4.2 dictates we ignore unknown options for forwards 1034 // compatibility. 1035 // However, make sure the option's type and length match. 1036 addMatchSection(2); // option type & length 1037 // optionLength is guaranteed to be >= 8. 1038 addIgnoreSection(optionLength - 2); 1039 break; 1040 } 1041 } 1042 mExpirationTime = getExpirationTime(); 1043 } 1044 1045 public enum MatchType { 1046 NO_MATCH, // the RAs do not match 1047 MATCH_PASS, // the RAS match, and the APF program would pass. 1048 MATCH_DROP, // the RAs match, but the APF program would drop. 1049 } 1050 1051 // Considering only the MATCH sections, does {@code packet} match this RA? matches(Ra newRa)1052 MatchType matches(Ra newRa) { 1053 // Does their size match? 1054 if (newRa.mPacket.capacity() != mPacket.capacity()) return MatchType.NO_MATCH; 1055 1056 // If the filter has expired, it cannot match the new RA. 1057 if (getRemainingFilterLft(secondsSinceBoot()) <= 0) return MatchType.NO_MATCH; 1058 1059 // Check if all MATCH sections are byte-identical. 1060 final byte[] newPacket = newRa.mPacket.array(); 1061 final byte[] oldPacket = mPacket.array(); 1062 for (PacketSection section : mPacketSections) { 1063 if (section.type != PacketSection.Type.MATCH) continue; 1064 for (int i = section.start; i < (section.start + section.length); i++) { 1065 if (newPacket[i] != oldPacket[i]) return MatchType.NO_MATCH; 1066 } 1067 } 1068 1069 // Apply APF lifetime matching to LIFETIME sections and decide whether a packet should 1070 // be processed (MATCH_PASS) or ignored (MATCH_DROP). This logic is needed to 1071 // consistently process / ignore packets no matter the current state of the APF program. 1072 // Note that userspace has no control (or knowledge) over when the APF program is 1073 // running. 1074 for (PacketSection section : mPacketSections) { 1075 if (section.type != PacketSection.Type.LIFETIME) continue; 1076 1077 // the lifetime of the new RA. 1078 long lft = 0; 1079 switch (section.length) { 1080 // section.length is guaranteed to be 2 or 4. 1081 case 2: lft = getUint16(newRa.mPacket, section.start); break; 1082 case 4: lft = getUint32(newRa.mPacket, section.start); break; 1083 } 1084 1085 // WARNING: keep this in sync with Ra#generateFilterLocked()! 1086 if (section.lifetime == 0) { 1087 // Case 1) old lft == 0 1088 if (section.min > 0) { 1089 // a) in the presence of a min value. 1090 // if lft >= min -> PASS 1091 // gen.addJumpIfR0GreaterThan(section.min - 1, nextFilterLabel); 1092 if (lft >= section.min) return MatchType.MATCH_PASS; 1093 } else { 1094 // b) if min is 0 / there is no min value. 1095 // if lft > 0 -> PASS 1096 // gen.addJumpIfR0GreaterThan(0, nextFilterLabel); 1097 if (lft > 0) return MatchType.MATCH_PASS; 1098 } 1099 } else if (section.min == 0) { 1100 // Case 2b) section is not affected by any minimum. 1101 // 1102 // if lft < (oldLft + 2) // 3 -> PASS 1103 // if lft > oldLft -> PASS 1104 // gen.addJumpIfR0LessThan(((section.lifetime + 2) / 3), 1105 // nextFilterLabel); 1106 if (lft < (section.lifetime + 2) / 3) return MatchType.MATCH_PASS; 1107 // gen.addJumpIfR0GreaterThan(section.lifetime, nextFilterLabel); 1108 if (lft > section.lifetime) return MatchType.MATCH_PASS; 1109 } else if (section.lifetime < section.min) { 1110 // Case 2a) 0 < old lft < min 1111 // 1112 // if lft == 0 -> PASS 1113 // if lft >= min -> PASS 1114 // gen.addJumpIfR0Equals(0, nextFilterLabel); 1115 if (lft == 0) return MatchType.MATCH_PASS; 1116 // gen.addJumpIfR0GreaterThan(section.min - 1, nextFilterLabel); 1117 if (lft >= section.min) return MatchType.MATCH_PASS; 1118 } else if (section.lifetime <= 3 * (long) section.min) { 1119 // Case 3a) min <= old lft <= 3 * min 1120 // Note that: 1121 // "(old lft + 2) / 3 <= min" is equivalent to "old lft <= 3 * min" 1122 // 1123 // Essentially, in this range there is no "renumbering support", as the 1124 // renumbering constant of 1/3 * old lft is smaller than the minimum 1125 // lifetime accepted by the kernel / userspace. 1126 // 1127 // if lft == 0 -> PASS 1128 // if lft > oldLft -> PASS 1129 // gen.addJumpIfR0Equals(0, nextFilterLabel); 1130 if (lft == 0) return MatchType.MATCH_PASS; 1131 // gen.addJumpIfR0GreaterThan(section.lifetime, nextFilterLabel); 1132 if (lft > section.lifetime) return MatchType.MATCH_PASS; 1133 } else { 1134 // Case 4a) otherwise 1135 // 1136 // if lft == 0 -> PASS 1137 // if lft < min -> CONTINUE 1138 // if lft < (oldLft + 2) // 3 -> PASS 1139 // if lft > oldLft -> PASS 1140 // gen.addJumpIfR0Equals(0, nextFilterLabel); 1141 if (lft == 0) return MatchType.MATCH_PASS; 1142 // gen.addJumpIfR0LessThan(section.min, continueLabel); 1143 if (lft < section.min) continue; 1144 // gen.addJumpIfR0LessThan(((section.lifetime + 2) / 3), 1145 // nextFilterLabel); 1146 if (lft < (section.lifetime + 2) / 3) return MatchType.MATCH_PASS; 1147 // gen.addJumpIfR0GreaterThan(section.lifetime, nextFilterLabel); 1148 if (lft > section.lifetime) return MatchType.MATCH_PASS; 1149 } 1150 } 1151 1152 return MatchType.MATCH_DROP; 1153 } 1154 1155 // Get the number of seconds in which some of the information contained in this RA expires. getExpirationTime()1156 private int getExpirationTime() { 1157 // While technically most lifetimes in the RA are u32s, as far as the RA filter is 1158 // concerned, INT_MAX is still a *much* longer lifetime than any filter would ever 1159 // reasonably be active for. 1160 // Clamp expirationTime at INT_MAX. 1161 int expirationTime = Integer.MAX_VALUE; 1162 for (PacketSection section : mPacketSections) { 1163 if (section.type != PacketSection.Type.LIFETIME) { 1164 continue; 1165 } 1166 // Ignore lifetimes below section.min and always ignore 0 lifetimes. 1167 if (section.lifetime < Math.max(section.min, 1)) { 1168 continue; 1169 } 1170 1171 expirationTime = (int) Math.min(expirationTime, section.lifetime); 1172 } 1173 return expirationTime; 1174 } 1175 1176 // Filter for a fraction of the expiration time and adjust for the age of the RA. getRemainingFilterLft(int currentTimeSeconds)1177 int getRemainingFilterLft(int currentTimeSeconds) { 1178 int filterLifetime = ((mExpirationTime / FRACTION_OF_LIFETIME_TO_FILTER) 1179 - (currentTimeSeconds - mLastSeen)); 1180 filterLifetime = Math.max(0, filterLifetime); 1181 // Clamp filterLifetime to <= 65535, so it fits in 2 bytes. 1182 return Math.min(65535, filterLifetime); 1183 } 1184 1185 // Append a filter for this RA to {@code gen}. Jump to DROP_LABEL if it should be dropped. 1186 // Jump to the next filter if packet doesn't match this RA. 1187 @GuardedBy("ApfFilter.this") generateFilterLocked(ApfV4GeneratorBase<?> gen, int timeSeconds)1188 void generateFilterLocked(ApfV4GeneratorBase<?> gen, int timeSeconds) 1189 throws IllegalInstructionException { 1190 String nextFilterLabel = gen.getUniqueLabel(); 1191 // Skip if packet is not the right size 1192 gen.addLoadFromMemory(R0, MemorySlot.PACKET_SIZE); 1193 gen.addJumpIfR0NotEquals(mPacket.capacity(), nextFilterLabel); 1194 // Skip filter if expired 1195 gen.addLoadFromMemory(R0, MemorySlot.FILTER_AGE_SECONDS); 1196 gen.addJumpIfR0GreaterThan(getRemainingFilterLft(timeSeconds), nextFilterLabel); 1197 for (PacketSection section : mPacketSections) { 1198 // Generate code to match the packet bytes. 1199 if (section.type == PacketSection.Type.MATCH) { 1200 gen.addLoadImmediate(R0, section.start); 1201 gen.addJumpIfBytesAtR0NotEqual( 1202 Arrays.copyOfRange(mPacket.array(), section.start, 1203 section.start + section.length), 1204 nextFilterLabel); 1205 } else { 1206 switch (section.length) { 1207 // length asserted to be either 2 or 4 on PacketSection construction 1208 case 2: gen.addLoad16(R0, section.start); break; 1209 case 4: gen.addLoad32(R0, section.start); break; 1210 } 1211 1212 // WARNING: keep this in sync with matches()! 1213 // For more information on lifetime comparisons in the APF bytecode, see 1214 // go/apf-ra-filter. 1215 if (section.lifetime == 0) { 1216 // Case 1) old lft == 0 1217 if (section.min > 0) { 1218 // a) in the presence of a min value. 1219 // if lft >= min -> PASS 1220 gen.addJumpIfR0GreaterThan(section.min - 1, nextFilterLabel); 1221 } else { 1222 // b) if min is 0 / there is no min value. 1223 // if lft > 0 -> PASS 1224 gen.addJumpIfR0GreaterThan(0, nextFilterLabel); 1225 } 1226 } else if (section.min == 0) { 1227 // Case 2b) section is not affected by any minimum. 1228 // 1229 // if lft < (oldLft + 2) // 3 -> PASS 1230 // if lft > oldLft -> PASS 1231 gen.addJumpIfR0LessThan(((section.lifetime + 2) / 3), 1232 nextFilterLabel); 1233 gen.addJumpIfR0GreaterThan(section.lifetime, nextFilterLabel); 1234 } else if (section.lifetime < section.min) { 1235 // Case 2a) 0 < old lft < min 1236 // 1237 // if lft == 0 -> PASS 1238 // if lft >= min -> PASS 1239 gen.addJumpIfR0Equals(0, nextFilterLabel); 1240 gen.addJumpIfR0GreaterThan(section.min - 1, nextFilterLabel); 1241 } else if (section.lifetime <= 3 * (long) section.min) { 1242 // Case 3a) min <= old lft <= 3 * min 1243 // Note that: 1244 // "(old lft + 2) / 3 <= min" is equivalent to "old lft <= 3 * min" 1245 // 1246 // Essentially, in this range there is no "renumbering support", as the 1247 // renumbering constant of 1/3 * old lft is smaller than the minimum 1248 // lifetime accepted by the kernel / userspace. 1249 // 1250 // if lft == 0 -> PASS 1251 // if lft > oldLft -> PASS 1252 gen.addJumpIfR0Equals(0, nextFilterLabel); 1253 gen.addJumpIfR0GreaterThan(section.lifetime, nextFilterLabel); 1254 } else { 1255 final String continueLabel = gen.getUniqueLabel(); 1256 // Case 4a) otherwise 1257 // 1258 // if lft == 0 -> PASS 1259 // if lft < min -> CONTINUE 1260 // if lft < (oldLft + 2) // 3 -> PASS 1261 // if lft > oldLft -> PASS 1262 gen.addJumpIfR0Equals(0, nextFilterLabel); 1263 gen.addJumpIfR0LessThan(section.min, continueLabel); 1264 gen.addJumpIfR0LessThan(((section.lifetime + 2) / 3), 1265 nextFilterLabel); 1266 gen.addJumpIfR0GreaterThan(section.lifetime, nextFilterLabel); 1267 1268 // CONTINUE 1269 gen.defineLabel(continueLabel); 1270 } 1271 } 1272 } 1273 gen.addCountAndDrop(Counter.DROPPED_RA); 1274 gen.defineLabel(nextFilterLabel); 1275 } 1276 } 1277 1278 // TODO: Refactor these subclasses to avoid so much repetition. 1279 private abstract static class KeepalivePacket { 1280 // Note that the offset starts from IP header. 1281 // These must be added ether header length when generating program. 1282 static final int IP_HEADER_OFFSET = 0; 1283 static final int IPV4_SRC_ADDR_OFFSET = IP_HEADER_OFFSET + 12; 1284 1285 // Append a filter for this keepalive ack to {@code gen}. 1286 // Jump to drop if it matches the keepalive ack. 1287 // Jump to the next filter if packet doesn't match the keepalive ack. generateFilterLocked(ApfV4GeneratorBase<?> gen)1288 abstract void generateFilterLocked(ApfV4GeneratorBase<?> gen) 1289 throws IllegalInstructionException; 1290 } 1291 1292 // A class to hold NAT-T keepalive ack information. 1293 private class NattKeepaliveResponse extends KeepalivePacket { 1294 static final int UDP_HEADER_LEN = 8; 1295 1296 protected class NattKeepaliveResponseData { 1297 public final byte[] srcAddress; 1298 public final int srcPort; 1299 public final byte[] dstAddress; 1300 public final int dstPort; 1301 NattKeepaliveResponseData(final NattKeepalivePacketDataParcelable sentKeepalivePacket)1302 NattKeepaliveResponseData(final NattKeepalivePacketDataParcelable sentKeepalivePacket) { 1303 srcAddress = sentKeepalivePacket.dstAddress; 1304 srcPort = sentKeepalivePacket.dstPort; 1305 dstAddress = sentKeepalivePacket.srcAddress; 1306 dstPort = sentKeepalivePacket.srcPort; 1307 } 1308 } 1309 1310 protected final NattKeepaliveResponseData mPacket; 1311 protected final byte[] mSrcDstAddr; 1312 protected final byte[] mPortFingerprint; 1313 // NAT-T keepalive packet 1314 protected final byte[] mPayload = {(byte) 0xff}; 1315 NattKeepaliveResponse(final NattKeepalivePacketDataParcelable sentKeepalivePacket)1316 NattKeepaliveResponse(final NattKeepalivePacketDataParcelable sentKeepalivePacket) { 1317 mPacket = new NattKeepaliveResponseData(sentKeepalivePacket); 1318 mSrcDstAddr = concatArrays(mPacket.srcAddress, mPacket.dstAddress); 1319 mPortFingerprint = generatePortFingerprint(mPacket.srcPort, mPacket.dstPort); 1320 } 1321 generatePortFingerprint(int srcPort, int dstPort)1322 byte[] generatePortFingerprint(int srcPort, int dstPort) { 1323 final ByteBuffer fp = ByteBuffer.allocate(4); 1324 fp.order(ByteOrder.BIG_ENDIAN); 1325 fp.putShort((short) srcPort); 1326 fp.putShort((short) dstPort); 1327 return fp.array(); 1328 } 1329 1330 @Override 1331 @GuardedBy("ApfFilter.this") generateFilterLocked(ApfV4GeneratorBase<?> gen)1332 void generateFilterLocked(ApfV4GeneratorBase<?> gen) throws IllegalInstructionException { 1333 final String nextFilterLabel = gen.getUniqueLabel(); 1334 1335 gen.addLoadImmediate(R0, ETH_HEADER_LEN + IPV4_SRC_ADDR_OFFSET); 1336 gen.addJumpIfBytesAtR0NotEqual(mSrcDstAddr, nextFilterLabel); 1337 1338 // A NAT-T keepalive packet contains 1 byte payload with the value 0xff 1339 // Check payload length is 1 1340 gen.addLoadFromMemory(R0, MemorySlot.IPV4_HEADER_SIZE); 1341 gen.addAdd(UDP_HEADER_LEN); 1342 gen.addSwap(); 1343 gen.addLoad16(R0, IPV4_TOTAL_LENGTH_OFFSET); 1344 gen.addNeg(R1); 1345 gen.addAddR1ToR0(); 1346 gen.addJumpIfR0NotEquals(1, nextFilterLabel); 1347 1348 // Check that the ports match 1349 gen.addLoadFromMemory(R0, MemorySlot.IPV4_HEADER_SIZE); 1350 gen.addAdd(ETH_HEADER_LEN); 1351 gen.addJumpIfBytesAtR0NotEqual(mPortFingerprint, nextFilterLabel); 1352 1353 // Payload offset = R0 + UDP header length 1354 gen.addAdd(UDP_HEADER_LEN); 1355 gen.addJumpIfBytesAtR0NotEqual(mPayload, nextFilterLabel); 1356 1357 gen.addCountAndDrop(Counter.DROPPED_IPV4_NATT_KEEPALIVE); 1358 gen.defineLabel(nextFilterLabel); 1359 } 1360 toString()1361 public String toString() { 1362 try { 1363 return String.format("%s -> %s", 1364 ConnectivityUtils.addressAndPortToString( 1365 InetAddress.getByAddress(mPacket.srcAddress), mPacket.srcPort), 1366 ConnectivityUtils.addressAndPortToString( 1367 InetAddress.getByAddress(mPacket.dstAddress), mPacket.dstPort)); 1368 } catch (UnknownHostException e) { 1369 return "Unknown host"; 1370 } 1371 } 1372 } 1373 1374 // A class to hold TCP keepalive ack information. 1375 private abstract static class TcpKeepaliveAck extends KeepalivePacket { 1376 protected static class TcpKeepaliveAckData { 1377 public final byte[] srcAddress; 1378 public final int srcPort; 1379 public final byte[] dstAddress; 1380 public final int dstPort; 1381 public final int seq; 1382 public final int ack; 1383 1384 // Create the characteristics of the ack packet from the sent keepalive packet. TcpKeepaliveAckData(final TcpKeepalivePacketDataParcelable sentKeepalivePacket)1385 TcpKeepaliveAckData(final TcpKeepalivePacketDataParcelable sentKeepalivePacket) { 1386 srcAddress = sentKeepalivePacket.dstAddress; 1387 srcPort = sentKeepalivePacket.dstPort; 1388 dstAddress = sentKeepalivePacket.srcAddress; 1389 dstPort = sentKeepalivePacket.srcPort; 1390 seq = sentKeepalivePacket.ack; 1391 ack = sentKeepalivePacket.seq + 1; 1392 } 1393 } 1394 1395 protected final TcpKeepaliveAckData mPacket; 1396 protected final byte[] mSrcDstAddr; 1397 protected final byte[] mPortSeqAckFingerprint; 1398 TcpKeepaliveAck(final TcpKeepaliveAckData packet, final byte[] srcDstAddr)1399 TcpKeepaliveAck(final TcpKeepaliveAckData packet, final byte[] srcDstAddr) { 1400 mPacket = packet; 1401 mSrcDstAddr = srcDstAddr; 1402 mPortSeqAckFingerprint = generatePortSeqAckFingerprint(mPacket.srcPort, 1403 mPacket.dstPort, mPacket.seq, mPacket.ack); 1404 } 1405 generatePortSeqAckFingerprint(int srcPort, int dstPort, int seq, int ack)1406 static byte[] generatePortSeqAckFingerprint(int srcPort, int dstPort, int seq, int ack) { 1407 final ByteBuffer fp = ByteBuffer.allocate(12); 1408 fp.order(ByteOrder.BIG_ENDIAN); 1409 fp.putShort((short) srcPort); 1410 fp.putShort((short) dstPort); 1411 fp.putInt(seq); 1412 fp.putInt(ack); 1413 return fp.array(); 1414 } 1415 toString()1416 public String toString() { 1417 try { 1418 return String.format("%s -> %s , seq=%d, ack=%d", 1419 ConnectivityUtils.addressAndPortToString( 1420 InetAddress.getByAddress(mPacket.srcAddress), mPacket.srcPort), 1421 ConnectivityUtils.addressAndPortToString( 1422 InetAddress.getByAddress(mPacket.dstAddress), mPacket.dstPort), 1423 Integer.toUnsignedLong(mPacket.seq), 1424 Integer.toUnsignedLong(mPacket.ack)); 1425 } catch (UnknownHostException e) { 1426 return "Unknown host"; 1427 } 1428 } 1429 1430 // Append a filter for this keepalive ack to {@code gen}. 1431 // Jump to drop if it matches the keepalive ack. 1432 // Jump to the next filter if packet doesn't match the keepalive ack. generateFilterLocked(ApfV4GeneratorBase<?> gen)1433 abstract void generateFilterLocked(ApfV4GeneratorBase<?> gen) 1434 throws IllegalInstructionException; 1435 } 1436 1437 private class TcpKeepaliveAckV4 extends TcpKeepaliveAck { 1438 TcpKeepaliveAckV4(final TcpKeepalivePacketDataParcelable sentKeepalivePacket)1439 TcpKeepaliveAckV4(final TcpKeepalivePacketDataParcelable sentKeepalivePacket) { 1440 this(new TcpKeepaliveAckData(sentKeepalivePacket)); 1441 } TcpKeepaliveAckV4(final TcpKeepaliveAckData packet)1442 TcpKeepaliveAckV4(final TcpKeepaliveAckData packet) { 1443 super(packet, concatArrays(packet.srcAddress, packet.dstAddress) /* srcDstAddr */); 1444 } 1445 1446 @Override 1447 @GuardedBy("ApfFilter.this") generateFilterLocked(ApfV4GeneratorBase<?> gen)1448 void generateFilterLocked(ApfV4GeneratorBase<?> gen) throws IllegalInstructionException { 1449 final String nextFilterLabel = gen.getUniqueLabel(); 1450 1451 gen.addLoadImmediate(R0, ETH_HEADER_LEN + IPV4_SRC_ADDR_OFFSET); 1452 gen.addJumpIfBytesAtR0NotEqual(mSrcDstAddr, nextFilterLabel); 1453 1454 // Skip to the next filter if it's not zero-sized : 1455 // TCP_HEADER_SIZE + IPV4_HEADER_SIZE - ipv4_total_length == 0 1456 // Load the IP header size into R1 1457 gen.addLoadFromMemory(R1, MemorySlot.IPV4_HEADER_SIZE); 1458 // Load the TCP header size into R0 (it's indexed by R1) 1459 gen.addLoad8Indexed(R0, ETH_HEADER_LEN + TCP_HEADER_SIZE_OFFSET); 1460 // Size offset is in the top nibble, but it must be multiplied by 4, and the two 1461 // top bits of the low nibble are guaranteed to be zeroes. Right-shift R0 by 2. 1462 gen.addRightShift(2); 1463 // R0 += R1 -> R0 contains TCP + IP headers length 1464 gen.addAddR1ToR0(); 1465 // Load IPv4 total length 1466 gen.addLoad16(R1, IPV4_TOTAL_LENGTH_OFFSET); 1467 gen.addNeg(R0); 1468 gen.addAddR1ToR0(); 1469 gen.addJumpIfR0NotEquals(0, nextFilterLabel); 1470 // Add IPv4 header length 1471 gen.addLoadFromMemory(R1, MemorySlot.IPV4_HEADER_SIZE); 1472 gen.addLoadImmediate(R0, ETH_HEADER_LEN); 1473 gen.addAddR1ToR0(); 1474 gen.addJumpIfBytesAtR0NotEqual(mPortSeqAckFingerprint, nextFilterLabel); 1475 1476 gen.addCountAndDrop(Counter.DROPPED_IPV4_KEEPALIVE_ACK); 1477 gen.defineLabel(nextFilterLabel); 1478 } 1479 } 1480 1481 private static class TcpKeepaliveAckV6 extends TcpKeepaliveAck { TcpKeepaliveAckV6(final TcpKeepalivePacketDataParcelable sentKeepalivePacket)1482 TcpKeepaliveAckV6(final TcpKeepalivePacketDataParcelable sentKeepalivePacket) { 1483 this(new TcpKeepaliveAckData(sentKeepalivePacket)); 1484 } TcpKeepaliveAckV6(final TcpKeepaliveAckData packet)1485 TcpKeepaliveAckV6(final TcpKeepaliveAckData packet) { 1486 super(packet, concatArrays(packet.srcAddress, packet.dstAddress) /* srcDstAddr */); 1487 } 1488 1489 @Override generateFilterLocked(ApfV4GeneratorBase<?> gen)1490 void generateFilterLocked(ApfV4GeneratorBase<?> gen) { 1491 throw new UnsupportedOperationException("IPv6 TCP Keepalive is not supported yet"); 1492 } 1493 } 1494 1495 // Maximum number of RAs to filter for. 1496 private static final int MAX_RAS = 10; 1497 1498 @GuardedBy("this") 1499 private final ArrayList<Ra> mRas = new ArrayList<>(); 1500 @GuardedBy("this") 1501 private final SparseArray<KeepalivePacket> mKeepalivePackets = new SparseArray<>(); 1502 @GuardedBy("this") 1503 // TODO: change the mMdnsAllowList to proper type for APFv6 based mDNS offload 1504 private final List<String[]> mMdnsAllowList = new ArrayList<>(); 1505 1506 // We don't want to filter an RA for it's whole lifetime as it'll be expired by the time we ever 1507 // see a refresh. Using half the lifetime might be a good idea except for the fact that 1508 // packets may be dropped, so let's use 6. 1509 private static final int FRACTION_OF_LIFETIME_TO_FILTER = 6; 1510 1511 // When did we last install a filter program? In seconds since Unix Epoch. 1512 @GuardedBy("this") 1513 private int mLastTimeInstalledProgram; 1514 // How long should the last installed filter program live for? In seconds. 1515 @GuardedBy("this") 1516 private int mLastInstalledProgramMinLifetime; 1517 1518 // For debugging only. The last program installed. 1519 @GuardedBy("this") 1520 private byte[] mLastInstalledProgram; 1521 1522 /** 1523 * For debugging only. Contains the latest APF buffer snapshot captured from the firmware. 1524 * <p> 1525 * A typical size for this buffer is 4KB. It is present only if the WiFi HAL supports 1526 * IWifiStaIface#readApfPacketFilterData(), and the APF interpreter advertised support for 1527 * the opcodes to access the data buffer (LDDW and STDW). 1528 */ 1529 @GuardedBy("this") @Nullable 1530 private byte[] mDataSnapshot; 1531 1532 // How many times the program was updated since we started. 1533 @GuardedBy("this") 1534 private int mNumProgramUpdates = 0; 1535 // The maximum program size that updated since we started. 1536 @GuardedBy("this") 1537 private int mMaxProgramSize = 0; 1538 // The maximum number of distinct RAs 1539 @GuardedBy("this") 1540 private int mMaxDistinctRas = 0; 1541 tryToConvertToApfV6Generator(ApfV4GeneratorBase<?> gen)1542 private ApfV6Generator tryToConvertToApfV6Generator(ApfV4GeneratorBase<?> gen) { 1543 if (gen instanceof ApfV6Generator) { 1544 return (ApfV6Generator) gen; 1545 } 1546 return null; 1547 } 1548 1549 /** 1550 * Generate filter code to process ARP packets. Execution of this code ends in either the 1551 * DROP_LABEL or PASS_LABEL and does not fall off the end. 1552 * Preconditions: 1553 * - Packet being filtered is ARP 1554 */ 1555 @GuardedBy("this") generateArpFilterLocked(ApfV4GeneratorBase<?> gen)1556 private void generateArpFilterLocked(ApfV4GeneratorBase<?> gen) 1557 throws IllegalInstructionException { 1558 // Here's a basic summary of what the ARP filter program does: 1559 // 1560 // if clat is enabled (and we're thus IPv6-only) 1561 // drop 1562 // if not ARP IPv4 1563 // drop 1564 // if unknown ARP opcode (ie. not reply or request) 1565 // drop 1566 // 1567 // if ARP reply: 1568 // if source ip is 0.0.0.0 1569 // drop 1570 // if unicast (or multicast) 1571 // pass 1572 // if interface has no IPv4 address 1573 // if target ip is 0.0.0.0 1574 // drop 1575 // else 1576 // if target ip is not the interface ip 1577 // drop 1578 // pass 1579 // 1580 // if ARP request: 1581 // if interface has IPv4 address 1582 // if target ip is not the interface ip 1583 // drop 1584 // pass 1585 1586 // For IPv6 only network, drop all ARP packet. 1587 if (mHasClat) { 1588 gen.addCountAndDrop(Counter.DROPPED_ARP_V6_ONLY); 1589 return; 1590 } 1591 1592 // Drop if not ARP IPv4. 1593 gen.addLoadImmediate(R0, ARP_HEADER_OFFSET); 1594 gen.addCountAndDropIfBytesAtR0NotEqual(ARP_IPV4_HEADER, Counter.DROPPED_ARP_NON_IPV4); 1595 1596 final String checkArpRequest = gen.getUniqueLabel(); 1597 1598 gen.addLoad16(R0, ARP_OPCODE_OFFSET); 1599 gen.addJumpIfR0Equals(ARP_OPCODE_REQUEST, checkArpRequest); // Skip to arp request check. 1600 // Drop if unknown ARP opcode. 1601 gen.addCountAndDropIfR0NotEquals(ARP_OPCODE_REPLY, Counter.DROPPED_ARP_UNKNOWN); 1602 1603 /*---------- Handle ARP Replies. ----------*/ 1604 1605 // Drop if ARP reply source IP is 0.0.0.0 1606 gen.addLoad32(R0, ARP_SOURCE_IP_ADDRESS_OFFSET); 1607 gen.addCountAndDropIfR0Equals(IPV4_ANY_HOST_ADDRESS, Counter.DROPPED_ARP_REPLY_SPA_NO_HOST); 1608 1609 // Pass if non-broadcast reply. 1610 // This also accepts multicast arp, but we assume those don't exist. 1611 gen.addLoadImmediate(R0, ETH_DEST_ADDR_OFFSET); 1612 gen.addCountAndPassIfBytesAtR0NotEqual(ETHER_BROADCAST, Counter.PASSED_ARP_UNICAST_REPLY); 1613 1614 // It is a broadcast reply. 1615 if (mIPv4Address == null) { 1616 // When there is no IPv4 address, drop GARP replies (b/29404209). 1617 gen.addLoad32(R0, ARP_TARGET_IP_ADDRESS_OFFSET); 1618 gen.addCountAndDropIfR0Equals(IPV4_ANY_HOST_ADDRESS, Counter.DROPPED_GARP_REPLY); 1619 } else { 1620 // When there is an IPv4 address, drop broadcast replies with a different target IPv4 1621 // address. 1622 gen.addLoad32(R0, ARP_TARGET_IP_ADDRESS_OFFSET); 1623 gen.addCountAndDropIfR0NotEquals(bytesToBEInt(mIPv4Address), 1624 Counter.DROPPED_ARP_OTHER_HOST); 1625 } 1626 gen.addCountAndPass(Counter.PASSED_ARP_BROADCAST_REPLY); 1627 1628 /*---------- Handle ARP Requests. ----------*/ 1629 1630 gen.defineLabel(checkArpRequest); 1631 if (mIPv4Address != null) { 1632 // When there is an IPv4 address, drop unicast/broadcast requests with a different 1633 // target IPv4 address. 1634 gen.addLoad32(R0, ARP_TARGET_IP_ADDRESS_OFFSET); 1635 gen.addCountAndDropIfR0NotEquals(bytesToBEInt(mIPv4Address), 1636 Counter.DROPPED_ARP_OTHER_HOST); 1637 1638 ApfV6Generator v6Gen = tryToConvertToApfV6Generator(gen); 1639 if (v6Gen != null && mShouldHandleArpOffload) { 1640 // Ethernet requires that all packets be at least 60 bytes long 1641 v6Gen.addAllocate(60) 1642 .addPacketCopy(ETHER_SRC_ADDR_OFFSET, ETHER_ADDR_LEN) 1643 .addDataCopy(mHardwareAddress) 1644 .addDataCopy(FIXED_ARP_REPLY_HEADER) 1645 .addDataCopy(mHardwareAddress) 1646 .addWrite32(mIPv4Address) 1647 .addPacketCopy(ETHER_SRC_ADDR_OFFSET, ETHER_ADDR_LEN) 1648 .addPacketCopy(ARP_SOURCE_IP_ADDRESS_OFFSET, IPV4_ADDR_LEN) 1649 .addLoadFromMemory(R0, MemorySlot.TX_BUFFER_OUTPUT_POINTER) 1650 .addAdd(18) 1651 .addStoreToMemory(MemorySlot.TX_BUFFER_OUTPUT_POINTER, R0) 1652 .addTransmitWithoutChecksum() 1653 .addCountAndDrop(Counter.DROPPED_ARP_REQUEST_REPLIED); 1654 } 1655 } 1656 // If we're not clat, and we don't have an ipv4 address, allow all ARP request to avoid 1657 // racing against DHCP. 1658 gen.addCountAndPass(Counter.PASSED_ARP_REQUEST); 1659 } 1660 1661 /** 1662 * Generate filter code to process IPv4 packets. Execution of this code ends in either the 1663 * DROP_LABEL or PASS_LABEL and does not fall off the end. 1664 * Preconditions: 1665 * - Packet being filtered is IPv4 1666 */ 1667 @GuardedBy("this") generateIPv4FilterLocked(ApfV4GeneratorBase<?> gen)1668 private void generateIPv4FilterLocked(ApfV4GeneratorBase<?> gen) 1669 throws IllegalInstructionException { 1670 // Here's a basic summary of what the IPv4 filter program does: 1671 // 1672 // if the network is IPv6 only network: 1673 // if the packet is fragmented: 1674 // drop 1675 // if the packet is a dhcp packet comes from server: 1676 // pass 1677 // else 1678 // drop 1679 // if filtering multicast (i.e. multicast lock not held): 1680 // if it's DHCP destined to our MAC: 1681 // pass 1682 // if it's L2 broadcast: 1683 // drop 1684 // if it's IPv4 multicast: 1685 // drop 1686 // if it's IPv4 broadcast: 1687 // drop 1688 // if keepalive ack 1689 // drop 1690 // pass 1691 1692 if (mHasClat) { 1693 // Check 1) it's not a fragment. 2) it's UDP. 1694 // Load 16 bit frag flags/offset field, 8 bit ttl, 8 bit protocol 1695 gen.addLoad32(R0, IPV4_FRAGMENT_OFFSET_OFFSET); 1696 gen.addAnd(0x3FFF00FF); 1697 gen.addCountAndDropIfR0NotEquals(IPPROTO_UDP, Counter.DROPPED_IPV4_NON_DHCP4); 1698 // Check it's addressed to DHCP client port. 1699 gen.addLoadFromMemory(R1, MemorySlot.IPV4_HEADER_SIZE); 1700 gen.addLoad32Indexed(R0, TCP_UDP_SOURCE_PORT_OFFSET); 1701 gen.addCountAndDropIfR0NotEquals(DHCP_SERVER_PORT << 16 | DHCP_CLIENT_PORT, 1702 Counter.DROPPED_IPV4_NON_DHCP4); 1703 gen.addCountAndPass(Counter.PASSED_IPV4_FROM_DHCPV4_SERVER); 1704 return; 1705 } 1706 1707 if (mMulticastFilter) { 1708 final String skipDhcpv4Filter = gen.getUniqueLabel(); 1709 1710 // Pass DHCP addressed to us. 1711 // Check 1) it's not a fragment. 2) it's UDP. 1712 // Load 16 bit frag flags/offset field, 8 bit ttl, 8 bit protocol 1713 gen.addLoad32(R0, IPV4_FRAGMENT_OFFSET_OFFSET); 1714 gen.addAnd(0x3FFF00FF); 1715 gen.addJumpIfR0NotEquals(IPPROTO_UDP, skipDhcpv4Filter); 1716 // Check it's addressed to DHCP client port. 1717 gen.addLoadFromMemory(R1, MemorySlot.IPV4_HEADER_SIZE); 1718 gen.addLoad16Indexed(R0, TCP_UDP_DESTINATION_PORT_OFFSET); 1719 gen.addJumpIfR0NotEquals(DHCP_CLIENT_PORT, skipDhcpv4Filter); 1720 // Check it's DHCP to our MAC address. 1721 gen.addLoadImmediate(R0, DHCP_CLIENT_MAC_OFFSET); 1722 // NOTE: Relies on R1 containing IPv4 header offset. 1723 gen.addAddR1ToR0(); 1724 gen.addJumpIfBytesAtR0NotEqual(mHardwareAddress, skipDhcpv4Filter); 1725 gen.addCountAndPass(Counter.PASSED_DHCP); 1726 1727 // Drop all multicasts/broadcasts. 1728 gen.defineLabel(skipDhcpv4Filter); 1729 1730 // If IPv4 destination address is in multicast range, drop. 1731 gen.addLoad8(R0, IPV4_DEST_ADDR_OFFSET); 1732 gen.addAnd(0xf0); 1733 gen.addCountAndDropIfR0Equals(0xe0, Counter.DROPPED_IPV4_MULTICAST); 1734 1735 // If IPv4 broadcast packet, drop regardless of L2 (b/30231088). 1736 gen.addLoad32(R0, IPV4_DEST_ADDR_OFFSET); 1737 gen.addCountAndDropIfR0Equals(IPV4_BROADCAST_ADDRESS, 1738 Counter.DROPPED_IPV4_BROADCAST_ADDR); 1739 if (mIPv4Address != null && mIPv4PrefixLength < 31) { 1740 int broadcastAddr = ipv4BroadcastAddress(mIPv4Address, mIPv4PrefixLength); 1741 gen.addCountAndDropIfR0Equals(broadcastAddr, Counter.DROPPED_IPV4_BROADCAST_NET); 1742 } 1743 } 1744 1745 // If any TCP keepalive filter matches, drop 1746 generateV4KeepaliveFilters(gen); 1747 1748 // If any NAT-T keepalive filter matches, drop 1749 generateV4NattKeepaliveFilters(gen); 1750 1751 // If TCP unicast on port 7, drop 1752 generateV4TcpPort7FilterLocked(gen); 1753 1754 if (mMulticastFilter) { 1755 // Otherwise, this is an IPv4 unicast, pass 1756 // If L2 broadcast packet, drop. 1757 // TODO: can we invert this condition to fall through to the common pass case below? 1758 gen.addLoadImmediate(R0, ETH_DEST_ADDR_OFFSET); 1759 gen.addCountAndPassIfBytesAtR0NotEqual(ETHER_BROADCAST, Counter.PASSED_IPV4_UNICAST); 1760 gen.addCountAndDrop(Counter.DROPPED_IPV4_L2_BROADCAST); 1761 } 1762 1763 // Otherwise, pass 1764 gen.addCountAndPass(Counter.PASSED_IPV4); 1765 } 1766 1767 @GuardedBy("this") generateKeepaliveFilters(ApfV4GeneratorBase<?> gen, Class<?> filterType, int proto, int offset, String label)1768 private void generateKeepaliveFilters(ApfV4GeneratorBase<?> gen, Class<?> filterType, int proto, 1769 int offset, String label) throws IllegalInstructionException { 1770 final boolean haveKeepaliveResponses = CollectionUtils.any(mKeepalivePackets, 1771 filterType::isInstance); 1772 1773 // If no keepalive packets of this type 1774 if (!haveKeepaliveResponses) return; 1775 1776 // If not the right proto, skip keepalive filters 1777 gen.addLoad8(R0, offset); 1778 gen.addJumpIfR0NotEquals(proto, label); 1779 1780 // Drop Keepalive responses 1781 for (int i = 0; i < mKeepalivePackets.size(); ++i) { 1782 final KeepalivePacket response = mKeepalivePackets.valueAt(i); 1783 if (filterType.isInstance(response)) response.generateFilterLocked(gen); 1784 } 1785 1786 gen.defineLabel(label); 1787 } 1788 1789 @GuardedBy("this") generateV4KeepaliveFilters(ApfV4GeneratorBase<?> gen)1790 private void generateV4KeepaliveFilters(ApfV4GeneratorBase<?> gen) 1791 throws IllegalInstructionException { 1792 generateKeepaliveFilters(gen, TcpKeepaliveAckV4.class, IPPROTO_TCP, IPV4_PROTOCOL_OFFSET, 1793 gen.getUniqueLabel()); 1794 } 1795 1796 @GuardedBy("this") generateV4NattKeepaliveFilters(ApfV4GeneratorBase<?> gen)1797 private void generateV4NattKeepaliveFilters(ApfV4GeneratorBase<?> gen) 1798 throws IllegalInstructionException { 1799 generateKeepaliveFilters(gen, NattKeepaliveResponse.class, 1800 IPPROTO_UDP, IPV4_PROTOCOL_OFFSET, gen.getUniqueLabel()); 1801 } 1802 getSolicitedNodeMcastAddressSuffix( @onNull List<byte[]> ipv6Addresses)1803 private List<byte[]> getSolicitedNodeMcastAddressSuffix( 1804 @NonNull List<byte[]> ipv6Addresses) { 1805 final List<byte[]> suffixes = new ArrayList<>(); 1806 for (byte[] addr: ipv6Addresses) { 1807 suffixes.add(Arrays.copyOfRange(addr, 13, 16)); 1808 } 1809 return suffixes; 1810 } 1811 1812 @GuardedBy("this") getIpv6Addresses( boolean includeNonTentative, boolean includeTentative, boolean includeAnycast)1813 private List<byte[]> getIpv6Addresses( 1814 boolean includeNonTentative, boolean includeTentative, boolean includeAnycast) { 1815 final List<byte[]> addresses = new ArrayList<>(); 1816 if (includeNonTentative) { 1817 for (Inet6Address addr : mIPv6NonTentativeAddresses) { 1818 addresses.add(addr.getAddress()); 1819 } 1820 } 1821 1822 if (includeTentative) { 1823 for (Inet6Address addr : mIPv6TentativeAddresses) { 1824 addresses.add(addr.getAddress()); 1825 } 1826 } 1827 1828 if (includeAnycast) { 1829 addresses.addAll(mDependencies.getAnycast6Addresses(mInterfaceParams.name)); 1830 } 1831 return addresses; 1832 } 1833 1834 @GuardedBy("this") getKnownMacAddresses()1835 private List<byte[]> getKnownMacAddresses() { 1836 final List<byte[]> addresses = new ArrayList<>(); 1837 addresses.addAll(mDependencies.getEtherMulticastAddresses(mInterfaceParams.name)); 1838 addresses.add(mHardwareAddress); 1839 addresses.add(ETHER_BROADCAST); 1840 return addresses; 1841 } 1842 1843 /** 1844 * Generate allocate and transmit code to send ICMPv6 non-DAD NA packets. 1845 */ 1846 @GuardedBy("this") generateNonDadNaTransmitLocked(ApfV6GeneratorBase<?> gen)1847 private void generateNonDadNaTransmitLocked(ApfV6GeneratorBase<?> gen) 1848 throws IllegalInstructionException { 1849 final int ipv6PayloadLen = ICMPV6_NA_HEADER_LEN + ICMPV6_ND_OPTION_TLLA_LEN; 1850 final int pktLen = ETH_HEADER_LEN + IPV6_HEADER_LEN + ipv6PayloadLen; 1851 1852 gen.addAllocate(pktLen); 1853 1854 // Ethernet Header 1855 gen.addPacketCopy(ICMP6_NS_OPTION_TYPE_OFFSET + 2, ETHER_ADDR_LEN) // dst MAC address 1856 .addDataCopy(mHardwareAddress) // src MAC address 1857 .addWriteU16(ETH_P_IPV6); // IPv6 type 1858 1859 int tclass = mDependencies.getNdTrafficClass(mInterfaceParams.name); 1860 int vtf = (0x60000000 | (tclass << 20)); 1861 // IPv6 header 1862 gen.addWrite32(vtf) // IPv6 Header: version, traffic class, flowlabel 1863 // payload length (2 bytes) | next header: ICMPv6 (1 byte) | hop limit (1 byte) 1864 .addWrite32((ipv6PayloadLen << 16) | ((IPPROTO_ICMPV6 << 8) | 255)) 1865 // target ip is guaranteed to be non-tentative as we already check before 1866 // we call transmit, but the link local ip can potentially be tentative. 1867 .addPacketCopy(ICMP6_NS_TARGET_IP_OFFSET, IPV6_ADDR_LEN) // src ip 1868 .addPacketCopy(IPV6_SRC_ADDR_OFFSET, IPV6_ADDR_LEN); // dst ip 1869 1870 // ICMPv6 header and payload 1871 // ICMPv6 type: NA (1 byte) | code: 0 (1 byte) | checksum: set to payload size (2 bytes) 1872 gen.addWrite32((ICMPV6_NEIGHBOR_ADVERTISEMENT << 24) | ipv6PayloadLen) 1873 // Always set Router flag to prevent host deleting routes point at the router 1874 // Always set Override flag to update neighbor's cache 1875 // Solicited flag set to 1 if non DAD, refer to RFC4861#7.2.4 1876 .addWrite32(0xe0000000) // flags: R=1, S=1, O=1 1877 .addPacketCopy(ICMP6_NS_TARGET_IP_OFFSET, IPV6_ADDR_LEN) // target address 1878 // lla option: type (1 byte) | lla option: length (1 byte) 1879 .addWriteU16((ICMPV6_ND_OPTION_TLLA << 8) | 1) 1880 .addDataCopy(mHardwareAddress); // lla option: link layer address 1881 1882 gen.addTransmitL4( 1883 ETHER_HEADER_LEN, // ip_ofs 1884 ICMP6_CHECKSUM_OFFSET, // csum_ofs 1885 IPV6_SRC_ADDR_OFFSET, // csum_start 1886 IPPROTO_ICMPV6, // partial_sum 1887 false // udp 1888 ); 1889 } 1890 1891 @GuardedBy("this") generateNsFilterLocked(ApfV6Generator v6Gen)1892 private void generateNsFilterLocked(ApfV6Generator v6Gen) 1893 throws IllegalInstructionException { 1894 final List<byte[]> allIPv6Addrs = getIpv6Addresses( 1895 true /* includeNonTentative */, 1896 true /* includeTentative */, 1897 true /* includeAnycast */); 1898 if (allIPv6Addrs.isEmpty()) { 1899 // If there is no IPv6 link local address, allow all NS packets to avoid racing 1900 // against RS. 1901 v6Gen.addCountAndPass(PASSED_IPV6_NS_NO_ADDRESS); 1902 return; 1903 } 1904 1905 // Warning: APF program may temporarily filter NS packets targeted for anycast addresses 1906 // used by processes other than clatd. This is because APF cannot reliably detect signal 1907 // on when IPV6_{JOIN,LEAVE}_ANYCAST is triggered. 1908 final List<byte[]> allMACs = getKnownMacAddresses(); 1909 v6Gen.addLoadImmediate(R0, ETH_DEST_ADDR_OFFSET) 1910 .addCountAndDropIfBytesAtR0EqualsNoneOf(allMACs, DROPPED_IPV6_NS_OTHER_HOST); 1911 1912 // Dst IPv6 address check: 1913 final List<byte[]> allSuffixes = getSolicitedNodeMcastAddressSuffix(allIPv6Addrs); 1914 final String notIpV6SolicitedNodeMcast = v6Gen.getUniqueLabel(); 1915 final String endOfIpV6DstCheck = v6Gen.getUniqueLabel(); 1916 v6Gen.addLoadImmediate(R0, IPV6_DEST_ADDR_OFFSET) 1917 .addJumpIfBytesAtR0NotEqual(IPV6_SOLICITED_NODES_PREFIX, notIpV6SolicitedNodeMcast) 1918 .addAdd(13) 1919 .addCountAndDropIfBytesAtR0EqualsNoneOf(allSuffixes, DROPPED_IPV6_NS_OTHER_HOST) 1920 .addJump(endOfIpV6DstCheck) 1921 .defineLabel(notIpV6SolicitedNodeMcast) 1922 .addCountAndDropIfBytesAtR0EqualsNoneOf(allIPv6Addrs, DROPPED_IPV6_NS_OTHER_HOST) 1923 .defineLabel(endOfIpV6DstCheck); 1924 1925 // Hop limit not 255, NS requires hop limit to be 255 -> drop 1926 v6Gen.addLoad8(R0, IPV6_HOP_LIMIT_OFFSET) 1927 .addCountAndDropIfR0NotEquals(255, DROPPED_IPV6_NS_INVALID); 1928 1929 // payload length < 24 (8 bytes ICMP6 header + 16 bytes target address) -> drop 1930 v6Gen.addLoad16(R0, IPV6_PAYLOAD_LEN_OFFSET) 1931 .addCountAndDropIfR0LessThan(24, DROPPED_IPV6_NS_INVALID); 1932 1933 // ICMPv6 code not 0 -> drop 1934 v6Gen.addLoad8(R0, ICMP6_CODE_OFFSET) 1935 .addCountAndDropIfR0NotEquals(0, DROPPED_IPV6_NS_INVALID); 1936 1937 // target address (ICMPv6 NS/NA payload) is not interface addresses -> drop 1938 v6Gen.addLoadImmediate(R0, ICMP6_NS_TARGET_IP_OFFSET) 1939 .addCountAndDropIfBytesAtR0EqualsNoneOf(allIPv6Addrs, DROPPED_IPV6_NS_OTHER_HOST); 1940 1941 // Only offload the following cases: 1942 // 1) NS packet with no options. 1943 // 2) NS packet with only one option: nonce. 1944 // 3) NS packet with only one option: SLLA. 1945 // For packets containing more than one option, 1946 // pass the packet to the CPU for processing. 1947 // payload length > 32 1948 // (8 bytes ICMP6 header + 16 bytes target address + 8 bytes option) -> pass 1949 v6Gen.addLoad16(R0, IPV6_PAYLOAD_LEN_OFFSET) 1950 .addCountAndPassIfR0GreaterThan(32, PASSED_IPV6_NS_MULTIPLE_OPTIONS); 1951 1952 v6Gen.addCountAndPass(Counter.PASSED_IPV6_ICMP); 1953 } 1954 1955 /** 1956 * Generate filter code to process IPv6 packets. Execution of this code ends in either the 1957 * DROP_LABEL or PASS_LABEL, or falls off the end for ICMPv6 packets. 1958 * Preconditions: 1959 * - Packet being filtered is IPv6 1960 */ 1961 @GuardedBy("this") generateIPv6FilterLocked(ApfV4GeneratorBase<?> gen)1962 private void generateIPv6FilterLocked(ApfV4GeneratorBase<?> gen) 1963 throws IllegalInstructionException { 1964 // Here's a basic summary of what the IPv6 filter program does: 1965 // 1966 // if there is a hop-by-hop option present (e.g. MLD query) 1967 // pass 1968 // if we're dropping multicast 1969 // if it's not IPCMv6 or it's ICMPv6 but we're in doze mode: 1970 // if it's multicast: 1971 // drop 1972 // pass 1973 // (APFv6+ specific logic) if it's ICMPv6 NS: 1974 // if there are no IPv6 addresses (including link local address) on the interface: 1975 // pass 1976 // if MAC dst is none of known {unicast, multicast, broadcast} MAC addresses 1977 // drop 1978 // if IPv6 dst prefix is "ff02::1:ff00:0/104" but is none of solicited-node multicast 1979 // IPv6 addresses: 1980 // drop 1981 // else if IPv6 dst is none of interface unicast IPv6 addresses (incl. anycast): 1982 // drop 1983 // if hop limit is not 255 (NS requires hop limit to be 255): 1984 // drop 1985 // if payload len < 24 (8 bytes ICMP6 header + 16 bytes target address): 1986 // drop 1987 // if ICMPv6 code is not 0: 1988 // drop 1989 // if target IP is none of interface unicast IPv6 addresses (incl. anycast): 1990 // drop 1991 // if payload len > 32 (8 bytes ICMP6 header + 16 bytes target address + 8 bytes option): 1992 // pass 1993 // if it's ICMPv6 RS to any: 1994 // drop 1995 // if it's ICMPv6 NA to anything in ff02::/120 1996 // drop 1997 // if keepalive ack 1998 // drop 1999 2000 gen.addLoad8(R0, IPV6_NEXT_HEADER_OFFSET); 2001 2002 // MLD packets set the router-alert hop-by-hop option. 2003 // TODO: be smarter about not blindly passing every packet with HBH options. 2004 gen.addCountAndPassIfR0Equals(IPPROTO_HOPOPTS, Counter.PASSED_MLD); 2005 2006 // Drop multicast if the multicast filter is enabled. 2007 if (mMulticastFilter) { 2008 final String skipIPv6MulticastFilterLabel = gen.getUniqueLabel(); 2009 final String dropAllIPv6MulticastsLabel = gen.getUniqueLabel(); 2010 2011 // While in doze mode, drop ICMPv6 multicast pings, let the others pass. 2012 // While awake, let all ICMPv6 multicasts through. 2013 if (mInDozeMode) { 2014 // Not ICMPv6? -> Proceed to multicast filtering 2015 gen.addJumpIfR0NotEquals(IPPROTO_ICMPV6, dropAllIPv6MulticastsLabel); 2016 2017 // ICMPv6 but not ECHO? -> Skip the multicast filter. 2018 // (ICMPv6 ECHO requests will go through the multicast filter below). 2019 gen.addLoad8(R0, ICMP6_TYPE_OFFSET); 2020 gen.addJumpIfR0NotEquals(ICMPV6_ECHO_REQUEST_TYPE, skipIPv6MulticastFilterLabel); 2021 } else { 2022 gen.addJumpIfR0Equals(IPPROTO_ICMPV6, skipIPv6MulticastFilterLabel); 2023 } 2024 2025 // Drop all other packets sent to ff00::/8 (multicast prefix). 2026 gen.defineLabel(dropAllIPv6MulticastsLabel); 2027 gen.addLoad8(R0, IPV6_DEST_ADDR_OFFSET); 2028 gen.addCountAndDropIfR0Equals(0xff, Counter.DROPPED_IPV6_NON_ICMP_MULTICAST); 2029 // If any keepalive filter matches, drop 2030 generateV6KeepaliveFilters(gen); 2031 // Not multicast. Pass. 2032 gen.addCountAndPass(Counter.PASSED_IPV6_UNICAST_NON_ICMP); 2033 gen.defineLabel(skipIPv6MulticastFilterLabel); 2034 } else { 2035 generateV6KeepaliveFilters(gen); 2036 // If not ICMPv6, pass. 2037 gen.addCountAndPassIfR0NotEquals(IPPROTO_ICMPV6, Counter.PASSED_IPV6_NON_ICMP); 2038 } 2039 2040 // If we got this far, the packet is ICMPv6. Drop some specific types. 2041 // Not ICMPv6 NS -> skip. 2042 gen.addLoad8(R0, ICMP6_TYPE_OFFSET); // warning: also used further below. 2043 final ApfV6Generator v6Gen = tryToConvertToApfV6Generator(gen); 2044 if (v6Gen != null) { 2045 final String skipNsPacketFilter = v6Gen.getUniqueLabel(); 2046 v6Gen.addJumpIfR0NotEquals(ICMPV6_NEIGHBOR_SOLICITATION, skipNsPacketFilter); 2047 generateNsFilterLocked(v6Gen); 2048 // End of NS filter. generateNsFilterLocked() method is terminal, so NS packet will be 2049 // either dropped or passed inside generateNsFilterLocked(). 2050 v6Gen.defineLabel(skipNsPacketFilter); 2051 } 2052 2053 // Add unsolicited multicast neighbor announcements filter 2054 String skipUnsolicitedMulticastNALabel = gen.getUniqueLabel(); 2055 // Drop all router solicitations (b/32833400) 2056 gen.addCountAndDropIfR0Equals(ICMPV6_ROUTER_SOLICITATION, 2057 Counter.DROPPED_IPV6_ROUTER_SOLICITATION); 2058 // If not neighbor announcements, skip filter. 2059 gen.addJumpIfR0NotEquals(ICMPV6_NEIGHBOR_ADVERTISEMENT, skipUnsolicitedMulticastNALabel); 2060 // Drop all multicast NA to ff02::/120. 2061 // This is a way to cover ff02::1 and ff02::2 with a single JNEBS. 2062 // TODO: Drop only if they don't contain the address of on-link neighbours. 2063 final byte[] unsolicitedNaDropPrefix = Arrays.copyOf(IPV6_ALL_NODES_ADDRESS, 15); 2064 gen.addLoadImmediate(R0, IPV6_DEST_ADDR_OFFSET); 2065 gen.addJumpIfBytesAtR0NotEqual(unsolicitedNaDropPrefix, skipUnsolicitedMulticastNALabel); 2066 2067 gen.addCountAndDrop(Counter.DROPPED_IPV6_MULTICAST_NA); 2068 gen.defineLabel(skipUnsolicitedMulticastNALabel); 2069 } 2070 2071 /** 2072 * Generate filter code to process mDNS packets. Execution of this code ends in * DROP_LABEL 2073 * or PASS_LABEL if the packet is mDNS packets. Otherwise, skip this check. 2074 */ 2075 @GuardedBy("this") generateMdnsFilterLocked(ApfV4GeneratorBase<?> gen)2076 private void generateMdnsFilterLocked(ApfV4GeneratorBase<?> gen) 2077 throws IllegalInstructionException { 2078 final String skipMdnsv4Filter = gen.getUniqueLabel(); 2079 final String skipMdnsFilter = gen.getUniqueLabel(); 2080 final String checkMdnsUdpPort = gen.getUniqueLabel(); 2081 2082 // Only turn on the filter if multicast filter is on and the qname allowlist is non-empty. 2083 if (!mMulticastFilter || mMdnsAllowList.isEmpty()) { 2084 return; 2085 } 2086 2087 // Here's a basic summary of what the mDNS filter program does: 2088 // 2089 // A packet is considered as a multicast mDNS packet if it matches all the following 2090 // conditions 2091 // 1. its destination MAC address matches 01:00:5E:00:00:FB or 33:33:00:00:00:FB, for 2092 // v4 and v6 respectively. 2093 // 2. it is an IPv4/IPv6 packet 2094 // 3. it is a UDP packet with port 5353 2095 2096 // Check it's L2 mDNS multicast address. 2097 gen.addLoadImmediate(R0, ETH_DEST_ADDR_OFFSET); 2098 gen.addJumpIfBytesAtR0NotEqual(ETH_MULTICAST_MDNS_V4_MAC_ADDRESS, skipMdnsv4Filter); 2099 2100 // Checks it's IPv4. 2101 gen.addLoad16(R0, ETH_ETHERTYPE_OFFSET); 2102 gen.addJumpIfR0NotEquals(ETH_P_IP, skipMdnsFilter); 2103 2104 // Check it's not a fragment. 2105 gen.addLoad16(R0, IPV4_FRAGMENT_OFFSET_OFFSET); 2106 gen.addJumpIfR0AnyBitsSet(IPV4_FRAGMENT_MORE_FRAGS_MASK | IPV4_FRAGMENT_OFFSET_MASK, 2107 skipMdnsFilter); 2108 2109 // Checks it's UDP. 2110 gen.addLoad8(R0, IPV4_PROTOCOL_OFFSET); 2111 gen.addJumpIfR0NotEquals(IPPROTO_UDP, skipMdnsFilter); 2112 2113 // Set R1 to IPv4 header. 2114 gen.addLoadFromMemory(R1, MemorySlot.IPV4_HEADER_SIZE); 2115 gen.addJump(checkMdnsUdpPort); 2116 2117 gen.defineLabel(skipMdnsv4Filter); 2118 2119 // Checks it's L2 mDNS multicast address. 2120 // Relies on R0 containing the ethernet destination mac address offset. 2121 gen.addJumpIfBytesAtR0NotEqual(ETH_MULTICAST_MDNS_V6_MAC_ADDRESS, skipMdnsFilter); 2122 2123 // Checks it's IPv6. 2124 gen.addLoad16(R0, ETH_ETHERTYPE_OFFSET); 2125 gen.addJumpIfR0NotEquals(ETH_P_IPV6, skipMdnsFilter); 2126 2127 // Checks it's UDP. 2128 gen.addLoad8(R0, IPV6_NEXT_HEADER_OFFSET); 2129 gen.addJumpIfR0NotEquals(IPPROTO_UDP, skipMdnsFilter); 2130 2131 // Set R1 to IPv6 header. 2132 gen.addLoadImmediate(R1, IPV6_HEADER_LEN); 2133 2134 // Checks it's mDNS UDP port 2135 gen.defineLabel(checkMdnsUdpPort); 2136 gen.addLoad16Indexed(R0, TCP_UDP_DESTINATION_PORT_OFFSET); 2137 gen.addJumpIfR0NotEquals(MDNS_PORT, skipMdnsFilter); 2138 2139 // TODO: implement APFv6 mDNS offload 2140 2141 // end of mDNS filter 2142 gen.defineLabel(skipMdnsFilter); 2143 } 2144 2145 /** 2146 * Generate filter code to drop IPv4 TCP packets on port 7. 2147 * <p> 2148 * On entry, we know it is IPv4 ethertype, but don't know anything else. 2149 * R0/R1 have nothing useful in them, and can be clobbered. 2150 */ 2151 @GuardedBy("this") generateV4TcpPort7FilterLocked(ApfV4GeneratorBase<?> gen)2152 private void generateV4TcpPort7FilterLocked(ApfV4GeneratorBase<?> gen) 2153 throws IllegalInstructionException { 2154 final String skipPort7V4Filter = gen.getUniqueLabel(); 2155 2156 // Check it's TCP. 2157 gen.addLoad8(R0, IPV4_PROTOCOL_OFFSET); 2158 gen.addJumpIfR0NotEquals(IPPROTO_TCP, skipPort7V4Filter); 2159 2160 // Check it's not a fragment or is the initial fragment. 2161 gen.addLoad16(R0, IPV4_FRAGMENT_OFFSET_OFFSET); 2162 gen.addJumpIfR0AnyBitsSet(IPV4_FRAGMENT_OFFSET_MASK, skipPort7V4Filter); 2163 2164 // Check it's destination port 7. 2165 gen.addLoadFromMemory(R1, MemorySlot.IPV4_HEADER_SIZE); 2166 gen.addLoad16Indexed(R0, TCP_UDP_DESTINATION_PORT_OFFSET); 2167 gen.addJumpIfR0NotEquals(ECHO_PORT, skipPort7V4Filter); 2168 2169 // Drop it. 2170 gen.addCountAndDrop(Counter.DROPPED_IPV4_TCP_PORT7_UNICAST); 2171 2172 // Skip label. 2173 gen.defineLabel(skipPort7V4Filter); 2174 } 2175 2176 @GuardedBy("this") generateV6KeepaliveFilters(ApfV4GeneratorBase<?> gen)2177 private void generateV6KeepaliveFilters(ApfV4GeneratorBase<?> gen) 2178 throws IllegalInstructionException { 2179 generateKeepaliveFilters(gen, TcpKeepaliveAckV6.class, IPPROTO_TCP, IPV6_NEXT_HEADER_OFFSET, 2180 gen.getUniqueLabel()); 2181 } 2182 2183 /** 2184 * Begin generating an APF program to: 2185 * <ul> 2186 * <li>Drop/Pass 802.3 frames (based on policy) 2187 * <li>Drop packets with EtherType within the Black List 2188 * <li>Drop ARP requests not for us, if mIPv4Address is set, 2189 * <li>Drop IPv4 broadcast packets, except DHCP destined to our MAC, 2190 * <li>Drop IPv4 multicast packets, if mMulticastFilter, 2191 * <li>Pass all other IPv4 packets, 2192 * <li>Drop all broadcast non-IP non-ARP packets. 2193 * <li>Pass all non-ICMPv6 IPv6 packets, 2194 * <li>Pass all non-IPv4 and non-IPv6 packets, 2195 * <li>Drop IPv6 ICMPv6 NAs to anything in ff02::/120. 2196 * <li>Drop IPv6 ICMPv6 RSs. 2197 * <li>Filter IPv4 packets (see generateIPv4FilterLocked()) 2198 * <li>Filter IPv6 packets (see generateIPv6FilterLocked()) 2199 * <li>Let execution continue off the end of the program for IPv6 ICMPv6 packets. This allows 2200 * insertion of RA filters here, or if there aren't any, just passes the packets. 2201 * </ul> 2202 */ 2203 @GuardedBy("this") 2204 @VisibleForTesting emitPrologueLocked()2205 protected ApfV4GeneratorBase<?> emitPrologueLocked() throws IllegalInstructionException { 2206 // This is guaranteed to succeed because of the check in maybeCreate. 2207 ApfV4GeneratorBase<?> gen; 2208 if (SdkLevel.isAtLeastV() 2209 && ApfV6Generator.supportsVersion(mApfCapabilities.apfVersionSupported)) { 2210 gen = new ApfV6Generator(mApfCapabilities.maximumApfProgramSize); 2211 } else { 2212 gen = new ApfV4Generator(mApfCapabilities.apfVersionSupported); 2213 } 2214 2215 if (hasDataAccess(mApfCapabilities)) { 2216 if (gen instanceof ApfV4Generator) { 2217 // Increment TOTAL_PACKETS. 2218 // Only needed in APFv4. 2219 // In APFv6, the interpreter will increase the counter on packet receive. 2220 gen.addIncrementCounter(Counter.TOTAL_PACKETS); 2221 } 2222 2223 gen.addLoadFromMemory(R0, MemorySlot.FILTER_AGE_SECONDS); 2224 gen.addStoreCounter(Counter.FILTER_AGE_SECONDS, R0); 2225 2226 // requires a new enough APFv5+ interpreter, otherwise will be 0 2227 gen.addLoadFromMemory(R0, MemorySlot.FILTER_AGE_16384THS); 2228 gen.addStoreCounter(Counter.FILTER_AGE_16384THS, R0); 2229 2230 // requires a new enough APFv5+ interpreter, otherwise will be 0 2231 gen.addLoadFromMemory(R0, MemorySlot.APF_VERSION); 2232 gen.addStoreCounter(Counter.APF_VERSION, R0); 2233 2234 // store this program's sequential id, for later comparison 2235 gen.addLoadImmediate(R0, mNumProgramUpdates); 2236 gen.addStoreCounter(Counter.APF_PROGRAM_ID, R0); 2237 } 2238 2239 // Here's a basic summary of what the initial program does: 2240 // 2241 // if it's a 802.3 Frame (ethtype < 0x0600): 2242 // drop or pass based on configurations 2243 // if it has a ether-type that belongs to the black list 2244 // drop 2245 // if it's ARP: 2246 // insert ARP filter to drop or pass these appropriately 2247 // if it's IPv4: 2248 // insert IPv4 filter to drop or pass these appropriately 2249 // if it's not IPv6: 2250 // if it's broadcast: 2251 // drop 2252 // pass 2253 // insert IPv6 filter to drop, pass, or fall off the end for ICMPv6 packets 2254 2255 gen.addLoad16(R0, ETH_ETHERTYPE_OFFSET); 2256 if (SdkLevel.isAtLeastV()) { 2257 // IPv4, ARP, IPv6, EAPOL, WAPI 2258 gen.addCountAndDropIfR0IsNoneOf(Set.of(0x0800L, 0x0806L, 0x86DDL, 0x888EL, 0x88B4L), 2259 Counter.DROPPED_ETHERTYPE_NOT_ALLOWED); 2260 } else { 2261 if (mDrop802_3Frames) { 2262 // drop 802.3 frames (ethtype < 0x0600) 2263 gen.addCountAndDropIfR0LessThan(ETH_TYPE_MIN, Counter.DROPPED_802_3_FRAME); 2264 } 2265 // Handle ether-type black list 2266 if (mEthTypeBlackList.length > 0) { 2267 final Set<Long> deniedEtherTypes = new ArraySet<>(); 2268 for (int p : mEthTypeBlackList) { 2269 deniedEtherTypes.add((long) p); 2270 } 2271 gen.addCountAndDropIfR0IsOneOf(deniedEtherTypes, 2272 Counter.DROPPED_ETHERTYPE_NOT_ALLOWED); 2273 } 2274 } 2275 2276 // Add ARP filters: 2277 String skipArpFiltersLabel = gen.getUniqueLabel(); 2278 gen.addJumpIfR0NotEquals(ETH_P_ARP, skipArpFiltersLabel); 2279 generateArpFilterLocked(gen); 2280 gen.defineLabel(skipArpFiltersLabel); 2281 2282 // Add mDNS filter: 2283 generateMdnsFilterLocked(gen); 2284 gen.addLoad16(R0, ETH_ETHERTYPE_OFFSET); 2285 2286 // Add IPv4 filters: 2287 String skipIPv4FiltersLabel = gen.getUniqueLabel(); 2288 gen.addJumpIfR0NotEquals(ETH_P_IP, skipIPv4FiltersLabel); 2289 generateIPv4FilterLocked(gen); 2290 gen.defineLabel(skipIPv4FiltersLabel); 2291 2292 // Check for IPv6: 2293 // NOTE: Relies on R0 containing ethertype. This is safe because if we got here, we did 2294 // not execute the IPv4 filter, since this filter do not fall through, but either drop or 2295 // pass. 2296 String ipv6FilterLabel = gen.getUniqueLabel(); 2297 gen.addJumpIfR0Equals(ETH_P_IPV6, ipv6FilterLabel); 2298 2299 // Drop non-IP non-ARP broadcasts, pass the rest 2300 gen.addLoadImmediate(R0, ETH_DEST_ADDR_OFFSET); 2301 gen.addCountAndPassIfBytesAtR0NotEqual(ETHER_BROADCAST, Counter.PASSED_NON_IP_UNICAST); 2302 gen.addCountAndDrop(Counter.DROPPED_ETH_BROADCAST); 2303 2304 // Add IPv6 filters: 2305 gen.defineLabel(ipv6FilterLabel); 2306 generateIPv6FilterLocked(gen); 2307 return gen; 2308 } 2309 2310 /** 2311 * Append packet counting epilogue to the APF program. 2312 * <p> 2313 * Currently, the epilogue consists of two trampolines which count passed and dropped packets 2314 * before jumping to the actual PASS and DROP labels. 2315 */ 2316 @GuardedBy("this") emitEpilogue(ApfV4GeneratorBase<?> gen)2317 private void emitEpilogue(ApfV4GeneratorBase<?> gen) throws IllegalInstructionException { 2318 // Execution will reach here if none of the filters match, which will pass the packet to 2319 // the application processor. 2320 gen.addCountAndPass(Counter.PASSED_IPV6_ICMP); 2321 2322 // TODO: merge the addCountTrampoline() into generate() method 2323 gen.addCountTrampoline(); 2324 } 2325 2326 /** 2327 * Generate and install a new filter program. 2328 */ 2329 @GuardedBy("this") 2330 @SuppressWarnings("GuardedBy") // errorprone false positive on ra#generateFilterLocked 2331 @VisibleForTesting installNewProgramLocked()2332 public void installNewProgramLocked() { 2333 ArrayList<Ra> rasToFilter = new ArrayList<>(); 2334 final byte[] program; 2335 int programMinLft = Integer.MAX_VALUE; 2336 int maximumApfProgramSize = mApfCapabilities.maximumApfProgramSize; 2337 if (hasDataAccess(mApfCapabilities)) { 2338 // Reserve space for the counters. 2339 maximumApfProgramSize -= Counter.totalSize(); 2340 } 2341 2342 // Prevent generating (and thus installing) larger programs 2343 if (maximumApfProgramSize > mInstallableProgramSizeClamp) { 2344 maximumApfProgramSize = mInstallableProgramSizeClamp; 2345 } 2346 2347 // Ensure the entire APF program uses the same time base. 2348 int timeSeconds = secondsSinceBoot(); 2349 try { 2350 // Step 1: Determine how many RA filters we can fit in the program. 2351 ApfV4GeneratorBase<?> gen = emitPrologueLocked(); 2352 2353 // The epilogue normally goes after the RA filters, but add it early to include its 2354 // length when estimating the total. 2355 emitEpilogue(gen); 2356 2357 // Can't fit the program even without any RA filters? 2358 if (gen.programLengthOverEstimate() > maximumApfProgramSize) { 2359 Log.e(TAG, "Program exceeds maximum size " + maximumApfProgramSize); 2360 sendNetworkQuirkMetrics(NetworkQuirkEvent.QE_APF_OVER_SIZE_FAILURE); 2361 return; 2362 } 2363 2364 for (Ra ra : mRas) { 2365 // skip filter if it has expired. 2366 if (ra.getRemainingFilterLft(timeSeconds) <= 0) continue; 2367 ra.generateFilterLocked(gen, timeSeconds); 2368 // Stop if we get too big. 2369 if (gen.programLengthOverEstimate() > maximumApfProgramSize) { 2370 if (VDBG) Log.d(TAG, "Past maximum program size, skipping RAs"); 2371 sendNetworkQuirkMetrics(NetworkQuirkEvent.QE_APF_OVER_SIZE_FAILURE); 2372 break; 2373 } 2374 2375 rasToFilter.add(ra); 2376 } 2377 2378 // Step 2: Actually generate the program 2379 gen = emitPrologueLocked(); 2380 for (Ra ra : rasToFilter) { 2381 ra.generateFilterLocked(gen, timeSeconds); 2382 programMinLft = Math.min(programMinLft, ra.getRemainingFilterLft(timeSeconds)); 2383 } 2384 emitEpilogue(gen); 2385 program = gen.generate(); 2386 } catch (IllegalInstructionException | IllegalStateException | IllegalArgumentException e) { 2387 Log.wtf(TAG, "Failed to generate APF program.", e); 2388 sendNetworkQuirkMetrics(NetworkQuirkEvent.QE_APF_GENERATE_FILTER_EXCEPTION); 2389 return; 2390 } 2391 if (mIsRunning) { 2392 // Update data snapshot every time we install a new program 2393 mIpClientCallback.startReadPacketFilter("new program install"); 2394 if (!mIpClientCallback.installPacketFilter(program)) { 2395 sendNetworkQuirkMetrics(NetworkQuirkEvent.QE_APF_INSTALL_FAILURE); 2396 } 2397 } 2398 mLastTimeInstalledProgram = timeSeconds; 2399 mLastInstalledProgramMinLifetime = programMinLft; 2400 mLastInstalledProgram = program; 2401 mNumProgramUpdates++; 2402 mMaxProgramSize = Math.max(mMaxProgramSize, program.length); 2403 2404 if (VDBG) { 2405 hexDump("Installing filter: ", program, program.length); 2406 } 2407 } 2408 hexDump(String msg, byte[] packet, int length)2409 private void hexDump(String msg, byte[] packet, int length) { 2410 log(msg + HexDump.toHexString(packet, 0, length, false /* lowercase */)); 2411 } 2412 2413 // Get the minimum value excludes zero. This is used for calculating the lowest lifetime values 2414 // in RA packets. Zero lifetimes are excluded because we want to detect whether there is any 2415 // unusually small lifetimes but zero lifetime is actually valid (cease to be a default router 2416 // or the option is no longer be used). Number of zero lifetime RAs is collected in a different 2417 // Metrics. getMinForPositiveValue(long oldMinValue, long value)2418 private long getMinForPositiveValue(long oldMinValue, long value) { 2419 if (value < 1) return oldMinValue; 2420 return Math.min(oldMinValue, value); 2421 } 2422 getMinForPositiveValue(int oldMinValue, int value)2423 private int getMinForPositiveValue(int oldMinValue, int value) { 2424 return (int) getMinForPositiveValue((long) oldMinValue, (long) value); 2425 } 2426 2427 /** 2428 * Process an RA packet, updating the list of known RAs and installing a new APF program 2429 * if the current APF program should be updated. 2430 */ 2431 @VisibleForTesting processRa(byte[] packet, int length)2432 public synchronized void processRa(byte[] packet, int length) { 2433 if (VDBG) hexDump("Read packet = ", packet, length); 2434 2435 final Ra ra; 2436 try { 2437 ra = new Ra(packet, length); 2438 } catch (Exception e) { 2439 Log.e(TAG, "Error parsing RA", e); 2440 mNumParseErrorRas++; 2441 return; 2442 } 2443 2444 // Update info for Metrics 2445 mLowestRouterLifetimeSeconds = getMinForPositiveValue( 2446 mLowestRouterLifetimeSeconds, ra.routerLifetime()); 2447 mLowestPioValidLifetimeSeconds = getMinForPositiveValue( 2448 mLowestPioValidLifetimeSeconds, ra.minPioValidLifetime()); 2449 mLowestRioRouteLifetimeSeconds = getMinForPositiveValue( 2450 mLowestRioRouteLifetimeSeconds, ra.minRioRouteLifetime()); 2451 mLowestRdnssLifetimeSeconds = getMinForPositiveValue( 2452 mLowestRdnssLifetimeSeconds, ra.minRdnssLifetime()); 2453 2454 // Remove all expired RA filters before trying to match the new RA. 2455 // TODO: matches() still checks that the old RA filter has not expired. Consider removing 2456 // that check. 2457 final int now = secondsSinceBoot(); 2458 mRas.removeIf(item -> item.getRemainingFilterLft(now) <= 0); 2459 2460 // Have we seen this RA before? 2461 for (int i = 0; i < mRas.size(); i++) { 2462 final Ra oldRa = mRas.get(i); 2463 final Ra.MatchType result = oldRa.matches(ra); 2464 if (result == Ra.MatchType.MATCH_PASS) { 2465 log("Updating RA from " + oldRa + " to " + ra); 2466 2467 // Keep mRas in LRU order so as to prioritize generating filters for recently seen 2468 // RAs. LRU prioritizes this because RA filters are generated in order from mRas 2469 // until the filter program exceeds the maximum filter program size allowed by the 2470 // chipset, so RAs appearing earlier in mRas are more likely to make it into the 2471 // filter program. 2472 // TODO: consider sorting the RAs in order of increasing expiry time as well. 2473 // Swap to front of array. 2474 mRas.remove(i); 2475 mRas.add(0, ra); 2476 2477 // Rate limit program installation 2478 if (mTokenBucket.get()) { 2479 installNewProgramLocked(); 2480 } else { 2481 Log.e(TAG, "Failed to install prog for tracked RA, too many updates. " + ra); 2482 } 2483 return; 2484 } else if (result == Ra.MatchType.MATCH_DROP) { 2485 log("Ignoring RA " + ra + " which matches " + oldRa); 2486 return; 2487 } 2488 } 2489 mMaxDistinctRas = Math.max(mMaxDistinctRas, mRas.size() + 1); 2490 if (mRas.size() >= MAX_RAS) { 2491 // Remove the last (i.e. oldest) RA. 2492 mRas.remove(mRas.size() - 1); 2493 } 2494 log("Adding " + ra); 2495 mRas.add(0, ra); 2496 // Rate limit program installation 2497 if (mTokenBucket.get()) { 2498 installNewProgramLocked(); 2499 } else { 2500 Log.e(TAG, "Failed to install prog for new RA, too many updates. " + ra); 2501 } 2502 } 2503 2504 /** 2505 * Create an {@link ApfFilter} if {@code apfCapabilities} indicates support for packet 2506 * filtering using APF programs. 2507 */ maybeCreate(Context context, ApfConfiguration config, InterfaceParams ifParams, IpClientCallbacksWrapper ipClientCallback, NetworkQuirkMetrics networkQuirkMetrics)2508 public static ApfFilter maybeCreate(Context context, ApfConfiguration config, 2509 InterfaceParams ifParams, IpClientCallbacksWrapper ipClientCallback, 2510 NetworkQuirkMetrics networkQuirkMetrics) { 2511 if (context == null || config == null || ifParams == null) return null; 2512 ApfCapabilities apfCapabilities = config.apfCapabilities; 2513 if (apfCapabilities == null) return null; 2514 if (apfCapabilities.apfVersionSupported < 2) return null; 2515 if (apfCapabilities.maximumApfProgramSize < 512) { 2516 Log.e(TAG, "Unacceptably small APF limit: " + apfCapabilities.maximumApfProgramSize); 2517 return null; 2518 } 2519 // For now only support generating programs for Ethernet frames. If this restriction is 2520 // lifted the program generator will need its offsets adjusted. 2521 if (apfCapabilities.apfPacketFormat != ARPHRD_ETHER) return null; 2522 if (!ApfV4Generator.supportsVersion(apfCapabilities.apfVersionSupported)) { 2523 Log.e(TAG, "Unsupported APF version: " + apfCapabilities.apfVersionSupported); 2524 return null; 2525 } 2526 2527 return new ApfFilter(context, config, ifParams, ipClientCallback, networkQuirkMetrics); 2528 } 2529 collectAndSendMetrics()2530 private synchronized void collectAndSendMetrics() { 2531 if (mIpClientRaInfoMetrics == null || mApfSessionInfoMetrics == null) return; 2532 final long sessionDurationMs = mClock.elapsedRealtime() - mSessionStartMs; 2533 if (sessionDurationMs < mMinMetricsSessionDurationMs) return; 2534 2535 // Collect and send IpClientRaInfoMetrics. 2536 mIpClientRaInfoMetrics.setMaxNumberOfDistinctRas(mMaxDistinctRas); 2537 mIpClientRaInfoMetrics.setNumberOfZeroLifetimeRas(mNumZeroLifetimeRas); 2538 mIpClientRaInfoMetrics.setNumberOfParsingErrorRas(mNumParseErrorRas); 2539 mIpClientRaInfoMetrics.setLowestRouterLifetimeSeconds(mLowestRouterLifetimeSeconds); 2540 mIpClientRaInfoMetrics.setLowestPioValidLifetimeSeconds(mLowestPioValidLifetimeSeconds); 2541 mIpClientRaInfoMetrics.setLowestRioRouteLifetimeSeconds(mLowestRioRouteLifetimeSeconds); 2542 mIpClientRaInfoMetrics.setLowestRdnssLifetimeSeconds(mLowestRdnssLifetimeSeconds); 2543 mIpClientRaInfoMetrics.statsWrite(); 2544 2545 // Collect and send ApfSessionInfoMetrics. 2546 mApfSessionInfoMetrics.setVersion(mApfCapabilities.apfVersionSupported); 2547 mApfSessionInfoMetrics.setMemorySize(mApfCapabilities.maximumApfProgramSize); 2548 mApfSessionInfoMetrics.setApfSessionDurationSeconds( 2549 (int) (sessionDurationMs / DateUtils.SECOND_IN_MILLIS)); 2550 mApfSessionInfoMetrics.setNumOfTimesApfProgramUpdated(mNumProgramUpdates); 2551 mApfSessionInfoMetrics.setMaxProgramSize(mMaxProgramSize); 2552 for (Map.Entry<Counter, Long> entry : mApfCounterTracker.getCounters().entrySet()) { 2553 if (entry.getValue() > 0) { 2554 mApfSessionInfoMetrics.addApfCounter(entry.getKey(), entry.getValue()); 2555 } 2556 } 2557 mApfSessionInfoMetrics.statsWrite(); 2558 } 2559 shutdown()2560 public synchronized void shutdown() { 2561 collectAndSendMetrics(); 2562 if (mReceiveThread != null) { 2563 log("shutting down"); 2564 mReceiveThread.halt(); // Also closes socket. 2565 mReceiveThread = null; 2566 } 2567 mRas.clear(); 2568 mDependencies.removeBroadcastReceiver(mDeviceIdleReceiver); 2569 } 2570 setMulticastFilter(boolean isEnabled)2571 public synchronized void setMulticastFilter(boolean isEnabled) { 2572 if (mMulticastFilter == isEnabled) return; 2573 mMulticastFilter = isEnabled; 2574 installNewProgramLocked(); 2575 } 2576 2577 @VisibleForTesting setDozeMode(boolean isEnabled)2578 public synchronized void setDozeMode(boolean isEnabled) { 2579 if (mInDozeMode == isEnabled) return; 2580 mInDozeMode = isEnabled; 2581 installNewProgramLocked(); 2582 } 2583 2584 @VisibleForTesting isInDozeMode()2585 public synchronized boolean isInDozeMode() { 2586 return mInDozeMode; 2587 } 2588 2589 /** Retrieve the single IPv4 LinkAddress if there is one, otherwise return null. */ retrieveIPv4LinkAddress(LinkProperties lp)2590 private static LinkAddress retrieveIPv4LinkAddress(LinkProperties lp) { 2591 LinkAddress ipv4Address = null; 2592 for (LinkAddress address : lp.getLinkAddresses()) { 2593 if (!(address.getAddress() instanceof Inet4Address)) { 2594 continue; 2595 } 2596 if (ipv4Address != null && !ipv4Address.isSameAddressAs(address)) { 2597 // More than one IPv4 address, abort. 2598 return null; 2599 } 2600 ipv4Address = address; 2601 } 2602 return ipv4Address; 2603 } 2604 2605 /** Retrieve the pair of IPv6 Inet6Address set, otherwise return pair with two empty set. 2606 * The first element is a set containing tentative IPv6 addresses, 2607 * the second element is a set containing non-tentative IPv6 addresses 2608 * */ 2609 private static Pair<Set<Inet6Address>, Set<Inet6Address>> retrieveIPv6LinkAddress(LinkProperties lp)2610 retrieveIPv6LinkAddress(LinkProperties lp) { 2611 final Set<Inet6Address> tentativeAddrs = new ArraySet<>(); 2612 final Set<Inet6Address> nonTentativeAddrs = new ArraySet<>(); 2613 for (LinkAddress address : lp.getLinkAddresses()) { 2614 if (!(address.getAddress() instanceof Inet6Address)) { 2615 continue; 2616 } 2617 2618 if ((address.getFlags() & IFA_F_TENTATIVE) == IFA_F_TENTATIVE) { 2619 tentativeAddrs.add((Inet6Address) address.getAddress()); 2620 } else { 2621 nonTentativeAddrs.add((Inet6Address) address.getAddress()); 2622 } 2623 } 2624 2625 2626 return new Pair<>(tentativeAddrs, nonTentativeAddrs); 2627 } 2628 setLinkProperties(LinkProperties lp)2629 public synchronized void setLinkProperties(LinkProperties lp) { 2630 // NOTE: Do not keep a copy of LinkProperties as it would further duplicate state. 2631 final LinkAddress ipv4Address = retrieveIPv4LinkAddress(lp); 2632 final byte[] addr = (ipv4Address != null) ? ipv4Address.getAddress().getAddress() : null; 2633 final int prefix = (ipv4Address != null) ? ipv4Address.getPrefixLength() : 0; 2634 final Pair<Set<Inet6Address>, Set<Inet6Address>> 2635 ipv6Addresses = retrieveIPv6LinkAddress(lp); 2636 2637 if ((prefix == mIPv4PrefixLength) 2638 && Arrays.equals(addr, mIPv4Address) 2639 && ipv6Addresses.first.equals(mIPv6TentativeAddresses) 2640 && ipv6Addresses.second.equals(mIPv6NonTentativeAddresses) 2641 ) { 2642 return; 2643 } 2644 mIPv4Address = addr; 2645 mIPv4PrefixLength = prefix; 2646 mIPv6TentativeAddresses = ipv6Addresses.first; 2647 mIPv6NonTentativeAddresses = ipv6Addresses.second; 2648 2649 installNewProgramLocked(); 2650 } 2651 2652 @Override updateClatInterfaceState(boolean add)2653 public synchronized void updateClatInterfaceState(boolean add) { 2654 if (mHasClat == add) { 2655 return; 2656 } 2657 mHasClat = add; 2658 installNewProgramLocked(); 2659 } 2660 2661 /** 2662 * Add TCP keepalive ack packet filter. 2663 * This will add a filter to drop acks to the keepalive packet passed as an argument. 2664 * 2665 * @param slot The index used to access the filter. 2666 * @param sentKeepalivePacket The attributes of the sent keepalive packet. 2667 */ addTcpKeepalivePacketFilter(final int slot, final TcpKeepalivePacketDataParcelable sentKeepalivePacket)2668 public synchronized void addTcpKeepalivePacketFilter(final int slot, 2669 final TcpKeepalivePacketDataParcelable sentKeepalivePacket) { 2670 log("Adding keepalive ack(" + slot + ")"); 2671 if (null != mKeepalivePackets.get(slot)) { 2672 throw new IllegalArgumentException("Keepalive slot " + slot + " is occupied"); 2673 } 2674 final int ipVersion = sentKeepalivePacket.srcAddress.length == 4 ? 4 : 6; 2675 mKeepalivePackets.put(slot, (ipVersion == 4) 2676 ? new TcpKeepaliveAckV4(sentKeepalivePacket) 2677 : new TcpKeepaliveAckV6(sentKeepalivePacket)); 2678 installNewProgramLocked(); 2679 } 2680 2681 /** 2682 * Add NAT-T keepalive packet filter. 2683 * This will add a filter to drop NAT-T keepalive packet which is passed as an argument. 2684 * 2685 * @param slot The index used to access the filter. 2686 * @param sentKeepalivePacket The attributes of the sent keepalive packet. 2687 */ addNattKeepalivePacketFilter(final int slot, final NattKeepalivePacketDataParcelable sentKeepalivePacket)2688 public synchronized void addNattKeepalivePacketFilter(final int slot, 2689 final NattKeepalivePacketDataParcelable sentKeepalivePacket) { 2690 log("Adding NAT-T keepalive packet(" + slot + ")"); 2691 if (null != mKeepalivePackets.get(slot)) { 2692 throw new IllegalArgumentException("NAT-T Keepalive slot " + slot + " is occupied"); 2693 } 2694 2695 // TODO : update ApfFilter to support dropping v6 keepalives 2696 if (sentKeepalivePacket.srcAddress.length != 4) { 2697 return; 2698 } 2699 2700 mKeepalivePackets.put(slot, new NattKeepaliveResponse(sentKeepalivePacket)); 2701 installNewProgramLocked(); 2702 } 2703 2704 /** 2705 * Remove keepalive packet filter. 2706 * 2707 * @param slot The index used to access the filter. 2708 */ removeKeepalivePacketFilter(int slot)2709 public synchronized void removeKeepalivePacketFilter(int slot) { 2710 log("Removing keepalive packet(" + slot + ")"); 2711 mKeepalivePackets.remove(slot); 2712 installNewProgramLocked(); 2713 } 2714 dump(IndentingPrintWriter pw)2715 public synchronized void dump(IndentingPrintWriter pw) { 2716 pw.println("Capabilities: " + mApfCapabilities); 2717 pw.println("InstallableProgramSizeClamp: " + mInstallableProgramSizeClamp); 2718 pw.println("Filter update status: " + (mIsRunning ? "RUNNING" : "PAUSED")); 2719 pw.println("Receive thread: " + (mReceiveThread != null ? "RUNNING" : "STOPPED")); 2720 pw.println("Multicast: " + (mMulticastFilter ? "DROP" : "ALLOW")); 2721 pw.println("Minimum RDNSS lifetime: " + mMinRdnssLifetimeSec); 2722 try { 2723 pw.println("IPv4 address: " + InetAddress.getByAddress(mIPv4Address).getHostAddress()); 2724 pw.println("IPv6 addresses: "); 2725 pw.increaseIndent(); 2726 for (Inet6Address addr: mIPv6NonTentativeAddresses) { 2727 pw.println(addr.getHostAddress()); 2728 } 2729 pw.decreaseIndent(); 2730 } catch (UnknownHostException|NullPointerException e) {} 2731 2732 if (mLastTimeInstalledProgram == 0) { 2733 pw.println("No program installed."); 2734 return; 2735 } 2736 pw.println("Program updates: " + mNumProgramUpdates); 2737 pw.println(String.format( 2738 "Last program length %d, installed %ds ago, lifetime %ds", 2739 mLastInstalledProgram.length, secondsSinceBoot() - mLastTimeInstalledProgram, 2740 mLastInstalledProgramMinLifetime)); 2741 2742 pw.print("Denylisted Ethertypes:"); 2743 for (int p : mEthTypeBlackList) { 2744 pw.print(String.format(" %04x", p)); 2745 } 2746 pw.println(); 2747 pw.println("RA filters:"); 2748 pw.increaseIndent(); 2749 for (Ra ra: mRas) { 2750 pw.println(ra); 2751 pw.increaseIndent(); 2752 pw.println(String.format( 2753 "Last seen %ds ago", secondsSinceBoot() - ra.mLastSeen)); 2754 if (DBG) { 2755 pw.println("Last match:"); 2756 pw.increaseIndent(); 2757 pw.println(ra.getLastMatchingPacket()); 2758 pw.decreaseIndent(); 2759 } 2760 pw.decreaseIndent(); 2761 } 2762 pw.decreaseIndent(); 2763 2764 pw.println("TCP Keepalive filters:"); 2765 pw.increaseIndent(); 2766 for (int i = 0; i < mKeepalivePackets.size(); ++i) { 2767 final KeepalivePacket keepalivePacket = mKeepalivePackets.valueAt(i); 2768 if (keepalivePacket instanceof TcpKeepaliveAck) { 2769 pw.print("Slot "); 2770 pw.print(mKeepalivePackets.keyAt(i)); 2771 pw.print(": "); 2772 pw.println(keepalivePacket); 2773 } 2774 } 2775 pw.decreaseIndent(); 2776 2777 pw.println("NAT-T Keepalive filters:"); 2778 pw.increaseIndent(); 2779 for (int i = 0; i < mKeepalivePackets.size(); ++i) { 2780 final KeepalivePacket keepalivePacket = mKeepalivePackets.valueAt(i); 2781 if (keepalivePacket instanceof NattKeepaliveResponse) { 2782 pw.print("Slot "); 2783 pw.print(mKeepalivePackets.keyAt(i)); 2784 pw.print(": "); 2785 pw.println(keepalivePacket); 2786 } 2787 } 2788 pw.decreaseIndent(); 2789 2790 if (DBG) { 2791 pw.println("Last program:"); 2792 pw.increaseIndent(); 2793 pw.println(HexDump.toHexString(mLastInstalledProgram, false /* lowercase */)); 2794 pw.decreaseIndent(); 2795 } 2796 2797 pw.println("APF packet counters: "); 2798 pw.increaseIndent(); 2799 if (!hasDataAccess(mApfCapabilities)) { 2800 pw.println("APF counters not supported"); 2801 } else if (mDataSnapshot == null) { 2802 pw.println("No last snapshot."); 2803 } else { 2804 try { 2805 Counter[] counters = Counter.class.getEnumConstants(); 2806 for (Counter c : Arrays.asList(counters).subList(1, counters.length)) { 2807 long value = ApfCounterTracker.getCounterValue(mDataSnapshot, c); 2808 // Only print non-zero counters 2809 if (value != 0) { 2810 pw.println(c.toString() + ": " + value); 2811 } 2812 2813 // If the counter's value decreases, it may have been cleaned up or there may be 2814 // a bug. 2815 if (value < mApfCounterTracker.getCounters().getOrDefault(c, 0L)) { 2816 Log.e(TAG, "Error: Counter value unexpectedly decreased."); 2817 } 2818 } 2819 } catch (ArrayIndexOutOfBoundsException e) { 2820 pw.println("Uh-oh: " + e); 2821 } 2822 if (VDBG) { 2823 pw.println("Raw data dump: "); 2824 pw.println(HexDump.dumpHexString(mDataSnapshot)); 2825 } 2826 } 2827 pw.decreaseIndent(); 2828 } 2829 2830 /** Return ApfFilter update status for testing purposes. */ isRunning()2831 public boolean isRunning() { 2832 return mIsRunning; 2833 } 2834 2835 /** Pause ApfFilter updates for testing purposes. */ pause()2836 public void pause() { 2837 mIsRunning = false; 2838 } 2839 2840 /** Resume ApfFilter updates for testing purposes. */ resume()2841 public void resume() { 2842 mIsRunning = true; 2843 } 2844 2845 /** Return data snapshot as hex string for testing purposes. */ getDataSnapshotHexString()2846 public synchronized @Nullable String getDataSnapshotHexString() { 2847 if (mDataSnapshot == null) { 2848 return null; 2849 } 2850 return HexDump.toHexString(mDataSnapshot, 0, mDataSnapshot.length, false /* lowercase */); 2851 } 2852 2853 // TODO: move to android.net.NetworkUtils 2854 @VisibleForTesting ipv4BroadcastAddress(byte[] addrBytes, int prefixLength)2855 public static int ipv4BroadcastAddress(byte[] addrBytes, int prefixLength) { 2856 return bytesToBEInt(addrBytes) | (int) (Integer.toUnsignedLong(-1) >>> prefixLength); 2857 } 2858 uint8(byte b)2859 private static int uint8(byte b) { 2860 return b & 0xff; 2861 } 2862 getUint16(ByteBuffer buffer, int position)2863 private static int getUint16(ByteBuffer buffer, int position) { 2864 return buffer.getShort(position) & 0xffff; 2865 } 2866 getUint32(ByteBuffer buffer, int position)2867 private static long getUint32(ByteBuffer buffer, int position) { 2868 return Integer.toUnsignedLong(buffer.getInt(position)); 2869 } 2870 getUint8(ByteBuffer buffer, int position)2871 private static int getUint8(ByteBuffer buffer, int position) { 2872 return uint8(buffer.get(position)); 2873 } 2874 bytesToBEInt(byte[] bytes)2875 private static int bytesToBEInt(byte[] bytes) { 2876 return (uint8(bytes[0]) << 24) 2877 + (uint8(bytes[1]) << 16) 2878 + (uint8(bytes[2]) << 8) 2879 + (uint8(bytes[3])); 2880 } 2881 concatArrays(final byte[]... arr)2882 private static byte[] concatArrays(final byte[]... arr) { 2883 int size = 0; 2884 for (byte[] a : arr) { 2885 size += a.length; 2886 } 2887 final byte[] result = new byte[size]; 2888 int offset = 0; 2889 for (byte[] a : arr) { 2890 System.arraycopy(a, 0, result, offset, a.length); 2891 offset += a.length; 2892 } 2893 return result; 2894 } 2895 sendNetworkQuirkMetrics(final NetworkQuirkEvent event)2896 private void sendNetworkQuirkMetrics(final NetworkQuirkEvent event) { 2897 if (mNetworkQuirkMetrics == null) return; 2898 mNetworkQuirkMetrics.setEvent(event); 2899 mNetworkQuirkMetrics.statsWrite(); 2900 } 2901 } 2902