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.DNS_HEADER_LEN; 31 import static android.net.apf.ApfConstants.ECHO_PORT; 32 import static android.net.apf.ApfConstants.ETH_DEST_ADDR_OFFSET; 33 import static android.net.apf.ApfConstants.ETH_ETHERTYPE_OFFSET; 34 import static android.net.apf.ApfConstants.ETH_HEADER_LEN; 35 import static android.net.apf.ApfConstants.ETH_MULTICAST_IGMP_V3_ALL_MULTICAST_ROUTERS_ADDRESS; 36 import static android.net.apf.ApfConstants.ETH_MULTICAST_MDNS_V4_MAC_ADDRESS; 37 import static android.net.apf.ApfConstants.ETH_MULTICAST_MDNS_V6_MAC_ADDRESS; 38 import static android.net.apf.ApfConstants.ETH_MULTICAST_MLD_V2_ALL_MULTICAST_ROUTERS_ADDRESS; 39 import static android.net.apf.ApfConstants.ETH_TYPE_MAX; 40 import static android.net.apf.ApfConstants.ETH_TYPE_MIN; 41 import static android.net.apf.ApfConstants.FIXED_ARP_REPLY_HEADER; 42 import static android.net.apf.ApfConstants.ICMP4_CHECKSUM_NO_OPTIONS_OFFSET; 43 import static android.net.apf.ApfConstants.ICMP4_CONTENT_NO_OPTIONS_OFFSET; 44 import static android.net.apf.ApfConstants.ICMP4_TYPE_NO_OPTIONS_OFFSET; 45 import static android.net.apf.ApfConstants.ICMP6_4_BYTE_LIFETIME_LEN; 46 import static android.net.apf.ApfConstants.ICMP6_4_BYTE_LIFETIME_OFFSET; 47 import static android.net.apf.ApfConstants.ICMP6_CAPTIVE_PORTAL_OPTION_TYPE; 48 import static android.net.apf.ApfConstants.ICMP6_CHECKSUM_OFFSET; 49 import static android.net.apf.ApfConstants.ICMP6_CODE_OFFSET; 50 import static android.net.apf.ApfConstants.ICMP6_CONTENT_OFFSET; 51 import static android.net.apf.ApfConstants.ICMP6_DNSSL_OPTION_TYPE; 52 import static android.net.apf.ApfConstants.ICMP6_ECHO_REQUEST_HEADER_LEN; 53 import static android.net.apf.ApfConstants.ICMP6_MTU_OPTION_TYPE; 54 import static android.net.apf.ApfConstants.ICMP6_NS_OPTION_TYPE_OFFSET; 55 import static android.net.apf.ApfConstants.ICMP6_NS_TARGET_IP_OFFSET; 56 import static android.net.apf.ApfConstants.ICMP6_PREF64_OPTION_TYPE; 57 import static android.net.apf.ApfConstants.ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_LEN; 58 import static android.net.apf.ApfConstants.ICMP6_PREFIX_OPTION_TYPE; 59 import static android.net.apf.ApfConstants.ICMP6_PREFIX_OPTION_VALID_LIFETIME_LEN; 60 import static android.net.apf.ApfConstants.ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET; 61 import static android.net.apf.ApfConstants.ICMP6_RA_CHECKSUM_LEN; 62 import static android.net.apf.ApfConstants.ICMP6_RA_CHECKSUM_OFFSET; 63 import static android.net.apf.ApfConstants.ICMP6_RA_FLAGS_EXTENSION_OPTION_TYPE; 64 import static android.net.apf.ApfConstants.ICMP6_RA_OPTION_OFFSET; 65 import static android.net.apf.ApfConstants.ICMP6_RA_ROUTER_LIFETIME_LEN; 66 import static android.net.apf.ApfConstants.ICMP6_RA_ROUTER_LIFETIME_OFFSET; 67 import static android.net.apf.ApfConstants.ICMP6_RDNSS_OPTION_TYPE; 68 import static android.net.apf.ApfConstants.ICMP6_ROUTE_INFO_OPTION_TYPE; 69 import static android.net.apf.ApfConstants.ICMP6_SOURCE_LL_ADDRESS_OPTION_TYPE; 70 import static android.net.apf.ApfConstants.ICMP6_TYPE_OFFSET; 71 import static android.net.apf.ApfConstants.IGMPV2_REPORT_FROM_IPV4_OPTION_TO_IGMP_CHECKSUM; 72 import static android.net.apf.ApfConstants.IGMPV3_MODE_IS_EXCLUDE; 73 import static android.net.apf.ApfConstants.IGMP_CHECKSUM_WITH_ROUTER_ALERT_OFFSET; 74 import static android.net.apf.ApfConstants.IGMP_MAX_RESP_TIME_OFFSET; 75 import static android.net.apf.ApfConstants.IGMP_MULTICAST_ADDRESS_OFFSET; 76 import static android.net.apf.ApfConstants.IGMP_TYPE_REPORTS; 77 import static android.net.apf.ApfConstants.IPPROTO_HOPOPTS; 78 import static android.net.apf.ApfConstants.IPV4_ALL_HOSTS_ADDRESS_IN_LONG; 79 import static android.net.apf.ApfConstants.IPV4_ALL_IGMPV3_MULTICAST_ROUTERS_ADDRESS; 80 import static android.net.apf.ApfConstants.IPV4_ANY_HOST_ADDRESS; 81 import static android.net.apf.ApfConstants.IPV4_BROADCAST_ADDRESS; 82 import static android.net.apf.ApfConstants.IPV4_DEST_ADDR_OFFSET; 83 import static android.net.apf.ApfConstants.IPV4_DNS_QDCOUNT_NO_OPTIONS_OFFSET; 84 import static android.net.apf.ApfConstants.IPV4_FRAGMENT_MORE_FRAGS_MASK; 85 import static android.net.apf.ApfConstants.IPV4_FRAGMENT_OFFSET_MASK; 86 import static android.net.apf.ApfConstants.IPV4_FRAGMENT_OFFSET_OFFSET; 87 import static android.net.apf.ApfConstants.IPV4_IGMP_TYPE_QUERY; 88 import static android.net.apf.ApfConstants.IPV4_PROTOCOL_OFFSET; 89 import static android.net.apf.ApfConstants.IPV4_SRC_ADDR_OFFSET; 90 import static android.net.apf.ApfConstants.IPV4_ROUTER_ALERT_OPTION; 91 import static android.net.apf.ApfConstants.IPV4_ROUTER_ALERT_OPTION_LEN; 92 import static android.net.apf.ApfConstants.IPV4_TOTAL_LENGTH_OFFSET; 93 import static android.net.apf.ApfConstants.IPV4_UDP_DESTINATION_CHECKSUM_NO_OPTIONS_OFFSET; 94 import static android.net.apf.ApfConstants.IPV4_UDP_DESTINATION_PORT_NO_OPTIONS_OFFSET; 95 import static android.net.apf.ApfConstants.IPV4_UDP_PAYLOAD_NO_OPTIONS_OFFSET; 96 import static android.net.apf.ApfConstants.IPV6_ALL_NODES_ADDRESS; 97 import static android.net.apf.ApfConstants.IPV6_DEST_ADDR_OFFSET; 98 import static android.net.apf.ApfConstants.IPV6_DNS_QDCOUNT_OFFSET; 99 import static android.net.apf.ApfConstants.IPV6_EXT_HEADER_OFFSET; 100 import static android.net.apf.ApfConstants.IPV6_FLOW_LABEL_LEN; 101 import static android.net.apf.ApfConstants.IPV6_FLOW_LABEL_OFFSET; 102 import static android.net.apf.ApfConstants.IPV6_HEADER_LEN; 103 import static android.net.apf.ApfConstants.IPV6_HOP_LIMIT_OFFSET; 104 import static android.net.apf.ApfConstants.IPV6_MLD_CHECKSUM_OFFSET; 105 import static android.net.apf.ApfConstants.IPV6_MLD_HOPOPTS; 106 import static android.net.apf.ApfConstants.IPV6_MLD_MESSAGE_MIN_SIZE; 107 import static android.net.apf.ApfConstants.IPV6_MLD_MIN_SIZE; 108 import static android.net.apf.ApfConstants.IPV6_MLD_MULTICAST_ADDR_OFFSET; 109 import static android.net.apf.ApfConstants.IPV6_MLD_TYPE_OFFSET; 110 import static android.net.apf.ApfConstants.IPV6_MLD_TYPE_QUERY; 111 import static android.net.apf.ApfConstants.IPV6_MLD_TYPE_REPORTS; 112 import static android.net.apf.ApfConstants.IPV6_MLD_TYPE_V1_REPORT; 113 import static android.net.apf.ApfConstants.IPV6_MLD_TYPE_V2_REPORT; 114 import static android.net.apf.ApfConstants.IPV6_MLD_V1_MESSAGE_SIZE; 115 import static android.net.apf.ApfConstants.IPV6_MLD_V2_ALL_ROUTERS_MULTICAST_ADDRESS; 116 import static android.net.apf.ApfConstants.IPV6_MLD_V2_MULTICAST_ADDRESS_RECORD_SIZE; 117 import static android.net.apf.ApfConstants.IPV6_NEXT_HEADER_OFFSET; 118 import static android.net.apf.ApfConstants.IPV6_PAYLOAD_LEN_OFFSET; 119 import static android.net.apf.ApfConstants.IPV6_SOLICITED_NODES_PREFIX; 120 import static android.net.apf.ApfConstants.IPV6_SRC_ADDR_OFFSET; 121 import static android.net.apf.ApfConstants.IPV6_UDP_DESTINATION_CHECKSUM_OFFSET; 122 import static android.net.apf.ApfConstants.IPV6_UDP_DESTINATION_PORT_OFFSET; 123 import static android.net.apf.ApfConstants.IPV6_UNSPECIFIED_ADDRESS; 124 import static android.net.apf.ApfConstants.MLD2_MODE_IS_EXCLUDE; 125 import static android.net.apf.ApfConstants.TCP_HEADER_SIZE_OFFSET; 126 import static android.net.apf.ApfConstants.TCP_UDP_DESTINATION_PORT_OFFSET; 127 import static android.net.apf.ApfConstants.TCP_UDP_SOURCE_PORT_OFFSET; 128 import static android.net.apf.ApfCounterTracker.Counter.APF_PROGRAM_ID; 129 import static android.net.apf.ApfCounterTracker.Counter.APF_VERSION; 130 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_802_3_FRAME; 131 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_ARP_NON_IPV4; 132 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_ARP_OTHER_HOST; 133 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_ARP_REPLY_SPA_NO_HOST; 134 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_ARP_REQUEST_REPLIED; 135 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_ARP_UNKNOWN; 136 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_ARP_V6_ONLY; 137 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_ETHERTYPE_NOT_ALLOWED; 138 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_ETHER_OUR_SRC_MAC; 139 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_ETH_BROADCAST; 140 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_GARP_REPLY; 141 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV4_BROADCAST_ADDR; 142 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV4_BROADCAST_NET; 143 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_IGMP_INVALID; 144 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_IGMP_REPORT; 145 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV4_ICMP_INVALID; 146 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV4_KEEPALIVE_ACK; 147 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV4_L2_BROADCAST; 148 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV4_MULTICAST; 149 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV4_NATT_KEEPALIVE; 150 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV4_NON_DHCP4; 151 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV4_PING_REQUEST_REPLIED; 152 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV4_TCP_PORT7_UNICAST; 153 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV6_ICMP6_ECHO_REQUEST_INVALID; 154 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV6_ICMP6_ECHO_REQUEST_REPLIED; 155 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV6_MLD_INVALID; 156 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV6_MLD_REPORT; 157 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV6_MLD_V1_GENERAL_QUERY_REPLIED; 158 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV6_MLD_V2_GENERAL_QUERY_REPLIED; 159 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV6_MULTICAST_NA; 160 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV6_NON_ICMP_MULTICAST; 161 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV6_NS_INVALID; 162 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV6_NS_OTHER_HOST; 163 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV6_NS_REPLIED_NON_DAD; 164 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_IPV6_ROUTER_SOLICITATION; 165 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_MDNS; 166 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_NON_UNICAST_TDLS; 167 import static android.net.apf.ApfCounterTracker.Counter.DROPPED_RA; 168 import static android.net.apf.ApfCounterTracker.Counter.FILTER_AGE_16384THS; 169 import static android.net.apf.ApfCounterTracker.Counter.FILTER_AGE_SECONDS; 170 import static android.net.apf.ApfCounterTracker.Counter.PASSED_ARP_BROADCAST_REPLY; 171 import static android.net.apf.ApfCounterTracker.Counter.PASSED_ARP_REQUEST; 172 import static android.net.apf.ApfCounterTracker.Counter.PASSED_ARP_UNICAST_REPLY; 173 import static android.net.apf.ApfCounterTracker.Counter.PASSED_DHCP; 174 import static android.net.apf.ApfConstants.IPv6_UDP_PAYLOAD_OFFSET; 175 import static android.net.apf.ApfConstants.MDNS_IPV4_ADDR; 176 import static android.net.apf.ApfConstants.MDNS_IPV4_ADDR_IN_LONG; 177 import static android.net.apf.ApfConstants.MDNS_IPV6_ADDR; 178 import static android.net.apf.ApfConstants.MDNS_PORT; 179 import static android.net.apf.ApfConstants.UDP_HEADER_LEN; 180 import static android.net.apf.ApfConstants.MDNS_PORT_IN_BYTES; 181 import static android.net.apf.ApfCounterTracker.Counter.PASSED_ETHER_OUR_SRC_MAC; 182 import static android.net.apf.ApfCounterTracker.Counter.PASSED_IPV4; 183 import static android.net.apf.ApfCounterTracker.Counter.PASSED_IPV4_FROM_DHCPV4_SERVER; 184 import static android.net.apf.ApfCounterTracker.Counter.PASSED_IPV4_UNICAST; 185 import static android.net.apf.ApfCounterTracker.Counter.PASSED_IPV6_HOPOPTS; 186 import static android.net.apf.ApfCounterTracker.Counter.PASSED_IPV6_ICMP; 187 import static android.net.apf.ApfCounterTracker.Counter.PASSED_IPV6_NON_ICMP; 188 import static android.net.apf.ApfCounterTracker.Counter.PASSED_IPV6_UNICAST_NON_ICMP; 189 import static android.net.apf.ApfCounterTracker.Counter.PASSED_MDNS; 190 import static android.net.apf.ApfCounterTracker.Counter.PASSED_NON_IP_UNICAST; 191 import static android.net.apf.ApfCounterTracker.Counter.TOTAL_PACKETS; 192 import static android.net.apf.ApfCounterTracker.getCounterValue; 193 import static android.net.apf.BaseApfGenerator.MemorySlot; 194 import static android.net.apf.BaseApfGenerator.Register.R0; 195 import static android.net.apf.BaseApfGenerator.Register.R1; 196 import static android.net.util.SocketUtils.makePacketSocketAddress; 197 import static android.os.PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED; 198 import static android.os.PowerManager.ACTION_DEVICE_LIGHT_IDLE_MODE_CHANGED; 199 import static android.system.OsConstants.AF_PACKET; 200 import static android.system.OsConstants.ETH_P_ALL; 201 import static android.system.OsConstants.ETH_P_ARP; 202 import static android.system.OsConstants.ETH_P_IP; 203 import static android.system.OsConstants.ETH_P_IPV6; 204 import static android.system.OsConstants.ICMP6_ECHO_REPLY; 205 import static android.system.OsConstants.ICMP_ECHO; 206 import static android.system.OsConstants.ICMP_ECHOREPLY; 207 import static android.system.OsConstants.IFA_F_TENTATIVE; 208 import static android.system.OsConstants.IPPROTO_ICMP; 209 import static android.system.OsConstants.IPPROTO_ICMPV6; 210 import static android.system.OsConstants.IPPROTO_TCP; 211 import static android.system.OsConstants.IPPROTO_UDP; 212 import static android.system.OsConstants.SOCK_CLOEXEC; 213 import static android.system.OsConstants.SOCK_NONBLOCK; 214 import static android.system.OsConstants.SOCK_RAW; 215 216 import static com.android.net.module.util.CollectionUtils.concatArrays; 217 import static com.android.net.module.util.NetworkStackConstants.ETHER_ADDR_LEN; 218 import static com.android.net.module.util.NetworkStackConstants.ETHER_BROADCAST; 219 import static com.android.net.module.util.NetworkStackConstants.ETHER_DST_ADDR_OFFSET; 220 import static com.android.net.module.util.NetworkStackConstants.ETHER_HEADER_LEN; 221 import static com.android.net.module.util.NetworkStackConstants.ETHER_SRC_ADDR_OFFSET; 222 import static com.android.net.module.util.NetworkStackConstants.ICMP_HEADER_LEN; 223 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ECHO_REQUEST_TYPE; 224 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_NA_HEADER_LEN; 225 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_SLLA; 226 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_TLLA; 227 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_TLLA_LEN; 228 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_NEIGHBOR_ADVERTISEMENT; 229 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_NEIGHBOR_SOLICITATION; 230 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ROUTER_ADVERTISEMENT; 231 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ROUTER_SOLICITATION; 232 import static com.android.net.module.util.NetworkStackConstants.IPV4_ADDR_ALL_HOST_MULTICAST; 233 import static com.android.net.module.util.NetworkStackConstants.IPV4_ADDR_LEN; 234 import static com.android.net.module.util.NetworkStackConstants.IPV4_HEADER_MIN_LEN; 235 import static com.android.net.module.util.NetworkStackConstants.IPV4_FLAG_DF; 236 import static com.android.net.module.util.NetworkStackConstants.IPV4_IGMP_GROUP_RECORD_SIZE; 237 import static com.android.net.module.util.NetworkStackConstants.IPV4_IGMP_MIN_SIZE; 238 import static com.android.net.module.util.NetworkStackConstants.IPV4_IGMP_TYPE_V3_REPORT; 239 import static com.android.net.module.util.NetworkStackConstants.IPV4_PROTOCOL_IGMP; 240 import static com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_ALL_NODES_MULTICAST; 241 import static com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_ANY; 242 import static com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_LEN; 243 import static com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_NODE_LOCAL_ALL_NODES_MULTICAST; 244 245 import android.annotation.ChecksSdkIntAtLeast; 246 import android.annotation.NonNull; 247 import android.annotation.Nullable; 248 import android.content.BroadcastReceiver; 249 import android.content.Context; 250 import android.content.Intent; 251 import android.content.IntentFilter; 252 import android.net.LinkAddress; 253 import android.net.LinkProperties; 254 import android.net.MacAddress; 255 import android.net.NattKeepalivePacketDataParcelable; 256 import android.net.TcpKeepalivePacketDataParcelable; 257 import android.net.apf.ApfCounterTracker.Counter; 258 import android.net.apf.BaseApfGenerator.IllegalInstructionException; 259 import android.net.ip.MulticastReportMonitor; 260 import android.net.nsd.NsdManager; 261 import android.os.Handler; 262 import android.os.PowerManager; 263 import android.os.SystemClock; 264 import android.stats.connectivity.NetworkQuirkEvent; 265 import android.system.ErrnoException; 266 import android.system.Os; 267 import android.text.format.DateUtils; 268 import android.util.ArraySet; 269 import android.util.Log; 270 import android.util.Pair; 271 import android.util.SparseArray; 272 273 import com.android.internal.annotations.VisibleForTesting; 274 import com.android.internal.util.HexDump; 275 import com.android.internal.util.IndentingPrintWriter; 276 import com.android.internal.util.TokenBucket; 277 import com.android.modules.utils.build.SdkLevel; 278 import com.android.net.module.util.CollectionUtils; 279 import com.android.net.module.util.ConnectivityUtils; 280 import com.android.net.module.util.InterfaceParams; 281 import com.android.net.module.util.PacketReader; 282 import com.android.networkstack.metrics.ApfSessionInfoMetrics; 283 import com.android.networkstack.metrics.IpClientRaInfoMetrics; 284 import com.android.networkstack.metrics.NetworkQuirkMetrics; 285 import com.android.networkstack.util.NetworkStackUtils; 286 287 import java.io.FileDescriptor; 288 import java.net.Inet4Address; 289 import java.net.Inet6Address; 290 import java.net.InetAddress; 291 import java.net.SocketAddress; 292 import java.net.SocketException; 293 import java.net.UnknownHostException; 294 import java.nio.BufferUnderflowException; 295 import java.nio.ByteBuffer; 296 import java.nio.ByteOrder; 297 import java.util.ArrayList; 298 import java.util.Arrays; 299 import java.util.List; 300 import java.util.Map; 301 import java.util.Set; 302 303 /** 304 * For networks that support packet filtering via APF programs, {@code ApfFilter} 305 * listens for IPv6 ICMPv6 router advertisements (RAs) and generates APF programs to 306 * filter out redundant duplicate ones. 307 * <p> 308 * Threading model: this class is not thread-safe and can only be accessed from IpClient's 309 * handler thread. 310 * 311 * @hide 312 */ 313 public class ApfFilter { 314 315 /** 316 * Defines the communication API between the ApfFilter and the APF interpreter 317 * residing within the Wi-Fi/Ethernet firmware. 318 */ 319 public interface IApfController { 320 /** 321 * Install the APF program to firmware. 322 */ installPacketFilter(@onNull byte[] filter, @NonNull String filterConfig)323 boolean installPacketFilter(@NonNull byte[] filter, @NonNull String filterConfig); 324 325 /** 326 * Read the APF RAM from firmware. 327 */ readPacketFilterRam(@onNull String event)328 void readPacketFilterRam(@NonNull String event); 329 } 330 331 // Helper class for specifying functional filter parameters. 332 public static class ApfConfiguration { 333 public int apfVersionSupported; 334 public int apfRamSize; 335 public int installableProgramSizeClamp = Integer.MAX_VALUE; 336 public boolean multicastFilter; 337 public boolean ieee802_3Filter; 338 public int[] ethTypeBlackList; 339 public int minRdnssLifetimeSec; 340 public int acceptRaMinLft; 341 public long minMetricsSessionDurationMs; 342 public boolean hasClatInterface; 343 public boolean handleArpOffload; 344 public boolean handleNdOffload; 345 public boolean handleMdnsOffload; 346 public boolean handleIgmpOffload; 347 public boolean handleMldOffload; 348 public boolean handleIpv4PingOffload; 349 public boolean handleIpv6PingOffload; 350 } 351 352 353 private class RaPacketReader extends PacketReader { 354 private static final int RECEIVE_BUFFER_SIZE = 1514; 355 private final int mIfIndex; 356 RaPacketReader(Handler handler, int ifIndex)357 RaPacketReader(Handler handler, int ifIndex) { 358 super(handler, RECEIVE_BUFFER_SIZE); 359 mIfIndex = ifIndex; 360 } 361 362 @Override createFd()363 protected FileDescriptor createFd() { 364 return mDependencies.createPacketReaderSocket(mIfIndex); 365 } 366 367 @Override handlePacket(byte[] recvbuf, int length)368 protected void handlePacket(byte[] recvbuf, int length) { 369 processRa(recvbuf, length); 370 } 371 } 372 373 private static final String TAG = "ApfFilter"; 374 375 private final int mApfRamSize; 376 private final int mMaximumApfProgramSize; 377 private final int mInstallableProgramSizeClamp; 378 private final IApfController mApfController; 379 private final InterfaceParams mInterfaceParams; 380 private final TokenBucket mTokenBucket; 381 382 @VisibleForTesting 383 public final int mApfVersionSupported; 384 @VisibleForTesting 385 @NonNull 386 public final byte[] mHardwareAddress; 387 private final RaPacketReader mRaPacketReader; 388 private final Handler mHandler; 389 private boolean mMulticastFilter; 390 private boolean mInDozeMode; 391 private final boolean mDrop802_3Frames; 392 private final int[] mEthTypeBlackList; 393 394 private final ApfCounterTracker mApfCounterTracker = new ApfCounterTracker(); 395 private final long mSessionStartMs; 396 private int mNumParseErrorRas = 0; 397 private int mNumZeroLifetimeRas = 0; 398 private int mLowestRouterLifetimeSeconds = Integer.MAX_VALUE; 399 private long mLowestPioValidLifetimeSeconds = Long.MAX_VALUE; 400 private long mLowestRioRouteLifetimeSeconds = Long.MAX_VALUE; 401 private long mLowestRdnssLifetimeSeconds = Long.MAX_VALUE; 402 403 // Ignore non-zero RDNSS lifetimes below this value. 404 private final int mMinRdnssLifetimeSec; 405 406 // Minimum session time for metrics, duration less than this time will not be logged. 407 private final long mMinMetricsSessionDurationMs; 408 409 // Tracks the value of /proc/sys/ipv6/conf/$iface/accept_ra_min_lft which affects router, RIO, 410 // and PIO valid lifetimes. 411 private final int mAcceptRaMinLft; 412 private final boolean mHandleArpOffload; 413 private final boolean mHandleNdOffload; 414 private final boolean mHandleMdnsOffload; 415 private final boolean mHandleIgmpOffload; 416 private final boolean mHandleMldOffload; 417 private final boolean mHandleIpv4PingOffload; 418 private final boolean mHandleIpv6PingOffload; 419 420 private final NetworkQuirkMetrics mNetworkQuirkMetrics; 421 private final IpClientRaInfoMetrics mIpClientRaInfoMetrics; 422 private final ApfSessionInfoMetrics mApfSessionInfoMetrics; 423 private final NsdManager mNsdManager; 424 private final MulticastReportMonitor mMulticastReportMonitor; 425 private final ApfMdnsOffloadEngine mApfMdnsOffloadEngine; 426 private final List<MdnsOffloadRule> mOffloadRules = new ArrayList<>(); 427 // The number of mDNS rules requiring APF to transmit a reply and drop the query packet. A 428 // value of -1 means all mDNS query packets should be passed; no mDNS query packets will trigger 429 // the transmit and reply logic. 430 private int mNumOfMdnsRuleToOffload = -1; 431 432 private int mOverEstimatedProgramSize = 0; 433 isDeviceIdleModeChangedAction(Intent intent)434 private static boolean isDeviceIdleModeChangedAction(Intent intent) { 435 return ACTION_DEVICE_IDLE_MODE_CHANGED.equals(intent.getAction()); 436 } 437 isDeviceLightIdleModeChangedAction(Intent intent)438 private boolean isDeviceLightIdleModeChangedAction(Intent intent) { 439 // The ACTION_DEVICE_LIGHT_IDLE_MODE_CHANGED only exist since T. For lower platform version, 440 // the check should return false. The explicit SDK check is needed to make linter happy 441 // about accessing ACTION_DEVICE_LIGHT_IDLE_MODE_CHANGED in this function. 442 if (!SdkLevel.isAtLeastT()) { 443 return false; 444 } 445 return ACTION_DEVICE_LIGHT_IDLE_MODE_CHANGED.equals(intent.getAction()); 446 } 447 isDeviceLightIdleMode(@onNull PowerManager powerManager)448 private boolean isDeviceLightIdleMode(@NonNull PowerManager powerManager) { 449 // The powerManager.isDeviceLightIdleMode() only exist since T. For lower platform version, 450 // the check should return false. The explicit SDK check is needed to make linter happy 451 // about accessing powerManager.isDeviceLightIdleMode() in this function. 452 if (!SdkLevel.isAtLeastT()) { 453 return false; 454 } 455 456 return powerManager.isDeviceLightIdleMode(); 457 } 458 459 // Detects doze mode state transitions. 460 private final BroadcastReceiver mDeviceIdleReceiver = new BroadcastReceiver() { 461 @Override 462 public void onReceive(Context context, Intent intent) { 463 mHandler.post(() -> { 464 if (mIsApfShutdown) return; 465 final PowerManager powerManager = context.getSystemService(PowerManager.class); 466 if (isDeviceIdleModeChangedAction(intent) 467 || isDeviceLightIdleModeChangedAction(intent)) { 468 final boolean deviceIdle = powerManager.isDeviceIdleMode() 469 || isDeviceLightIdleMode(powerManager); 470 setDozeMode(deviceIdle); 471 } 472 }); 473 } 474 }; 475 476 private boolean mIsApfShutdown; 477 478 // Our IPv4 address, if we have just one, otherwise null. 479 private byte[] mIPv4Address; 480 // The subnet prefix length of our IPv4 network. Only valid if mIPv4Address is not null. 481 private int mIPv4PrefixLength; 482 483 // Our IPv6 non-tentative addresses 484 private Set<Inet6Address> mIPv6NonTentativeAddresses = new ArraySet<>(); 485 486 // Our tentative IPv6 addresses 487 private Set<Inet6Address> mIPv6TentativeAddresses = new ArraySet<>(); 488 489 // Our link-local IPv6 address 490 private Inet6Address mIPv6LinkLocalAddress; 491 492 // Our joined IPv4 multicast addresses 493 @VisibleForTesting 494 final Set<Inet4Address> mIPv4MulticastAddresses = new ArraySet<>(); 495 496 // Our joined IPv4 multicast address exclude all all host multicast (224.0.0.1) 497 @VisibleForTesting 498 final Set<Inet4Address> mIPv4McastAddrsExcludeAllHost = new ArraySet<>(); 499 500 // Our joined IPv6 multicast addresses 501 @VisibleForTesting 502 final Set<Inet6Address> mIPv6MulticastAddresses = new ArraySet<>(); 503 504 // Our joined IPv6 multicast address exclude ff02::1, ff01::1 505 @VisibleForTesting 506 final Set<Inet6Address> mIPv6McastAddrsExcludeAllHost = new ArraySet<>(); 507 508 // Whether CLAT is enabled. 509 private boolean mHasClat; 510 511 // mIsRunning is reflects the state of the ApfFilter during integration tests. ApfFilter can be 512 // paused using "adb shell cmd apf <iface> <cmd>" commands. A paused ApfFilter will not install 513 // any new programs, but otherwise operates normally. 514 private volatile boolean mIsRunning = true; 515 516 private final Dependencies mDependencies; 517 ApfFilter(Handler handler, Context context, ApfConfiguration config, InterfaceParams ifParams, IApfController apfController, NetworkQuirkMetrics networkQuirkMetrics)518 public ApfFilter(Handler handler, Context context, ApfConfiguration config, 519 InterfaceParams ifParams, IApfController apfController, 520 NetworkQuirkMetrics networkQuirkMetrics) { 521 this(handler, context, config, ifParams, apfController, networkQuirkMetrics, 522 new Dependencies(context)); 523 } 524 maybeCleanUpApfRam()525 private void maybeCleanUpApfRam() { 526 // Clear the APF memory to reset all counters upon connecting to the first AP 527 // in an SSID. This is limited to APFv3 devices because this large write triggers 528 // a crash on some older devices (b/78905546). 529 if (hasDataAccess(mApfVersionSupported)) { 530 installPacketFilter(new byte[mApfRamSize], getApfConfigMessage() + " (cleanup)"); 531 } 532 } 533 534 @VisibleForTesting ApfFilter(Handler handler, Context context, ApfConfiguration config, InterfaceParams ifParams, IApfController apfController, NetworkQuirkMetrics networkQuirkMetrics, Dependencies dependencies)535 public ApfFilter(Handler handler, Context context, ApfConfiguration config, 536 InterfaceParams ifParams, IApfController apfController, 537 NetworkQuirkMetrics networkQuirkMetrics, Dependencies dependencies) { 538 mHandler = handler; 539 mApfVersionSupported = config.apfVersionSupported; 540 mApfRamSize = config.apfRamSize; 541 mInstallableProgramSizeClamp = config.installableProgramSizeClamp; 542 int maximumApfProgramSize = mApfRamSize; 543 if (hasDataAccess(mApfVersionSupported)) { 544 // Reserve space for the counters. 545 maximumApfProgramSize -= Counter.totalSize(); 546 } 547 // Prevent generating (and thus installing) larger programs 548 if (maximumApfProgramSize > mInstallableProgramSizeClamp) { 549 maximumApfProgramSize = mInstallableProgramSizeClamp; 550 } 551 mMaximumApfProgramSize = Math.max(0, maximumApfProgramSize); 552 mApfController = apfController; 553 mInterfaceParams = ifParams; 554 mMulticastFilter = config.multicastFilter; 555 mDrop802_3Frames = config.ieee802_3Filter; 556 mMinRdnssLifetimeSec = config.minRdnssLifetimeSec; 557 mAcceptRaMinLft = config.acceptRaMinLft; 558 mHandleArpOffload = config.handleArpOffload; 559 mHandleNdOffload = config.handleNdOffload; 560 mHandleMdnsOffload = config.handleMdnsOffload; 561 mHandleIgmpOffload = config.handleIgmpOffload; 562 mHandleMldOffload = config.handleMldOffload; 563 mHandleIpv4PingOffload = config.handleIpv4PingOffload; 564 mHandleIpv6PingOffload = config.handleIpv6PingOffload; 565 mDependencies = dependencies; 566 mNetworkQuirkMetrics = networkQuirkMetrics; 567 mIpClientRaInfoMetrics = dependencies.getIpClientRaInfoMetrics(); 568 mApfSessionInfoMetrics = dependencies.getApfSessionInfoMetrics(); 569 mSessionStartMs = dependencies.elapsedRealtime(); 570 mMinMetricsSessionDurationMs = config.minMetricsSessionDurationMs; 571 mHasClat = config.hasClatInterface; 572 573 mIsApfShutdown = false; 574 575 // Now fill the black list from the passed array 576 mEthTypeBlackList = filterEthTypeBlackList(config.ethTypeBlackList); 577 578 // TokenBucket for rate limiting filter installation. APF filtering relies on the filter 579 // always being up-to-date and APF bytecode being in sync with userspace. The TokenBucket 580 // merely prevents illconfigured / abusive networks from impacting the system, so it does 581 // not need to be very restrictive. 582 // The TokenBucket starts with its full capacity of 20 tokens (= 20 filter updates). A new 583 // token is generated every 3 seconds limiting the filter update rate to at most once every 584 // 3 seconds. 585 mTokenBucket = new TokenBucket(3_000 /* deltaMs */, 20 /* capacity */, 20 /* tokens */); 586 587 mHardwareAddress = mInterfaceParams.macAddr.toByteArray(); 588 // TODO: ApfFilter should not generate programs until IpClient sends provisioning success. 589 maybeCleanUpApfRam(); 590 // Install basic filters 591 installNewProgram(); 592 593 mRaPacketReader = new RaPacketReader(mHandler, mInterfaceParams.index); 594 // The class constructor must be called from the IpClient's handler thread 595 if (!mRaPacketReader.start()) { 596 Log.wtf(TAG, "Failed to start RaPacketReader"); 597 } 598 599 mMulticastReportMonitor = createMulticastReportMonitor(); 600 if (mMulticastReportMonitor != null) { 601 mMulticastReportMonitor.start(); 602 } 603 604 // Listen for doze-mode transition changes to enable/disable the IPv6 multicast filter. 605 mDependencies.addDeviceIdleReceiver(mDeviceIdleReceiver); 606 607 mNsdManager = context.getSystemService(NsdManager.class); 608 if (enableOffloadEngineRegistration()) { 609 mApfMdnsOffloadEngine = new ApfMdnsOffloadEngine(mInterfaceParams.name, mHandler, 610 mNsdManager, 611 allRules -> { 612 mOffloadRules.clear(); 613 mOffloadRules.addAll(allRules); 614 installNewProgram(); 615 }); 616 mApfMdnsOffloadEngine.registerOffloadEngine(); 617 } else { 618 mApfMdnsOffloadEngine = null; 619 } 620 621 mIPv4MulticastAddresses.addAll( 622 mDependencies.getIPv4MulticastAddresses(mInterfaceParams.name)); 623 mIPv4McastAddrsExcludeAllHost.addAll(mIPv4MulticastAddresses); 624 mIPv4McastAddrsExcludeAllHost.remove((IPV4_ADDR_ALL_HOST_MULTICAST)); 625 626 mIPv6MulticastAddresses.addAll( 627 mDependencies.getIPv6MulticastAddresses(mInterfaceParams.name)); 628 mIPv6McastAddrsExcludeAllHost.addAll(mIPv6MulticastAddresses); 629 mIPv6McastAddrsExcludeAllHost.remove(IPV6_ADDR_ALL_NODES_MULTICAST); 630 mIPv6McastAddrsExcludeAllHost.remove(IPV6_ADDR_NODE_LOCAL_ALL_NODES_MULTICAST); 631 } 632 633 /** 634 * Dependencies class for testing. 635 */ 636 @VisibleForTesting 637 public static class Dependencies { 638 private final Context mContext; Dependencies(final Context context)639 public Dependencies(final Context context) { 640 mContext = context; 641 } 642 643 /** 644 * Create a socket to read RAs. 645 */ 646 @Nullable createPacketReaderSocket(int ifIndex)647 public FileDescriptor createPacketReaderSocket(int ifIndex) { 648 FileDescriptor socket; 649 try { 650 socket = Os.socket(AF_PACKET, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, 0); 651 NetworkStackUtils.attachRaFilter(socket); 652 SocketAddress addr = makePacketSocketAddress(ETH_P_IPV6, ifIndex); 653 Os.bind(socket, addr); 654 } catch (SocketException | ErrnoException e) { 655 Log.wtf(TAG, "Error starting filter", e); 656 return null; 657 } 658 return socket; 659 } 660 661 /** 662 * Create a socket to read egress IGMPv2/v3 reports. 663 */ 664 @Nullable createEgressIgmpReportsReaderSocket(int ifIndex)665 public FileDescriptor createEgressIgmpReportsReaderSocket(int ifIndex) { 666 FileDescriptor socket; 667 try { 668 socket = Os.socket(AF_PACKET, SOCK_RAW | SOCK_NONBLOCK, 0); 669 NetworkStackUtils.attachEgressIgmpReportFilter(socket); 670 Os.bind(socket, makePacketSocketAddress(ETH_P_ALL, ifIndex)); 671 } catch (SocketException | ErrnoException e) { 672 Log.wtf(TAG, "Error starting filter", e); 673 return null; 674 } 675 676 return socket; 677 } 678 679 /** 680 * Create a socket to read egress IGMPv2/v3, MLDv1/v2 reports. 681 */ 682 @Nullable createEgressMulticastReportsReaderSocket(int ifIndex)683 public FileDescriptor createEgressMulticastReportsReaderSocket(int ifIndex) { 684 FileDescriptor socket; 685 try { 686 socket = Os.socket(AF_PACKET, SOCK_RAW | SOCK_NONBLOCK, 0); 687 NetworkStackUtils.attachEgressMulticastReportFilter(socket); 688 Os.bind(socket, makePacketSocketAddress(ETH_P_ALL, ifIndex)); 689 } catch (SocketException | ErrnoException e) { 690 Log.wtf(TAG, "Error starting filter", e); 691 return null; 692 } 693 694 return socket; 695 } 696 697 /** 698 * Get elapsedRealtime. 699 */ elapsedRealtime()700 public long elapsedRealtime() { 701 return SystemClock.elapsedRealtime(); 702 } 703 704 /** Add receiver for detecting doze mode change */ addDeviceIdleReceiver(@onNull final BroadcastReceiver receiver)705 public void addDeviceIdleReceiver(@NonNull final BroadcastReceiver receiver) { 706 final IntentFilter intentFilter = new IntentFilter(ACTION_DEVICE_IDLE_MODE_CHANGED); 707 if (SdkLevel.isAtLeastT()) { 708 intentFilter.addAction(ACTION_DEVICE_LIGHT_IDLE_MODE_CHANGED); 709 } 710 mContext.registerReceiver(receiver, intentFilter); 711 } 712 713 /** Remove broadcast receiver. */ removeBroadcastReceiver(@onNull final BroadcastReceiver receiver)714 public void removeBroadcastReceiver(@NonNull final BroadcastReceiver receiver) { 715 mContext.unregisterReceiver(receiver); 716 } 717 718 /** 719 * Get a ApfSessionInfoMetrics instance. 720 */ getApfSessionInfoMetrics()721 public ApfSessionInfoMetrics getApfSessionInfoMetrics() { 722 return new ApfSessionInfoMetrics(); 723 } 724 725 /** 726 * Get a IpClientRaInfoMetrics instance. 727 */ getIpClientRaInfoMetrics()728 public IpClientRaInfoMetrics getIpClientRaInfoMetrics() { 729 return new IpClientRaInfoMetrics(); 730 } 731 732 /** 733 * Callback to be called when an ApfFilter instance is created. 734 * 735 * This method is designed to be overridden in test classes to collect created ApfFilter 736 * instances. 737 */ onApfFilterCreated(@onNull ApfFilter apfFilter)738 public void onApfFilterCreated(@NonNull ApfFilter apfFilter) { 739 } 740 741 /** 742 * Callback to be called when a ReceiveThread instance is created. 743 * 744 * This method is designed for overriding in test classes to collect created threads and 745 * waits for the termination. 746 */ onThreadCreated(@onNull Thread thread)747 public void onThreadCreated(@NonNull Thread thread) { 748 } 749 750 /** 751 * Loads the existing IPv6 anycast addresses from the file `/proc/net/anycast6`. 752 */ getAnycast6Addresses(@onNull String ifname)753 public List<byte[]> getAnycast6Addresses(@NonNull String ifname) { 754 final List<Inet6Address> anycast6Addresses = 755 ProcfsParsingUtils.getAnycast6Addresses(ifname); 756 final List<byte[]> addresses = new ArrayList<>(); 757 for (Inet6Address addr : anycast6Addresses) { 758 addresses.add(addr.getAddress()); 759 } 760 761 return addresses; 762 } 763 764 /** 765 * Loads the existing Ethernet multicast addresses from the file 766 * `/proc/net/dev_mcast`. 767 */ getEtherMulticastAddresses(@onNull String ifname)768 public List<byte[]> getEtherMulticastAddresses(@NonNull String ifname) { 769 final List<MacAddress> etherAddresses = 770 ProcfsParsingUtils.getEtherMulticastAddresses(ifname); 771 final List<byte[]> addresses = new ArrayList<>(); 772 for (MacAddress addr : etherAddresses) { 773 addresses.add(addr.toByteArray()); 774 } 775 776 return addresses; 777 } 778 779 /** 780 * Loads the existing ND traffic class for the specific interface from the file 781 * /proc/sys/net/ipv6/conf/{ifname}/ndisc_tclass. 782 * 783 * If the file does not exist or the interface is not found, 784 * the function returns 0..255, 0 as default ND traffic class. 785 */ getNdTrafficClass(@onNull String ifname)786 public int getNdTrafficClass(@NonNull String ifname) { 787 return ProcfsParsingUtils.getNdTrafficClass(ifname); 788 } 789 790 /** 791 * Returns the default TTL value for IPv4 packets from '/proc/sys/net/ipv4/ip_default_ttl'. 792 */ getIpv4DefaultTtl()793 public int getIpv4DefaultTtl() { 794 return ProcfsParsingUtils.getIpv4DefaultTtl(); 795 } 796 797 /** 798 * Returns the default HopLimit value for IPv6 packets. 799 */ getIpv6DefaultHopLimit(@onNull String ifname)800 public int getIpv6DefaultHopLimit(@NonNull String ifname) { 801 return ProcfsParsingUtils.getIpv6DefaultHopLimit(ifname); 802 } 803 804 /** 805 * Loads the existing IPv4 multicast addresses from the file 806 * `/proc/net/igmp`. 807 */ getIPv4MulticastAddresses(@onNull String ifname)808 public List<Inet4Address> getIPv4MulticastAddresses(@NonNull String ifname) { 809 return ProcfsParsingUtils.getIPv4MulticastAddresses(ifname); 810 } 811 812 /** 813 * Loads the existing IPv6 multicast addresses from the file `/proc/net/igmp6`. 814 */ getIPv6MulticastAddresses(@onNull String ifname)815 public List<Inet6Address> getIPv6MulticastAddresses(@NonNull String ifname) { 816 return ProcfsParsingUtils.getIpv6MulticastAddresses(ifname); 817 } 818 } 819 getApfController()820 public IApfController getApfController() { 821 return mApfController; 822 } 823 setDataSnapshot(byte[] data)824 public String setDataSnapshot(byte[] data) { 825 mDataSnapshot = data; 826 if (mIsRunning) { 827 mApfCounterTracker.updateCountersFromData(data); 828 } 829 return mApfCounterTracker.getCounters().toString(); 830 } 831 createMulticastReportMonitor()832 private MulticastReportMonitor createMulticastReportMonitor() { 833 FileDescriptor socketFd = null; 834 835 // Check if MLD report monitor is enabled first, it includes the IGMP report monitor. 836 if (enableMldReportsMonitor()) { 837 socketFd = 838 mDependencies.createEgressMulticastReportsReaderSocket(mInterfaceParams.index); 839 } else if (enableIgmpReportsMonitor()) { 840 socketFd = 841 mDependencies.createEgressIgmpReportsReaderSocket(mInterfaceParams.index); 842 } 843 844 return socketFd != null ? new MulticastReportMonitor( 845 mHandler, 846 mInterfaceParams, 847 this::updateMulticastAddrs, 848 socketFd 849 ) : null; 850 } 851 log(String s)852 private void log(String s) { 853 Log.d(TAG, "(" + mInterfaceParams.name + "): " + s); 854 } 855 filterEthTypeBlackList(int[] ethTypeBlackList)856 private static int[] filterEthTypeBlackList(int[] ethTypeBlackList) { 857 ArrayList<Integer> bl = new ArrayList<>(); 858 859 for (int p : ethTypeBlackList) { 860 // Check if the protocol is a valid ether type 861 if ((p < ETH_TYPE_MIN) || (p > ETH_TYPE_MAX)) { 862 continue; 863 } 864 865 // Check if the protocol is not repeated in the passed array 866 if (bl.contains(p)) { 867 continue; 868 } 869 870 // Check if list reach its max size 871 if (bl.size() == APF_MAX_ETH_TYPE_BLACK_LIST_LEN) { 872 Log.w(TAG, "Passed EthType Black List size too large (" + bl.size() + 873 ") using top " + APF_MAX_ETH_TYPE_BLACK_LIST_LEN + " protocols"); 874 break; 875 } 876 877 // Now add the protocol to the list 878 bl.add(p); 879 } 880 881 return bl.stream().mapToInt(Integer::intValue).toArray(); 882 } 883 884 // Returns seconds since device boot. secondsSinceBoot()885 private int secondsSinceBoot() { 886 return (int) (mDependencies.elapsedRealtime() / DateUtils.SECOND_IN_MILLIS); 887 } 888 889 public static class InvalidRaException extends Exception { InvalidRaException(String m)890 public InvalidRaException(String m) { 891 super(m); 892 } 893 } 894 895 /** 896 * Class to keep track of a section in a packet. 897 */ 898 private static class PacketSection { 899 public enum Type { 900 MATCH, // A field that should be matched (e.g., the router IP address). 901 LIFETIME, // A lifetime. Not matched, and counts toward minimum RA lifetime if >= min. 902 } 903 904 /** The type of section. */ 905 public final Type type; 906 /** Offset into the packet at which this section begins. */ 907 public final int start; 908 /** Length of this section in bytes. */ 909 public final int length; 910 /** If this is a lifetime, the lifetime value. */ 911 public final long lifetime; 912 /** If this is a lifetime, the value below which the lifetime is ignored */ 913 public final int min; 914 PacketSection(int start, int length, Type type, long lifetime, int min)915 PacketSection(int start, int length, Type type, long lifetime, int min) { 916 this.start = start; 917 918 if (type == Type.LIFETIME && length != 2 && length != 4) { 919 throw new IllegalArgumentException("LIFETIME section length must be 2 or 4 bytes"); 920 } 921 this.length = length; 922 this.type = type; 923 924 if (type == Type.MATCH && (lifetime != 0 || min != 0)) { 925 throw new IllegalArgumentException("lifetime, min must be 0 for MATCH sections"); 926 } 927 this.lifetime = lifetime; 928 929 // It has already been asserted that min is 0 for MATCH sections. 930 if (min < 0) { 931 throw new IllegalArgumentException("min must be >= 0 for LIFETIME sections"); 932 } 933 this.min = min; 934 } 935 936 @Override toString()937 public String toString() { 938 if (type == Type.LIFETIME) { 939 return String.format("%s: (%d, %d) %d %d", type, start, length, lifetime, min); 940 } else { 941 return String.format("%s: (%d, %d)", type, start, length); 942 } 943 } 944 } 945 946 // A class to hold information about an RA. 947 @VisibleForTesting 948 public class Ra { 949 // Note: mPacket's position() cannot be assumed to be reset. 950 private final ByteBuffer mPacket; 951 952 // List of sections in the packet. 953 private final ArrayList<PacketSection> mPacketSections = new ArrayList<>(); 954 955 // Router lifetime in packet 956 private final int mRouterLifetime; 957 // Minimum valid lifetime of PIOs in packet, Long.MAX_VALUE means not seen. 958 private final long mMinPioValidLifetime; 959 // Minimum route lifetime of RIOs in packet, Long.MAX_VALUE means not seen. 960 private final long mMinRioRouteLifetime; 961 // Minimum lifetime of RDNSSs in packet, Long.MAX_VALUE means not seen. 962 private final long mMinRdnssLifetime; 963 // The time in seconds in which some of the information contained in this RA expires. 964 private final int mExpirationTime; 965 // When the packet was last captured, in seconds since Unix Epoch 966 private final int mLastSeen; 967 968 // For debugging only. Offsets into the packet where PIOs are. 969 private final ArrayList<Integer> mPrefixOptionOffsets = new ArrayList<>(); 970 971 // For debugging only. Offsets into the packet where RDNSS options are. 972 private final ArrayList<Integer> mRdnssOptionOffsets = new ArrayList<>(); 973 974 // For debugging only. Offsets into the packet where RIO options are. 975 private final ArrayList<Integer> mRioOptionOffsets = new ArrayList<>(); 976 977 // For debugging only. Returns the hex representation of the last matching packet. getLastMatchingPacket()978 String getLastMatchingPacket() { 979 return HexDump.toHexString(mPacket.array(), 0, mPacket.capacity(), 980 false /* lowercase */); 981 } 982 983 // For debugging only. Returns the string representation of the IPv6 address starting at 984 // position pos in the packet. IPv6AddresstoString(int pos)985 private String IPv6AddresstoString(int pos) { 986 try { 987 byte[] array = mPacket.array(); 988 // Can't just call copyOfRange() and see if it throws, because if it reads past the 989 // end it pads with zeros instead of throwing. 990 if (pos < 0 || pos + 16 > array.length || pos + 16 < pos) { 991 return "???"; 992 } 993 byte[] addressBytes = Arrays.copyOfRange(array, pos, pos + 16); 994 InetAddress address = InetAddress.getByAddress(addressBytes); 995 return address.getHostAddress(); 996 } catch (UnsupportedOperationException e) { 997 // array() failed. Cannot happen, mPacket is array-backed and read-write. 998 return "???"; 999 } catch (ClassCastException|UnknownHostException e) { 1000 // Cannot happen. 1001 return "???"; 1002 } 1003 } 1004 1005 // Can't be static because it's in a non-static inner class. 1006 // TODO: Make this static once RA is its own class. prefixOptionToString(StringBuffer sb, int offset)1007 private void prefixOptionToString(StringBuffer sb, int offset) { 1008 String prefix = IPv6AddresstoString(offset + 16); 1009 int length = getUint8(mPacket, offset + 2); 1010 long valid = getUint32(mPacket, offset + 4); 1011 long preferred = getUint32(mPacket, offset + 8); 1012 sb.append(String.format("%s/%d %ds/%ds ", prefix, length, valid, preferred)); 1013 } 1014 rdnssOptionToString(StringBuffer sb, int offset)1015 private void rdnssOptionToString(StringBuffer sb, int offset) { 1016 int optLen = getUint8(mPacket, offset + 1) * 8; 1017 if (optLen < 24) return; // Malformed or empty. 1018 long lifetime = getUint32(mPacket, offset + 4); 1019 int numServers = (optLen - 8) / 16; 1020 sb.append("DNS ").append(lifetime).append("s"); 1021 for (int server = 0; server < numServers; server++) { 1022 sb.append(" ").append(IPv6AddresstoString(offset + 8 + 16 * server)); 1023 } 1024 sb.append(" "); 1025 } 1026 rioOptionToString(StringBuffer sb, int offset)1027 private void rioOptionToString(StringBuffer sb, int offset) { 1028 int optLen = getUint8(mPacket, offset + 1) * 8; 1029 if (optLen < 8 || optLen > 24) return; // Malformed or empty. 1030 int prefixLen = getUint8(mPacket, offset + 2); 1031 long lifetime = getUint32(mPacket, offset + 4); 1032 1033 // This read is variable length because the prefix can be 0, 8 or 16 bytes long. 1034 // We can't use any of the ByteBuffer#get methods here because they all start reading 1035 // from the buffer's current position. 1036 byte[] prefix = new byte[IPV6_ADDR_LEN]; 1037 System.arraycopy(mPacket.array(), offset + 8, prefix, 0, optLen - 8); 1038 sb.append("RIO ").append(lifetime).append("s "); 1039 try { 1040 InetAddress address = InetAddress.getByAddress(prefix); 1041 sb.append(address.getHostAddress()); 1042 } catch (UnknownHostException impossible) { 1043 sb.append("???"); 1044 } 1045 sb.append("/").append(prefixLen).append(" "); 1046 } 1047 1048 @Override toString()1049 public String toString() { 1050 try { 1051 StringBuffer sb = new StringBuffer(); 1052 sb.append(String.format("RA %s -> %s %ds ", 1053 IPv6AddresstoString(IPV6_SRC_ADDR_OFFSET), 1054 IPv6AddresstoString(IPV6_DEST_ADDR_OFFSET), 1055 getUint16(mPacket, ICMP6_RA_ROUTER_LIFETIME_OFFSET))); 1056 for (int i: mPrefixOptionOffsets) { 1057 prefixOptionToString(sb, i); 1058 } 1059 for (int i: mRdnssOptionOffsets) { 1060 rdnssOptionToString(sb, i); 1061 } 1062 for (int i: mRioOptionOffsets) { 1063 rioOptionToString(sb, i); 1064 } 1065 return sb.toString(); 1066 } catch (BufferUnderflowException|IndexOutOfBoundsException e) { 1067 return "<Malformed RA>"; 1068 } 1069 } 1070 1071 /** 1072 * Add a packet section that should be matched, starting from the current position. 1073 * @param length the length of the section 1074 */ addMatchSection(int length)1075 private void addMatchSection(int length) { 1076 // Don't generate JNEBS instruction for 0 bytes as they will fail the 1077 // ASSERT_FORWARD_IN_PROGRAM(pc + cmp_imm - 1) check (where cmp_imm is 1078 // the number of bytes to compare) and immediately pass the packet. 1079 // The code does not attempt to generate such matches, but add a safety 1080 // check to prevent doing so in the presence of bugs or malformed or 1081 // truncated packets. 1082 if (length == 0) return; 1083 1084 // we need to add a MATCH section 'from, length, MATCH, 0, 0' 1085 int from = mPacket.position(); 1086 1087 // if possible try to increase the length of the previous match section 1088 int lastIdx = mPacketSections.size() - 1; 1089 if (lastIdx >= 0) { // there had to be a previous section 1090 PacketSection prev = mPacketSections.get(lastIdx); 1091 if (prev.type == PacketSection.Type.MATCH) { // of type match 1092 if (prev.start + prev.length == from) { // ending where we start 1093 from -= prev.length; 1094 length += prev.length; 1095 mPacketSections.remove(lastIdx); 1096 } 1097 } 1098 } 1099 1100 mPacketSections.add(new PacketSection(from, length, PacketSection.Type.MATCH, 0, 0)); 1101 mPacket.position(from + length); 1102 } 1103 1104 /** 1105 * Add a packet section that should be matched, starting from the current position. 1106 * @param end the offset in the packet before which the section ends 1107 */ addMatchUntil(int end)1108 private void addMatchUntil(int end) { 1109 addMatchSection(end - mPacket.position()); 1110 } 1111 1112 /** 1113 * Add a packet section that should be ignored, starting from the current position. 1114 * @param length the length of the section in bytes 1115 */ addIgnoreSection(int length)1116 private void addIgnoreSection(int length) { 1117 mPacket.position(mPacket.position() + length); 1118 } 1119 1120 /** 1121 * Add a packet section that represents a lifetime, starting from the current position. 1122 * @param length the length of the section in bytes 1123 * @param lifetime the lifetime 1124 * @param min the minimum acceptable lifetime 1125 */ addLifetimeSection(int length, long lifetime, int min)1126 private void addLifetimeSection(int length, long lifetime, int min) { 1127 mPacketSections.add( 1128 new PacketSection(mPacket.position(), length, PacketSection.Type.LIFETIME, 1129 lifetime, min)); 1130 mPacket.position(mPacket.position() + length); 1131 } 1132 1133 /** 1134 * Adds packet sections for an RA option with a 4-byte lifetime 4 bytes into the option 1135 * @param optionLength the length of the option in bytes 1136 * @param min the minimum acceptable lifetime 1137 * @param isRdnss true iff this is an RDNSS option 1138 */ add4ByteLifetimeOption(int optionLength, int min, boolean isRdnss)1139 private long add4ByteLifetimeOption(int optionLength, int min, boolean isRdnss) { 1140 if (isRdnss) { 1141 addMatchSection(ICMP6_4_BYTE_LIFETIME_OFFSET - 2); 1142 addIgnoreSection(2); // reserved, but observed non-zero 1143 } else { 1144 addMatchSection(ICMP6_4_BYTE_LIFETIME_OFFSET); 1145 } 1146 final long lifetime = getUint32(mPacket, mPacket.position()); 1147 addLifetimeSection(ICMP6_4_BYTE_LIFETIME_LEN, lifetime, min); 1148 addMatchSection(optionLength - ICMP6_4_BYTE_LIFETIME_OFFSET 1149 - ICMP6_4_BYTE_LIFETIME_LEN); 1150 return lifetime; 1151 } 1152 1153 // Note that this parses RA and may throw InvalidRaException (from 1154 // Buffer.position(int) or due to an invalid-length option) or IndexOutOfBoundsException 1155 // (from ByteBuffer.get(int) ) if parsing encounters something non-compliant with 1156 // specifications. 1157 @VisibleForTesting Ra(byte[] packet, int length)1158 public Ra(byte[] packet, int length) throws InvalidRaException { 1159 if (length < ICMP6_RA_OPTION_OFFSET) { 1160 throw new InvalidRaException("Not an ICMP6 router advertisement: too short"); 1161 } 1162 1163 mPacket = ByteBuffer.wrap(Arrays.copyOf(packet, length)); 1164 mLastSeen = secondsSinceBoot(); 1165 1166 // Check packet in case a packet arrives before we attach RA filter 1167 // to our packet socket. b/29586253 1168 if (getUint16(mPacket, ETH_ETHERTYPE_OFFSET) != ETH_P_IPV6 || 1169 getUint8(mPacket, IPV6_NEXT_HEADER_OFFSET) != IPPROTO_ICMPV6 || 1170 getUint8(mPacket, ICMP6_TYPE_OFFSET) != ICMPV6_ROUTER_ADVERTISEMENT) { 1171 throw new InvalidRaException("Not an ICMP6 router advertisement"); 1172 } 1173 1174 // Ignore destination MAC address. 1175 addIgnoreSection(6 /* Size of MAC address */); 1176 1177 // Ignore the flow label and low 4 bits of traffic class. 1178 addMatchUntil(IPV6_FLOW_LABEL_OFFSET); 1179 addIgnoreSection(IPV6_FLOW_LABEL_LEN); 1180 1181 // Ignore IPv6 destination address. 1182 addMatchUntil(IPV6_DEST_ADDR_OFFSET); 1183 addIgnoreSection(IPV6_ADDR_LEN); 1184 1185 // Ignore checksum. 1186 addMatchUntil(ICMP6_RA_CHECKSUM_OFFSET); 1187 addIgnoreSection(ICMP6_RA_CHECKSUM_LEN); 1188 1189 // Parse router lifetime 1190 addMatchUntil(ICMP6_RA_ROUTER_LIFETIME_OFFSET); 1191 mRouterLifetime = getUint16(mPacket, ICMP6_RA_ROUTER_LIFETIME_OFFSET); 1192 addLifetimeSection(ICMP6_RA_ROUTER_LIFETIME_LEN, mRouterLifetime, mAcceptRaMinLft); 1193 if (mRouterLifetime == 0) mNumZeroLifetimeRas++; 1194 1195 // Add remaining fields (reachable time and retransmission timer) to match section. 1196 addMatchUntil(ICMP6_RA_OPTION_OFFSET); 1197 1198 long minPioValidLifetime = Long.MAX_VALUE; 1199 long minRioRouteLifetime = Long.MAX_VALUE; 1200 long minRdnssLifetime = Long.MAX_VALUE; 1201 1202 while (mPacket.hasRemaining()) { 1203 final int position = mPacket.position(); 1204 final int optionType = getUint8(mPacket, position); 1205 final int optionLength = getUint8(mPacket, position + 1) * 8; 1206 if (optionLength <= 0) { 1207 throw new InvalidRaException(String.format( 1208 "Invalid option length opt=%d len=%d", optionType, optionLength)); 1209 } 1210 1211 long lifetime; 1212 switch (optionType) { 1213 case ICMP6_PREFIX_OPTION_TYPE: 1214 mPrefixOptionOffsets.add(position); 1215 1216 // Parse valid lifetime 1217 addMatchSection(ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET); 1218 lifetime = getUint32(mPacket, mPacket.position()); 1219 addLifetimeSection(ICMP6_PREFIX_OPTION_VALID_LIFETIME_LEN, 1220 lifetime, mAcceptRaMinLft); 1221 minPioValidLifetime = getMinForPositiveValue( 1222 minPioValidLifetime, lifetime); 1223 if (lifetime == 0) mNumZeroLifetimeRas++; 1224 1225 // Parse preferred lifetime 1226 lifetime = getUint32(mPacket, mPacket.position()); 1227 // The PIO preferred lifetime is not affected by accept_ra_min_lft and 1228 // therefore does not have a minimum. 1229 addLifetimeSection(ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_LEN, 1230 lifetime, 0 /* min lifetime */); 1231 1232 addMatchSection(4); // Reserved bytes 1233 addMatchSection(IPV6_ADDR_LEN); // The prefix itself 1234 break; 1235 // These three options have the same lifetime offset and size, and 1236 // are processed with the same specialized add4ByteLifetimeOption: 1237 case ICMP6_RDNSS_OPTION_TYPE: 1238 mRdnssOptionOffsets.add(position); 1239 lifetime = add4ByteLifetimeOption(optionLength, mMinRdnssLifetimeSec, true); 1240 minRdnssLifetime = getMinForPositiveValue(minRdnssLifetime, lifetime); 1241 if (lifetime == 0) mNumZeroLifetimeRas++; 1242 break; 1243 case ICMP6_ROUTE_INFO_OPTION_TYPE: 1244 mRioOptionOffsets.add(position); 1245 lifetime = add4ByteLifetimeOption(optionLength, mAcceptRaMinLft, false); 1246 minRioRouteLifetime = getMinForPositiveValue( 1247 minRioRouteLifetime, lifetime); 1248 if (lifetime == 0) mNumZeroLifetimeRas++; 1249 break; 1250 case ICMP6_SOURCE_LL_ADDRESS_OPTION_TYPE: 1251 case ICMP6_MTU_OPTION_TYPE: 1252 case ICMP6_PREF64_OPTION_TYPE: 1253 case ICMP6_RA_FLAGS_EXTENSION_OPTION_TYPE: 1254 addMatchSection(optionLength); 1255 break; 1256 case ICMP6_CAPTIVE_PORTAL_OPTION_TYPE: // unlikely to ever change. 1257 case ICMP6_DNSSL_OPTION_TYPE: // currently unsupported in userspace. 1258 default: 1259 // RFC4861 section 4.2 dictates we ignore unknown options for forwards 1260 // compatibility. 1261 // However, make sure the option's type and length match. 1262 addMatchSection(2); // option type & length 1263 // optionLength is guaranteed to be >= 8. 1264 addIgnoreSection(optionLength - 2); 1265 break; 1266 } 1267 } 1268 1269 mMinPioValidLifetime = minPioValidLifetime; 1270 mMinRioRouteLifetime = minRioRouteLifetime; 1271 mMinRdnssLifetime = minRdnssLifetime; 1272 mExpirationTime = getExpirationTime(); 1273 } 1274 1275 public enum MatchType { 1276 NO_MATCH, // the RAs do not match 1277 MATCH_PASS, // the RAS match, and the APF program would pass. 1278 MATCH_DROP, // the RAs match, but the APF program would drop. 1279 } 1280 1281 // Considering only the MATCH sections, does {@code packet} match this RA? matches(Ra newRa)1282 MatchType matches(Ra newRa) { 1283 // Does their size match? 1284 if (newRa.mPacket.capacity() != mPacket.capacity()) return MatchType.NO_MATCH; 1285 1286 // If the filter has expired, it cannot match the new RA. 1287 if (getRemainingFilterLft(secondsSinceBoot()) <= 0) return MatchType.NO_MATCH; 1288 1289 // Check if all MATCH sections are byte-identical. 1290 final byte[] newPacket = newRa.mPacket.array(); 1291 final byte[] oldPacket = mPacket.array(); 1292 for (PacketSection section : mPacketSections) { 1293 if (section.type != PacketSection.Type.MATCH) continue; 1294 for (int i = section.start; i < (section.start + section.length); i++) { 1295 if (newPacket[i] != oldPacket[i]) return MatchType.NO_MATCH; 1296 } 1297 } 1298 1299 // Apply APF lifetime matching to LIFETIME sections and decide whether a packet should 1300 // be processed (MATCH_PASS) or ignored (MATCH_DROP). This logic is needed to 1301 // consistently process / ignore packets no matter the current state of the APF program. 1302 // Note that userspace has no control (or knowledge) over when the APF program is 1303 // running. 1304 for (PacketSection section : mPacketSections) { 1305 if (section.type != PacketSection.Type.LIFETIME) continue; 1306 1307 // the lifetime of the new RA. 1308 long lft = 0; 1309 switch (section.length) { 1310 // section.length is guaranteed to be 2 or 4. 1311 case 2: lft = getUint16(newRa.mPacket, section.start); break; 1312 case 4: lft = getUint32(newRa.mPacket, section.start); break; 1313 } 1314 1315 // WARNING: keep this in sync with Ra#generateFilter()! 1316 if (section.lifetime == 0) { 1317 // Case 1) old lft == 0 1318 if (section.min > 0) { 1319 // a) in the presence of a min value. 1320 // if lft >= min -> PASS 1321 // gen.addJumpIfR0GreaterThan(section.min - 1, nextFilterLabel); 1322 if (lft >= section.min) return MatchType.MATCH_PASS; 1323 } else { 1324 // b) if min is 0 / there is no min value. 1325 // if lft > 0 -> PASS 1326 // gen.addJumpIfR0GreaterThan(0, nextFilterLabel); 1327 if (lft > 0) return MatchType.MATCH_PASS; 1328 } 1329 } else if (section.min == 0) { 1330 // Case 2b) section is not affected by any minimum. 1331 // 1332 // if lft < (oldLft + 2) // 3 -> PASS 1333 // if lft > oldLft -> PASS 1334 // gen.addJumpIfR0LessThan(((section.lifetime + 2) / 3), 1335 // nextFilterLabel); 1336 if (lft < (section.lifetime + 2) / 3) return MatchType.MATCH_PASS; 1337 // gen.addJumpIfR0GreaterThan(section.lifetime, nextFilterLabel); 1338 if (lft > section.lifetime) return MatchType.MATCH_PASS; 1339 } else if (section.lifetime < section.min) { 1340 // Case 2a) 0 < old lft < min 1341 // 1342 // if lft == 0 -> PASS 1343 // if lft >= min -> PASS 1344 // gen.addJumpIfR0Equals(0, nextFilterLabel); 1345 if (lft == 0) return MatchType.MATCH_PASS; 1346 // gen.addJumpIfR0GreaterThan(section.min - 1, nextFilterLabel); 1347 if (lft >= section.min) return MatchType.MATCH_PASS; 1348 } else if (section.lifetime <= 3 * (long) section.min) { 1349 // Case 3a) min <= old lft <= 3 * min 1350 // Note that: 1351 // "(old lft + 2) / 3 <= min" is equivalent to "old lft <= 3 * min" 1352 // 1353 // Essentially, in this range there is no "renumbering support", as the 1354 // renumbering constant of 1/3 * old lft is smaller than the minimum 1355 // lifetime accepted by the kernel / userspace. 1356 // 1357 // if lft == 0 -> PASS 1358 // if lft > oldLft -> PASS 1359 // gen.addJumpIfR0Equals(0, nextFilterLabel); 1360 if (lft == 0) return MatchType.MATCH_PASS; 1361 // gen.addJumpIfR0GreaterThan(section.lifetime, nextFilterLabel); 1362 if (lft > section.lifetime) return MatchType.MATCH_PASS; 1363 } else { 1364 // Case 4a) otherwise 1365 // 1366 // if lft == 0 -> PASS 1367 // if lft < min -> CONTINUE 1368 // if lft < (oldLft + 2) // 3 -> PASS 1369 // if lft > oldLft -> PASS 1370 // gen.addJumpIfR0Equals(0, nextFilterLabel); 1371 if (lft == 0) return MatchType.MATCH_PASS; 1372 // gen.addJumpIfR0LessThan(section.min, continueLabel); 1373 if (lft < section.min) continue; 1374 // gen.addJumpIfR0LessThan(((section.lifetime + 2) / 3), 1375 // nextFilterLabel); 1376 if (lft < (section.lifetime + 2) / 3) return MatchType.MATCH_PASS; 1377 // gen.addJumpIfR0GreaterThan(section.lifetime, nextFilterLabel); 1378 if (lft > section.lifetime) return MatchType.MATCH_PASS; 1379 } 1380 } 1381 1382 return MatchType.MATCH_DROP; 1383 } 1384 1385 // Get the number of seconds in which some of the information contained in this RA expires. getExpirationTime()1386 private int getExpirationTime() { 1387 // While technically most lifetimes in the RA are u32s, as far as the RA filter is 1388 // concerned, INT_MAX is still a *much* longer lifetime than any filter would ever 1389 // reasonably be active for. 1390 // Clamp expirationTime at INT_MAX. 1391 int expirationTime = Integer.MAX_VALUE; 1392 for (PacketSection section : mPacketSections) { 1393 if (section.type != PacketSection.Type.LIFETIME) { 1394 continue; 1395 } 1396 // Ignore lifetimes below section.min and always ignore 0 lifetimes. 1397 if (section.lifetime < Math.max(section.min, 1)) { 1398 continue; 1399 } 1400 1401 expirationTime = (int) Math.min(expirationTime, section.lifetime); 1402 } 1403 return expirationTime; 1404 } 1405 1406 // Filter for a fraction of the expiration time and adjust for the age of the RA. getRemainingFilterLft(int currentTimeSeconds)1407 int getRemainingFilterLft(int currentTimeSeconds) { 1408 int filterLifetime = ((mExpirationTime / FRACTION_OF_LIFETIME_TO_FILTER) 1409 - (currentTimeSeconds - mLastSeen)); 1410 filterLifetime = Math.max(0, filterLifetime); 1411 // Clamp filterLifetime to <= 65535, so it fits in 2 bytes. 1412 return Math.min(65535, filterLifetime); 1413 } 1414 getRaProgramLengthOverEstimate(int timeSeconds)1415 int getRaProgramLengthOverEstimate(int timeSeconds) throws IllegalInstructionException { 1416 final ApfV4GeneratorBase<?> gen = createApfGenerator(); 1417 generateFilter(gen, timeSeconds); 1418 return gen.programLengthOverEstimate() - gen.getBaseProgramSize(); 1419 } 1420 1421 // Append a filter for this RA to {@code gen}. Jump to DROP_LABEL if it should be dropped. 1422 // Jump to the next filter if packet doesn't match this RA. generateFilter(ApfV4GeneratorBase<?> gen, int timeSeconds)1423 void generateFilter(ApfV4GeneratorBase<?> gen, int timeSeconds) 1424 throws IllegalInstructionException { 1425 short nextFilterLabel = gen.getUniqueLabel(); 1426 // Skip if packet is not the right size 1427 gen.addLoadFromMemory(R0, MemorySlot.PACKET_SIZE); 1428 gen.addJumpIfR0NotEquals(mPacket.capacity(), nextFilterLabel); 1429 // Skip filter if expired 1430 gen.addLoadFromMemory(R0, MemorySlot.FILTER_AGE_SECONDS); 1431 gen.addJumpIfR0GreaterThan(getRemainingFilterLft(timeSeconds), nextFilterLabel); 1432 for (PacketSection section : mPacketSections) { 1433 // Generate code to match the packet bytes. 1434 if (section.type == PacketSection.Type.MATCH) { 1435 gen.addLoadImmediate(R0, section.start); 1436 gen.addJumpIfBytesAtR0NotEqual( 1437 Arrays.copyOfRange(mPacket.array(), section.start, 1438 section.start + section.length), 1439 nextFilterLabel); 1440 } else { 1441 switch (section.length) { 1442 // length asserted to be either 2 or 4 on PacketSection construction 1443 case 2: gen.addLoad16intoR0(section.start); break; 1444 case 4: gen.addLoad32intoR0(section.start); break; 1445 } 1446 1447 // WARNING: keep this in sync with matches()! 1448 // For more information on lifetime comparisons in the APF bytecode, see 1449 // go/apf-ra-filter. 1450 if (section.lifetime == 0) { 1451 // Case 1) old lft == 0 1452 if (section.min > 0) { 1453 // a) in the presence of a min value. 1454 // if lft >= min -> PASS 1455 gen.addJumpIfR0GreaterThan(section.min - 1, nextFilterLabel); 1456 } else { 1457 // b) if min is 0 / there is no min value. 1458 // if lft > 0 -> PASS 1459 gen.addJumpIfR0GreaterThan(0, nextFilterLabel); 1460 } 1461 } else if (section.min == 0) { 1462 // Case 2b) section is not affected by any minimum. 1463 // 1464 // if lft < (oldLft + 2) // 3 -> PASS 1465 // if lft > oldLft -> PASS 1466 gen.addJumpIfR0LessThan(((section.lifetime + 2) / 3), 1467 nextFilterLabel); 1468 gen.addJumpIfR0GreaterThan(section.lifetime, nextFilterLabel); 1469 } else if (section.lifetime < section.min) { 1470 // Case 2a) 0 < old lft < min 1471 // 1472 // if lft == 0 -> PASS 1473 // if lft >= min -> PASS 1474 gen.addJumpIfR0Equals(0, nextFilterLabel); 1475 gen.addJumpIfR0GreaterThan(section.min - 1, nextFilterLabel); 1476 } else if (section.lifetime <= 3 * (long) section.min) { 1477 // Case 3a) min <= old lft <= 3 * min 1478 // Note that: 1479 // "(old lft + 2) / 3 <= min" is equivalent to "old lft <= 3 * min" 1480 // 1481 // Essentially, in this range there is no "renumbering support", as the 1482 // renumbering constant of 1/3 * old lft is smaller than the minimum 1483 // lifetime accepted by the kernel / userspace. 1484 // 1485 // if lft == 0 -> PASS 1486 // if lft > oldLft -> PASS 1487 gen.addJumpIfR0Equals(0, nextFilterLabel); 1488 gen.addJumpIfR0GreaterThan(section.lifetime, nextFilterLabel); 1489 } else { 1490 final short continueLabel = gen.getUniqueLabel(); 1491 // Case 4a) otherwise 1492 // 1493 // if lft == 0 -> PASS 1494 // if lft < min -> CONTINUE 1495 // if lft < (oldLft + 2) // 3 -> PASS 1496 // if lft > oldLft -> PASS 1497 gen.addJumpIfR0Equals(0, nextFilterLabel); 1498 gen.addJumpIfR0LessThan(section.min, continueLabel); 1499 gen.addJumpIfR0LessThan(((section.lifetime + 2) / 3), 1500 nextFilterLabel); 1501 gen.addJumpIfR0GreaterThan(section.lifetime, nextFilterLabel); 1502 1503 // CONTINUE 1504 gen.defineLabel(continueLabel); 1505 } 1506 } 1507 } 1508 gen.addCountAndDrop(DROPPED_RA); 1509 gen.defineLabel(nextFilterLabel); 1510 } 1511 } 1512 1513 // TODO: Refactor these subclasses to avoid so much repetition. 1514 private abstract static class KeepalivePacket { 1515 // Note that the offset starts from IP header. 1516 // These must be added ether header length when generating program. 1517 static final int IP_HEADER_OFFSET = 0; 1518 static final int IPV4_SRC_ADDR_OFFSET = IP_HEADER_OFFSET + 12; 1519 1520 // Append a filter for this keepalive ack to {@code gen}. 1521 // Jump to drop if it matches the keepalive ack. 1522 // Jump to the next filter if packet doesn't match the keepalive ack. generateFilter(ApfV4GeneratorBase<?> gen)1523 abstract void generateFilter(ApfV4GeneratorBase<?> gen) 1524 throws IllegalInstructionException; 1525 } 1526 1527 // A class to hold NAT-T keepalive ack information. 1528 private class NattKeepaliveResponse extends KeepalivePacket { 1529 static final int UDP_HEADER_LEN = 8; 1530 1531 protected class NattKeepaliveResponseData { 1532 public final byte[] srcAddress; 1533 public final int srcPort; 1534 public final byte[] dstAddress; 1535 public final int dstPort; 1536 NattKeepaliveResponseData(final NattKeepalivePacketDataParcelable sentKeepalivePacket)1537 NattKeepaliveResponseData(final NattKeepalivePacketDataParcelable sentKeepalivePacket) { 1538 srcAddress = sentKeepalivePacket.dstAddress; 1539 srcPort = sentKeepalivePacket.dstPort; 1540 dstAddress = sentKeepalivePacket.srcAddress; 1541 dstPort = sentKeepalivePacket.srcPort; 1542 } 1543 } 1544 1545 protected final NattKeepaliveResponseData mPacket; 1546 protected final byte[] mSrcDstAddr; 1547 protected final byte[] mPortFingerprint; 1548 // NAT-T keepalive packet 1549 protected final byte[] mPayload = {(byte) 0xff}; 1550 NattKeepaliveResponse(final NattKeepalivePacketDataParcelable sentKeepalivePacket)1551 NattKeepaliveResponse(final NattKeepalivePacketDataParcelable sentKeepalivePacket) { 1552 mPacket = new NattKeepaliveResponseData(sentKeepalivePacket); 1553 mSrcDstAddr = CollectionUtils.concatArrays(mPacket.srcAddress, mPacket.dstAddress); 1554 mPortFingerprint = generatePortFingerprint(mPacket.srcPort, mPacket.dstPort); 1555 } 1556 generatePortFingerprint(int srcPort, int dstPort)1557 byte[] generatePortFingerprint(int srcPort, int dstPort) { 1558 final ByteBuffer fp = ByteBuffer.allocate(4); 1559 fp.order(ByteOrder.BIG_ENDIAN); 1560 fp.putShort((short) srcPort); 1561 fp.putShort((short) dstPort); 1562 return fp.array(); 1563 } 1564 1565 @Override generateFilter(ApfV4GeneratorBase<?> gen)1566 void generateFilter(ApfV4GeneratorBase<?> gen) throws IllegalInstructionException { 1567 final short nextFilterLabel = gen.getUniqueLabel(); 1568 1569 gen.addLoadImmediate(R0, ETH_HEADER_LEN + IPV4_SRC_ADDR_OFFSET); 1570 gen.addJumpIfBytesAtR0NotEqual(mSrcDstAddr, nextFilterLabel); 1571 1572 // A NAT-T keepalive packet contains 1 byte payload with the value 0xff 1573 // Check payload length is 1 1574 gen.addLoadFromMemory(R0, MemorySlot.IPV4_HEADER_SIZE); 1575 gen.addAdd(UDP_HEADER_LEN); 1576 gen.addSwap(); 1577 gen.addLoad16intoR0(IPV4_TOTAL_LENGTH_OFFSET); 1578 gen.addNeg(R1); 1579 gen.addAddR1ToR0(); 1580 gen.addJumpIfR0NotEquals(1, nextFilterLabel); 1581 1582 // Check that the ports match 1583 gen.addLoadFromMemory(R0, MemorySlot.IPV4_HEADER_SIZE); 1584 gen.addAdd(ETH_HEADER_LEN); 1585 gen.addJumpIfBytesAtR0NotEqual(mPortFingerprint, nextFilterLabel); 1586 1587 // Payload offset = R0 + UDP header length 1588 gen.addAdd(UDP_HEADER_LEN); 1589 gen.addJumpIfBytesAtR0NotEqual(mPayload, nextFilterLabel); 1590 1591 gen.addCountAndDrop(DROPPED_IPV4_NATT_KEEPALIVE); 1592 gen.defineLabel(nextFilterLabel); 1593 } 1594 1595 @Override toString()1596 public String toString() { 1597 try { 1598 return String.format("%s -> %s", 1599 ConnectivityUtils.addressAndPortToString( 1600 InetAddress.getByAddress(mPacket.srcAddress), mPacket.srcPort), 1601 ConnectivityUtils.addressAndPortToString( 1602 InetAddress.getByAddress(mPacket.dstAddress), mPacket.dstPort)); 1603 } catch (UnknownHostException e) { 1604 return "Unknown host"; 1605 } 1606 } 1607 } 1608 1609 // A class to hold TCP keepalive ack information. 1610 private abstract static class TcpKeepaliveAck extends KeepalivePacket { 1611 protected static class TcpKeepaliveAckData { 1612 public final byte[] srcAddress; 1613 public final int srcPort; 1614 public final byte[] dstAddress; 1615 public final int dstPort; 1616 public final int seq; 1617 public final int ack; 1618 1619 // Create the characteristics of the ack packet from the sent keepalive packet. TcpKeepaliveAckData(final TcpKeepalivePacketDataParcelable sentKeepalivePacket)1620 TcpKeepaliveAckData(final TcpKeepalivePacketDataParcelable sentKeepalivePacket) { 1621 srcAddress = sentKeepalivePacket.dstAddress; 1622 srcPort = sentKeepalivePacket.dstPort; 1623 dstAddress = sentKeepalivePacket.srcAddress; 1624 dstPort = sentKeepalivePacket.srcPort; 1625 seq = sentKeepalivePacket.ack; 1626 ack = sentKeepalivePacket.seq + 1; 1627 } 1628 } 1629 1630 protected final TcpKeepaliveAckData mPacket; 1631 protected final byte[] mSrcDstAddr; 1632 protected final byte[] mPortSeqAckFingerprint; 1633 TcpKeepaliveAck(final TcpKeepaliveAckData packet, final byte[] srcDstAddr)1634 TcpKeepaliveAck(final TcpKeepaliveAckData packet, final byte[] srcDstAddr) { 1635 mPacket = packet; 1636 mSrcDstAddr = srcDstAddr; 1637 mPortSeqAckFingerprint = generatePortSeqAckFingerprint(mPacket.srcPort, 1638 mPacket.dstPort, mPacket.seq, mPacket.ack); 1639 } 1640 generatePortSeqAckFingerprint(int srcPort, int dstPort, int seq, int ack)1641 static byte[] generatePortSeqAckFingerprint(int srcPort, int dstPort, int seq, int ack) { 1642 final ByteBuffer fp = ByteBuffer.allocate(12); 1643 fp.order(ByteOrder.BIG_ENDIAN); 1644 fp.putShort((short) srcPort); 1645 fp.putShort((short) dstPort); 1646 fp.putInt(seq); 1647 fp.putInt(ack); 1648 return fp.array(); 1649 } 1650 1651 @Override toString()1652 public String toString() { 1653 try { 1654 return String.format("%s -> %s , seq=%d, ack=%d", 1655 ConnectivityUtils.addressAndPortToString( 1656 InetAddress.getByAddress(mPacket.srcAddress), mPacket.srcPort), 1657 ConnectivityUtils.addressAndPortToString( 1658 InetAddress.getByAddress(mPacket.dstAddress), mPacket.dstPort), 1659 Integer.toUnsignedLong(mPacket.seq), 1660 Integer.toUnsignedLong(mPacket.ack)); 1661 } catch (UnknownHostException e) { 1662 return "Unknown host"; 1663 } 1664 } 1665 1666 // Append a filter for this keepalive ack to {@code gen}. 1667 // Jump to drop if it matches the keepalive ack. 1668 // Jump to the next filter if packet doesn't match the keepalive ack. generateFilter(ApfV4GeneratorBase<?> gen)1669 abstract void generateFilter(ApfV4GeneratorBase<?> gen) 1670 throws IllegalInstructionException; 1671 } 1672 1673 private class TcpKeepaliveAckV4 extends TcpKeepaliveAck { 1674 TcpKeepaliveAckV4(final TcpKeepalivePacketDataParcelable sentKeepalivePacket)1675 TcpKeepaliveAckV4(final TcpKeepalivePacketDataParcelable sentKeepalivePacket) { 1676 this(new TcpKeepaliveAckData(sentKeepalivePacket)); 1677 } TcpKeepaliveAckV4(final TcpKeepaliveAckData packet)1678 TcpKeepaliveAckV4(final TcpKeepaliveAckData packet) { 1679 super(packet, CollectionUtils.concatArrays(packet.srcAddress, 1680 packet.dstAddress) /* srcDstAddr */); 1681 } 1682 1683 @Override generateFilter(ApfV4GeneratorBase<?> gen)1684 void generateFilter(ApfV4GeneratorBase<?> gen) throws IllegalInstructionException { 1685 final short nextFilterLabel = gen.getUniqueLabel(); 1686 1687 gen.addLoadImmediate(R0, ETH_HEADER_LEN + IPV4_SRC_ADDR_OFFSET); 1688 gen.addJumpIfBytesAtR0NotEqual(mSrcDstAddr, nextFilterLabel); 1689 1690 // Skip to the next filter if it's not zero-sized : 1691 // TCP_HEADER_SIZE + IPV4_HEADER_SIZE - ipv4_total_length == 0 1692 // Load the IP header size into R1 1693 gen.addLoadFromMemory(R1, MemorySlot.IPV4_HEADER_SIZE); 1694 // Load the TCP header size into R0 (it's indexed by R1) 1695 gen.addLoad8R1IndexedIntoR0(ETH_HEADER_LEN + TCP_HEADER_SIZE_OFFSET); 1696 // Size offset is in the top nibble, bottom nibble is reserved, 1697 // but not necessarily zero. Thus we need to >> 4 then << 2, 1698 // achieve this by >> 2 and masking with 0b00111100. 1699 gen.addRightShift(2); 1700 gen.addAnd(0x3C); 1701 // R0 += R1 -> R0 contains TCP + IP headers length 1702 gen.addAddR1ToR0(); 1703 // Load IPv4 total length 1704 gen.addSwap(); 1705 gen.addLoad16intoR0(IPV4_TOTAL_LENGTH_OFFSET); 1706 gen.addNeg(R1); 1707 gen.addAddR1ToR0(); 1708 gen.addJumpIfR0NotEquals(0, nextFilterLabel); 1709 // Add IPv4 header length 1710 gen.addLoadFromMemory(R1, MemorySlot.IPV4_HEADER_SIZE); 1711 gen.addLoadImmediate(R0, ETH_HEADER_LEN); 1712 gen.addAddR1ToR0(); 1713 gen.addJumpIfBytesAtR0NotEqual(mPortSeqAckFingerprint, nextFilterLabel); 1714 1715 gen.addCountAndDrop(DROPPED_IPV4_KEEPALIVE_ACK); 1716 gen.defineLabel(nextFilterLabel); 1717 } 1718 } 1719 1720 private static class TcpKeepaliveAckV6 extends TcpKeepaliveAck { TcpKeepaliveAckV6(final TcpKeepalivePacketDataParcelable sentKeepalivePacket)1721 TcpKeepaliveAckV6(final TcpKeepalivePacketDataParcelable sentKeepalivePacket) { 1722 this(new TcpKeepaliveAckData(sentKeepalivePacket)); 1723 } TcpKeepaliveAckV6(final TcpKeepaliveAckData packet)1724 TcpKeepaliveAckV6(final TcpKeepaliveAckData packet) { 1725 super(packet, CollectionUtils.concatArrays(packet.srcAddress, 1726 packet.dstAddress) /* srcDstAddr */); 1727 } 1728 1729 @Override generateFilter(ApfV4GeneratorBase<?> gen)1730 void generateFilter(ApfV4GeneratorBase<?> gen) { 1731 throw new UnsupportedOperationException("IPv6 TCP Keepalive is not supported yet"); 1732 } 1733 } 1734 1735 // Maximum number of RAs to filter for. 1736 private static final int MAX_RAS = 10; 1737 1738 private final ArrayList<Ra> mRas = new ArrayList<>(); 1739 private int mNumFilteredRas = 0; 1740 private final SparseArray<KeepalivePacket> mKeepalivePackets = new SparseArray<>(); 1741 1742 // We don't want to filter an RA for it's whole lifetime as it'll be expired by the time we ever 1743 // see a refresh. Using half the lifetime might be a good idea except for the fact that 1744 // packets may be dropped, so let's use 6. 1745 private static final int FRACTION_OF_LIFETIME_TO_FILTER = 6; 1746 1747 // When did we last install a filter program? In seconds since Unix Epoch. 1748 private int mLastTimeInstalledProgram; 1749 // How long should the last installed filter program live for? In seconds. 1750 private int mLastInstalledProgramMinLifetime; 1751 1752 // For debugging only. The last program installed. 1753 private byte[] mLastInstalledProgram; 1754 1755 /** 1756 * For debugging only. Contains the latest APF buffer snapshot captured from the firmware. 1757 * <p> 1758 * A typical size for this buffer is 4KB. It is present only if the WiFi HAL supports 1759 * IWifiStaIface#readApfPacketFilterData(), and the APF interpreter advertised support for 1760 * the opcodes to access the data buffer (LDDW and STDW). 1761 */ 1762 @Nullable 1763 private byte[] mDataSnapshot; 1764 1765 // How many times the program was updated since we started. 1766 private int mNumProgramUpdates = 0; 1767 // The maximum program size that updated since we started. 1768 private int mMaxProgramSize = 0; 1769 // The maximum number of distinct RAs 1770 private int mMaxDistinctRas = 0; 1771 1772 /** 1773 * Generate filter code to process ARP packets. Execution of this code ends in either the 1774 * DROP_LABEL or PASS_LABEL and does not fall off the end. 1775 * Preconditions: 1776 * - Packet being filtered is ARP 1777 */ generateArpFilter(ApfV4GeneratorBase<?> gen)1778 private void generateArpFilter(ApfV4GeneratorBase<?> gen) 1779 throws IllegalInstructionException { 1780 // Here's a basic summary of what the ARP filter program does: 1781 // 1782 // if clat is enabled (and we're thus IPv6-only) 1783 // drop 1784 // if not ARP IPv4 1785 // drop 1786 // if unknown ARP opcode (ie. not reply or request) 1787 // drop 1788 // 1789 // if ARP reply: 1790 // if source ip is 0.0.0.0 1791 // drop 1792 // if unicast (or multicast) 1793 // pass 1794 // if interface has no IPv4 address 1795 // if target ip is 0.0.0.0 1796 // drop 1797 // else 1798 // if target ip is not the interface ip 1799 // drop 1800 // pass 1801 // 1802 // if ARP request: 1803 // if interface has IPv4 address 1804 // if target ip is not the interface ip 1805 // drop 1806 // pass 1807 1808 // For IPv6 only network, drop all ARP packet. 1809 if (mHasClat) { 1810 gen.addCountAndDrop(DROPPED_ARP_V6_ONLY); 1811 return; 1812 } 1813 1814 // Drop if not ARP IPv4. 1815 gen.addCountAndDropIfBytesAtOffsetNotEqual(ARP_HEADER_OFFSET, ARP_IPV4_HEADER, 1816 DROPPED_ARP_NON_IPV4); 1817 1818 final short checkArpRequest = gen.getUniqueLabel(); 1819 1820 gen.addLoad16intoR0(ARP_OPCODE_OFFSET); 1821 gen.addJumpIfR0Equals(ARP_OPCODE_REQUEST, checkArpRequest); // Skip to arp request check. 1822 // Drop if unknown ARP opcode. 1823 gen.addCountAndDropIfR0NotEquals(ARP_OPCODE_REPLY, DROPPED_ARP_UNKNOWN); 1824 1825 /*---------- Handle ARP Replies. ----------*/ 1826 1827 // Drop if ARP reply source IP is 0.0.0.0 1828 gen.addLoad32intoR0(ARP_SOURCE_IP_ADDRESS_OFFSET); 1829 gen.addCountAndDropIfR0Equals(IPV4_ANY_HOST_ADDRESS, DROPPED_ARP_REPLY_SPA_NO_HOST); 1830 1831 // Pass if non-broadcast reply. 1832 // This also accepts multicast arp, but we assume those don't exist. 1833 gen.addCountAndPassIfBytesAtOffsetNotEqual(ETH_DEST_ADDR_OFFSET, ETHER_BROADCAST, 1834 PASSED_ARP_UNICAST_REPLY); 1835 1836 // It is a broadcast reply. 1837 if (mIPv4Address == null) { 1838 // When there is no IPv4 address, drop GARP replies (b/29404209). 1839 gen.addLoad32intoR0(ARP_TARGET_IP_ADDRESS_OFFSET); 1840 gen.addCountAndDropIfR0Equals(IPV4_ANY_HOST_ADDRESS, DROPPED_GARP_REPLY); 1841 } else { 1842 // When there is an IPv4 address, drop broadcast replies with a different target IPv4 1843 // address. 1844 gen.addLoad32intoR0(ARP_TARGET_IP_ADDRESS_OFFSET); 1845 gen.addCountAndDropIfR0NotEquals(bytesToBEInt(mIPv4Address), DROPPED_ARP_OTHER_HOST); 1846 } 1847 gen.addCountAndPass(PASSED_ARP_BROADCAST_REPLY); 1848 1849 /*---------- Handle ARP Requests. ----------*/ 1850 1851 gen.defineLabel(checkArpRequest); 1852 if (mIPv4Address != null) { 1853 // When there is an IPv4 address, drop unicast/broadcast requests with a different 1854 // target IPv4 address. 1855 gen.addLoad32intoR0(ARP_TARGET_IP_ADDRESS_OFFSET); 1856 gen.addCountAndDropIfR0NotEquals(bytesToBEInt(mIPv4Address), DROPPED_ARP_OTHER_HOST); 1857 1858 if (enableArpOffload()) { 1859 ApfV6GeneratorBase<?> v6Gen = (ApfV6GeneratorBase<?>) gen; 1860 // Ethernet requires that all packets be at least 60 bytes long 1861 v6Gen.addAllocate(60) 1862 .addPacketCopy(ETHER_SRC_ADDR_OFFSET, ETHER_ADDR_LEN) 1863 .addDataCopy(mHardwareAddress) 1864 .addDataCopy(FIXED_ARP_REPLY_HEADER) 1865 .addDataCopy(mHardwareAddress) 1866 .addWrite32(mIPv4Address) 1867 .addPacketCopy(ETHER_SRC_ADDR_OFFSET, ETHER_ADDR_LEN) 1868 .addPacketCopy(ARP_SOURCE_IP_ADDRESS_OFFSET, IPV4_ADDR_LEN) 1869 .addLoadFromMemory(R0, MemorySlot.TX_BUFFER_OUTPUT_POINTER) 1870 .addAdd(18) 1871 .addStoreToMemory(MemorySlot.TX_BUFFER_OUTPUT_POINTER, R0) 1872 .addTransmitWithoutChecksum() 1873 .addCountAndDrop(DROPPED_ARP_REQUEST_REPLIED); 1874 } 1875 } 1876 // If we're not clat, and we don't have an ipv4 address, allow all ARP request to avoid 1877 // racing against DHCP. 1878 gen.addCountAndPass(PASSED_ARP_REQUEST); 1879 } 1880 1881 /** 1882 * Generate filter code to reply and drop unicast ICMPv4 echo request. 1883 * <p> 1884 * On entry, we know it is IPv4 ethertype, but don't know anything else. 1885 * R0/R1 have nothing useful in them, and can be clobbered. 1886 */ generateUnicastIpv4PingOffload(ApfV6GeneratorBase<?> gen)1887 private void generateUnicastIpv4PingOffload(ApfV6GeneratorBase<?> gen) 1888 throws IllegalInstructionException { 1889 1890 final short skipIpv4PingFilter = gen.getUniqueLabel(); 1891 // Check 1) it's not a fragment. 2) it's ICMP. 1892 // If condition not match then skip the ping filter logic 1893 gen.addJumpIfNotUnfragmentedIPv4Protocol(IPPROTO_ICMP, skipIpv4PingFilter); 1894 1895 // Only offload unicast Ipv4 ping request for now. 1896 // While we could potentially support offloading multicast and broadcast ping requests in 1897 // the future, such packets will likely be dropped by multicast filters. 1898 // Since the device may have packet forwarding enabled, APF needs to pass any received 1899 // unicast IPv4 ping not destined for the device's IP address to the kernel. 1900 gen.addJumpIfBytesAtOffsetNotEqual( 1901 ETH_DEST_ADDR_OFFSET, mHardwareAddress, skipIpv4PingFilter) 1902 .addLoadImmediate(R0, IPV4_DEST_ADDR_OFFSET) 1903 .addJumpIfBytesAtR0NotEqual(mIPv4Address, skipIpv4PingFilter); 1904 1905 // Ignore ping packets with IPv4 options (header size != 20) as they are rare. 1906 // Pass them to the kernel to save bytecode space. 1907 gen.addLoadFromMemory(R0, MemorySlot.IPV4_HEADER_SIZE) 1908 .addJumpIfR0NotEquals(IPV4_HEADER_MIN_LEN, skipIpv4PingFilter); 1909 1910 // We need to check if the packet is sufficiently large to be a valid ICMP packet. 1911 gen.addLoadFromMemory(R0, MemorySlot.PACKET_SIZE) 1912 .addCountAndDropIfR0LessThan( 1913 ETHER_HEADER_LEN + IPV4_HEADER_MIN_LEN + ICMP_HEADER_LEN, 1914 DROPPED_IPV4_ICMP_INVALID); 1915 1916 // If it is not a ICMP echo request, then skip. 1917 gen.addLoad8intoR0(ICMP4_TYPE_NO_OPTIONS_OFFSET) 1918 .addJumpIfR0NotEquals(ICMP_ECHO, skipIpv4PingFilter); 1919 1920 final int defaultTtl = mDependencies.getIpv4DefaultTtl(); 1921 // Construct the ICMP echo reply packet. 1922 gen.addLoadFromMemory(R0, MemorySlot.PACKET_SIZE) 1923 .addAllocateR0() 1924 .addPacketCopy(ETHER_SRC_ADDR_OFFSET, ETHER_ADDR_LEN) // Dst MAC address 1925 .addDataCopy(mHardwareAddress) // Src MAC address 1926 // Reuse the following fields from the input packet: 1927 // 2 bytes: EtherType 1928 // 4 bytes: version, IHL, TOS, total length 1929 // 4 bytes: identification, flags, fragment offset 1930 .addPacketCopy(ETH_ETHERTYPE_OFFSET, 10) 1931 // Ttl: default ttl, Protocol: IPPROTO_ICMP, checksum: 0 1932 .addWrite32((defaultTtl << 24) | (IPPROTO_ICMP << 16)) 1933 .addWrite32(mIPv4Address) // Src ip 1934 .addPacketCopy(IPV4_SRC_ADDR_OFFSET, IPV4_ADDR_LEN) // Dst ip 1935 .addWrite32((ICMP_ECHOREPLY << 24)) // Type: echo reply, code: 0, checksum: 0 1936 // Copy identifier, sequence number and ping payload 1937 .addSub(ICMP4_CONTENT_NO_OPTIONS_OFFSET) 1938 .addLoadImmediate(R1, ICMP4_CONTENT_NO_OPTIONS_OFFSET) 1939 .addSwap() // Swaps R0 and R1, so they're the offset and length. 1940 .addPacketCopyFromR0LenR1() 1941 .addTransmitL4( 1942 ETHER_HEADER_LEN, // ip_ofs 1943 ICMP4_CHECKSUM_NO_OPTIONS_OFFSET, // csum_ofs 1944 ICMP4_TYPE_NO_OPTIONS_OFFSET, // csum_start 1945 0, // partial_sum 1946 false // udp 1947 ) 1948 .addCountAndDrop(DROPPED_IPV4_PING_REQUEST_REPLIED); 1949 1950 gen.defineLabel(skipIpv4PingFilter); 1951 } 1952 1953 /** 1954 * Generates filter code to handle IPv4 mDNS packets. 1955 * <p> 1956 * On entry, this filter knows it is processing an IPv4 packet. It will then process all IPv4 1957 * mDNS packets, either passing or dropping them. IPv4 non-mDNS packets are skipped. 1958 * 1959 * @param gen the APF generator to generate the filter code 1960 * @param labelCheckMdnsQueryPayload the label to jump to for checking the mDNS query payload 1961 */ generateIPv4MdnsFilter(ApfV6GeneratorBase<?> gen, short labelCheckMdnsQueryPayload)1962 private void generateIPv4MdnsFilter(ApfV6GeneratorBase<?> gen, 1963 short labelCheckMdnsQueryPayload) 1964 throws IllegalInstructionException { 1965 final short skipMdnsFilter = gen.getUniqueLabel(); 1966 1967 // If the packet is too short to be a valid IPv4 mDNS packet, the filter is skipped. 1968 // For APF performance reasons, we check udp destination port before confirming it is 1969 // non-fragmented IPv4 udp packet. We proceed only if the destination port is 5353 (mDNS). 1970 // Otherwise, skip filtering. 1971 gen.addLoadFromMemory(R0, MemorySlot.PACKET_SIZE) 1972 .addJumpIfR0LessThan( 1973 ETH_HEADER_LEN + IPV4_HEADER_MIN_LEN + UDP_HEADER_LEN + DNS_HEADER_LEN, 1974 skipMdnsFilter) 1975 .addLoad16intoR0(IPV4_UDP_DESTINATION_PORT_NO_OPTIONS_OFFSET) 1976 .addJumpIfR0NotEquals(MDNS_PORT, skipMdnsFilter); 1977 1978 // If the destination MAC address is not 01:00:5e:00:00:fb (the mDNS multicast MAC 1979 // address for IPv4 mDNS packet) or the device's MAC address, skip filtering. 1980 // We need to check both the mDNS multicast MAC address and the device's MAC address 1981 // because multicast to unicast conversion might have occurred. 1982 gen.addJumpIfBytesAtOffsetEqualsNoneOf( 1983 ETH_DEST_ADDR_OFFSET, 1984 List.of(mHardwareAddress, ETH_MULTICAST_MDNS_V4_MAC_ADDRESS), 1985 skipMdnsFilter 1986 ); 1987 1988 // Ignore packets with IPv4 options (header size not equal to 20) as they are rare. 1989 gen.addLoadFromMemory(R0, MemorySlot.IPV4_HEADER_SIZE) 1990 .addJumpIfR0NotEquals(IPV4_HEADER_MIN_LEN, skipMdnsFilter); 1991 1992 // Skip filtering if the packet is not a non-fragmented IPv4 UDP packet. 1993 gen.addJumpIfNotUnfragmentedIPv4Protocol(IPPROTO_UDP, skipMdnsFilter); 1994 1995 // Skip filtering if the IPv4 destination address is not 224.0.0.251 (the mDNS multicast 1996 // address). 1997 // Some devices can use unicast queries for mDNS to improve performance and reliability. 1998 // These packets are not currently offloaded and will be passed by APF and handled 1999 // by NsdService. 2000 gen.addLoad32intoR0(IPV4_DEST_ADDR_OFFSET) 2001 .addJumpIfR0NotEquals(MDNS_IPV4_ADDR_IN_LONG, skipMdnsFilter); 2002 2003 // We now know that the packet is an mDNS packet, 2004 // i.e., a non-fragmented IPv4 UDP packet destined for port 5353 with the expected 2005 // destination MAC and IP addresses. 2006 2007 // If the packet contains questions, check the query payload. Otherwise, check the 2008 // reply payload. 2009 gen.addLoad16intoR0(IPV4_DNS_QDCOUNT_NO_OPTIONS_OFFSET) 2010 // Set the UDP payload offset in R1 before potentially jumping to the payload 2011 // check logic. 2012 .addLoadImmediate(R1, IPV4_UDP_PAYLOAD_NO_OPTIONS_OFFSET) 2013 .addJumpIfR0NotEquals(0, labelCheckMdnsQueryPayload); 2014 2015 // TODO: check the reply payload. 2016 if (mMulticastFilter) { 2017 gen.addCountAndDrop(DROPPED_MDNS); 2018 } else { 2019 gen.addCountAndPass(PASSED_MDNS); 2020 } 2021 2022 gen.defineLabel(skipMdnsFilter); 2023 } 2024 2025 /** 2026 * Generate filter code to process IPv4 packets. Execution of this code ends in either the 2027 * DROP_LABEL or PASS_LABEL and does not fall off the end. 2028 * Preconditions: 2029 * - Packet being filtered is IPv4 2030 * 2031 * @param gen the APF generator to generate the filter code 2032 * @param labelCheckMdnsQueryPayload the label to jump to for checking the mDNS query payload 2033 */ generateIPv4Filter(ApfV4GeneratorBase<?> gen, short labelCheckMdnsQueryPayload)2034 private void generateIPv4Filter(ApfV4GeneratorBase<?> gen, short labelCheckMdnsQueryPayload) 2035 throws IllegalInstructionException { 2036 // Here's a basic summary of what the IPv4 filter program does: 2037 // 2038 // if the network is IPv6 only network: 2039 // if the packet is fragmented: 2040 // drop 2041 // if the packet is a dhcp packet comes from server: 2042 // pass 2043 // else 2044 // drop 2045 // 2046 // (APFv6+ specific logic) 2047 // if it's mDNS: 2048 // if it's a query: 2049 // if mNumOfMdnsRuleToOffload == -1: 2050 // pass 2051 // if the query matches one of the offload rules from idx [0, mNumOfMdnsRuleToOffload): 2052 // transmit mDNS reply and drop 2053 // else if query matches one of the rest of the offload rules: 2054 // pass 2055 // else if filtering multicast (i.e. multicast lock not held): 2056 // drop 2057 // else 2058 // pass 2059 // else: 2060 // if filtering multicast (i.e. multicast lock not held): 2061 // drop 2062 // else 2063 // pass 2064 // 2065 // (APFv6+ specific logic) 2066 // if it's IGMP: 2067 // if payload length is invalid (less than 8 or equal to 9, 10, 11): 2068 // drop 2069 // if the packet is an IGMP report: 2070 // drop 2071 // if the packet is not an IGMP query: 2072 // drop 2073 // if the group_addr is not 0.0.0.0, then it is group specific query: 2074 // pass 2075 // ===== handle IGMPv1/v2/v3 general query ===== 2076 // if the IPv4 dst addr is not 224.0.0.1: 2077 // drop 2078 // if the packet length >= 12, then it is IGMPv3: 2079 // transmit IGMPv3 report and drop 2080 // else if the packet length == 8, then it is either IGMPv1 or IGMPv2: 2081 // if the max_res_code == 0, then it is IGMPv1: 2082 // pass 2083 // else it is IGMPv2: 2084 // transmit IGMPv2 reports (one report per group) and drop 2085 // 2086 // if filtering multicast (i.e. multicast lock not held): 2087 // if it's DHCP destined to our MAC: 2088 // pass 2089 // if it's L2 broadcast: 2090 // drop 2091 // if it's IPv4 multicast: 2092 // drop 2093 // if it's IPv4 broadcast: 2094 // drop 2095 // 2096 // if keepalive ack 2097 // drop 2098 // 2099 // (APFv6+ specific logic) if it's unicast IPv4 ICMP echo request to our host: 2100 // transmit echo reply and drop 2101 // 2102 // pass 2103 2104 if (mHasClat) { 2105 // Check 1) it's not a fragment. 2) it's UDP. 2106 // Load 16 bit frag flags/offset field, 8 bit ttl, 8 bit protocol 2107 gen.addLoad32intoR0(IPV4_FRAGMENT_OFFSET_OFFSET); 2108 // Mask out the reserved and don't fragment bits, plus the TTL field. 2109 // Because: 2110 // IPV4_FRAGMENT_OFFSET_MASK = 0x1fff 2111 // IPV4_FRAGMENT_MORE_FRAGS_MASK = 0x2000 2112 // hence this constant ends up being 0x3FFF00FF. 2113 // We want the more flag bit and offset to be 0 (ie. not a fragment), 2114 // so after this masking we end up with just the ip protocol (hopefully UDP). 2115 gen.addAnd((IPV4_FRAGMENT_MORE_FRAGS_MASK | IPV4_FRAGMENT_OFFSET_MASK) << 16 | 0xFF); 2116 gen.addCountAndDropIfR0NotEquals(IPPROTO_UDP, DROPPED_IPV4_NON_DHCP4); 2117 // Check it's addressed to DHCP client port. 2118 gen.addLoadFromMemory(R1, MemorySlot.IPV4_HEADER_SIZE); 2119 gen.addLoad32R1IndexedIntoR0(TCP_UDP_SOURCE_PORT_OFFSET); 2120 gen.addCountAndDropIfR0NotEquals(DHCP_SERVER_PORT << 16 | DHCP_CLIENT_PORT, 2121 DROPPED_IPV4_NON_DHCP4); 2122 gen.addCountAndPass(PASSED_IPV4_FROM_DHCPV4_SERVER); 2123 return; 2124 } 2125 2126 if (enableMdns4Offload()) { 2127 generateIPv4MdnsFilter((ApfV6GeneratorBase<?>) gen, labelCheckMdnsQueryPayload); 2128 } 2129 2130 if (enableIgmpOffload()) { 2131 generateIgmpFilter((ApfV6GeneratorBase<?>) gen); 2132 } 2133 2134 if (mMulticastFilter) { 2135 final short skipDhcpv4Filter = gen.getUniqueLabel(); 2136 2137 // Pass DHCP addressed to us. 2138 // Check 1) it's not a fragment. 2) it's UDP. 2139 gen.addJumpIfNotUnfragmentedIPv4Protocol(IPPROTO_UDP, skipDhcpv4Filter); 2140 // Check it's addressed to DHCP client port. 2141 gen.addLoadFromMemory(R1, MemorySlot.IPV4_HEADER_SIZE); 2142 gen.addLoad16R1IndexedIntoR0(TCP_UDP_DESTINATION_PORT_OFFSET); 2143 gen.addJumpIfR0NotEquals(DHCP_CLIENT_PORT, skipDhcpv4Filter); 2144 // Check it's DHCP to our MAC address. 2145 gen.addLoadImmediate(R0, DHCP_CLIENT_MAC_OFFSET); 2146 // NOTE: Relies on R1 containing IPv4 header offset. 2147 gen.addAddR1ToR0(); 2148 gen.addJumpIfBytesAtR0NotEqual(mHardwareAddress, skipDhcpv4Filter); 2149 gen.addCountAndPass(PASSED_DHCP); 2150 2151 // Drop all multicasts/broadcasts. 2152 gen.defineLabel(skipDhcpv4Filter); 2153 2154 // If IPv4 destination address is in multicast range, drop. 2155 gen.addLoad8intoR0(IPV4_DEST_ADDR_OFFSET); 2156 // we just loaded a byte, so top 24 bits are zero, thus and'ing 2157 // with either one of 0xF0 and 0xFFFFFFF0 accomplishes the same thing, 2158 // we thus choose the one which encodes shorter 2159 gen.addAnd((gen instanceof ApfV4Generator) ? 0xF0 : 0xFFFFFFF0); 2160 gen.addCountAndDropIfR0Equals(0xe0, DROPPED_IPV4_MULTICAST); 2161 2162 // If IPv4 broadcast packet, drop regardless of L2 (b/30231088). 2163 gen.addLoad32intoR0(IPV4_DEST_ADDR_OFFSET); 2164 gen.addCountAndDropIfR0Equals(IPV4_BROADCAST_ADDRESS, DROPPED_IPV4_BROADCAST_ADDR); 2165 if (mIPv4Address != null && mIPv4PrefixLength < 31) { 2166 int broadcastAddr = ipv4BroadcastAddress(mIPv4Address, mIPv4PrefixLength); 2167 gen.addCountAndDropIfR0Equals(broadcastAddr, DROPPED_IPV4_BROADCAST_NET); 2168 } 2169 } 2170 2171 // If any TCP keepalive filter matches, drop 2172 generateV4KeepaliveFilters(gen); 2173 2174 // If any NAT-T keepalive filter matches, drop 2175 generateV4NattKeepaliveFilters(gen); 2176 2177 // If TCP unicast on port 7, drop 2178 generateV4TcpPort7Filter(gen); 2179 2180 if (enableIpv4PingOffload()) { 2181 generateUnicastIpv4PingOffload((ApfV6GeneratorBase<?>) gen); 2182 } 2183 2184 if (mMulticastFilter) { 2185 // Otherwise, this is an IPv4 unicast, pass 2186 // If L2 broadcast packet, drop. 2187 // TODO: can we invert this condition to fall through to the common pass case below? 2188 gen.addCountAndPassIfBytesAtOffsetNotEqual(ETH_DEST_ADDR_OFFSET, ETHER_BROADCAST, 2189 PASSED_IPV4_UNICAST); 2190 gen.addCountAndDrop(DROPPED_IPV4_L2_BROADCAST); 2191 } 2192 2193 // Otherwise, pass 2194 gen.addCountAndPass(PASSED_IPV4); 2195 } 2196 generateKeepaliveFilters(ApfV4GeneratorBase<?> gen, Class<?> filterType, int proto, int offset, short label)2197 private void generateKeepaliveFilters(ApfV4GeneratorBase<?> gen, Class<?> filterType, int proto, 2198 int offset, short label) throws IllegalInstructionException { 2199 final boolean haveKeepaliveResponses = CollectionUtils.any(mKeepalivePackets, 2200 filterType::isInstance); 2201 2202 // If no keepalive packets of this type 2203 if (!haveKeepaliveResponses) return; 2204 2205 // If not the right proto, skip keepalive filters 2206 gen.addLoad8intoR0(offset); 2207 gen.addJumpIfR0NotEquals(proto, label); 2208 2209 // Drop Keepalive responses 2210 for (int i = 0; i < mKeepalivePackets.size(); ++i) { 2211 final KeepalivePacket response = mKeepalivePackets.valueAt(i); 2212 if (filterType.isInstance(response)) response.generateFilter(gen); 2213 } 2214 2215 gen.defineLabel(label); 2216 } 2217 generateV4KeepaliveFilters(ApfV4GeneratorBase<?> gen)2218 private void generateV4KeepaliveFilters(ApfV4GeneratorBase<?> gen) 2219 throws IllegalInstructionException { 2220 generateKeepaliveFilters(gen, TcpKeepaliveAckV4.class, IPPROTO_TCP, IPV4_PROTOCOL_OFFSET, 2221 gen.getUniqueLabel()); 2222 } 2223 generateV4NattKeepaliveFilters(ApfV4GeneratorBase<?> gen)2224 private void generateV4NattKeepaliveFilters(ApfV4GeneratorBase<?> gen) 2225 throws IllegalInstructionException { 2226 generateKeepaliveFilters(gen, NattKeepaliveResponse.class, 2227 IPPROTO_UDP, IPV4_PROTOCOL_OFFSET, gen.getUniqueLabel()); 2228 } 2229 getSolicitedNodeMcastAddressSuffix( @onNull List<byte[]> ipv6Addresses)2230 private List<byte[]> getSolicitedNodeMcastAddressSuffix( 2231 @NonNull List<byte[]> ipv6Addresses) { 2232 final List<byte[]> suffixes = new ArrayList<>(); 2233 for (byte[] addr: ipv6Addresses) { 2234 suffixes.add(Arrays.copyOfRange(addr, 13, 16)); 2235 } 2236 return suffixes; 2237 } 2238 getIpv6Addresses( boolean includeNonTentative, boolean includeTentative, boolean includeAnycast)2239 private List<byte[]> getIpv6Addresses( 2240 boolean includeNonTentative, boolean includeTentative, boolean includeAnycast) { 2241 final List<byte[]> addresses = new ArrayList<>(); 2242 if (includeNonTentative) { 2243 for (Inet6Address addr : mIPv6NonTentativeAddresses) { 2244 addresses.add(addr.getAddress()); 2245 } 2246 } 2247 2248 if (includeTentative) { 2249 for (Inet6Address addr : mIPv6TentativeAddresses) { 2250 addresses.add(addr.getAddress()); 2251 } 2252 } 2253 2254 if (includeAnycast) { 2255 addresses.addAll(mDependencies.getAnycast6Addresses(mInterfaceParams.name)); 2256 } 2257 return addresses; 2258 } 2259 getKnownMacAddresses()2260 private List<byte[]> getKnownMacAddresses() { 2261 final List<byte[]> addresses = new ArrayList<>(); 2262 addresses.addAll(mDependencies.getEtherMulticastAddresses(mInterfaceParams.name)); 2263 addresses.add(mHardwareAddress); 2264 addresses.add(ETHER_BROADCAST); 2265 return addresses; 2266 } 2267 2268 /** 2269 * Generate allocate and transmit code to send ICMPv6 non-DAD NA packets. 2270 */ generateNonDadNaTransmit(ApfV6GeneratorBase<?> gen)2271 private void generateNonDadNaTransmit(ApfV6GeneratorBase<?> gen) 2272 throws IllegalInstructionException { 2273 final int ipv6PayloadLen = ICMPV6_NA_HEADER_LEN + ICMPV6_ND_OPTION_TLLA_LEN; 2274 final int pktLen = ETH_HEADER_LEN + IPV6_HEADER_LEN + ipv6PayloadLen; 2275 2276 gen.addAllocate(pktLen); 2277 2278 // Ethernet Header 2279 gen.addPacketCopy(ICMP6_NS_OPTION_TYPE_OFFSET + 2, ETHER_ADDR_LEN) // dst MAC address 2280 .addDataCopy(mHardwareAddress) // src MAC address 2281 .addWriteU16(ETH_P_IPV6); // IPv6 type 2282 2283 int tclass = mDependencies.getNdTrafficClass(mInterfaceParams.name); 2284 int vtf = (0x60000000 | (tclass << 20)); 2285 // IPv6 header 2286 gen.addWrite32(vtf) // IPv6 Header: version, traffic class, flowlabel 2287 // payload length (2 bytes) | next header: ICMPv6 (1 byte) | hop limit (1 byte) 2288 .addWrite32((ipv6PayloadLen << 16) | ((IPPROTO_ICMPV6 << 8) | 255)) 2289 // target ip is guaranteed to be non-tentative as we already check before 2290 // we call transmit, but the link local ip can potentially be tentative. 2291 .addPacketCopy(ICMP6_NS_TARGET_IP_OFFSET, IPV6_ADDR_LEN) // src ip 2292 .addPacketCopy(IPV6_SRC_ADDR_OFFSET, IPV6_ADDR_LEN); // dst ip 2293 2294 // ICMPv6 header and payload 2295 // ICMPv6 type: NA (1 byte) | code: 0 (1 byte) | checksum: set to payload size (2 bytes) 2296 gen.addWrite32((ICMPV6_NEIGHBOR_ADVERTISEMENT << 24) | ipv6PayloadLen) 2297 // Always set Router flag to prevent host deleting routes point at the router 2298 // Always set Override flag to update neighbor's cache 2299 // Solicited flag set to 1 if non DAD, refer to RFC4861#7.2.4 2300 .addWrite32(0xe0000000) // flags: R=1, S=1, O=1 2301 .addPacketCopy(ICMP6_NS_TARGET_IP_OFFSET, IPV6_ADDR_LEN) // target address 2302 // lla option: type (1 byte) | lla option: length (1 byte) 2303 .addWriteU16((ICMPV6_ND_OPTION_TLLA << 8) | 1) 2304 .addDataCopy(mHardwareAddress); // lla option: link layer address 2305 2306 gen.addTransmitL4( 2307 ETHER_HEADER_LEN, // ip_ofs 2308 ICMP6_CHECKSUM_OFFSET, // csum_ofs 2309 IPV6_SRC_ADDR_OFFSET, // csum_start 2310 IPPROTO_ICMPV6, // partial_sum 2311 false // udp 2312 ); 2313 } 2314 generateNsFilter(ApfV6GeneratorBase<?> v6Gen)2315 private void generateNsFilter(ApfV6GeneratorBase<?> v6Gen) 2316 throws IllegalInstructionException { 2317 final List<byte[]> allIPv6Addrs = getIpv6Addresses( 2318 true /* includeNonTentative */, 2319 true /* includeTentative */, 2320 true /* includeAnycast */); 2321 if (allIPv6Addrs.isEmpty()) { 2322 // If there is no IPv6 link local address, allow all NS packets to avoid racing 2323 // against RS. 2324 v6Gen.addCountAndPass(PASSED_IPV6_ICMP); 2325 return; 2326 } 2327 2328 // Warning: APF program may temporarily filter NS packets targeted for anycast addresses 2329 // used by processes other than clatd. This is because APF cannot reliably detect signal 2330 // on when IPV6_{JOIN,LEAVE}_ANYCAST is triggered. 2331 final List<byte[]> allMACs = getKnownMacAddresses(); 2332 v6Gen.addCountAndDropIfBytesAtOffsetEqualsNoneOf(ETH_DEST_ADDR_OFFSET, allMACs, 2333 DROPPED_IPV6_NS_OTHER_HOST); 2334 2335 // Dst IPv6 address check: 2336 final List<byte[]> allSuffixes = getSolicitedNodeMcastAddressSuffix(allIPv6Addrs); 2337 final short notIpV6SolicitedNodeMcast = v6Gen.getUniqueLabel(); 2338 final short endOfIpV6DstCheck = v6Gen.getUniqueLabel(); 2339 v6Gen.addJumpIfBytesAtOffsetNotEqual( 2340 IPV6_DEST_ADDR_OFFSET, IPV6_SOLICITED_NODES_PREFIX, notIpV6SolicitedNodeMcast) 2341 .addLoadImmediate(R0, IPV6_DEST_ADDR_OFFSET + 13) 2342 .addCountAndDropIfBytesAtR0EqualsNoneOf(allSuffixes, DROPPED_IPV6_NS_OTHER_HOST) 2343 .addJump(endOfIpV6DstCheck) 2344 .defineLabel(notIpV6SolicitedNodeMcast) 2345 .addCountAndDropIfBytesAtOffsetEqualsNoneOf( 2346 IPV6_DEST_ADDR_OFFSET, allIPv6Addrs, DROPPED_IPV6_NS_OTHER_HOST) 2347 .defineLabel(endOfIpV6DstCheck); 2348 2349 // Hop limit not 255, NS requires hop limit to be 255 -> drop 2350 v6Gen.addLoad8intoR0(IPV6_HOP_LIMIT_OFFSET) 2351 .addCountAndDropIfR0NotEquals(255, DROPPED_IPV6_NS_INVALID); 2352 2353 // payload length < 24 (8 bytes ICMP6 header + 16 bytes target address) -> drop 2354 v6Gen.addLoad16intoR0(IPV6_PAYLOAD_LEN_OFFSET) 2355 .addCountAndDropIfR0LessThan(24, DROPPED_IPV6_NS_INVALID); 2356 2357 // ICMPv6 code not 0 -> drop 2358 v6Gen.addLoad8intoR0(ICMP6_CODE_OFFSET) 2359 .addCountAndDropIfR0NotEquals(0, DROPPED_IPV6_NS_INVALID); 2360 2361 // target address (ICMPv6 NS payload) 2362 // 1) is one of tentative addresses -> pass 2363 // 2) is none of {non-tentative, anycast} addresses -> drop 2364 final List<byte[]> tentativeIPv6Addrs = getIpv6Addresses( 2365 false, /* includeNonTentative */ 2366 true, /* includeTentative */ 2367 false /* includeAnycast */ 2368 ); 2369 2370 if (!tentativeIPv6Addrs.isEmpty()) { 2371 v6Gen.addCountAndPassIfBytesAtOffsetEqualsAnyOf( 2372 ICMP6_NS_TARGET_IP_OFFSET, tentativeIPv6Addrs, PASSED_IPV6_ICMP); 2373 } 2374 2375 final List<byte[]> nonTentativeIpv6Addrs = getIpv6Addresses( 2376 true, /* includeNonTentative */ 2377 false, /* includeTentative */ 2378 true /* includeAnycast */ 2379 ); 2380 if (nonTentativeIpv6Addrs.isEmpty()) { 2381 v6Gen.addCountAndDrop(DROPPED_IPV6_NS_OTHER_HOST); 2382 return; 2383 } 2384 v6Gen.addCountAndDropIfBytesAtOffsetEqualsNoneOf( 2385 ICMP6_NS_TARGET_IP_OFFSET, nonTentativeIpv6Addrs, DROPPED_IPV6_NS_OTHER_HOST); 2386 2387 // if source ip is unspecified (::), it's DAD request -> pass 2388 v6Gen.addCountAndPassIfBytesAtOffsetEqual( 2389 IPV6_SRC_ADDR_OFFSET, IPV6_UNSPECIFIED_ADDRESS, PASSED_IPV6_ICMP); 2390 2391 // Only offload NUD/Address resolution packets that have SLLA as the their first option. 2392 // For option-less NUD packets or NUD/Address resolution packets where 2393 // the first option is not SLLA, pass them to the kernel for handling. 2394 // if payload len < 32 -> pass 2395 v6Gen.addLoad16intoR0(IPV6_PAYLOAD_LEN_OFFSET) 2396 .addCountAndPassIfR0LessThan(32, PASSED_IPV6_ICMP); 2397 2398 // if the first option is not SLLA -> pass 2399 // 0 1 2 3 2400 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2401 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 2402 // | Type | Length |Link-Layer Addr | 2403 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 2404 v6Gen.addLoad8intoR0(ICMP6_NS_OPTION_TYPE_OFFSET) 2405 .addCountAndPassIfR0NotEquals(ICMPV6_ND_OPTION_SLLA, PASSED_IPV6_ICMP); 2406 2407 // Src IPv6 address check: 2408 // if multicast address (FF::/8) or loopback address (00::/8) -> drop 2409 v6Gen.addLoad8intoR0(IPV6_SRC_ADDR_OFFSET) 2410 .addCountAndDropIfR0IsOneOf(Set.of(0L, 0xffL), DROPPED_IPV6_NS_INVALID); 2411 2412 // if multicast MAC in SLLA option -> drop 2413 v6Gen.addLoad8intoR0(ICMP6_NS_OPTION_TYPE_OFFSET + 2) 2414 .addCountAndDropIfR0AnyBitsSet(1, DROPPED_IPV6_NS_INVALID); 2415 generateNonDadNaTransmit(v6Gen); 2416 v6Gen.addCountAndDrop(DROPPED_IPV6_NS_REPLIED_NON_DAD); 2417 } 2418 2419 /** 2420 * Generates filter code to handle IPv6 mDNS packets. 2421 * <p> 2422 * On entry, this filter knows it is processing an IPv6 packet. It will then process all IPv6 2423 * mDNS packets, either passing or dropping them. IPv6 non-mDNS packets are skipped. 2424 * 2425 * @param gen the APF generator to generate the filter code 2426 * @param labelCheckMdnsQueryPayload the label to jump to for checking the mDNS query payload 2427 */ generateIPv6MdnsFilter(ApfV6GeneratorBase<?> gen, short labelCheckMdnsQueryPayload)2428 private void generateIPv6MdnsFilter(ApfV6GeneratorBase<?> gen, 2429 short labelCheckMdnsQueryPayload) throws IllegalInstructionException { 2430 final short skipMdnsFilter = gen.getUniqueLabel(); 2431 2432 // If the packet is too short to be a valid IPv6 mDNS packet, the filter is skipped. 2433 // For APF performance reasons, we check udp destination port before confirming it is IPv6 2434 // udp packet. We proceed only if the destination port is 5353 (mDNS). Otherwise, skip 2435 // filtering. 2436 gen.addLoadFromMemory(R0, MemorySlot.PACKET_SIZE) 2437 .addJumpIfR0LessThan( 2438 ETH_HEADER_LEN + IPV6_HEADER_LEN + UDP_HEADER_LEN + DNS_HEADER_LEN, 2439 skipMdnsFilter) 2440 .addLoad16intoR0(IPV6_UDP_DESTINATION_PORT_OFFSET) 2441 .addJumpIfR0NotEquals(MDNS_PORT, skipMdnsFilter); 2442 2443 // If the destination MAC address is not 33:33:00:00:00:fb (the mDNS multicast MAC 2444 // address for IPv6 mDNS packet) or the device's MAC address, skip filtering. 2445 // We need to check both the mDNS multicast MAC address and the device's MAC address 2446 // because multicast to unicast conversion might have occurred. 2447 gen.addJumpIfBytesAtOffsetEqualsNoneOf( 2448 ETH_DEST_ADDR_OFFSET, 2449 List.of(mHardwareAddress, ETH_MULTICAST_MDNS_V6_MAC_ADDRESS), 2450 skipMdnsFilter 2451 ); 2452 2453 // Skip filtering if the packet is not an IPv6 UDP packet. 2454 gen.addLoad8intoR0(IPV6_NEXT_HEADER_OFFSET) 2455 .addJumpIfR0NotEquals(IPPROTO_UDP, skipMdnsFilter); 2456 2457 // Skip filtering if the IPv6 destination address is not ff02::fb (the mDNS multicast 2458 // IPv6 address). 2459 // Some devices can use unicast queries for mDNS to improve performance and reliability. 2460 // These packets are not currently offloaded and will be passed by APF and handled 2461 // by NsdService. 2462 gen.addJumpIfBytesAtOffsetNotEqual(IPV6_DEST_ADDR_OFFSET, MDNS_IPV6_ADDR, skipMdnsFilter); 2463 2464 // We now know that the packet is an mDNS packet, 2465 // i.e., an IPv6 UDP packet destined for port 5353 with the expected destination MAC and IP 2466 // addresses. 2467 2468 // If the packet contains questions, check the query payload. Otherwise, check the 2469 // reply payload. 2470 gen.addLoad16intoR0(IPV6_DNS_QDCOUNT_OFFSET) 2471 // Set the UDP payload offset in R1 before potentially jumping to the payload 2472 // check logic. 2473 .addLoadImmediate(R1, IPv6_UDP_PAYLOAD_OFFSET) 2474 .addJumpIfR0NotEquals(0, labelCheckMdnsQueryPayload); 2475 2476 // TODO: check the reply payload. 2477 if (mMulticastFilter) { 2478 gen.addCountAndDrop(DROPPED_MDNS); 2479 } else { 2480 gen.addCountAndPass(PASSED_MDNS); 2481 } 2482 2483 gen.defineLabel(skipMdnsFilter); 2484 } 2485 2486 /** 2487 * Generate filter code to reply and drop unicast ICMPv6 echo request. 2488 * <p> 2489 * On entry, we know it is IPv6 packet, but don't know anything else. 2490 * R0 contains the u8 IPv6 next header. 2491 * R1 contains nothing useful in it, and can be clobbered. 2492 */ generateUnicastIpv6PingOffload(ApfV6GeneratorBase<?> gen)2493 private void generateUnicastIpv6PingOffload(ApfV6GeneratorBase<?> gen) 2494 throws IllegalInstructionException { 2495 2496 final short skipPing6Offload = gen.getUniqueLabel(); 2497 gen.addJumpIfR0NotEquals(IPPROTO_ICMPV6, skipPing6Offload); 2498 2499 gen.addLoad8intoR0(ICMP6_TYPE_OFFSET) 2500 .addJumpIfR0NotEquals(ICMPV6_ECHO_REQUEST_TYPE, skipPing6Offload); 2501 2502 // Only offload unicast ping6. 2503 // While we could potentially support offloading multicast and broadcast ping6 requests in 2504 // the future, such packets will likely be dropped by the multicast filter. 2505 // Since the device may have packet forwarding enabled, APF needs to pass any received 2506 // unicast ping6 not destined for the device's IP address to the kernel. 2507 final List<byte[]> nonTentativeIPv6Addrs = getIpv6Addresses( 2508 true /* includeNonTentative */, 2509 false /* includeTentative */, 2510 false /* includeAnycast */); 2511 gen.addJumpIfBytesAtOffsetNotEqual( 2512 ETHER_DST_ADDR_OFFSET, mHardwareAddress, skipPing6Offload) 2513 .addJumpIfBytesAtOffsetEqualsNoneOf( 2514 IPV6_DEST_ADDR_OFFSET, nonTentativeIPv6Addrs, skipPing6Offload); 2515 2516 // We need to check if the packet is sufficiently large to be a valid ICMPv6 echo packet. 2517 gen.addLoadFromMemory(R0, MemorySlot.PACKET_SIZE) 2518 .addCountAndDropIfR0LessThan( 2519 ETHER_HEADER_LEN + IPV6_HEADER_LEN + ICMP6_ECHO_REQUEST_HEADER_LEN, 2520 DROPPED_IPV6_ICMP6_ECHO_REQUEST_INVALID); 2521 2522 int hopLimit = mDependencies.getIpv6DefaultHopLimit(mInterfaceParams.name); 2523 // Construct the ICMPv6 echo reply packet. 2524 gen.addLoadFromMemory(R0, MemorySlot.PACKET_SIZE) 2525 .addAllocateR0() 2526 // Eth header 2527 .addPacketCopy(ETHER_SRC_ADDR_OFFSET, ETHER_ADDR_LEN) // Dst MAC address 2528 .addDataCopy(mHardwareAddress) // Src MAC address 2529 // Reuse the following fields from input packet 2530 // 2 byte: ethertype 2531 // 4 bytes: version, traffic class, flowlabel 2532 // 2 bytes: payload length 2533 // 1 byte: next header 2534 .addPacketCopy(ETH_ETHERTYPE_OFFSET, 9) 2535 .addWriteU8(hopLimit) 2536 .addPacketCopy(IPV6_DEST_ADDR_OFFSET, IPV6_ADDR_LEN) // Src ip 2537 .addPacketCopy(IPV6_SRC_ADDR_OFFSET, IPV6_ADDR_LEN) // Dst ip 2538 .addWriteU16((ICMP6_ECHO_REPLY << 8) | 0) // Type: echo reply, code: 0 2539 // Checksum: initialized to the IPv6 payload length as a partial checksum. The final 2540 // checksum will be calculated by the interpreter. 2541 .addPacketCopy(IPV6_PAYLOAD_LEN_OFFSET, 2) 2542 // Copy identifier, sequence number and ping payload 2543 .addSub(ICMP6_CONTENT_OFFSET) 2544 .addLoadImmediate(R1, ICMP6_CONTENT_OFFSET) 2545 .addSwap() // Swaps R0 and R1, so they're the offset and length. 2546 .addPacketCopyFromR0LenR1() 2547 .addTransmitL4( 2548 ETHER_HEADER_LEN, // ip_ofs 2549 ICMP6_CHECKSUM_OFFSET, // csum_ofs 2550 IPV6_SRC_ADDR_OFFSET, // csum_start 2551 IPPROTO_ICMPV6, // partial_sum 2552 false // udp 2553 ) 2554 .addCountAndDrop(DROPPED_IPV6_ICMP6_ECHO_REQUEST_REPLIED); 2555 2556 gen.defineLabel(skipPing6Offload); 2557 } 2558 2559 /** 2560 * Generate filter code to process IPv6 packets. Execution of this code ends in either the 2561 * DROP_LABEL or PASS_LABEL, or falls off the end for ICMPv6 packets. 2562 * Preconditions: 2563 * - Packet being filtered is IPv6 2564 * 2565 * @param gen the APF generator to generate the filter code 2566 * @param labelCheckMdnsQueryPayload the label to jump to for checking the mDNS query payload 2567 */ generateIPv6Filter(ApfV4GeneratorBase<?> gen, short labelCheckMdnsQueryPayload)2568 private void generateIPv6Filter(ApfV4GeneratorBase<?> gen, short labelCheckMdnsQueryPayload) 2569 throws IllegalInstructionException { 2570 // Here's a basic summary of what the IPv6 filter program does: 2571 // 2572 // if there is a HOPOPTS option present (e.g. MLD query) 2573 // (APFv6+ specific logic) 2574 // if MLD offload is enabled: 2575 // if it is an MLDv1 report/done or MLDv2 report: 2576 // drop 2577 // if the payload length is invalid (25, 26, 27): 2578 // drop 2579 // if the IPv6 src addr is not link-local address: 2580 // drop 2581 // if the IPv6 hop limit is not 1: 2582 // drop 2583 // if it is an multicast address specific query (the MLD multicast address is not "::"): 2584 // pass 2585 // if the IPv6 dst addr is not ff02::1: 2586 // drop 2587 // if it is an MLDv2 general query (payload length is not 24): 2588 // transmit MLDv2 report and drop 2589 // else it is an MLDv1 general query: 2590 // transmit MLDv1 reports (one report per multicast group) and drop 2591 // else 2592 // pass (on APFv2+) 2593 // 2594 // (APFv6+ specific logic) 2595 // if it's mDNS: 2596 // if it's a query: 2597 // if mNumOfMdnsRuleToOffload == -1: 2598 // pass 2599 // if the query matches one of the offload rules from idx [0, mNumOfMdnsRuleToOffload): 2600 // transmit mDNS reply and drop 2601 // else if query matches one of the rest of the offload rules: 2602 // pass 2603 // else if filtering multicast (i.e. multicast lock not held): 2604 // drop 2605 // else 2606 // pass 2607 // else: 2608 // if filtering multicast (i.e. multicast lock not held): 2609 // drop 2610 // else 2611 // pass 2612 // 2613 // (APFv6+ specific logic) if it's unicast ICMPv6 echo request to our host: 2614 // transmit echo reply and drop 2615 // 2616 // if we're dropping multicast 2617 // if it's not ICMPv6 or it's ICMPv6 but we're in doze mode: 2618 // if it's multicast: 2619 // drop 2620 // pass 2621 // 2622 // (APFv6+ specific logic) 2623 // if it's ICMPv6 NS: 2624 // if there are no IPv6 addresses (including link local address) on the interface: 2625 // pass 2626 // if MAC dst is none of known {unicast, multicast, broadcast} MAC addresses 2627 // drop 2628 // if IPv6 dst prefix is "ff02::1:ff00:0/104" but is none of solicited-node multicast 2629 // IPv6 addresses: 2630 // drop 2631 // else if IPv6 dst is none of interface unicast IPv6 addresses (incl. anycast): 2632 // drop 2633 // if hop limit is not 255 (NS requires hop limit to be 255): 2634 // drop 2635 // if payload len < 24 (8 bytes ICMP6 header + 16 bytes target address): 2636 // drop 2637 // if ICMPv6 code is not 0: 2638 // drop 2639 // if target IP is one of tentative IPv6 addresses: 2640 // pass 2641 // if target IP is none of non-tentative IPv6 addresses (incl. anycast): 2642 // drop 2643 // if IPv6 src is unspecified (::): 2644 // pass 2645 // if payload len < 32 (8 bytes ICMP6 header + 16 bytes target address + 8 bytes option): 2646 // pass 2647 // if IPv6 src is multicast address (FF::/8) or loopback address (00::/8): 2648 // drop 2649 // if multicast MAC in SLLA option: 2650 // drop 2651 // transmit NA and drop 2652 // 2653 // if it's ICMPv6 RS to any: 2654 // drop 2655 // 2656 // if it's ICMPv6 NA to anything in ff02::/120 2657 // drop 2658 // 2659 // if keepalive ack 2660 // drop 2661 2662 gen.addLoad8intoR0(IPV6_NEXT_HEADER_OFFSET); 2663 2664 if (enableMldOffload()) { 2665 generateMldFilter((ApfV6GeneratorBase<?>) gen); 2666 gen.addLoad8intoR0(IPV6_NEXT_HEADER_OFFSET); 2667 } else { 2668 gen.addCountAndPassIfR0Equals(IPPROTO_HOPOPTS, PASSED_IPV6_HOPOPTS); 2669 } 2670 2671 if (enableMdns6Offload()) { 2672 generateIPv6MdnsFilter((ApfV6GeneratorBase<?>) gen, labelCheckMdnsQueryPayload); 2673 gen.addLoad8intoR0(IPV6_NEXT_HEADER_OFFSET); 2674 } 2675 2676 if (enableIpv6PingOffload()) { 2677 generateUnicastIpv6PingOffload((ApfV6GeneratorBase<?>) gen); 2678 gen.addLoad8intoR0(IPV6_NEXT_HEADER_OFFSET); 2679 } 2680 2681 // Drop multicast if the multicast filter is enabled. 2682 if (mMulticastFilter) { 2683 final short skipIPv6MulticastFilterLabel = gen.getUniqueLabel(); 2684 final short dropAllIPv6MulticastsLabel = gen.getUniqueLabel(); 2685 2686 // While in doze mode, drop ICMPv6 multicast pings, let the others pass. 2687 // While awake, let all ICMPv6 multicasts through. 2688 if (mInDozeMode) { 2689 // Not ICMPv6? -> Proceed to multicast filtering 2690 gen.addJumpIfR0NotEquals(IPPROTO_ICMPV6, dropAllIPv6MulticastsLabel); 2691 2692 // ICMPv6 but not ECHO? -> Skip the multicast filter. 2693 // (ICMPv6 ECHO requests will go through the multicast filter below). 2694 gen.addLoad8intoR0(ICMP6_TYPE_OFFSET); 2695 gen.addJumpIfR0NotEquals(ICMPV6_ECHO_REQUEST_TYPE, skipIPv6MulticastFilterLabel); 2696 } else { 2697 gen.addJumpIfR0Equals(IPPROTO_ICMPV6, skipIPv6MulticastFilterLabel); 2698 } 2699 2700 // Drop all other packets sent to ff00::/8 (multicast prefix). 2701 gen.defineLabel(dropAllIPv6MulticastsLabel); 2702 gen.addLoad8intoR0(IPV6_DEST_ADDR_OFFSET); 2703 gen.addCountAndDropIfR0Equals(0xff, DROPPED_IPV6_NON_ICMP_MULTICAST); 2704 // If any keepalive filter matches, drop 2705 generateV6KeepaliveFilters(gen); 2706 // Not multicast. Pass. 2707 gen.addCountAndPass(PASSED_IPV6_UNICAST_NON_ICMP); 2708 gen.defineLabel(skipIPv6MulticastFilterLabel); 2709 } else { 2710 generateV6KeepaliveFilters(gen); 2711 // If not ICMPv6, pass. 2712 gen.addCountAndPassIfR0NotEquals(IPPROTO_ICMPV6, PASSED_IPV6_NON_ICMP); 2713 } 2714 2715 // If we got this far, the packet is ICMPv6. Drop some specific types. 2716 // Not ICMPv6 NS -> skip. 2717 gen.addLoad8intoR0(ICMP6_TYPE_OFFSET); // warning: also used further below. 2718 if (enableNdOffload()) { 2719 final short skipNsPacketFilter = gen.getUniqueLabel(); 2720 gen.addJumpIfR0NotEquals(ICMPV6_NEIGHBOR_SOLICITATION, skipNsPacketFilter); 2721 generateNsFilter((ApfV6GeneratorBase<?>) gen); 2722 // End of NS filter. generateNsFilter() method is terminal, so NS packet will be 2723 // either dropped or passed inside generateNsFilter(). 2724 gen.defineLabel(skipNsPacketFilter); 2725 } 2726 2727 // Add unsolicited multicast neighbor announcements filter 2728 short skipUnsolicitedMulticastNALabel = gen.getUniqueLabel(); 2729 // Drop all router solicitations (b/32833400) 2730 gen.addCountAndDropIfR0Equals(ICMPV6_ROUTER_SOLICITATION, DROPPED_IPV6_ROUTER_SOLICITATION); 2731 // If not neighbor announcements, skip filter. 2732 gen.addJumpIfR0NotEquals(ICMPV6_NEIGHBOR_ADVERTISEMENT, skipUnsolicitedMulticastNALabel); 2733 // Drop all multicast NA to ff02::/120. 2734 // This is a way to cover ff02::1 and ff02::2 with a single JNEBS. 2735 // TODO: Drop only if they don't contain the address of on-link neighbours. 2736 final byte[] unsolicitedNaDropPrefix = Arrays.copyOf(IPV6_ALL_NODES_ADDRESS, 15); 2737 gen.addJumpIfBytesAtOffsetNotEqual( 2738 IPV6_DEST_ADDR_OFFSET, unsolicitedNaDropPrefix, skipUnsolicitedMulticastNALabel); 2739 2740 gen.addCountAndDrop(DROPPED_IPV6_MULTICAST_NA); 2741 gen.defineLabel(skipUnsolicitedMulticastNALabel); 2742 } 2743 2744 /** 2745 * Creates the portion of an IGMP packet from the Ethernet source MAC address to the IPv4 2746 * Type of Service field. 2747 */ createIgmpPktFromEthSrcToIPv4Tos()2748 private byte[] createIgmpPktFromEthSrcToIPv4Tos() { 2749 return CollectionUtils.concatArrays( 2750 mHardwareAddress, 2751 new byte[] { 2752 // etherType: IPv4 2753 (byte) 0x08, 0x00, 2754 // version, IHL 2755 (byte) 0x46, 2756 // Tos: 0xC0 (ref: net/ipv4/igmp.c#igmp_send_report()) 2757 (byte) 0xc0} 2758 ); 2759 } 2760 2761 /** 2762 * Creates the portion of an IGMP packet from the IPv4 Identification field to the IPv4 2763 * Source Address. 2764 */ createIgmpPktFromIPv4IdToSrc()2765 private byte[] createIgmpPktFromIPv4IdToSrc() { 2766 final byte[] ipIdToSrc = new byte[] { 2767 // identification 2768 0, 0, 2769 // fragment flag 2770 (byte) (IPV4_FLAG_DF >> 8), 0, 2771 // TTL 2772 (byte) 1, 2773 // protocol 2774 (byte) IPV4_PROTOCOL_IGMP, 2775 // router alert option is { 0x94, 0x04, 0x00, 0x00 }, so we precalculate IPv4 2776 // checksum as 0x9404 + 0x0000 = 0x9404 2777 (byte) 0x94, (byte) 0x04 2778 }; 2779 return CollectionUtils.concatArrays( 2780 ipIdToSrc, 2781 mIPv4Address 2782 ); 2783 } 2784 2785 /** 2786 * Creates IGMPv3 Membership Report packet payload (rfc3376#section-7.3.2). 2787 */ createIgmpV3ReportPayload()2788 private byte[] createIgmpV3ReportPayload() { 2789 final int groupNum = mIPv4McastAddrsExcludeAllHost.size(); 2790 final byte[] igmpHeader = new byte[] { 2791 // IGMP type 2792 (byte) IPV4_IGMP_TYPE_V3_REPORT, 2793 // reserved 2794 0, 2795 // checksum, calculate later 2796 0, 0, 2797 // reserved 2798 0, 0, 2799 // num group records 2800 (byte) ((groupNum >> 8) & 0xff), (byte) (groupNum & 0xff) 2801 }; 2802 final byte[] groupRecordHeader = new byte[] { 2803 // record type 2804 (byte) IGMPV3_MODE_IS_EXCLUDE, 2805 // aux data len, 2806 0, 2807 // num src 2808 0, 0 2809 }; 2810 final byte[] payload = 2811 new byte[igmpHeader.length + groupNum * (groupRecordHeader.length + IPV4_ADDR_LEN)]; 2812 int offset = 0; 2813 2814 System.arraycopy(igmpHeader, 0, payload, offset, igmpHeader.length); 2815 offset += igmpHeader.length; 2816 for (Inet4Address mcastAddr: mIPv4McastAddrsExcludeAllHost) { 2817 System.arraycopy(groupRecordHeader, 0, payload, offset, groupRecordHeader.length); 2818 offset += groupRecordHeader.length; 2819 System.arraycopy(mcastAddr.getAddress(), 0, payload, offset, IPV4_ADDR_LEN); 2820 offset += IPV4_ADDR_LEN; 2821 } 2822 2823 return payload; 2824 } 2825 2826 /** 2827 * Generate transmit code to send IGMPv3 report in response to general query packets. 2828 */ generateIgmpV3ReportTransmit(ApfV6GeneratorBase<?> gen, byte[] igmpPktFromEthSrcToIpTos, byte[] igmpPktFromIpIdToSrc)2829 private void generateIgmpV3ReportTransmit(ApfV6GeneratorBase<?> gen, 2830 byte[] igmpPktFromEthSrcToIpTos, byte[] igmpPktFromIpIdToSrc) 2831 throws IllegalInstructionException { 2832 // We place template packet chunks in the data region first to reduce the number of 2833 // instructions needed for creating multiple IGMPv2 reports. 2834 // The following packet chunks can be used for creating both IGMPv2 and IGMPv3 reports: 2835 // - from Ethernet source to IPv4 Tos: 10 bytes 2836 // - from IPv4 identification to source address: 12 bytes 2837 final int igmpV2Ipv4TotalLen = 2838 IPV4_HEADER_MIN_LEN + IPV4_ROUTER_ALERT_OPTION_LEN + IPV4_IGMP_MIN_SIZE; 2839 final byte[] igmpV3ReportPayload = createIgmpV3ReportPayload(); 2840 final byte[] igmpReportTemplate = CollectionUtils.concatArrays( 2841 ETH_MULTICAST_IGMP_V3_ALL_MULTICAST_ROUTERS_ADDRESS, 2842 igmpPktFromEthSrcToIpTos, 2843 new byte[] { 2844 (byte) ((igmpV2Ipv4TotalLen >> 8) & 0xff), 2845 (byte) (igmpV2Ipv4TotalLen & 0xff), 2846 }, 2847 igmpPktFromIpIdToSrc, 2848 IPV4_ALL_IGMPV3_MULTICAST_ROUTERS_ADDRESS, 2849 IPV4_ROUTER_ALERT_OPTION, 2850 igmpV3ReportPayload 2851 ); 2852 gen.maybeUpdateDataRegion(igmpReportTemplate); 2853 2854 final int ipv4TotalLen = IPV4_HEADER_MIN_LEN 2855 + IPV4_ROUTER_ALERT_OPTION_LEN 2856 + IPV4_IGMP_MIN_SIZE 2857 + (mIPv4McastAddrsExcludeAllHost.size() * IPV4_IGMP_GROUP_RECORD_SIZE); 2858 final byte[] igmpV3FromEthDstToIpTos = CollectionUtils.concatArrays( 2859 ETH_MULTICAST_IGMP_V3_ALL_MULTICAST_ROUTERS_ADDRESS, 2860 igmpPktFromEthSrcToIpTos 2861 ); 2862 final byte[] igmpV3PktFromIpIdToEnd = CollectionUtils.concatArrays( 2863 igmpPktFromIpIdToSrc, 2864 IPV4_ALL_IGMPV3_MULTICAST_ROUTERS_ADDRESS, 2865 IPV4_ROUTER_ALERT_OPTION, 2866 igmpV3ReportPayload 2867 ); 2868 gen.addAllocate(ETHER_HEADER_LEN + ipv4TotalLen) 2869 .addDataCopy(igmpV3FromEthDstToIpTos) 2870 .addWriteU16(ipv4TotalLen) 2871 .addDataCopy(igmpV3PktFromIpIdToEnd) 2872 .addTransmitL4( 2873 // ip_ofs 2874 ETHER_HEADER_LEN, 2875 // csum_ofs 2876 IGMP_CHECKSUM_WITH_ROUTER_ALERT_OFFSET, 2877 // csum_start 2878 ETHER_HEADER_LEN + IPV4_HEADER_MIN_LEN + IPV4_ROUTER_ALERT_OPTION_LEN, 2879 // partial_sum 2880 0, 2881 // udp 2882 false 2883 ) 2884 .addCountAndDrop(Counter.DROPPED_IGMP_V3_GENERAL_QUERY_REPLIED); 2885 } 2886 2887 /** 2888 * Generate transmit code to send IGMPv2 report in response to general query packets. 2889 */ generateIgmpV2ReportTransmit(ApfV6GeneratorBase<?> gen, byte[] igmpPktFromEthSrcToIpTos, byte[] igmpPktFromIpIdToSrc)2890 private void generateIgmpV2ReportTransmit(ApfV6GeneratorBase<?> gen, 2891 byte[] igmpPktFromEthSrcToIpTos, byte[] igmpPktFromIpIdToSrc) 2892 throws IllegalInstructionException { 2893 final int ipv4TotalLen = 2894 IPV4_HEADER_MIN_LEN + IPV4_ROUTER_ALERT_OPTION_LEN + IPV4_IGMP_MIN_SIZE; 2895 final byte[] igmpV2PktFromEthSrcToIpSrc = CollectionUtils.concatArrays( 2896 igmpPktFromEthSrcToIpTos, 2897 new byte[] { 2898 (byte) ((ipv4TotalLen >> 8) & 0xff), (byte) (ipv4TotalLen & 0xff), 2899 }, 2900 igmpPktFromIpIdToSrc 2901 ); 2902 for (Inet4Address mcastAddr: mIPv4McastAddrsExcludeAllHost) { 2903 final MacAddress mcastEther = 2904 NetworkStackUtils.ipv4MulticastToEthernetMulticast(mcastAddr); 2905 gen.addAllocate(ETHER_HEADER_LEN + ipv4TotalLen) 2906 .addDataCopy(mcastEther.toByteArray()) 2907 .addDataCopy(igmpV2PktFromEthSrcToIpSrc) 2908 .addDataCopy(mcastAddr.getAddress()) 2909 .addDataCopy(IGMPV2_REPORT_FROM_IPV4_OPTION_TO_IGMP_CHECKSUM) 2910 .addDataCopy(mcastAddr.getAddress()) 2911 .addTransmitL4( 2912 // ip_ofs 2913 ETHER_HEADER_LEN, 2914 // csum_ofs 2915 IGMP_CHECKSUM_WITH_ROUTER_ALERT_OFFSET, 2916 // csum_start 2917 ETHER_HEADER_LEN + IPV4_HEADER_MIN_LEN + IPV4_ROUTER_ALERT_OPTION_LEN, 2918 // partial_sum 2919 0, 2920 // udp 2921 false 2922 ); 2923 } 2924 2925 gen.addCountAndDrop(Counter.DROPPED_IGMP_V2_GENERAL_QUERY_REPLIED); 2926 } 2927 2928 /** 2929 * Generates filter code to handle IGMP packets. 2930 * <p> 2931 * On entry, this filter know it is processing an IPv4 packet. It will then process all IGMP 2932 * packets, either passing or dropping them. Non-IGMP packets are skipped. 2933 */ generateIgmpFilter(ApfV6GeneratorBase<?> v6Gen)2934 private void generateIgmpFilter(ApfV6GeneratorBase<?> v6Gen) 2935 throws IllegalInstructionException { 2936 final short skipIgmpFilter = v6Gen.getUniqueLabel(); 2937 final short checkIgmpV1orV2 = v6Gen.getUniqueLabel(); 2938 2939 // Check 1) it's not a fragment. 2) it's IGMP. 2940 v6Gen.addJumpIfNotUnfragmentedIPv4Protocol(IPV4_PROTOCOL_IGMP, skipIgmpFilter); 2941 2942 // Calculate the IPv4 payload length: (total length - IPv4 header length). 2943 // Memory slot 0 is occupied temporarily to store the length. 2944 v6Gen.addLoad16intoR0(IPV4_TOTAL_LENGTH_OFFSET) 2945 .addLoadFromMemory(R1, MemorySlot.IPV4_HEADER_SIZE) 2946 .addNeg(R1) 2947 .addAddR1ToR0() 2948 .addStoreToMemory(MemorySlot.SLOT_0, R0); 2949 2950 // If payload length is less than 8 or equal to 9, 10, 11, it's invalid IGMP packet: drop. 2951 v6Gen.addCountAndDropIfR0LessThan(IPV4_IGMP_MIN_SIZE, DROPPED_IGMP_INVALID) 2952 .addCountAndDropIfR0IsOneOf(Set.of(9L, 10L, 11L), DROPPED_IGMP_INVALID); 2953 2954 // If it's an IGMPv1/IGMPv2/IGMPv3 report: drop. 2955 // A host normally cancels its own pending report if it observes 2956 // an identical report from another host on the network (host suppression). 2957 // While dropping reports here technically disrupts this host's suppression behavior, 2958 // it is acceptable since other devices on the network will perform the suppression. 2959 // If the IGMP type is not one of the reports, it's either a query(type=0x11) or an 2960 // invalid packet. 2961 v6Gen.addLoadFromMemory(R1, MemorySlot.IPV4_HEADER_SIZE) 2962 .addLoad8R1IndexedIntoR0(ETHER_HEADER_LEN) 2963 .addCountAndDropIfR0IsOneOf(IGMP_TYPE_REPORTS, DROPPED_IGMP_REPORT) 2964 .addCountAndDropIfR0NotEquals(IPV4_IGMP_TYPE_QUERY, DROPPED_IGMP_INVALID); 2965 2966 // If group address is not 0.0.0.0, it's an IGMPv2/v3 group specific query: pass. 2967 // rfc3376#section-6.1 mentions group specific queries are sent when a router receives a 2968 // State-Change record indicating a system is leaving a group. Therefore, since the 2969 // router only sends group-specific queries after receiving a leave message, it is not 2970 // sent out periodically. 2971 // Increased APF bytecode size for offloading these queries may not yield significant 2972 // power benefits. In this case, letting the kernel handle group-specific queries is 2973 // acceptable. 2974 v6Gen.addLoad32R1IndexedIntoR0(IGMP_MULTICAST_ADDRESS_OFFSET) 2975 .addCountAndPassIfR0NotEquals(0 /* 0.0.0.0 */, PASSED_IPV4); 2976 2977 // If we reach here, we know it is an IGMPv1/IGMPv2/IGMPv3 general query. 2978 2979 // The general query IPv4 destination address must be 224.0.0.1. 2980 v6Gen.addLoad32intoR0(IPV4_DEST_ADDR_OFFSET) 2981 .addCountAndDropIfR0NotEquals(IPV4_ALL_HOSTS_ADDRESS_IN_LONG, 2982 DROPPED_IGMP_INVALID); 2983 2984 // Check payload length, since invalid length already checked, 2985 // it should be 8 (IGMPv1 or IGMPv2) or >=12 (IGMPv3) 2986 v6Gen.addLoadFromMemory(R0, MemorySlot.SLOT_0) 2987 .addJumpIfR0Equals(IPV4_IGMP_MIN_SIZE, checkIgmpV1orV2); 2988 2989 // ===== IGMPv3 general query ===== 2990 // To optimize for bytecode size, the IGMPv3 report is constructed first. 2991 // Its packet structure is then reused as a template when creating the IGMPv2 report. 2992 final byte[] igmpPktFromEthSrcToIpTos = createIgmpPktFromEthSrcToIPv4Tos(); 2993 final byte[] igmpPktFromIpIdToSrc = createIgmpPktFromIPv4IdToSrc(); 2994 generateIgmpV3ReportTransmit(v6Gen, igmpPktFromEthSrcToIpTos, igmpPktFromIpIdToSrc); 2995 2996 // ===== IGMPv1 or IGMPv2 general query ===== 2997 v6Gen.defineLabel(checkIgmpV1orV2); 2998 // Based on rfc3376#section-7.1 If max resp time is 0, it's IGMPv1: pass. 2999 // We don't expect many networks are still using IGMPv1, pass it to the kernel to save 3000 // bytecode size. 3001 // (Note: R1 is still IPV4_HEADER_SIZE) 3002 v6Gen.addLoad8R1IndexedIntoR0(IGMP_MAX_RESP_TIME_OFFSET) 3003 .addCountAndPassIfR0Equals(0, PASSED_IPV4); // IGMPv1 3004 3005 // Drop and transmit IGMPv2 reports 3006 generateIgmpV2ReportTransmit(v6Gen, igmpPktFromEthSrcToIpTos, igmpPktFromIpIdToSrc); 3007 3008 v6Gen.defineLabel(skipIgmpFilter); 3009 } 3010 3011 /** 3012 * Creates MLDv1 Listener Report packet message (rfc2710#section-3). 3013 */ createMldV1ReportMessage(final Inet6Address mcastAddr)3014 private byte[] createMldV1ReportMessage(final Inet6Address mcastAddr) { 3015 final byte[] mldv1Header = new byte[] { 3016 // MLD type 3017 (byte) IPV6_MLD_TYPE_V1_REPORT, 3018 // code 3019 0, 3020 // hop-by-hop option is { 0x3a, 0x00, 0x05, 0x02, 0x00, 0x00, 0x01, 0x00 } 3021 // so we precalculate MLD checksum as follows: 3022 // 0xffff - (0x3a00 + 0x0502 + 0x0000 + 0x0100) = 0xbffd 3023 (byte) 0xbf, (byte) 0xfd, 3024 // max response delay 3025 0, 0, 3026 // reserved 3027 0, 0 3028 }; 3029 3030 return CollectionUtils.concatArrays(mldv1Header, mcastAddr.getAddress()); 3031 } 3032 3033 /** 3034 * Creates MLDv2 Listener Report packet payload (rfc3810#section-5.2). 3035 */ createMldV2ReportPayload()3036 private byte[] createMldV2ReportPayload() { 3037 final int mcastAddrsNum = mIPv6McastAddrsExcludeAllHost.size(); 3038 final byte[] mldHeader = new byte[] { 3039 // MLD type 3040 (byte) IPV6_MLD_TYPE_V2_REPORT, 3041 // code 3042 0, 3043 // hop-by-hop option is { 0x3a, 0x00, 0x05, 0x02, 0x00, 0x00, 0x01, 0x00 } 3044 // so we precalculate MLD checksum as follows: 3045 // 0xffff - (0x3a00 + 0x0502 + 0x0000 + 0x0100) = 0xbffd 3046 (byte) 0xbf, (byte) 0xfd, 3047 // reserved 3048 0, 0, 3049 // num of multicast address records 3050 (byte) ((mcastAddrsNum >> 8) & 0xff), (byte) (mcastAddrsNum & 0xff) 3051 }; 3052 3053 final byte[] mcastRecordHeader = new byte[] { 3054 // record type 3055 (byte) MLD2_MODE_IS_EXCLUDE, 3056 // aux data len, 3057 0, 3058 // num src 3059 0, 0 3060 }; 3061 3062 final byte[] payload = 3063 new byte[ 3064 mldHeader.length + mcastAddrsNum * IPV6_MLD_V2_MULTICAST_ADDRESS_RECORD_SIZE 3065 ]; 3066 int offset = 0; 3067 3068 System.arraycopy(mldHeader, 0, payload, offset, mldHeader.length); 3069 offset += mldHeader.length; 3070 for (Inet6Address mcastAddr: mIPv6McastAddrsExcludeAllHost) { 3071 System.arraycopy(mcastRecordHeader, 0, payload, offset, mcastRecordHeader.length); 3072 offset += mcastRecordHeader.length; 3073 System.arraycopy(mcastAddr.getAddress(), 0, payload, offset, IPV6_ADDR_LEN); 3074 offset += IPV6_ADDR_LEN; 3075 } 3076 3077 return payload; 3078 } 3079 3080 /** 3081 * Creates the portion of an MLD packet from the Ethernet source MAC address to the IPv6 3082 * VTF field. 3083 */ createMldPktFromEthSrcToIPv6Vtf()3084 private byte[] createMldPktFromEthSrcToIPv6Vtf() { 3085 return CollectionUtils.concatArrays( 3086 mHardwareAddress, 3087 new byte[] { 3088 // etherType: IPv6 3089 (byte) 0x86, (byte) 0xdd, 3090 // version, traffic class, flow label 3091 // 0x60000000 (ref: net/ipv6/mcast.c#ip6_mc_hdr()) 3092 (byte) 0x60, 0, 0, 0} 3093 ); 3094 } 3095 3096 /** 3097 * Creates the portion of an MLD packet from the IPv6 Next Header to the IPv6 Source Address. 3098 */ createMldPktFromIPv6NextHdrToSrc()3099 private byte[] createMldPktFromIPv6NextHdrToSrc() { 3100 final byte[] ipv6FromNextHdrToHoplimit = new byte[] { 3101 // Next header: HOPOPTS 3102 0, 3103 // Hop limit 3104 (byte) 1 3105 }; 3106 return CollectionUtils.concatArrays( 3107 ipv6FromNextHdrToHoplimit, 3108 mIPv6LinkLocalAddress.getAddress() 3109 ); 3110 } 3111 3112 /** 3113 * Generate transmit code to send MLDv1 report in response to general query packets. 3114 */ generateMldV1ReportTransmit(ApfV6GeneratorBase<?> gen, byte[] mldPktFromEthSrcToIpv6Vtf, byte[] mldPktFromIpv6NextHdrToSrc)3115 private void generateMldV1ReportTransmit(ApfV6GeneratorBase<?> gen, 3116 byte[] mldPktFromEthSrcToIpv6Vtf, byte[] mldPktFromIpv6NextHdrToSrc) 3117 throws IllegalInstructionException { 3118 final int packetSize = 3119 ETHER_HEADER_LEN 3120 + IPV6_HEADER_LEN 3121 + IPV6_MLD_HOPOPTS.length 3122 + IPV6_MLD_V1_MESSAGE_SIZE; 3123 final int mldV1Ipv6PayloadLength = IPV6_MLD_HOPOPTS.length + IPV6_MLD_V1_MESSAGE_SIZE; 3124 final byte[] mldV1PktFromEthSrcToIpv6Src = CollectionUtils.concatArrays( 3125 mldPktFromEthSrcToIpv6Vtf, 3126 new byte[] { 3127 (byte) ((mldV1Ipv6PayloadLength >> 8) & 0xff), 3128 (byte) (mldV1Ipv6PayloadLength & 0xff), 3129 }, 3130 mldPktFromIpv6NextHdrToSrc 3131 ); 3132 for (Inet6Address mcastAddr: mIPv6McastAddrsExcludeAllHost) { 3133 final MacAddress mcastEther = 3134 NetworkStackUtils.ipv6MulticastToEthernetMulticast(mcastAddr); 3135 gen.addAllocate(packetSize) 3136 .addDataCopy(mcastEther.toByteArray()) 3137 .addDataCopy(mldV1PktFromEthSrcToIpv6Src) 3138 .addDataCopy(mcastAddr.getAddress()) 3139 .addDataCopy(IPV6_MLD_HOPOPTS) 3140 .addDataCopy(createMldV1ReportMessage(mcastAddr)) 3141 .addTransmitL4( 3142 // ip_ofs 3143 ETHER_HEADER_LEN, 3144 // csum_ofs 3145 IPV6_MLD_CHECKSUM_OFFSET, 3146 // csum_start 3147 IPV6_SRC_ADDR_OFFSET, 3148 // partial_sum 3149 IPPROTO_ICMPV6 + IPV6_MLD_V1_MESSAGE_SIZE, 3150 // udp 3151 false 3152 ); 3153 } 3154 3155 gen.addCountAndDrop(DROPPED_IPV6_MLD_V1_GENERAL_QUERY_REPLIED); 3156 } 3157 3158 /** 3159 * Generate transmit code to send MLDv2 report in response to general query packets. 3160 */ generateMldV2ReportTransmit(ApfV6GeneratorBase<?> gen, byte[] mldPktFromEthSrcToIpv6Vtf, byte[] mldPktFromIpv6NextHdrToSrc)3161 private void generateMldV2ReportTransmit(ApfV6GeneratorBase<?> gen, 3162 byte[] mldPktFromEthSrcToIpv6Vtf, byte[] mldPktFromIpv6NextHdrToSrc) 3163 throws IllegalInstructionException { 3164 final int mldV1Ipv6PayloadLength = IPV6_MLD_HOPOPTS.length + IPV6_MLD_V1_MESSAGE_SIZE; 3165 final byte[] encodedMldV1Ipv6PayloadLength = { 3166 (byte) ((mldV1Ipv6PayloadLength >> 8) & 0xff), (byte) (mldV1Ipv6PayloadLength & 0xff), 3167 }; 3168 // We place template packet chunks in the data region first to reduce the number of 3169 // instructions needed for creating multiple MLDv1 reports. 3170 // The following packet chunks can be used for creating both MLDv1 and MLDv2 reports: 3171 // - from Ethernet source to IPv6 VTF: 12 bytes 3172 // - from IPv6 next header to source address: 18 bytes 3173 final byte[] mldV2ReportPayload = createMldV2ReportPayload(); 3174 final byte[] template = CollectionUtils.concatArrays( 3175 ETH_MULTICAST_MLD_V2_ALL_MULTICAST_ROUTERS_ADDRESS, 3176 mldPktFromEthSrcToIpv6Vtf, 3177 encodedMldV1Ipv6PayloadLength, 3178 mldPktFromIpv6NextHdrToSrc, 3179 IPV6_MLD_V2_ALL_ROUTERS_MULTICAST_ADDRESS, 3180 IPV6_MLD_HOPOPTS, 3181 mldV2ReportPayload 3182 ); 3183 gen.maybeUpdateDataRegion(template); 3184 3185 final byte[] mldV2PktFromEthDstToIpv6Vtf = CollectionUtils.concatArrays( 3186 ETH_MULTICAST_MLD_V2_ALL_MULTICAST_ROUTERS_ADDRESS, 3187 mldPktFromEthSrcToIpv6Vtf 3188 ); 3189 final byte[] mldV2PktFromIpv6NextHdrToEnd = CollectionUtils.concatArrays( 3190 mldPktFromIpv6NextHdrToSrc, 3191 IPV6_MLD_V2_ALL_ROUTERS_MULTICAST_ADDRESS, 3192 IPV6_MLD_HOPOPTS, 3193 mldV2ReportPayload 3194 ); 3195 final int mcastAddrsNum = mIPv6McastAddrsExcludeAllHost.size(); 3196 final int ipv6PayloadLength = IPV6_MLD_HOPOPTS.length 3197 + IPV6_MLD_MESSAGE_MIN_SIZE 3198 + (mcastAddrsNum * IPV6_MLD_V2_MULTICAST_ADDRESS_RECORD_SIZE); 3199 gen.addAllocate(ETHER_HEADER_LEN + IPV6_HEADER_LEN + ipv6PayloadLength) 3200 .addDataCopy(mldV2PktFromEthDstToIpv6Vtf) 3201 .addWriteU16(ipv6PayloadLength) 3202 .addDataCopy(mldV2PktFromIpv6NextHdrToEnd) 3203 .addTransmitL4( 3204 // ip_ofs 3205 ETHER_HEADER_LEN, 3206 // csum_ofs 3207 IPV6_MLD_CHECKSUM_OFFSET, 3208 // csum_start 3209 IPV6_SRC_ADDR_OFFSET, 3210 // partial_sum 3211 IPPROTO_ICMPV6 + (ipv6PayloadLength - IPV6_MLD_HOPOPTS.length), 3212 // udp 3213 false 3214 ).addCountAndDrop(DROPPED_IPV6_MLD_V2_GENERAL_QUERY_REPLIED); 3215 } 3216 3217 /** 3218 * Generates filter code to handle MLD packets. 3219 * <p> 3220 * On entry, this filter knows it is processing an IPv6 packet. It will then process all MLD 3221 * packets, either passing or dropping them. Non-MLD packets are skipped. 3222 * R0 contains the u8 IPv6 next header. 3223 */ generateMldFilter(ApfV6GeneratorBase<?> gen)3224 private void generateMldFilter(ApfV6GeneratorBase<?> gen) 3225 throws IllegalInstructionException { 3226 final short skipMldFilter = gen.getUniqueLabel(); 3227 final short checkMldv1 = gen.getUniqueLabel(); 3228 3229 // If next header is not hop-by-hop, then skip 3230 gen.addJumpIfR0NotEquals(IPPROTO_HOPOPTS, skipMldFilter); 3231 3232 final int mldPacketMinSize = 3233 ETHER_HEADER_LEN + IPV6_HEADER_LEN + IPV6_MLD_HOPOPTS.length + IPV6_MLD_MIN_SIZE; 3234 // If packet is too small to be MLD packet, then skip 3235 gen.addLoadFromMemory(R0, MemorySlot.PACKET_SIZE) 3236 .addJumpIfR0LessThan(mldPacketMinSize, skipMldFilter) 3237 .addSub(ETHER_HEADER_LEN + IPV6_HEADER_LEN + IPV6_MLD_HOPOPTS.length) 3238 // Memory slot 0 is occupied temporarily to store the MLD payload length. 3239 .addStoreToMemory(MemorySlot.SLOT_0, R0); 3240 3241 // If the hop-by-hop option is not the one used by MLD, then skip 3242 gen.addLoadImmediate(R0, IPV6_EXT_HEADER_OFFSET) 3243 .addJumpIfBytesAtR0NotEqual(IPV6_MLD_HOPOPTS, skipMldFilter); 3244 3245 // If the packet is an MLDv1 report or done, or an MLDv2 report, then drop it. 3246 // Else if the packet is not an MLD query packet, then skip. 3247 gen.addLoad8intoR0(IPV6_MLD_TYPE_OFFSET) 3248 .addCountAndDropIfR0IsOneOf(IPV6_MLD_TYPE_REPORTS, DROPPED_IPV6_MLD_REPORT) 3249 .addJumpIfR0NotEquals(IPV6_MLD_TYPE_QUERY, skipMldFilter); 3250 3251 // If we reach here, we know it is an MLDv1/MLDv2 query. 3252 3253 // If the payload length is 25, 26, or 27, the MLD packet is invalid and should be dropped. 3254 gen.addLoadFromMemory(R0, MemorySlot.SLOT_0) 3255 .addCountAndDropIfR0IsOneOf(Set.of(25L, 26L, 27L), DROPPED_IPV6_MLD_INVALID); 3256 3257 // rfc3810#section-5 and rfc2710#section-3 describe that all MLD messages are sent with a 3258 // link-local IPv6 source address, an IPv6 Hop Limit of 1, and an IPv6 Router Alert 3259 // option [RTR-ALERT] in a Hop-by-Hop Options header. 3260 // rfc3810#section-5.2.13 describes that an MLDv2 Report MUST be sent with a valid 3261 // IPv6 link-local source address, or the unspecified address (::), if the sending interface 3262 // has not yet acquired a valid link-local address. 3263 // Its OK to not check :: here since we also drop MLD reports. 3264 // If the source address is a not a link-local address, then drop. 3265 gen.addLoad16intoR0(IPV6_SRC_ADDR_OFFSET) 3266 .addCountAndDropIfR0NotEquals(0xfe80, DROPPED_IPV6_MLD_INVALID); 3267 3268 // If hop limit is not 1, then drop. 3269 gen.addLoad8intoR0(IPV6_HOP_LIMIT_OFFSET) 3270 .addCountAndDropIfR0NotEquals(1, DROPPED_IPV6_MLD_INVALID); 3271 3272 // If the multicast address is not "::", it is an MLD2 multicast-address-specific query, 3273 // then pass. 3274 gen.addCountAndPassIfBytesAtOffsetNotEqual( 3275 IPV6_MLD_MULTICAST_ADDR_OFFSET, IPV6_ADDR_ANY.getAddress(), PASSED_IPV6_ICMP); 3276 3277 // If we reach here, we know it is an MLDv1/MLDv2 general query. 3278 3279 // The general query IPv6 destination address must be ff02::1. 3280 gen.addCountAndDropIfBytesAtOffsetNotEqual( 3281 IPV6_DEST_ADDR_OFFSET, IPV6_ALL_NODES_ADDRESS, DROPPED_IPV6_MLD_INVALID); 3282 3283 // If the MLD payload length is 24, it is an MLDv1 packet, otherwise, it is an MLDv2 packet. 3284 gen.addLoadFromMemory(R0, MemorySlot.SLOT_0) 3285 .addJumpIfR0Equals(IPV6_MLD_MIN_SIZE, checkMldv1); 3286 3287 // ===== MLDv2 general query ===== 3288 // To optimize for bytecode size, the MLDv2 report is constructed first. 3289 // Its packet structure is then reused as a template when creating the IGMPv1 report. 3290 final byte[] mldPktFromEthSrcToIPv6Vtf = createMldPktFromEthSrcToIPv6Vtf(); 3291 final byte[] mldPktFromIPv6NextHdrToSrc = createMldPktFromIPv6NextHdrToSrc(); 3292 generateMldV2ReportTransmit(gen, mldPktFromEthSrcToIPv6Vtf, mldPktFromIPv6NextHdrToSrc); 3293 3294 gen.defineLabel(checkMldv1); 3295 // ===== MLDv1 general query ===== 3296 generateMldV1ReportTransmit(gen, mldPktFromEthSrcToIPv6Vtf, mldPktFromIPv6NextHdrToSrc); 3297 3298 gen.defineLabel(skipMldFilter); 3299 } 3300 3301 /** 3302 * Generate filter code to drop IPv4 TCP packets on port 7. 3303 * <p> 3304 * On entry, we know it is IPv4 ethertype, but don't know anything else. 3305 * R0/R1 have nothing useful in them, and can be clobbered. 3306 */ generateV4TcpPort7Filter(ApfV4GeneratorBase<?> gen)3307 private void generateV4TcpPort7Filter(ApfV4GeneratorBase<?> gen) 3308 throws IllegalInstructionException { 3309 final short skipPort7V4Filter = gen.getUniqueLabel(); 3310 3311 // Check it's TCP. 3312 gen.addLoad8intoR0(IPV4_PROTOCOL_OFFSET); 3313 gen.addJumpIfR0NotEquals(IPPROTO_TCP, skipPort7V4Filter); 3314 3315 // Check it's not a fragment or is the initial fragment. 3316 gen.addLoad16intoR0(IPV4_FRAGMENT_OFFSET_OFFSET); 3317 gen.addJumpIfR0AnyBitsSet(IPV4_FRAGMENT_OFFSET_MASK, skipPort7V4Filter); 3318 3319 // Check it's destination port 7. 3320 gen.addLoadFromMemory(R1, MemorySlot.IPV4_HEADER_SIZE); 3321 gen.addLoad16R1IndexedIntoR0(TCP_UDP_DESTINATION_PORT_OFFSET); 3322 gen.addJumpIfR0NotEquals(ECHO_PORT, skipPort7V4Filter); 3323 3324 // Drop it. 3325 gen.addCountAndDrop(DROPPED_IPV4_TCP_PORT7_UNICAST); 3326 3327 // Skip label. 3328 gen.defineLabel(skipPort7V4Filter); 3329 } 3330 generateV6KeepaliveFilters(ApfV4GeneratorBase<?> gen)3331 private void generateV6KeepaliveFilters(ApfV4GeneratorBase<?> gen) 3332 throws IllegalInstructionException { 3333 generateKeepaliveFilters(gen, TcpKeepaliveAckV6.class, IPPROTO_TCP, IPV6_NEXT_HEADER_OFFSET, 3334 gen.getUniqueLabel()); 3335 } 3336 createMdns4PktFromEthDstToIPv4Tos(boolean enabled)3337 private byte[] createMdns4PktFromEthDstToIPv4Tos(boolean enabled) { 3338 if (!enabled) { 3339 return null; 3340 } 3341 return concatArrays( 3342 ETH_MULTICAST_MDNS_V4_MAC_ADDRESS, 3343 mHardwareAddress, 3344 new byte[]{ 3345 0x08, 0x00, // ethertype: IPv4 3346 0x45, 0x00, // version, IHL, DSCP, ECN, 3347 }); 3348 } 3349 createMdns6PktFromEthDstToIPv6FlowLabel(boolean enabled)3350 private byte[] createMdns6PktFromEthDstToIPv6FlowLabel(boolean enabled) { 3351 if (!enabled) { 3352 return null; 3353 } 3354 return concatArrays( 3355 ETH_MULTICAST_MDNS_V6_MAC_ADDRESS, 3356 mHardwareAddress, 3357 new byte[]{ 3358 (byte) 0x86, (byte) 0xdd, // ethertype: IPv6 3359 0x60, 0x00, 0x00, 0x00, // version, traffic class, flow label 3360 }); 3361 } 3362 3363 createMdns4PktFromIPv4IdToUdpDport(boolean enabled)3364 private byte[] createMdns4PktFromIPv4IdToUdpDport(boolean enabled) { 3365 if (!enabled) { 3366 return null; 3367 } 3368 return concatArrays( 3369 new byte[]{ 3370 0x00, 0x00, // identification 3371 (byte) (IPV4_FLAG_DF >> 8), 0, // flags, fragment offset 3372 (byte) 0xff, // set TTL to 255 per rfc6762#section-11 3373 (byte) IPPROTO_UDP, 3374 0x00, 0x00, // checksum, it's a placeholder that will be filled in later. 3375 }, 3376 mIPv4Address, 3377 MDNS_IPV4_ADDR, 3378 MDNS_PORT_IN_BYTES, // source port 3379 MDNS_PORT_IN_BYTES); // destination port 3380 } 3381 createMdns6PktFromIPv6NextHdrToUdpDport(boolean enabled)3382 private byte[] createMdns6PktFromIPv6NextHdrToUdpDport(boolean enabled) { 3383 if (!enabled) { 3384 return null; 3385 } 3386 return concatArrays( 3387 new byte[]{ 3388 (byte) IPPROTO_UDP, 3389 (byte) 0xff, // set hop limit to 255 per rfc6762#section-11 3390 }, 3391 mIPv6LinkLocalAddress.getAddress(), 3392 MDNS_IPV6_ADDR, 3393 MDNS_PORT_IN_BYTES, // source port 3394 MDNS_PORT_IN_BYTES); // destination port 3395 } 3396 3397 /** 3398 * Generates filter code to process an mDNS payload against offload rules. 3399 * The generated filter code is guaranteed to process all IPv4 and IPv6 mDNS packets, 3400 * ensuring each packet is either passed or dropped. 3401 * <p> 3402 * The only way to enter the mDNS offload payload check logic is by jumping to the 3403 * labelCheckMdnsQueryPayload label. 3404 * On entry, the packet is known to be an IPv4/IPv6 mDNS query packet, and register R1 3405 * is set to the offset of the beginning of the UDP payload (the DNS header). 3406 * 3407 * @param gen the APF generator to generate the filter code 3408 * @param labelCheckMdnsQueryPayload the label to jump to for checking the mDNS query payload 3409 */ generateMdnsQueryOffload(ApfV6GeneratorBase<?> gen, short labelCheckMdnsQueryPayload, int numOfMdnsRuleToOffload)3410 private void generateMdnsQueryOffload(ApfV6GeneratorBase<?> gen, 3411 short labelCheckMdnsQueryPayload, int numOfMdnsRuleToOffload) 3412 throws IllegalInstructionException { 3413 // The mDNS payload check logic is terminal; the program will always result in either 3414 // PASS or DROP. 3415 gen.defineLabel(labelCheckMdnsQueryPayload); 3416 3417 if (numOfMdnsRuleToOffload == -1) { 3418 gen.addCountAndPass(PASSED_MDNS); 3419 return; 3420 } 3421 3422 // Set R0 to the offset of the beginning of the UDP payload (the DNS header) 3423 gen.addSwap(); 3424 3425 final boolean enableMdns4 = enableMdns4Offload(); 3426 final boolean enableMdns6 = enableMdns6Offload(); 3427 final byte[] mdns4EthDstToTos = createMdns4PktFromEthDstToIPv4Tos(enableMdns4); 3428 final byte[] mdns4IdToUdpDport = createMdns4PktFromIPv4IdToUdpDport(enableMdns4); 3429 final byte[] mdns6EthDstToFlowLabel = createMdns6PktFromEthDstToIPv6FlowLabel(enableMdns6); 3430 final byte[] mdns6NextHdrToUdpDport = createMdns6PktFromIPv6NextHdrToUdpDport(enableMdns6); 3431 3432 for (int i = 0; i < mOffloadRules.size(); i++) { 3433 final MdnsOffloadRule rule = mOffloadRules.get(i); 3434 final short ruleNotMatch = gen.getUniqueLabel(); 3435 final short ruleMatch = gen.getUniqueLabel(); 3436 final short offloadIPv6Mdns = gen.getUniqueLabel(); 3437 3438 for (MdnsOffloadRule.Matcher matcher : rule.mMatchers) { 3439 try { 3440 gen.addJumpIfPktAtR0ContainDnsQ(matcher.mQnames, matcher.mQtypes, ruleMatch); 3441 } catch (IllegalArgumentException e) { 3442 Log.e(TAG, "Failed to generate mDNS offload filter for rule: " + rule, e); 3443 } 3444 } 3445 3446 gen.addJump(ruleNotMatch); 3447 3448 gen.defineLabel(ruleMatch); 3449 3450 // If there is no offload payload, pass the packet to let NsdService handle it. 3451 // If there isn't enough space to offload all rules, packets should be processed 3452 // by iterating through the rules, starting with the lowest priority. 3453 if (rule.mOffloadPayload == null || i >= numOfMdnsRuleToOffload) { 3454 gen.addCountAndPass(PASSED_MDNS); 3455 } else { 3456 if (enableMdns4 && enableMdns6) { 3457 gen.addLoad16intoR0(ETH_ETHERTYPE_OFFSET) 3458 .addJumpIfR0NotEquals(ETH_P_IP, offloadIPv6Mdns); 3459 } 3460 3461 if (enableMdns4) { 3462 final int udpLength = UDP_HEADER_LEN + rule.mOffloadPayload.length; 3463 final int ipv4TotalLength = IPV4_HEADER_MIN_LEN + udpLength; 3464 final int pktLength = ETH_HEADER_LEN + ipv4TotalLength; 3465 3466 gen.addAllocate(pktLength) 3467 .addDataCopy(mdns4EthDstToTos) 3468 .addWriteU16(ipv4TotalLength) 3469 .addDataCopy(mdns4IdToUdpDport) 3470 .addWrite32(udpLength << 16) // udp length and checksum 3471 .addDataCopy(rule.mOffloadPayload) 3472 .addTransmitL4( 3473 ETH_HEADER_LEN, // ip_ofs 3474 IPV4_UDP_DESTINATION_CHECKSUM_NO_OPTIONS_OFFSET, // csum_ofs 3475 IPV4_SRC_ADDR_OFFSET, // csum_start 3476 IPPROTO_UDP + udpLength, // partial_sum 3477 true // udp 3478 ).addCountAndDrop(Counter.DROPPED_MDNS_REPLIED); 3479 } 3480 3481 if (enableMdns4 && enableMdns6) { 3482 gen.defineLabel(offloadIPv6Mdns); 3483 } 3484 3485 if (enableMdns6) { 3486 final int udpLength = UDP_HEADER_LEN + rule.mOffloadPayload.length; 3487 final int pktLength = ETH_HEADER_LEN + IPV6_HEADER_LEN + udpLength; 3488 gen.addAllocate(pktLength) 3489 .addDataCopy(mdns6EthDstToFlowLabel) 3490 .addWriteU16(udpLength) // payload length 3491 .addDataCopy(mdns6NextHdrToUdpDport) 3492 .addWrite32(udpLength << 16) // udp length and checksum 3493 .addDataCopy(rule.mOffloadPayload) 3494 .addTransmitL4( 3495 ETH_HEADER_LEN, // ip_ofs 3496 IPV6_UDP_DESTINATION_CHECKSUM_OFFSET, // csum_ofs 3497 IPV6_SRC_ADDR_OFFSET, // csum_start 3498 IPPROTO_UDP + udpLength, // partial_sum 3499 true // udp 3500 ).addCountAndDrop(Counter.DROPPED_MDNS_REPLIED); 3501 } 3502 } 3503 3504 gen.defineLabel(ruleNotMatch); 3505 } 3506 3507 // If no offload rules match, we should still respect the multicast filter. During the 3508 // transition period, not all apps will use NsdManager for mDNS advertising. If an app 3509 // decides to perform mDNS advertising itself, it must acquire a multicast lock, and no 3510 // offload rules will be registered for that app. In this case, the APF should pass the 3511 // mDNS packet and allow the app to handle the query. 3512 if (mMulticastFilter) { 3513 gen.addCountAndDrop(DROPPED_MDNS); 3514 } else { 3515 gen.addCountAndPass(PASSED_MDNS); 3516 } 3517 } 3518 3519 /** 3520 * Begin generating an APF program to: 3521 * <ul> 3522 * <li>Drop/Pass 802.3 frames (based on policy) 3523 * <li>Drop packets with EtherType within the Black List 3524 * <li>Drop ARP requests not for us, if mIPv4Address is set, 3525 * <li>Drop IPv4 broadcast packets, except DHCP destined to our MAC, 3526 * <li>Drop IPv4 multicast packets, if mMulticastFilter, 3527 * <li>Pass all other IPv4 packets, 3528 * <li>Drop all broadcast non-IP non-ARP packets. 3529 * <li>Pass all non-ICMPv6 IPv6 packets, 3530 * <li>Pass all non-IPv4 and non-IPv6 packets, 3531 * <li>Drop IPv6 ICMPv6 NAs to anything in ff02::/120. 3532 * <li>Drop IPv6 ICMPv6 RSs. 3533 * <li>Filter IPv4 packets (see generateIPv4Filter()) 3534 * <li>Filter IPv6 packets (see generateIPv6Filter()) 3535 * <li>Let execution continue off the end of the program for IPv6 ICMPv6 packets. This allows 3536 * insertion of RA filters here, or if there aren't any, just passes the packets. 3537 * </ul> 3538 * @param gen the APF generator to generate the filter code 3539 * @param labelCheckMdnsQueryPayload the label to jump to for checking the mDNS query payload 3540 */ emitPrologue(@onNull ApfV4GeneratorBase<?> gen, short labelCheckMdnsQueryPayload)3541 private void emitPrologue(@NonNull ApfV4GeneratorBase<?> gen, short labelCheckMdnsQueryPayload) 3542 throws IllegalInstructionException { 3543 if (hasDataAccess(mApfVersionSupported)) { 3544 if (gen instanceof ApfV4Generator) { 3545 // Increment TOTAL_PACKETS. 3546 // Only needed in APFv4. 3547 // In APFv6, the interpreter will increase the counter on packet receive. 3548 gen.addIncrementCounter(TOTAL_PACKETS); 3549 } 3550 3551 gen.addLoadFromMemory(R0, MemorySlot.FILTER_AGE_SECONDS); 3552 gen.addStoreCounter(FILTER_AGE_SECONDS, R0); 3553 3554 // requires a new enough APFv5+ interpreter, otherwise will be 0 3555 gen.addLoadFromMemory(R0, MemorySlot.FILTER_AGE_16384THS); 3556 gen.addStoreCounter(FILTER_AGE_16384THS, R0); 3557 3558 // requires a new enough APFv5+ interpreter, otherwise will be 0 3559 gen.addLoadFromMemory(R0, MemorySlot.APF_VERSION); 3560 gen.addStoreCounter(APF_VERSION, R0); 3561 3562 // store this program's sequential id, for later comparison 3563 gen.addLoadImmediate(R0, mNumProgramUpdates); 3564 gen.addStoreCounter(APF_PROGRAM_ID, R0); 3565 } 3566 3567 // Here's a basic summary of what the initial program does: 3568 // 3569 // if it is a loopback (src mac is nic's primary mac) packet 3570 // if 25Q2+: 3571 // drop 3572 // else 3573 // pass 3574 // if it's a TDLS packet: 3575 // it is unicast: 3576 // pass 3577 // else 3578 // drop 3579 // if it's a 802.3 Frame (ethtype < 0x0600): 3580 // drop or pass based on configurations 3581 // if it has a ether-type that belongs to the black list 3582 // drop 3583 // if it's ARP: 3584 // insert ARP filter to drop or pass these appropriately 3585 // if it's IPv4: 3586 // insert IPv4 filter to drop or pass these appropriately 3587 // if it's not IPv6: 3588 // if it's broadcast: 3589 // drop 3590 // pass 3591 // insert IPv6 filter to drop, pass, or fall off the end for ICMPv6 packets 3592 3593 if (NetworkStackUtils.isAtLeast25Q2()) { 3594 gen.addCountAndDropIfBytesAtOffsetEqual(ETHER_SRC_ADDR_OFFSET, mHardwareAddress, 3595 DROPPED_ETHER_OUR_SRC_MAC); 3596 } else { 3597 // TODO: we don't have test coverage for this line 3598 gen.addCountAndPassIfBytesAtOffsetEqual(ETHER_SRC_ADDR_OFFSET, mHardwareAddress, 3599 PASSED_ETHER_OUR_SRC_MAC); 3600 } 3601 3602 gen.addLoad16intoR0(ETH_ETHERTYPE_OFFSET); 3603 if (SdkLevel.isAtLeastV()) { 3604 // Pass unicast TDLS packet but drop non-unicast TDLS packet. 3605 short skipTDLScheck = gen.getUniqueLabel(); 3606 gen.addJumpIfR0NotEquals(0x890DL, skipTDLScheck) 3607 .addCountAndDropIfBytesAtOffsetNotEqual( 3608 ETH_DEST_ADDR_OFFSET, mHardwareAddress, DROPPED_NON_UNICAST_TDLS) 3609 .addCountAndPass(PASSED_NON_IP_UNICAST) 3610 .defineLabel(skipTDLScheck); 3611 3612 // IPv4, ARP, IPv6, EAPOL, WAPI 3613 gen.addCountAndDropIfR0IsNoneOf( 3614 Set.of(0x0800L, 0x0806L, 0x86DDL, 0x888EL, 0x88B4L), 3615 DROPPED_ETHERTYPE_NOT_ALLOWED); 3616 } else { 3617 if (mDrop802_3Frames) { 3618 // drop 802.3 frames (ethtype < 0x0600) 3619 gen.addCountAndDropIfR0LessThan(ETH_TYPE_MIN, DROPPED_802_3_FRAME); 3620 } 3621 // Handle ether-type black list 3622 if (mEthTypeBlackList.length > 0) { 3623 final Set<Long> deniedEtherTypes = new ArraySet<>(); 3624 for (int p : mEthTypeBlackList) { 3625 deniedEtherTypes.add((long) p); 3626 } 3627 gen.addCountAndDropIfR0IsOneOf(deniedEtherTypes, DROPPED_ETHERTYPE_NOT_ALLOWED); 3628 } 3629 } 3630 3631 // Add ARP filters: 3632 short skipArpFiltersLabel = gen.getUniqueLabel(); 3633 gen.addJumpIfR0NotEquals(ETH_P_ARP, skipArpFiltersLabel); 3634 generateArpFilter(gen); 3635 gen.defineLabel(skipArpFiltersLabel); 3636 3637 gen.addLoad16intoR0(ETH_ETHERTYPE_OFFSET); 3638 3639 // Add IPv4 filters: 3640 short skipIPv4FiltersLabel = gen.getUniqueLabel(); 3641 gen.addJumpIfR0NotEquals(ETH_P_IP, skipIPv4FiltersLabel); 3642 generateIPv4Filter(gen, labelCheckMdnsQueryPayload); 3643 gen.defineLabel(skipIPv4FiltersLabel); 3644 3645 // Check for IPv6: 3646 // NOTE: Relies on R0 containing ethertype. This is safe because if we got here, we did 3647 // not execute the IPv4 filter, since this filter do not fall through, but either drop or 3648 // pass. 3649 short ipv6FilterLabel = gen.getUniqueLabel(); 3650 gen.addJumpIfR0Equals(ETH_P_IPV6, ipv6FilterLabel); 3651 3652 // Drop non-IP non-ARP broadcasts, pass the rest 3653 gen.addCountAndPassIfBytesAtOffsetNotEqual(ETH_DEST_ADDR_OFFSET, ETHER_BROADCAST, 3654 PASSED_NON_IP_UNICAST); 3655 gen.addCountAndDrop(DROPPED_ETH_BROADCAST); 3656 3657 // Add IPv6 filters: 3658 gen.defineLabel(ipv6FilterLabel); 3659 generateIPv6Filter(gen, labelCheckMdnsQueryPayload); 3660 } 3661 getApfConfigMessage()3662 private String getApfConfigMessage() { 3663 final StringBuilder sb = new StringBuilder(); 3664 sb.append("{ "); 3665 sb.append("mcast: "); 3666 sb.append(mMulticastFilter ? "DROP" : "ALLOW"); 3667 sb.append(", "); 3668 sb.append("doze: "); 3669 sb.append(mInDozeMode ? "TRUE" : "FALSE"); 3670 sb.append(", "); 3671 sb.append("offloads: "); 3672 sb.append("[ "); 3673 if (enableArpOffload()) { 3674 sb.append("ARP, "); 3675 } 3676 if (enableNdOffload()) { 3677 sb.append("ND, "); 3678 } 3679 if (enableIgmpOffload()) { 3680 sb.append("IGMP, "); 3681 } 3682 if (enableMldOffload()) { 3683 sb.append("MLD, "); 3684 } 3685 if (enableIpv4PingOffload()) { 3686 sb.append("Ping4, "); 3687 } 3688 if (enableIpv6PingOffload()) { 3689 sb.append("Ping6, "); 3690 } 3691 if (enableMdns4Offload()) { 3692 sb.append("Mdns4, "); 3693 } 3694 if (enableMdns6Offload()) { 3695 sb.append("Mdns6, "); 3696 } 3697 sb.append("] "); 3698 sb.append("total RAs: "); 3699 sb.append(mRas.size()); 3700 sb.append(" filtered RAs: "); 3701 sb.append(mNumFilteredRas); 3702 sb.append(" mDNSs: "); 3703 sb.append(mOffloadRules.size()); 3704 sb.append(" }"); 3705 return sb.toString(); 3706 } 3707 installPacketFilter(byte[] program, String logInfo)3708 private void installPacketFilter(byte[] program, String logInfo) { 3709 if (!mApfController.installPacketFilter(program, logInfo)) { 3710 sendNetworkQuirkMetrics(NetworkQuirkEvent.QE_APF_INSTALL_FAILURE); 3711 } 3712 } 3713 createApfGenerator()3714 private ApfV4GeneratorBase<?> createApfGenerator() throws IllegalInstructionException { 3715 if (useApfV61Generator()) { 3716 return new ApfV61Generator(mApfVersionSupported, mApfRamSize, 3717 mInstallableProgramSizeClamp); 3718 } else if (useApfV6Generator()) { 3719 return new ApfV6Generator(mApfVersionSupported, mApfRamSize, 3720 mInstallableProgramSizeClamp); 3721 } else { 3722 return new ApfV4Generator(mApfVersionSupported, mApfRamSize, 3723 mInstallableProgramSizeClamp); 3724 } 3725 } 3726 3727 @VisibleForTesting getOverEstimatedProgramSize()3728 public int getOverEstimatedProgramSize() { 3729 return mOverEstimatedProgramSize; 3730 } 3731 calcMdnsOffloadProgramSizeOverEstimate(int numOfMdnsRuleToOffload)3732 private int calcMdnsOffloadProgramSizeOverEstimate(int numOfMdnsRuleToOffload) 3733 throws IllegalInstructionException { 3734 ApfV6GeneratorBase<?> gen = (ApfV6GeneratorBase<?>) createApfGenerator(); 3735 // We need to preload data for size estimation because the preloaded data contains mDNS 3736 // data chunks. If we don't preload, generateMdnsQueryOffload() will add data to the data 3737 // region, resulting in an incorrect estimated size. 3738 if (gen instanceof ApfV61GeneratorBase<?>) { 3739 preloadData((ApfV61GeneratorBase<?>) gen); 3740 } 3741 final int programLengthOverEstimateBefore = gen.programLengthOverEstimate(); 3742 short tmpLabelCheckMdnsQueryPayload = gen.getUniqueLabel(); 3743 generateMdnsQueryOffload(gen, tmpLabelCheckMdnsQueryPayload, 3744 numOfMdnsRuleToOffload); 3745 return gen.programLengthOverEstimate() - programLengthOverEstimateBefore; 3746 } 3747 preloadData(ApfV61GeneratorBase<?> gen)3748 void preloadData(ApfV61GeneratorBase<?> gen) throws IllegalInstructionException { 3749 final List<byte[]> preloadedMacAddress = getKnownMacAddresses(); 3750 final List<byte[]> preloadedIPv6Address = getIpv6Addresses(true /* includeNonTentative */, 3751 true /* includeTentative */, true /* includeAnycast */); 3752 preloadedIPv6Address.add(IPV6_ADDR_ALL_NODES_MULTICAST.getAddress()); 3753 preloadedIPv6Address.add(IPV6_ADDR_ANY.getAddress()); 3754 byte[] mdns6NextHdrToUdpDport = new byte[0]; 3755 byte[] mdns6EthDstToFlowLabel = new byte[0]; 3756 byte[] mdns4EthDstToTos = new byte[0]; 3757 if (enableMdns6Offload()) { 3758 mdns6NextHdrToUdpDport = createMdns6PktFromIPv6NextHdrToUdpDport(true); 3759 preloadedIPv6Address.removeIf( 3760 addr -> Arrays.equals(addr, mIPv6LinkLocalAddress.getAddress())); 3761 mdns6EthDstToFlowLabel = createMdns6PktFromEthDstToIPv6FlowLabel(true); 3762 preloadedMacAddress.removeIf( 3763 addr -> Arrays.equals(addr, mHardwareAddress) || Arrays.equals(addr, 3764 ETH_MULTICAST_MDNS_V6_MAC_ADDRESS)); 3765 } 3766 3767 if (enableMdns4Offload()) { 3768 mdns4EthDstToTos = createMdns4PktFromEthDstToIPv4Tos(true); 3769 preloadedMacAddress.removeIf( 3770 addr -> Arrays.equals(addr, mHardwareAddress) || Arrays.equals(addr, 3771 ETH_MULTICAST_MDNS_V4_MAC_ADDRESS)); 3772 } 3773 3774 int preloadDataSize = mdns6NextHdrToUdpDport.length + mdns6EthDstToFlowLabel.length 3775 + mdns4EthDstToTos.length + preloadedIPv6Address.size() * 16 3776 + preloadedMacAddress.size() * 6; 3777 3778 if (enableArpOffload()) { 3779 preloadDataSize += FIXED_ARP_REPLY_HEADER.length; 3780 } 3781 3782 final byte[] preloadData = new byte[preloadDataSize]; 3783 int offset = 0; 3784 System.arraycopy(mdns6NextHdrToUdpDport, 0, preloadData, offset, 3785 mdns6NextHdrToUdpDport.length); 3786 offset += mdns6NextHdrToUdpDport.length; 3787 System.arraycopy(mdns6EthDstToFlowLabel, 0, preloadData, offset, 3788 mdns6EthDstToFlowLabel.length); 3789 offset += mdns6EthDstToFlowLabel.length; 3790 System.arraycopy(mdns4EthDstToTos, 0, preloadData, offset, mdns4EthDstToTos.length); 3791 offset += mdns4EthDstToTos.length; 3792 for (byte[] addr : preloadedMacAddress) { 3793 System.arraycopy(addr, 0, preloadData, offset, 6); 3794 offset += 6; 3795 } 3796 for (byte[] addr : preloadedIPv6Address) { 3797 System.arraycopy(addr, 0, preloadData, offset, 16); 3798 offset += 16; 3799 } 3800 if (enableArpOffload()) { 3801 System.arraycopy(FIXED_ARP_REPLY_HEADER, 0, preloadData, offset, 3802 FIXED_ARP_REPLY_HEADER.length); 3803 offset += FIXED_ARP_REPLY_HEADER.length; 3804 } 3805 3806 if (preloadDataSize > 0) { 3807 gen.addPreloadData(preloadData); 3808 } 3809 } 3810 3811 /** 3812 * Generate and install a new filter program. 3813 */ 3814 @VisibleForTesting installNewProgram()3815 public void installNewProgram() { 3816 ArrayList<Ra> rasToFilter = new ArrayList<>(); 3817 final byte[] program; 3818 int programMinLft = Integer.MAX_VALUE; 3819 3820 // Ensure the entire APF program uses the same time base. 3821 final int timeSeconds = secondsSinceBoot(); 3822 // Every return from this function calls installPacketFilter(). 3823 mLastTimeInstalledProgram = timeSeconds; 3824 3825 // Increase the counter before we generate the program. 3826 // This keeps the APF_PROGRAM_ID counter in sync with the program. 3827 mNumProgramUpdates++; 3828 3829 try { 3830 // Step 1: Determine how many RA filters/mDNS offloads we can fit in the program. 3831 ApfV4GeneratorBase<?> gen = createApfGenerator(); 3832 if (gen instanceof ApfV61GeneratorBase<?>) { 3833 preloadData((ApfV61GeneratorBase<?>) gen); 3834 } 3835 short labelCheckMdnsQueryPayload = gen.getUniqueLabel(); 3836 3837 emitPrologue(gen, labelCheckMdnsQueryPayload); 3838 3839 int programLengthOverEstimate = gen.programLengthOverEstimate(); 3840 3841 // The default packet handling normally goes after the RA filters, but add it early to 3842 // include its length when estimating the total. 3843 programLengthOverEstimate += gen.getDefaultPacketHandlingSizeOverEstimate(); 3844 3845 // Can't fit the program even without any RA filters/Mdns offloads? 3846 if (programLengthOverEstimate > mMaximumApfProgramSize) { 3847 Log.e(TAG, "Program exceeds maximum size " + mMaximumApfProgramSize); 3848 sendNetworkQuirkMetrics(NetworkQuirkEvent.QE_APF_OVER_SIZE_FAILURE); 3849 installPacketFilter(new byte[mMaximumApfProgramSize], 3850 getApfConfigMessage() + " (clear memory, reason: program too large)"); 3851 return; 3852 } 3853 3854 // We attempt to fit the mDNS offload rules into the program before fitting RAs. The 3855 // strategy is as follows: 3856 // 1. If sufficient memory is available, offload all rules. 3857 // 2. If memory is insufficient, switch low-priority rules to passthrough mode. 3858 // 3. If memory remains insufficient after all rules are switched to passthrough 3859 // mode, fail open to pass all mDNS packets. 3860 // 3861 // We prioritize mDNS offload over RA filters because: 3862 // 1. We plan to move away from the multicast lock API, making mDNS offload critical 3863 // for the application's proper function. Without it, app developers would likely 3864 // still use the multicast lock, which would wake the device for almost all 3865 // multicast traffic, leading to serious power problems. 3866 // 2. For devices like TVs, reliable mDNS offload is key to meeting EU power regulation 3867 // requirement. These devices are usually on home networks with very chatty mDNS 3868 // traffic. 3869 if (enableMdns4Offload() || enableMdns6Offload()) { 3870 final int remainSize = mMaximumApfProgramSize - programLengthOverEstimate; 3871 mNumOfMdnsRuleToOffload = mOffloadRules.size(); 3872 int mDnsProgramLengthOverEstimate = 0; 3873 for (; mNumOfMdnsRuleToOffload >= -1; --mNumOfMdnsRuleToOffload) { 3874 mDnsProgramLengthOverEstimate = calcMdnsOffloadProgramSizeOverEstimate( 3875 mNumOfMdnsRuleToOffload); 3876 if (mDnsProgramLengthOverEstimate <= remainSize) { 3877 break; 3878 } 3879 } 3880 3881 // When the size of offload rules is non-zero, at bare minimum, the 3882 // program should be pass the mDNS packets. Otherwise, the application use case will 3883 // be broken after we migrate away from multicast lock. 3884 // If the remaining size is insufficient for mDNS fail-open, we should fail-open 3885 // for the entire program. 3886 if (mNumOfMdnsRuleToOffload < -1) { 3887 Log.e(TAG, "Program exceeds maximum size (unable to fail-open for mDNS) " 3888 + mMaximumApfProgramSize); 3889 sendNetworkQuirkMetrics(NetworkQuirkEvent.QE_APF_OVER_SIZE_FAILURE); 3890 installPacketFilter(new byte[mMaximumApfProgramSize], getApfConfigMessage() 3891 + " (clear memory, reason: unable to fail-open for mDNS)"); 3892 return; 3893 } 3894 3895 programLengthOverEstimate += mDnsProgramLengthOverEstimate; 3896 } else { 3897 mNumOfMdnsRuleToOffload = -1; 3898 } 3899 3900 3901 for (Ra ra : mRas) { 3902 // skip filter if it has expired. 3903 if (ra.getRemainingFilterLft(timeSeconds) <= 0) continue; 3904 programLengthOverEstimate += ra.getRaProgramLengthOverEstimate(timeSeconds); 3905 // Stop if we get too big. 3906 if (programLengthOverEstimate > mMaximumApfProgramSize) { 3907 Log.i(TAG, "Past maximum program size, skipping RAs"); 3908 break; 3909 } 3910 3911 ra.generateFilter(gen, timeSeconds); 3912 programMinLft = Math.min(programMinLft, ra.getRemainingFilterLft(timeSeconds)); 3913 rasToFilter.add(ra); 3914 } 3915 3916 gen.addDefaultPacketHandling(); 3917 if (enableMdns4Offload() || enableMdns6Offload()) { 3918 generateMdnsQueryOffload((ApfV6GeneratorBase<?>) gen, labelCheckMdnsQueryPayload, 3919 mNumOfMdnsRuleToOffload); 3920 } 3921 3922 mNumFilteredRas = rasToFilter.size(); 3923 mOverEstimatedProgramSize = gen.programLengthOverEstimate(); 3924 program = gen.generate(); 3925 } catch (IllegalInstructionException | IllegalStateException | IllegalArgumentException e) { 3926 Log.wtf(TAG, "Failed to generate APF program.", e); 3927 sendNetworkQuirkMetrics(NetworkQuirkEvent.QE_APF_GENERATE_FILTER_EXCEPTION); 3928 installPacketFilter(new byte[mMaximumApfProgramSize], 3929 getApfConfigMessage() + String.format(" (clear memory, reason: %s)", 3930 e.getMessage())); 3931 return; 3932 } 3933 if (mIsRunning) { 3934 if (program.length > mMaximumApfProgramSize) { 3935 Log.wtf(TAG, String.format( 3936 "Size estimation logic is wrong: final program size: %d exceeds maximum " 3937 + "size: %d. ", 3938 program.length, mMaximumApfProgramSize)); 3939 sendNetworkQuirkMetrics(NetworkQuirkEvent.QE_APF_OVER_SIZE_FAILURE); 3940 installPacketFilter(new byte[mMaximumApfProgramSize], 3941 getApfConfigMessage() + " (clear memory, reason: wrong size estimation)"); 3942 return; 3943 } 3944 installPacketFilter(program, getApfConfigMessage()); 3945 } 3946 mLastInstalledProgramMinLifetime = programMinLft; 3947 mLastInstalledProgram = program; 3948 mMaxProgramSize = Math.max(mMaxProgramSize, program.length); 3949 3950 } 3951 hexDump(String msg, byte[] packet, int length)3952 private void hexDump(String msg, byte[] packet, int length) { 3953 log(msg + HexDump.toHexString(packet, 0, length, false /* lowercase */)); 3954 } 3955 3956 // Get the minimum value excludes zero. This is used for calculating the lowest lifetime values 3957 // in RA packets. Zero lifetimes are excluded because we want to detect whether there is any 3958 // unusually small lifetimes but zero lifetime is actually valid (cease to be a default router 3959 // or the option is no longer be used). Number of zero lifetime RAs is collected in a different 3960 // Metrics. getMinForPositiveValue(long oldMinValue, long value)3961 private long getMinForPositiveValue(long oldMinValue, long value) { 3962 if (value < 1) return oldMinValue; 3963 return Math.min(oldMinValue, value); 3964 } 3965 getMinForPositiveValue(int oldMinValue, int value)3966 private int getMinForPositiveValue(int oldMinValue, int value) { 3967 return (int) getMinForPositiveValue((long) oldMinValue, (long) value); 3968 } 3969 3970 /** 3971 * Process an RA packet, updating the list of known RAs and installing a new APF program 3972 * if the current APF program should be updated. 3973 */ 3974 @VisibleForTesting processRa(byte[] packet, int length)3975 public void processRa(byte[] packet, int length) { 3976 final Ra ra; 3977 try { 3978 ra = new Ra(packet, length); 3979 } catch (Exception e) { 3980 Log.e(TAG, "Error parsing RA", e); 3981 mNumParseErrorRas++; 3982 return; 3983 } 3984 3985 // Update info for Metrics 3986 mLowestRouterLifetimeSeconds = getMinForPositiveValue( 3987 mLowestRouterLifetimeSeconds, ra.mRouterLifetime); 3988 mLowestPioValidLifetimeSeconds = getMinForPositiveValue( 3989 mLowestPioValidLifetimeSeconds, ra.mMinPioValidLifetime); 3990 mLowestRioRouteLifetimeSeconds = getMinForPositiveValue( 3991 mLowestRioRouteLifetimeSeconds, ra.mMinRioRouteLifetime); 3992 mLowestRdnssLifetimeSeconds = getMinForPositiveValue( 3993 mLowestRdnssLifetimeSeconds, ra.mMinRdnssLifetime); 3994 3995 // Remove all expired RA filters before trying to match the new RA. 3996 // TODO: matches() still checks that the old RA filter has not expired. Consider removing 3997 // that check. 3998 final int now = secondsSinceBoot(); 3999 mRas.removeIf(item -> item.getRemainingFilterLft(now) <= 0); 4000 4001 // Have we seen this RA before? 4002 for (int i = 0; i < mRas.size(); i++) { 4003 final Ra oldRa = mRas.get(i); 4004 final Ra.MatchType result = oldRa.matches(ra); 4005 if (result == Ra.MatchType.MATCH_PASS) { 4006 log("Updating RA from " + oldRa + " to " + ra); 4007 4008 // Keep mRas in LRU order so as to prioritize generating filters for recently seen 4009 // RAs. LRU prioritizes this because RA filters are generated in order from mRas 4010 // until the filter program exceeds the maximum filter program size allowed by the 4011 // chipset, so RAs appearing earlier in mRas are more likely to make it into the 4012 // filter program. 4013 // TODO: consider sorting the RAs in order of increasing expiry time as well. 4014 // Swap to front of array. 4015 mRas.remove(i); 4016 mRas.add(0, ra); 4017 4018 // Rate limit program installation 4019 if (mTokenBucket.get()) { 4020 installNewProgram(); 4021 } else { 4022 Log.e(TAG, "Failed to install prog for tracked RA, too many updates. " + ra); 4023 } 4024 return; 4025 } else if (result == Ra.MatchType.MATCH_DROP) { 4026 log("Ignoring RA " + ra + " which matches " + oldRa); 4027 return; 4028 } 4029 } 4030 mMaxDistinctRas = Math.max(mMaxDistinctRas, mRas.size() + 1); 4031 if (mRas.size() >= MAX_RAS) { 4032 // Remove the last (i.e. oldest) RA. 4033 mRas.remove(mRas.size() - 1); 4034 } 4035 log("Adding " + ra); 4036 mRas.add(0, ra); 4037 // Rate limit program installation 4038 if (mTokenBucket.get()) { 4039 installNewProgram(); 4040 } else { 4041 Log.e(TAG, "Failed to install prog for new RA, too many updates. " + ra); 4042 } 4043 } 4044 4045 /** 4046 * Create an {@link ApfFilter} if {@code apfCapabilities} indicates support for packet 4047 * filtering using APF programs. 4048 */ maybeCreate(Handler handler, Context context, ApfConfiguration config, InterfaceParams ifParams, IApfController apfController, NetworkQuirkMetrics networkQuirkMetrics)4049 public static ApfFilter maybeCreate(Handler handler, Context context, ApfConfiguration config, 4050 InterfaceParams ifParams, IApfController apfController, 4051 NetworkQuirkMetrics networkQuirkMetrics) { 4052 if (context == null || config == null || ifParams == null) return null; 4053 if (!ApfV4Generator.supportsVersion(config.apfVersionSupported)) { 4054 return null; 4055 } 4056 if (config.apfRamSize < 512) { 4057 Log.e(TAG, "Unacceptably small APF limit: " + config.apfRamSize); 4058 return null; 4059 } 4060 4061 return new ApfFilter(handler, context, config, ifParams, apfController, 4062 networkQuirkMetrics); 4063 } 4064 collectAndSendMetrics()4065 private void collectAndSendMetrics() { 4066 if (mIpClientRaInfoMetrics == null || mApfSessionInfoMetrics == null) return; 4067 final long sessionDurationMs = mDependencies.elapsedRealtime() - mSessionStartMs; 4068 if (sessionDurationMs < mMinMetricsSessionDurationMs) return; 4069 4070 // Collect and send IpClientRaInfoMetrics. 4071 mIpClientRaInfoMetrics.setMaxNumberOfDistinctRas(mMaxDistinctRas); 4072 mIpClientRaInfoMetrics.setNumberOfZeroLifetimeRas(mNumZeroLifetimeRas); 4073 mIpClientRaInfoMetrics.setNumberOfParsingErrorRas(mNumParseErrorRas); 4074 mIpClientRaInfoMetrics.setLowestRouterLifetimeSeconds(mLowestRouterLifetimeSeconds); 4075 mIpClientRaInfoMetrics.setLowestPioValidLifetimeSeconds(mLowestPioValidLifetimeSeconds); 4076 mIpClientRaInfoMetrics.setLowestRioRouteLifetimeSeconds(mLowestRioRouteLifetimeSeconds); 4077 mIpClientRaInfoMetrics.setLowestRdnssLifetimeSeconds(mLowestRdnssLifetimeSeconds); 4078 mIpClientRaInfoMetrics.statsWrite(); 4079 4080 // Collect and send ApfSessionInfoMetrics. 4081 mApfSessionInfoMetrics.setVersion(mApfVersionSupported); 4082 mApfSessionInfoMetrics.setMemorySize(mApfRamSize); 4083 mApfSessionInfoMetrics.setApfSessionDurationSeconds( 4084 (int) (sessionDurationMs / DateUtils.SECOND_IN_MILLIS)); 4085 mApfSessionInfoMetrics.setNumOfTimesApfProgramUpdated(mNumProgramUpdates); 4086 mApfSessionInfoMetrics.setMaxProgramSize(mMaxProgramSize); 4087 for (Map.Entry<Counter, Long> entry : mApfCounterTracker.getCounters().entrySet()) { 4088 if (entry.getValue() > 0) { 4089 mApfSessionInfoMetrics.addApfCounter(entry.getKey(), entry.getValue()); 4090 } 4091 } 4092 mApfSessionInfoMetrics.statsWrite(); 4093 } 4094 shutdown()4095 public void shutdown() { 4096 collectAndSendMetrics(); 4097 // The shutdown() must be called from the IpClient's handler thread 4098 mRaPacketReader.stop(); 4099 mRas.clear(); 4100 mDependencies.removeBroadcastReceiver(mDeviceIdleReceiver); 4101 mIsApfShutdown = true; 4102 if (SdkLevel.isAtLeastV() && mApfMdnsOffloadEngine != null) { 4103 mApfMdnsOffloadEngine.unregisterOffloadEngine(); 4104 } 4105 4106 if (mMulticastReportMonitor != null) { 4107 mMulticastReportMonitor.stop(); 4108 } 4109 } 4110 setMulticastFilter(boolean isEnabled)4111 public void setMulticastFilter(boolean isEnabled) { 4112 if (mMulticastFilter == isEnabled) return; 4113 mMulticastFilter = isEnabled; 4114 installNewProgram(); 4115 } 4116 4117 @VisibleForTesting setDozeMode(boolean isEnabled)4118 public void setDozeMode(boolean isEnabled) { 4119 if (mInDozeMode == isEnabled) return; 4120 mInDozeMode = isEnabled; 4121 installNewProgram(); 4122 } 4123 4124 /** Retrieve the single IPv4 LinkAddress if there is one, otherwise return null. */ retrieveIPv4LinkAddress(LinkProperties lp)4125 private static LinkAddress retrieveIPv4LinkAddress(LinkProperties lp) { 4126 LinkAddress ipv4Address = null; 4127 for (LinkAddress address : lp.getLinkAddresses()) { 4128 if (!(address.getAddress() instanceof Inet4Address)) { 4129 continue; 4130 } 4131 if (ipv4Address != null && !ipv4Address.isSameAddressAs(address)) { 4132 // More than one IPv4 address, abort. 4133 return null; 4134 } 4135 ipv4Address = address; 4136 } 4137 return ipv4Address; 4138 } 4139 4140 /** Retrieve the pair of IPv6 Inet6Address set, otherwise return pair with two empty set. 4141 * The first element is a set containing tentative IPv6 addresses, 4142 * the second element is a set containing non-tentative IPv6 addresses 4143 * */ 4144 private static Pair<Set<Inet6Address>, Set<Inet6Address>> retrieveIPv6LinkAddress(LinkProperties lp)4145 retrieveIPv6LinkAddress(LinkProperties lp) { 4146 final Set<Inet6Address> tentativeAddrs = new ArraySet<>(); 4147 final Set<Inet6Address> nonTentativeAddrs = new ArraySet<>(); 4148 for (LinkAddress address : lp.getLinkAddresses()) { 4149 if (!(address.getAddress() instanceof Inet6Address)) { 4150 continue; 4151 } 4152 4153 if ((address.getFlags() & IFA_F_TENTATIVE) == IFA_F_TENTATIVE) { 4154 tentativeAddrs.add((Inet6Address) address.getAddress()); 4155 } else { 4156 nonTentativeAddrs.add((Inet6Address) address.getAddress()); 4157 } 4158 } 4159 4160 4161 return new Pair<>(tentativeAddrs, nonTentativeAddrs); 4162 } 4163 setLinkProperties(LinkProperties lp)4164 public void setLinkProperties(LinkProperties lp) { 4165 // NOTE: Do not keep a copy of LinkProperties as it would further duplicate state. 4166 final LinkAddress ipv4Address = retrieveIPv4LinkAddress(lp); 4167 final byte[] addr = (ipv4Address != null) ? ipv4Address.getAddress().getAddress() : null; 4168 final int prefix = (ipv4Address != null) ? ipv4Address.getPrefixLength() : 0; 4169 final Pair<Set<Inet6Address>, Set<Inet6Address>> 4170 ipv6Addresses = retrieveIPv6LinkAddress(lp); 4171 4172 if ((prefix == mIPv4PrefixLength) 4173 && Arrays.equals(addr, mIPv4Address) 4174 && ipv6Addresses.first.equals(mIPv6TentativeAddresses) 4175 && ipv6Addresses.second.equals(mIPv6NonTentativeAddresses) 4176 ) { 4177 return; 4178 } 4179 mIPv4Address = addr; 4180 mIPv4PrefixLength = prefix; 4181 mIPv6TentativeAddresses = ipv6Addresses.first; 4182 mIPv6NonTentativeAddresses = ipv6Addresses.second; 4183 mIPv6LinkLocalAddress = NetworkStackUtils.selectPreferredIPv6LinkLocalAddress(lp); 4184 4185 installNewProgram(); 4186 } 4187 updateClatInterfaceState(boolean add)4188 public void updateClatInterfaceState(boolean add) { 4189 if (mHasClat == add) { 4190 return; 4191 } 4192 mHasClat = add; 4193 installNewProgram(); 4194 } 4195 updateIPv6MulticastAddrs()4196 private boolean updateIPv6MulticastAddrs() { 4197 final Set<Inet6Address> mcastAddrs = 4198 new ArraySet<>(mDependencies.getIPv6MulticastAddresses(mInterfaceParams.name)); 4199 4200 if (!mIPv6MulticastAddresses.equals(mcastAddrs)) { 4201 mIPv6MulticastAddresses.clear(); 4202 mIPv6MulticastAddresses.addAll(mcastAddrs); 4203 4204 mIPv6McastAddrsExcludeAllHost.clear(); 4205 mIPv6McastAddrsExcludeAllHost.addAll(mIPv6MulticastAddresses); 4206 mIPv6McastAddrsExcludeAllHost.remove(IPV6_ADDR_ALL_NODES_MULTICAST); 4207 mIPv6McastAddrsExcludeAllHost.remove(IPV6_ADDR_NODE_LOCAL_ALL_NODES_MULTICAST); 4208 return true; 4209 } 4210 return false; 4211 } 4212 updateIPv4MulticastAddrs()4213 private boolean updateIPv4MulticastAddrs() { 4214 final Set<Inet4Address> mcastAddrs = 4215 new ArraySet<>(mDependencies.getIPv4MulticastAddresses(mInterfaceParams.name)); 4216 4217 if (!mIPv4MulticastAddresses.equals(mcastAddrs)) { 4218 mIPv4MulticastAddresses.clear(); 4219 mIPv4MulticastAddresses.addAll(mcastAddrs); 4220 4221 mIPv4McastAddrsExcludeAllHost.clear(); 4222 mIPv4McastAddrsExcludeAllHost.addAll(mcastAddrs); 4223 mIPv4McastAddrsExcludeAllHost.remove(IPV4_ADDR_ALL_HOST_MULTICAST); 4224 return true; 4225 } 4226 return false; 4227 } 4228 4229 /** 4230 * Updates IPv4/IPv6 multicast addresses. 4231 */ updateMulticastAddrs()4232 public void updateMulticastAddrs() { 4233 boolean ipv6MulticastUpdated = updateIPv6MulticastAddrs(); 4234 boolean ipv4MulticastUpdated = updateIPv4MulticastAddrs(); 4235 if (ipv6MulticastUpdated || ipv4MulticastUpdated) { 4236 installNewProgram(); 4237 } 4238 } 4239 4240 @ChecksSdkIntAtLeast(api = 35 /* Build.VERSION_CODES.VanillaIceCream */) enableArpOffload()4241 private boolean enableArpOffload() { 4242 return mHandleArpOffload && useApfV6Generator() && mIPv4Address != null; 4243 } 4244 4245 @ChecksSdkIntAtLeast(api = 35 /* Build.VERSION_CODES.VanillaIceCream */) enableNdOffload()4246 public boolean enableNdOffload() { 4247 return mHandleNdOffload && useApfV6Generator(); 4248 } 4249 4250 @ChecksSdkIntAtLeast(api = 35 /* Build.VERSION_CODES.VanillaIceCream */) enableOffloadEngineRegistration()4251 private boolean enableOffloadEngineRegistration() { 4252 return mHandleMdnsOffload && useApfV6Generator(); 4253 } 4254 4255 @ChecksSdkIntAtLeast(api = 35 /* Build.VERSION_CODES.VanillaIceCream */) enableIgmpReportsMonitor()4256 private boolean enableIgmpReportsMonitor() { 4257 return mHandleIgmpOffload && useApfV6Generator(); 4258 } 4259 4260 @ChecksSdkIntAtLeast(api = 35 /* Build.VERSION_CODES.VanillaIceCream */) enableMdns4Offload()4261 private boolean enableMdns4Offload() { 4262 return enableOffloadEngineRegistration() && mIPv4Address != null 4263 && !mOffloadRules.isEmpty(); 4264 } 4265 4266 @ChecksSdkIntAtLeast(api = 35 /* Build.VERSION_CODES.VanillaIceCream */) enableMdns6Offload()4267 private boolean enableMdns6Offload() { 4268 return enableOffloadEngineRegistration() && mIPv6LinkLocalAddress != null 4269 && !mOffloadRules.isEmpty(); 4270 } 4271 4272 @ChecksSdkIntAtLeast(api = 35 /* Build.VERSION_CODES.VanillaIceCream */) enableIgmpOffload()4273 private boolean enableIgmpOffload() { 4274 // Since the all-hosts multicast address (224.0.0.1) is always present for IPv4 4275 // multicast, and IGMP packets are not needed for this address, IGMP offloading is only 4276 // necessary if there are additional joined multicast addresses 4277 // (mIPv4MulticastAddresses.size() > 1). 4278 return enableIgmpReportsMonitor() && mIPv4MulticastAddresses.size() > 1 4279 && mIPv4Address != null; 4280 } 4281 4282 @ChecksSdkIntAtLeast(api = 35 /* Build.VERSION_CODES.VanillaIceCream */) enableIpv4PingOffload()4283 private boolean enableIpv4PingOffload() { 4284 return mHandleIpv4PingOffload && useApfV6Generator() && mIPv4Address != null; 4285 } 4286 4287 @ChecksSdkIntAtLeast(api = 35 /* Build.VERSION_CODES.VanillaIceCream */) enableIpv6PingOffload()4288 private boolean enableIpv6PingOffload() { 4289 return mHandleIpv6PingOffload && useApfV6Generator() 4290 && !mIPv6NonTentativeAddresses.isEmpty(); 4291 } 4292 4293 @ChecksSdkIntAtLeast(api = 35 /* Build.VERSION_CODES.VanillaIceCream */) enableMldReportsMonitor()4294 private boolean enableMldReportsMonitor() { 4295 return mHandleMldOffload && useApfV6Generator(); 4296 } 4297 4298 @ChecksSdkIntAtLeast(api = 35 /* Build.VERSION_CODES.VanillaIceCream */) enableMldOffload()4299 private boolean enableMldOffload() { 4300 return enableMldReportsMonitor() && mIPv6LinkLocalAddress != null 4301 && !mIPv6McastAddrsExcludeAllHost.isEmpty(); 4302 } 4303 4304 @ChecksSdkIntAtLeast(api = 35 /* Build.VERSION_CODES.VanillaIceCream */) useApfV6Generator()4305 private boolean useApfV6Generator() { 4306 return SdkLevel.isAtLeastV() && ApfV6Generator.supportsVersion(mApfVersionSupported); 4307 } 4308 4309 @ChecksSdkIntAtLeast(api = 35 /* Build.VERSION_CODES.VanillaIceCream */) useApfV61Generator()4310 private boolean useApfV61Generator() { 4311 return SdkLevel.isAtLeastV() && ApfV61Generator.supportsVersion(mApfVersionSupported); 4312 } 4313 4314 /** 4315 * Add TCP keepalive ack packet filter. 4316 * This will add a filter to drop acks to the keepalive packet passed as an argument. 4317 * 4318 * @param slot The index used to access the filter. 4319 * @param sentKeepalivePacket The attributes of the sent keepalive packet. 4320 */ addTcpKeepalivePacketFilter(final int slot, final TcpKeepalivePacketDataParcelable sentKeepalivePacket)4321 public void addTcpKeepalivePacketFilter(final int slot, 4322 final TcpKeepalivePacketDataParcelable sentKeepalivePacket) { 4323 log("Adding keepalive ack(" + slot + ")"); 4324 if (null != mKeepalivePackets.get(slot)) { 4325 throw new IllegalArgumentException("Keepalive slot " + slot + " is occupied"); 4326 } 4327 final int ipVersion = sentKeepalivePacket.srcAddress.length == 4 ? 4 : 6; 4328 mKeepalivePackets.put(slot, (ipVersion == 4) 4329 ? new TcpKeepaliveAckV4(sentKeepalivePacket) 4330 : new TcpKeepaliveAckV6(sentKeepalivePacket)); 4331 installNewProgram(); 4332 } 4333 4334 /** 4335 * Add NAT-T keepalive packet filter. 4336 * This will add a filter to drop NAT-T keepalive packet which is passed as an argument. 4337 * 4338 * @param slot The index used to access the filter. 4339 * @param sentKeepalivePacket The attributes of the sent keepalive packet. 4340 */ addNattKeepalivePacketFilter(final int slot, final NattKeepalivePacketDataParcelable sentKeepalivePacket)4341 public void addNattKeepalivePacketFilter(final int slot, 4342 final NattKeepalivePacketDataParcelable sentKeepalivePacket) { 4343 log("Adding NAT-T keepalive packet(" + slot + ")"); 4344 if (null != mKeepalivePackets.get(slot)) { 4345 throw new IllegalArgumentException("NAT-T Keepalive slot " + slot + " is occupied"); 4346 } 4347 4348 // TODO : update ApfFilter to support dropping v6 keepalives 4349 if (sentKeepalivePacket.srcAddress.length != 4) { 4350 return; 4351 } 4352 4353 mKeepalivePackets.put(slot, new NattKeepaliveResponse(sentKeepalivePacket)); 4354 installNewProgram(); 4355 } 4356 4357 /** 4358 * Remove keepalive packet filter. 4359 * 4360 * @param slot The index used to access the filter. 4361 */ removeKeepalivePacketFilter(int slot)4362 public void removeKeepalivePacketFilter(int slot) { 4363 log("Removing keepalive packet(" + slot + ")"); 4364 mKeepalivePackets.remove(slot); 4365 installNewProgram(); 4366 } 4367 4368 /** 4369 * Determines whether the APF interpreter advertises support for the data buffer access 4370 * opcodes LDDW (LoaD Data Word) and STDW (STore Data Word). 4371 */ hasDataAccess(int apfVersionSupported)4372 public boolean hasDataAccess(int apfVersionSupported) { 4373 return apfVersionSupported > 2; 4374 } 4375 dump(IndentingPrintWriter pw)4376 public void dump(IndentingPrintWriter pw) { 4377 pw.println(String.format( 4378 "Capabilities: { apfVersionSupported: %d, maximumApfProgramSize: %d }", 4379 mApfVersionSupported, mApfRamSize)); 4380 pw.println("InstallableProgramSizeClamp: " + mInstallableProgramSizeClamp); 4381 pw.println("Filter update status: " + (mIsRunning ? "RUNNING" : "PAUSED")); 4382 pw.println("ApfConfig: " + getApfConfigMessage()); 4383 pw.println("Minimum RDNSS lifetime: " + mMinRdnssLifetimeSec); 4384 pw.println("Interface MAC address: " + MacAddress.fromBytes(mHardwareAddress)); 4385 pw.println("Multicast MAC addresses:"); 4386 pw.increaseIndent(); 4387 for (byte[] addr : mDependencies.getEtherMulticastAddresses(mInterfaceParams.name)) { 4388 pw.println(MacAddress.fromBytes(addr)); 4389 } 4390 pw.decreaseIndent(); 4391 if (SdkLevel.isAtLeastV()) { 4392 pw.print("Hardcoded not denylisted Ethertypes:"); 4393 pw.println( 4394 " 0800(IPv4) 0806(ARP) 86DD(IPv6) 888E(EAPOL) 88B4(WAPI) 890D(TDLS unicast)"); 4395 } else { 4396 pw.print("Denylisted Ethertypes:"); 4397 for (int p : mEthTypeBlackList) { 4398 pw.print(String.format(" %04x", p)); 4399 } 4400 } 4401 try { 4402 pw.println("IPv4 address: " + InetAddress.getByAddress(mIPv4Address).getHostAddress()); 4403 } catch (UnknownHostException | NullPointerException e) { 4404 pw.println("IPv4 address: None"); 4405 } 4406 4407 pw.println("IPv4 multicast addresses:"); 4408 pw.increaseIndent(); 4409 final List<Inet4Address> ipv4McastAddrs = 4410 ProcfsParsingUtils.getIPv4MulticastAddresses(mInterfaceParams.name); 4411 for (Inet4Address addr: ipv4McastAddrs) { 4412 pw.println(addr.getHostAddress()); 4413 } 4414 pw.decreaseIndent(); 4415 pw.println("IPv6 non-tentative addresses:"); 4416 pw.increaseIndent(); 4417 for (Inet6Address addr : mIPv6NonTentativeAddresses) { 4418 pw.println(addr.getHostAddress()); 4419 } 4420 pw.decreaseIndent(); 4421 pw.println("IPv6 tentative addresses:"); 4422 pw.increaseIndent(); 4423 for (Inet6Address addr : mIPv6TentativeAddresses) { 4424 pw.println(addr.getHostAddress()); 4425 } 4426 pw.decreaseIndent(); 4427 pw.println("IPv6 anycast addresses:"); 4428 pw.increaseIndent(); 4429 final List<Inet6Address> anycastAddrs = 4430 ProcfsParsingUtils.getAnycast6Addresses(mInterfaceParams.name); 4431 for (Inet6Address addr : anycastAddrs) { 4432 pw.println(addr.getHostAddress()); 4433 } 4434 pw.decreaseIndent(); 4435 pw.println("IPv6 multicast addresses:"); 4436 pw.increaseIndent(); 4437 final List<Inet6Address> multicastAddrs = 4438 ProcfsParsingUtils.getIpv6MulticastAddresses(mInterfaceParams.name); 4439 for (Inet6Address addr : multicastAddrs) { 4440 pw.println(addr.getHostAddress()); 4441 } 4442 pw.decreaseIndent(); 4443 4444 if (mLastTimeInstalledProgram == 0) { 4445 pw.println("No program installed."); 4446 return; 4447 } 4448 pw.println("Program updates: " + mNumProgramUpdates); 4449 int filterAgeSeconds = secondsSinceBoot() - mLastTimeInstalledProgram; 4450 pw.println(String.format( 4451 "Last program length %d, installed %ds ago, lifetime %ds", 4452 mLastInstalledProgram.length, filterAgeSeconds, 4453 mLastInstalledProgramMinLifetime)); 4454 pw.println(); 4455 pw.println("Mdns filters:"); 4456 pw.increaseIndent(); 4457 if (mNumOfMdnsRuleToOffload == -1) { 4458 pw.println("pass all mDNS packet"); 4459 } else { 4460 for (int i = 0; i < mOffloadRules.size(); ++i) { 4461 final MdnsOffloadRule rule = mOffloadRules.get(i); 4462 if (i >= mNumOfMdnsRuleToOffload) { 4463 pw.println(String.format("passthrough service: %s", rule.mFullServiceName)); 4464 } else { 4465 pw.println(String.format("offload service: %s, payloadSize: %d", 4466 rule.mFullServiceName, 4467 rule.mOffloadPayload == null ? 0 : rule.mOffloadPayload.length)); 4468 } 4469 } 4470 } 4471 pw.decreaseIndent(); 4472 pw.println(); 4473 pw.println("RA filters:"); 4474 pw.increaseIndent(); 4475 for (int i = 0; i < mRas.size(); ++i) { 4476 if (i < mNumFilteredRas) { 4477 pw.println("Filtered: "); 4478 } else { 4479 pw.println("Ignored: "); 4480 } 4481 final Ra ra = mRas.get(i); 4482 pw.println(ra); 4483 pw.increaseIndent(); 4484 pw.println(String.format( 4485 "Last seen %ds ago", secondsSinceBoot() - ra.mLastSeen)); 4486 pw.println("Last match:"); 4487 pw.increaseIndent(); 4488 pw.println(ra.getLastMatchingPacket()); 4489 pw.decreaseIndent(); 4490 pw.decreaseIndent(); 4491 } 4492 pw.decreaseIndent(); 4493 4494 pw.println("TCP Keepalive filters:"); 4495 pw.increaseIndent(); 4496 for (int i = 0; i < mKeepalivePackets.size(); ++i) { 4497 final KeepalivePacket keepalivePacket = mKeepalivePackets.valueAt(i); 4498 if (keepalivePacket instanceof TcpKeepaliveAck) { 4499 pw.print("Slot "); 4500 pw.print(mKeepalivePackets.keyAt(i)); 4501 pw.print(": "); 4502 pw.println(keepalivePacket); 4503 } 4504 } 4505 pw.decreaseIndent(); 4506 4507 pw.println("NAT-T Keepalive filters:"); 4508 pw.increaseIndent(); 4509 for (int i = 0; i < mKeepalivePackets.size(); ++i) { 4510 final KeepalivePacket keepalivePacket = mKeepalivePackets.valueAt(i); 4511 if (keepalivePacket instanceof NattKeepaliveResponse) { 4512 pw.print("Slot "); 4513 pw.print(mKeepalivePackets.keyAt(i)); 4514 pw.print(": "); 4515 pw.println(keepalivePacket); 4516 } 4517 } 4518 pw.decreaseIndent(); 4519 4520 pw.println("Last program:"); 4521 pw.increaseIndent(); 4522 pw.println(HexDump.toHexString(mLastInstalledProgram, false /* lowercase */)); 4523 pw.decreaseIndent(); 4524 4525 pw.println("APF packet counters:"); 4526 pw.increaseIndent(); 4527 if (!hasDataAccess(mApfVersionSupported)) { 4528 pw.println("APF counters not supported"); 4529 } else if (mDataSnapshot == null) { 4530 pw.println("No last snapshot."); 4531 } else { 4532 try { 4533 Counter[] counters = Counter.class.getEnumConstants(); 4534 long counterFilterAgeSeconds = 4535 getCounterValue(mDataSnapshot, FILTER_AGE_SECONDS); 4536 long counterApfProgramId = 4537 getCounterValue(mDataSnapshot, APF_PROGRAM_ID); 4538 for (Counter c : Arrays.asList(counters).subList(1, counters.length)) { 4539 long value = getCounterValue(mDataSnapshot, c); 4540 4541 String note = ""; 4542 boolean checkValueIncreases = true; 4543 switch (c) { 4544 case FILTER_AGE_SECONDS: 4545 checkValueIncreases = false; 4546 if (value != counterFilterAgeSeconds) { 4547 note = " [ERROR: impossible]"; 4548 } else if (counterApfProgramId < mNumProgramUpdates) { 4549 note = " [IGNORE: obsolete program]"; 4550 } else if (value > filterAgeSeconds) { 4551 long offset = value - filterAgeSeconds; 4552 note = " [ERROR: in the future by " + offset + "s]"; 4553 } 4554 break; 4555 case FILTER_AGE_16384THS: 4556 if (mApfVersionSupported > BaseApfGenerator.APF_VERSION_4) { 4557 checkValueIncreases = false; 4558 if (value % 16384 == 0) { 4559 // valid, but unlikely 4560 note = " [INFO: zero fractional portion]"; 4561 } 4562 if (value / 16384 != counterFilterAgeSeconds) { 4563 // should not be able to happen 4564 note = " [ERROR: mismatch with FILTER_AGE_SECONDS]"; 4565 } 4566 } else if (value != 0) { 4567 note = " [UNEXPECTED: APF<=4, yet non-zero]"; 4568 } 4569 break; 4570 case APF_PROGRAM_ID: 4571 if (value != counterApfProgramId) { 4572 note = " [ERROR: impossible]"; 4573 } else if (value < mNumProgramUpdates) { 4574 note = " [WARNING: OBSOLETE PROGRAM]"; 4575 } else if (value > mNumProgramUpdates) { 4576 note = " [ERROR: INVALID FUTURE ID]"; 4577 } 4578 break; 4579 default: 4580 break; 4581 } 4582 4583 // Only print non-zero counters (or those with a note) 4584 if (value != 0 || !note.equals("")) { 4585 pw.println(c.toString() + ": " + value + note); 4586 } 4587 4588 if (checkValueIncreases) { 4589 // If the counter's value decreases, it may have been cleaned up or there 4590 // may be a bug. 4591 long oldValue = mApfCounterTracker.getCounters().getOrDefault(c, 0L); 4592 if (value < oldValue) { 4593 Log.e(TAG, String.format( 4594 "Apf Counter: %s unexpectedly decreased. oldValue: %d. " 4595 + "newValue: %d", c.toString(), oldValue, value)); 4596 } 4597 } 4598 } 4599 } catch (ArrayIndexOutOfBoundsException e) { 4600 pw.println("Uh-oh: " + e); 4601 } 4602 } 4603 pw.decreaseIndent(); 4604 } 4605 4606 /** Return ApfFilter update status for testing purposes. */ isRunning()4607 public boolean isRunning() { 4608 return mIsRunning; 4609 } 4610 4611 /** Pause ApfFilter updates for testing purposes. */ pause()4612 public void pause() { 4613 mIsRunning = false; 4614 } 4615 4616 /** Resume ApfFilter updates for testing purposes. */ resume()4617 public void resume() { 4618 maybeCleanUpApfRam(); 4619 // Since the resume() function and cleanup process invalidate previous counter 4620 // snapshots, the ApfCounterTracker needs to be reset to maintain reliable, incremental 4621 // counter tracking. 4622 mApfCounterTracker.clearCounters(); 4623 mIsRunning = true; 4624 } 4625 4626 /** Return data snapshot as hex string for testing purposes. */ getDataSnapshotHexString()4627 public @Nullable String getDataSnapshotHexString() { 4628 if (mDataSnapshot == null) { 4629 return null; 4630 } 4631 return HexDump.toHexString(mDataSnapshot, 0, mDataSnapshot.length, false /* lowercase */); 4632 } 4633 4634 // TODO: move to android.net.NetworkUtils 4635 @VisibleForTesting ipv4BroadcastAddress(byte[] addrBytes, int prefixLength)4636 public static int ipv4BroadcastAddress(byte[] addrBytes, int prefixLength) { 4637 return bytesToBEInt(addrBytes) | (int) (Integer.toUnsignedLong(-1) >>> prefixLength); 4638 } 4639 uint8(byte b)4640 private static int uint8(byte b) { 4641 return b & 0xff; 4642 } 4643 getUint16(ByteBuffer buffer, int position)4644 private static int getUint16(ByteBuffer buffer, int position) { 4645 return buffer.getShort(position) & 0xffff; 4646 } 4647 getUint32(ByteBuffer buffer, int position)4648 private static long getUint32(ByteBuffer buffer, int position) { 4649 return Integer.toUnsignedLong(buffer.getInt(position)); 4650 } 4651 getUint8(ByteBuffer buffer, int position)4652 private static int getUint8(ByteBuffer buffer, int position) { 4653 return uint8(buffer.get(position)); 4654 } 4655 bytesToBEInt(byte[] bytes)4656 private static int bytesToBEInt(byte[] bytes) { 4657 return (uint8(bytes[0]) << 24) 4658 + (uint8(bytes[1]) << 16) 4659 + (uint8(bytes[2]) << 8) 4660 + (uint8(bytes[3])); 4661 } 4662 sendNetworkQuirkMetrics(final NetworkQuirkEvent event)4663 private void sendNetworkQuirkMetrics(final NetworkQuirkEvent event) { 4664 if (mNetworkQuirkMetrics == null) return; 4665 mNetworkQuirkMetrics.setEvent(event); 4666 mNetworkQuirkMetrics.statsWrite(); 4667 } 4668 } 4669