• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.net.apf;
18 
19 import static android.net.util.SocketUtils.makePacketSocketAddress;
20 import static android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY;
21 import static android.system.OsConstants.AF_PACKET;
22 import static android.system.OsConstants.ARPHRD_ETHER;
23 import static android.system.OsConstants.ETH_P_ARP;
24 import static android.system.OsConstants.ETH_P_IP;
25 import static android.system.OsConstants.ETH_P_IPV6;
26 import static android.system.OsConstants.IPPROTO_ICMPV6;
27 import static android.system.OsConstants.IPPROTO_TCP;
28 import static android.system.OsConstants.IPPROTO_UDP;
29 import static android.system.OsConstants.SOCK_RAW;
30 
31 import static com.android.net.module.util.NetworkStackConstants.ETHER_BROADCAST;
32 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ECHO_REQUEST_TYPE;
33 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_NEIGHBOR_ADVERTISEMENT;
34 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ROUTER_ADVERTISEMENT;
35 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ROUTER_SOLICITATION;
36 import static com.android.net.module.util.NetworkStackConstants.IPV6_ADDR_LEN;
37 import static com.android.networkstack.util.NetworkStackUtils.APF_USE_RA_LIFETIME_CALCULATION_FIX_VERSION;
38 
39 import android.content.BroadcastReceiver;
40 import android.content.Context;
41 import android.content.Intent;
42 import android.content.IntentFilter;
43 import android.net.LinkAddress;
44 import android.net.LinkProperties;
45 import android.net.NattKeepalivePacketDataParcelable;
46 import android.net.TcpKeepalivePacketDataParcelable;
47 import android.net.apf.ApfGenerator.IllegalInstructionException;
48 import android.net.apf.ApfGenerator.Register;
49 import android.net.ip.IpClient.IpClientCallbacksWrapper;
50 import android.net.metrics.ApfProgramEvent;
51 import android.net.metrics.ApfStats;
52 import android.net.metrics.IpConnectivityLog;
53 import android.net.metrics.RaEvent;
54 import android.os.PowerManager;
55 import android.os.SystemClock;
56 import android.system.ErrnoException;
57 import android.system.Os;
58 import android.text.format.DateUtils;
59 import android.util.Log;
60 import android.util.SparseArray;
61 
62 import androidx.annotation.Nullable;
63 
64 import com.android.internal.annotations.GuardedBy;
65 import com.android.internal.annotations.VisibleForTesting;
66 import com.android.internal.util.HexDump;
67 import com.android.internal.util.IndentingPrintWriter;
68 import com.android.net.module.util.CollectionUtils;
69 import com.android.net.module.util.ConnectivityUtils;
70 import com.android.net.module.util.DeviceConfigUtils;
71 import com.android.net.module.util.InterfaceParams;
72 import com.android.net.module.util.SocketUtils;
73 import com.android.networkstack.util.NetworkStackUtils;
74 
75 import java.io.ByteArrayOutputStream;
76 import java.io.FileDescriptor;
77 import java.io.IOException;
78 import java.net.Inet4Address;
79 import java.net.Inet6Address;
80 import java.net.InetAddress;
81 import java.net.SocketAddress;
82 import java.net.SocketException;
83 import java.net.UnknownHostException;
84 import java.nio.BufferUnderflowException;
85 import java.nio.ByteBuffer;
86 import java.nio.ByteOrder;
87 import java.nio.charset.StandardCharsets;
88 import java.util.ArrayList;
89 import java.util.Arrays;
90 import java.util.List;
91 
92 /**
93  * For networks that support packet filtering via APF programs, {@code ApfFilter}
94  * listens for IPv6 ICMPv6 router advertisements (RAs) and generates APF programs to
95  * filter out redundant duplicate ones.
96  *
97  * Threading model:
98  * A collection of RAs we've received is kept in mRas. Generating APF programs uses mRas to
99  * know what RAs to filter for, thus generating APF programs is dependent on mRas.
100  * mRas can be accessed by multiple threads:
101  * - ReceiveThread, which listens for RAs and adds them to mRas, and generates APF programs.
102  * - callers of:
103  *    - setMulticastFilter(), which can cause an APF program to be generated.
104  *    - dump(), which dumps mRas among other things.
105  *    - shutdown(), which clears mRas.
106  * So access to mRas is synchronized.
107  *
108  * @hide
109  */
110 public class ApfFilter {
111 
112     // Helper class for specifying functional filter parameters.
113     public static class ApfConfiguration {
114         public ApfCapabilities apfCapabilities;
115         public boolean multicastFilter;
116         public boolean ieee802_3Filter;
117         public int[] ethTypeBlackList;
118         public int minRdnssLifetimeSec;
119     }
120 
121     // Enums describing the outcome of receiving an RA packet.
122     private static enum ProcessRaResult {
123         MATCH,          // Received RA matched a known RA
124         DROPPED,        // Received RA ignored due to MAX_RAS
125         PARSE_ERROR,    // Received RA could not be parsed
126         ZERO_LIFETIME,  // Received RA had 0 lifetime
127         UPDATE_NEW_RA,  // APF program updated for new RA
128         UPDATE_EXPIRY   // APF program updated for expiry
129     }
130 
131     /**
132      * APF packet counters.
133      *
134      * Packet counters are 32bit big-endian values, and allocated near the end of the APF data
135      * buffer, using negative byte offsets, where -4 is equivalent to maximumApfProgramSize - 4,
136      * the last writable 32bit word.
137      */
138     @VisibleForTesting
139     public static enum Counter {
140         RESERVED_OOB,  // Points to offset 0 from the end of the buffer (out-of-bounds)
141         TOTAL_PACKETS,
142         PASSED_ARP,
143         PASSED_DHCP,
144         PASSED_IPV4,
145         PASSED_IPV6_NON_ICMP,
146         PASSED_IPV4_UNICAST,
147         PASSED_IPV6_ICMP,
148         PASSED_IPV6_UNICAST_NON_ICMP,
149         PASSED_ARP_NON_IPV4,
150         PASSED_ARP_UNKNOWN,
151         PASSED_ARP_UNICAST_REPLY,
152         PASSED_NON_IP_UNICAST,
153         PASSED_MDNS,
154         DROPPED_ETH_BROADCAST,
155         DROPPED_RA,
156         DROPPED_GARP_REPLY,
157         DROPPED_ARP_OTHER_HOST,
158         DROPPED_IPV4_L2_BROADCAST,
159         DROPPED_IPV4_BROADCAST_ADDR,
160         DROPPED_IPV4_BROADCAST_NET,
161         DROPPED_IPV4_MULTICAST,
162         DROPPED_IPV6_ROUTER_SOLICITATION,
163         DROPPED_IPV6_MULTICAST_NA,
164         DROPPED_IPV6_MULTICAST,
165         DROPPED_IPV6_MULTICAST_PING,
166         DROPPED_IPV6_NON_ICMP_MULTICAST,
167         DROPPED_802_3_FRAME,
168         DROPPED_ETHERTYPE_BLACKLISTED,
169         DROPPED_ARP_REPLY_SPA_NO_HOST,
170         DROPPED_IPV4_KEEPALIVE_ACK,
171         DROPPED_IPV6_KEEPALIVE_ACK,
172         DROPPED_IPV4_NATT_KEEPALIVE,
173         DROPPED_MDNS;
174 
175         // Returns the negative byte offset from the end of the APF data segment for
176         // a given counter.
offset()177         public int offset() {
178             return - this.ordinal() * 4;  // Currently, all counters are 32bit long.
179         }
180 
181         // Returns the total size of the data segment in bytes.
totalSize()182         public static int totalSize() {
183             return (Counter.class.getEnumConstants().length - 1) * 4;
184         }
185     }
186 
187     /**
188      * When APFv4 is supported, loads R1 with the offset of the specified counter.
189      */
maybeSetupCounter(ApfGenerator gen, Counter c)190     private void maybeSetupCounter(ApfGenerator gen, Counter c) {
191         if (mApfCapabilities.hasDataAccess()) {
192             gen.addLoadImmediate(Register.R1, c.offset());
193         }
194     }
195 
196     // When APFv4 is supported, these point to the trampolines generated by emitEpilogue().
197     // Otherwise, they're just aliases for PASS_LABEL and DROP_LABEL.
198     private final String mCountAndPassLabel;
199     private final String mCountAndDropLabel;
200 
201     // Thread to listen for RAs.
202     @VisibleForTesting
203     public class ReceiveThread extends Thread {
204         private final byte[] mPacket = new byte[1514];
205         private final FileDescriptor mSocket;
206         private final long mStart = SystemClock.elapsedRealtime();
207 
208         private int mReceivedRas = 0;
209         private int mMatchingRas = 0;
210         private int mDroppedRas = 0;
211         private int mParseErrors = 0;
212         private int mZeroLifetimeRas = 0;
213         private int mProgramUpdates = 0;
214 
215         private volatile boolean mStopped;
216 
ReceiveThread(FileDescriptor socket)217         public ReceiveThread(FileDescriptor socket) {
218             mSocket = socket;
219         }
220 
halt()221         public void halt() {
222             mStopped = true;
223             // Interrupts the read() call the thread is blocked in.
224             SocketUtils.closeSocketQuietly(mSocket);
225         }
226 
227         @Override
run()228         public void run() {
229             log("begin monitoring");
230             while (!mStopped) {
231                 try {
232                     int length = Os.read(mSocket, mPacket, 0, mPacket.length);
233                     updateStats(processRa(mPacket, length));
234                 } catch (IOException|ErrnoException e) {
235                     if (!mStopped) {
236                         Log.e(TAG, "Read error", e);
237                     }
238                 }
239             }
240             logStats();
241         }
242 
updateStats(ProcessRaResult result)243         private void updateStats(ProcessRaResult result) {
244             mReceivedRas++;
245             switch(result) {
246                 case MATCH:
247                     mMatchingRas++;
248                     return;
249                 case DROPPED:
250                     mDroppedRas++;
251                     return;
252                 case PARSE_ERROR:
253                     mParseErrors++;
254                     return;
255                 case ZERO_LIFETIME:
256                     mZeroLifetimeRas++;
257                     return;
258                 case UPDATE_EXPIRY:
259                     mMatchingRas++;
260                     mProgramUpdates++;
261                     return;
262                 case UPDATE_NEW_RA:
263                     mProgramUpdates++;
264                     return;
265             }
266         }
267 
logStats()268         private void logStats() {
269             final long nowMs = SystemClock.elapsedRealtime();
270             synchronized (this) {
271                 final ApfStats stats = new ApfStats.Builder()
272                         .setReceivedRas(mReceivedRas)
273                         .setMatchingRas(mMatchingRas)
274                         .setDroppedRas(mDroppedRas)
275                         .setParseErrors(mParseErrors)
276                         .setZeroLifetimeRas(mZeroLifetimeRas)
277                         .setProgramUpdates(mProgramUpdates)
278                         .setDurationMs(nowMs - mStart)
279                         .setMaxProgramSize(mApfCapabilities.maximumApfProgramSize)
280                         .setProgramUpdatesAll(mNumProgramUpdates)
281                         .setProgramUpdatesAllowingMulticast(mNumProgramUpdatesAllowingMulticast)
282                         .build();
283                 mMetricsLog.log(stats);
284                 logApfProgramEventLocked(nowMs / DateUtils.SECOND_IN_MILLIS);
285             }
286         }
287     }
288 
289     private static final String TAG = "ApfFilter";
290     private static final boolean DBG = true;
291     private static final boolean VDBG = false;
292 
293     private static final int ETH_HEADER_LEN = 14;
294     private static final int ETH_DEST_ADDR_OFFSET = 0;
295     private static final int ETH_ETHERTYPE_OFFSET = 12;
296     private static final int ETH_TYPE_MIN = 0x0600;
297     private static final int ETH_TYPE_MAX = 0xFFFF;
298     // TODO: Make these offsets relative to end of link-layer header; don't include ETH_HEADER_LEN.
299     private static final int IPV4_TOTAL_LENGTH_OFFSET = ETH_HEADER_LEN + 2;
300     private static final int IPV4_FRAGMENT_OFFSET_OFFSET = ETH_HEADER_LEN + 6;
301     // Endianness is not an issue for this constant because the APF interpreter always operates in
302     // network byte order.
303     private static final int IPV4_FRAGMENT_OFFSET_MASK = 0x1fff;
304     private static final int IPV4_PROTOCOL_OFFSET = ETH_HEADER_LEN + 9;
305     private static final int IPV4_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 16;
306     private static final int IPV4_ANY_HOST_ADDRESS = 0;
307     private static final int IPV4_BROADCAST_ADDRESS = -1; // 255.255.255.255
308     private static final int IPV4_HEADER_LEN = 20; // Without options
309 
310     // Traffic class and Flow label are not byte aligned. Luckily we
311     // don't care about either value so we'll consider bytes 1-3 of the
312     // IPv6 header as don't care.
313     private static final int IPV6_FLOW_LABEL_OFFSET = ETH_HEADER_LEN + 1;
314     private static final int IPV6_FLOW_LABEL_LEN = 3;
315     private static final int IPV6_NEXT_HEADER_OFFSET = ETH_HEADER_LEN + 6;
316     private static final int IPV6_SRC_ADDR_OFFSET = ETH_HEADER_LEN + 8;
317     private static final int IPV6_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 24;
318     private static final int IPV6_HEADER_LEN = 40;
319     // The IPv6 all nodes address ff02::1
320     private static final byte[] IPV6_ALL_NODES_ADDRESS =
321             { (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
322 
323     private static final int ICMP6_TYPE_OFFSET = ETH_HEADER_LEN + IPV6_HEADER_LEN;
324 
325     // NOTE: this must be added to the IPv4 header length in IPV4_HEADER_SIZE_MEMORY_SLOT
326     private static final int UDP_DESTINATION_PORT_OFFSET = ETH_HEADER_LEN + 2;
327     private static final int UDP_HEADER_LEN = 8;
328 
329     private static final int TCP_HEADER_SIZE_OFFSET = 12;
330 
331     private static final int DHCP_CLIENT_PORT = 68;
332     // NOTE: this must be added to the IPv4 header length in IPV4_HEADER_SIZE_MEMORY_SLOT
333     private static final int DHCP_CLIENT_MAC_OFFSET = ETH_HEADER_LEN + UDP_HEADER_LEN + 28;
334 
335     private static final int ARP_HEADER_OFFSET = ETH_HEADER_LEN;
336     private static final byte[] ARP_IPV4_HEADER = {
337             0, 1, // Hardware type: Ethernet (1)
338             8, 0, // Protocol type: IP (0x0800)
339             6,    // Hardware size: 6
340             4,    // Protocol size: 4
341     };
342     private static final int ARP_OPCODE_OFFSET = ARP_HEADER_OFFSET + 6;
343     // Opcode: ARP request (0x0001), ARP reply (0x0002)
344     private static final short ARP_OPCODE_REQUEST = 1;
345     private static final short ARP_OPCODE_REPLY = 2;
346     private static final int ARP_SOURCE_IP_ADDRESS_OFFSET = ARP_HEADER_OFFSET + 14;
347     private static final int ARP_TARGET_IP_ADDRESS_OFFSET = ARP_HEADER_OFFSET + 24;
348     // Do not log ApfProgramEvents whose actual lifetimes was less than this.
349     private static final int APF_PROGRAM_EVENT_LIFETIME_THRESHOLD = 2;
350     // Limit on the Black List size to cap on program usage for this
351     // TODO: Select a proper max length
352     private static final int APF_MAX_ETH_TYPE_BLACK_LIST_LEN = 20;
353 
354     private static final byte[] ETH_MULTICAST_MDNS_V4_MAC_ADDRESS =
355             {(byte) 0x01, (byte) 0x00, (byte) 0x5e, (byte) 0x00, (byte) 0x00, (byte) 0xfb};
356     private static final byte[] ETH_MULTICAST_MDNS_V6_MAC_ADDRESS =
357             {(byte) 0x33, (byte) 0x33, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0xfb};
358     private static final int MDNS_PORT = 5353;
359     private static final int DNS_HEADER_LEN = 12;
360     private static final int DNS_QDCOUNT_OFFSET = 4;
361     // NOTE: this must be added to the IPv4 header length in IPV4_HEADER_SIZE_MEMORY_SLOT, or the
362     // IPv6 header length.
363     private static final int MDNS_QDCOUNT_OFFSET =
364             ETH_HEADER_LEN + UDP_HEADER_LEN + DNS_QDCOUNT_OFFSET;
365     private static final int MDNS_QNAME_OFFSET =
366             ETH_HEADER_LEN + UDP_HEADER_LEN + DNS_HEADER_LEN;
367 
368 
369 
370     private final ApfCapabilities mApfCapabilities;
371     private final IpClientCallbacksWrapper mIpClientCallback;
372     private final InterfaceParams mInterfaceParams;
373     private final IpConnectivityLog mMetricsLog;
374 
375     @VisibleForTesting
376     public byte[] mHardwareAddress;
377     @VisibleForTesting
378     public ReceiveThread mReceiveThread;
379     @GuardedBy("this")
380     private long mUniqueCounter;
381     @GuardedBy("this")
382     private boolean mMulticastFilter;
383     @GuardedBy("this")
384     private boolean mInDozeMode;
385     private final boolean mDrop802_3Frames;
386     private final int[] mEthTypeBlackList;
387 
388     // Ignore non-zero RDNSS lifetimes below this value.
389     private final int mMinRdnssLifetimeSec;
390 
391     // Flag to use the RA lifetime calculation fix in aosp/2276160.
392     private final boolean mUseLifetimeCalculationFix;
393 
394     // Detects doze mode state transitions.
395     private final BroadcastReceiver mDeviceIdleReceiver = new BroadcastReceiver() {
396         @Override
397         public void onReceive(Context context, Intent intent) {
398             String action = intent.getAction();
399             if (action.equals(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED)) {
400                 PowerManager powerManager =
401                         (PowerManager) context.getSystemService(Context.POWER_SERVICE);
402                 final boolean deviceIdle = powerManager.isDeviceIdleMode();
403                 setDozeMode(deviceIdle);
404             }
405         }
406     };
407     private final Context mContext;
408 
409     // Our IPv4 address, if we have just one, otherwise null.
410     @GuardedBy("this")
411     private byte[] mIPv4Address;
412     // The subnet prefix length of our IPv4 network. Only valid if mIPv4Address is not null.
413     @GuardedBy("this")
414     private int mIPv4PrefixLength;
415 
416     /**
417      * Dependencies for the ApfFilter. Useful to be mocked in tests.
418      */
419     public static class Dependencies {
420         /**
421          * Return whether a feature guarded by a feature flag is enabled.
422          * @see NetworkStackUtils#isFeatureEnabled(Context, String, String)
423          */
isFeatureEnabled(final Context context, final String name, boolean defaultEnabled)424         public boolean isFeatureEnabled(final Context context, final String name,
425                 boolean defaultEnabled) {
426             return DeviceConfigUtils.isFeatureEnabled(context, NAMESPACE_CONNECTIVITY, name,
427                     defaultEnabled);
428         }
429     }
430 
ApfFilter(Context context, ApfConfiguration config, InterfaceParams ifParams, IpClientCallbacksWrapper ipClientCallback, IpConnectivityLog log)431     public ApfFilter(Context context, ApfConfiguration config, InterfaceParams ifParams,
432             IpClientCallbacksWrapper ipClientCallback, IpConnectivityLog log) {
433         this(context, config, ifParams, ipClientCallback, log, new Dependencies());
434     }
435 
436     @VisibleForTesting
ApfFilter(Context context, ApfConfiguration config, InterfaceParams ifParams, IpClientCallbacksWrapper ipClientCallback, IpConnectivityLog log, Dependencies deps)437     public ApfFilter(Context context, ApfConfiguration config, InterfaceParams ifParams,
438             IpClientCallbacksWrapper ipClientCallback, IpConnectivityLog log, Dependencies deps) {
439         mApfCapabilities = config.apfCapabilities;
440         mIpClientCallback = ipClientCallback;
441         mInterfaceParams = ifParams;
442         mMulticastFilter = config.multicastFilter;
443         mDrop802_3Frames = config.ieee802_3Filter;
444         mMinRdnssLifetimeSec = config.minRdnssLifetimeSec;
445         mUseLifetimeCalculationFix = deps.isFeatureEnabled(context,
446                 APF_USE_RA_LIFETIME_CALCULATION_FIX_VERSION, true /* defaultEnabled */);
447         mContext = context;
448 
449         if (mApfCapabilities.hasDataAccess()) {
450             mCountAndPassLabel = "countAndPass";
451             mCountAndDropLabel = "countAndDrop";
452         } else {
453             // APFv4 unsupported: turn jumps to the counter trampolines to immediately PASS or DROP,
454             // preserving the original pre-APFv4 behavior.
455             mCountAndPassLabel = ApfGenerator.PASS_LABEL;
456             mCountAndDropLabel = ApfGenerator.DROP_LABEL;
457         }
458 
459         // Now fill the black list from the passed array
460         mEthTypeBlackList = filterEthTypeBlackList(config.ethTypeBlackList);
461 
462         mMetricsLog = log;
463 
464         // TODO: ApfFilter should not generate programs until IpClient sends provisioning success.
465         maybeStartFilter();
466 
467         // Listen for doze-mode transition changes to enable/disable the IPv6 multicast filter.
468         mContext.registerReceiver(mDeviceIdleReceiver,
469                 new IntentFilter(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED));
470     }
471 
setDataSnapshot(byte[] data)472     public synchronized void setDataSnapshot(byte[] data) {
473         mDataSnapshot = data;
474     }
475 
log(String s)476     private void log(String s) {
477         Log.d(TAG, "(" + mInterfaceParams.name + "): " + s);
478     }
479 
480     @GuardedBy("this")
getUniqueNumberLocked()481     private long getUniqueNumberLocked() {
482         return mUniqueCounter++;
483     }
484 
485     @GuardedBy("this")
filterEthTypeBlackList(int[] ethTypeBlackList)486     private static int[] filterEthTypeBlackList(int[] ethTypeBlackList) {
487         ArrayList<Integer> bl = new ArrayList<Integer>();
488 
489         for (int p : ethTypeBlackList) {
490             // Check if the protocol is a valid ether type
491             if ((p < ETH_TYPE_MIN) || (p > ETH_TYPE_MAX)) {
492                 continue;
493             }
494 
495             // Check if the protocol is not repeated in the passed array
496             if (bl.contains(p)) {
497                 continue;
498             }
499 
500             // Check if list reach its max size
501             if (bl.size() == APF_MAX_ETH_TYPE_BLACK_LIST_LEN) {
502                 Log.w(TAG, "Passed EthType Black List size too large (" + bl.size() +
503                         ") using top " + APF_MAX_ETH_TYPE_BLACK_LIST_LEN + " protocols");
504                 break;
505             }
506 
507             // Now add the protocol to the list
508             bl.add(p);
509         }
510 
511         return bl.stream().mapToInt(Integer::intValue).toArray();
512     }
513 
514     /**
515      * Attempt to start listening for RAs and, if RAs are received, generating and installing
516      * filters to ignore useless RAs.
517      */
518     @VisibleForTesting
maybeStartFilter()519     public void maybeStartFilter() {
520         FileDescriptor socket;
521         try {
522             mHardwareAddress = mInterfaceParams.macAddr.toByteArray();
523             synchronized(this) {
524                 // Clear the APF memory to reset all counters upon connecting to the first AP
525                 // in an SSID. This is limited to APFv4 devices because this large write triggers
526                 // a crash on some older devices (b/78905546).
527                 if (mApfCapabilities.hasDataAccess()) {
528                     byte[] zeroes = new byte[mApfCapabilities.maximumApfProgramSize];
529                     mIpClientCallback.installPacketFilter(zeroes);
530                 }
531 
532                 // Install basic filters
533                 installNewProgramLocked();
534             }
535             socket = Os.socket(AF_PACKET, SOCK_RAW, ETH_P_IPV6);
536             SocketAddress addr = makePacketSocketAddress(ETH_P_IPV6, mInterfaceParams.index);
537             Os.bind(socket, addr);
538             NetworkStackUtils.attachRaFilter(socket, mApfCapabilities.apfPacketFormat);
539         } catch(SocketException|ErrnoException e) {
540             Log.e(TAG, "Error starting filter", e);
541             return;
542         }
543         mReceiveThread = new ReceiveThread(socket);
544         mReceiveThread.start();
545     }
546 
547     // Returns seconds since device boot.
548     @VisibleForTesting
currentTimeSeconds()549     protected long currentTimeSeconds() {
550         return SystemClock.elapsedRealtime() / DateUtils.SECOND_IN_MILLIS;
551     }
552 
553     public static class InvalidRaException extends Exception {
InvalidRaException(String m)554         public InvalidRaException(String m) {
555             super(m);
556         }
557     }
558 
559     /**
560      *  Class to keep track of a section in a packet.
561      */
562     private static class PacketSection {
563         public enum Type {
564             MATCH,     // A field that should be matched (e.g., the router IP address).
565             IGNORE,    // An ignored field such as the checksum of the flow label. Not matched.
566             LIFETIME,  // A lifetime. Not matched, and generally counts toward minimum RA lifetime.
567         }
568 
569         /** The type of section. */
570         public final Type type;
571         /** Offset into the packet at which this section begins. */
572         public final int start;
573         /** Length of this section in bytes. */
574         public final int length;
575         /** If this is a lifetime, the ICMP option that defined it. 0 for router lifetime. */
576         public final int option;
577         /** If this is a lifetime, the lifetime value. */
578         public final long lifetime;
579 
PacketSection(int start, int length, Type type, int option, long lifetime)580         PacketSection(int start, int length, Type type, int option, long lifetime) {
581             this.start = start;
582             this.length = length;
583             this.type = type;
584             this.option = option;
585             this.lifetime = lifetime;
586         }
587 
toString()588         public String toString() {
589             if (type == Type.LIFETIME) {
590                 return String.format("%s: (%d, %d) %d %d", type, start, length, option, lifetime);
591             } else {
592                 return String.format("%s: (%d, %d)", type, start, length);
593             }
594         }
595     }
596 
597     // A class to hold information about an RA.
598     @VisibleForTesting
599     public class Ra {
600         // From RFC4861:
601         private static final int ICMP6_RA_HEADER_LEN = 16;
602         private static final int ICMP6_RA_CHECKSUM_OFFSET =
603                 ETH_HEADER_LEN + IPV6_HEADER_LEN + 2;
604         private static final int ICMP6_RA_CHECKSUM_LEN = 2;
605         private static final int ICMP6_RA_OPTION_OFFSET =
606                 ETH_HEADER_LEN + IPV6_HEADER_LEN + ICMP6_RA_HEADER_LEN;
607         private static final int ICMP6_RA_ROUTER_LIFETIME_OFFSET =
608                 ETH_HEADER_LEN + IPV6_HEADER_LEN + 6;
609         private static final int ICMP6_RA_ROUTER_LIFETIME_LEN = 2;
610         // Prefix information option.
611         private static final int ICMP6_PREFIX_OPTION_TYPE = 3;
612         private static final int ICMP6_PREFIX_OPTION_LEN = 32;
613         private static final int ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET = 4;
614         private static final int ICMP6_PREFIX_OPTION_VALID_LIFETIME_LEN = 4;
615         private static final int ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET = 8;
616         private static final int ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_LEN = 4;
617 
618         // From RFC6106: Recursive DNS Server option
619         private static final int ICMP6_RDNSS_OPTION_TYPE = 25;
620         // From RFC6106: DNS Search List option
621         private static final int ICMP6_DNSSL_OPTION_TYPE = 31;
622 
623         // From RFC4191: Route Information option
624         private static final int ICMP6_ROUTE_INFO_OPTION_TYPE = 24;
625         // Above three options all have the same format:
626         private static final int ICMP6_4_BYTE_LIFETIME_OFFSET = 4;
627         private static final int ICMP6_4_BYTE_LIFETIME_LEN = 4;
628 
629         // Note: mPacket's position() cannot be assumed to be reset.
630         private final ByteBuffer mPacket;
631 
632         // List of sections in the packet.
633         private final ArrayList<PacketSection> mPacketSections = new ArrayList<>();
634 
635         // Minimum lifetime in packet
636         long mMinLifetime;
637         // When the packet was last captured, in seconds since Unix Epoch
638         long mLastSeen;
639 
640         // For debugging only. Offsets into the packet where PIOs are.
641         private final ArrayList<Integer> mPrefixOptionOffsets = new ArrayList<>();
642 
643         // For debugging only. Offsets into the packet where RDNSS options are.
644         private final ArrayList<Integer> mRdnssOptionOffsets = new ArrayList<>();
645 
646         // For debugging only. Offsets into the packet where RIO options are.
647         private final ArrayList<Integer> mRioOptionOffsets = new ArrayList<>();
648 
649         // For debugging only. How many times this RA was seen.
650         int seenCount = 0;
651 
652         // For debugging only. Returns the hex representation of the last matching packet.
getLastMatchingPacket()653         String getLastMatchingPacket() {
654             return HexDump.toHexString(mPacket.array(), 0, mPacket.capacity(),
655                     false /* lowercase */);
656         }
657 
658         // For debugging only. Returns the string representation of the IPv6 address starting at
659         // position pos in the packet.
IPv6AddresstoString(int pos)660         private String IPv6AddresstoString(int pos) {
661             try {
662                 byte[] array = mPacket.array();
663                 // Can't just call copyOfRange() and see if it throws, because if it reads past the
664                 // end it pads with zeros instead of throwing.
665                 if (pos < 0 || pos + 16 > array.length || pos + 16 < pos) {
666                     return "???";
667                 }
668                 byte[] addressBytes = Arrays.copyOfRange(array, pos, pos + 16);
669                 InetAddress address = (Inet6Address) InetAddress.getByAddress(addressBytes);
670                 return address.getHostAddress();
671             } catch (UnsupportedOperationException e) {
672                 // array() failed. Cannot happen, mPacket is array-backed and read-write.
673                 return "???";
674             } catch (ClassCastException|UnknownHostException e) {
675                 // Cannot happen.
676                 return "???";
677             }
678         }
679 
680         // Can't be static because it's in a non-static inner class.
681         // TODO: Make this static once RA is its own class.
prefixOptionToString(StringBuffer sb, int offset)682         private void prefixOptionToString(StringBuffer sb, int offset) {
683             String prefix = IPv6AddresstoString(offset + 16);
684             int length = getUint8(mPacket, offset + 2);
685             long valid = getUint32(mPacket, offset + 4);
686             long preferred = getUint32(mPacket, offset + 8);
687             sb.append(String.format("%s/%d %ds/%ds ", prefix, length, valid, preferred));
688         }
689 
rdnssOptionToString(StringBuffer sb, int offset)690         private void rdnssOptionToString(StringBuffer sb, int offset) {
691             int optLen = getUint8(mPacket, offset + 1) * 8;
692             if (optLen < 24) return;  // Malformed or empty.
693             long lifetime = getUint32(mPacket, offset + 4);
694             int numServers = (optLen - 8) / 16;
695             sb.append("DNS ").append(lifetime).append("s");
696             for (int server = 0; server < numServers; server++) {
697                 sb.append(" ").append(IPv6AddresstoString(offset + 8 + 16 * server));
698             }
699             sb.append(" ");
700         }
701 
rioOptionToString(StringBuffer sb, int offset)702         private void rioOptionToString(StringBuffer sb, int offset) {
703             int optLen = getUint8(mPacket, offset + 1) * 8;
704             if (optLen < 8 || optLen > 24) return;  // Malformed or empty.
705             int prefixLen = getUint8(mPacket, offset + 2);
706             long lifetime = getUint32(mPacket, offset + 4);
707 
708             // This read is variable length because the prefix can be 0, 8 or 16 bytes long.
709             // We can't use any of the ByteBuffer#get methods here because they all start reading
710             // from the buffer's current position.
711             byte[] prefix = new byte[IPV6_ADDR_LEN];
712             System.arraycopy(mPacket.array(), offset + 8, prefix, 0, optLen - 8);
713             sb.append("RIO ").append(lifetime).append("s ");
714             try {
715                 InetAddress address = (Inet6Address) InetAddress.getByAddress(prefix);
716                 sb.append(address.getHostAddress());
717             } catch (UnknownHostException impossible) {
718                 sb.append("???");
719             }
720             sb.append("/").append(prefixLen).append(" ");
721         }
722 
toString()723         public String toString() {
724             try {
725                 StringBuffer sb = new StringBuffer();
726                 sb.append(String.format("RA %s -> %s %ds ",
727                         IPv6AddresstoString(IPV6_SRC_ADDR_OFFSET),
728                         IPv6AddresstoString(IPV6_DEST_ADDR_OFFSET),
729                         getUint16(mPacket, ICMP6_RA_ROUTER_LIFETIME_OFFSET)));
730                 for (int i: mPrefixOptionOffsets) {
731                     prefixOptionToString(sb, i);
732                 }
733                 for (int i: mRdnssOptionOffsets) {
734                     rdnssOptionToString(sb, i);
735                 }
736                 for (int i: mRioOptionOffsets) {
737                     rioOptionToString(sb, i);
738                 }
739                 return sb.toString();
740             } catch (BufferUnderflowException|IndexOutOfBoundsException e) {
741                 return "<Malformed RA>";
742             }
743         }
744 
745         /**
746          * Add a packet section that should be matched, starting from the current position.
747          * @param length the length of the section
748          */
addMatchSection(int length)749         private void addMatchSection(int length) {
750             // Don't generate JNEBS instruction for 0 bytes as they will fail the
751             // ASSERT_FORWARD_IN_PROGRAM(pc + cmp_imm - 1) check (where cmp_imm is
752             // the number of bytes to compare) and immediately pass the packet.
753             // The code does not attempt to generate such matches, but add a safety
754             // check to prevent doing so in the presence of bugs or malformed or
755             // truncated packets.
756             if (length == 0) return;
757             mPacketSections.add(
758                     new PacketSection(mPacket.position(), length, PacketSection.Type.MATCH, 0, 0));
759             mPacket.position(mPacket.position() + length);
760         }
761 
762         /**
763          * Add a packet section that should be matched, starting from the current position.
764          * @param end the offset in the packet before which the section ends
765          */
addMatchUntil(int end)766         private void addMatchUntil(int end) {
767             addMatchSection(end - mPacket.position());
768         }
769 
770         /**
771          * Add a packet section that should be ignored, starting from the current position.
772          * @param length the length of the section in bytes
773          */
addIgnoreSection(int length)774         private void addIgnoreSection(int length) {
775             mPacketSections.add(
776                     new PacketSection(mPacket.position(), length, PacketSection.Type.IGNORE, 0, 0));
777             mPacket.position(mPacket.position() + length);
778         }
779 
780         /**
781          * Add a packet section that represents a lifetime, starting from the current position.
782          * @param length the length of the section in bytes
783          * @param optionType the RA option containing this lifetime, or 0 for router lifetime
784          * @param lifetime the lifetime
785          */
addLifetimeSection(int length, int optionType, long lifetime)786         private void addLifetimeSection(int length, int optionType, long lifetime) {
787             mPacketSections.add(
788                     new PacketSection(mPacket.position(), length, PacketSection.Type.LIFETIME,
789                             optionType, lifetime));
790             mPacket.position(mPacket.position() + length);
791         }
792 
793         /**
794          * Adds packet sections for an RA option with a 4-byte lifetime 4 bytes into the option
795          * @param optionType the RA option that is being added
796          * @param optionLength the length of the option in bytes
797          */
add4ByteLifetimeOption(int optionType, int optionLength)798         private long add4ByteLifetimeOption(int optionType, int optionLength) {
799             addMatchSection(ICMP6_4_BYTE_LIFETIME_OFFSET);
800             final long lifetime = getUint32(mPacket, mPacket.position());
801             addLifetimeSection(ICMP6_4_BYTE_LIFETIME_LEN, optionType, lifetime);
802             addMatchSection(optionLength - ICMP6_4_BYTE_LIFETIME_OFFSET
803                     - ICMP6_4_BYTE_LIFETIME_LEN);
804             return lifetime;
805         }
806 
807         // http://b/66928272 http://b/65056012
808         // DnsServerRepository ignores RDNSS servers with lifetimes that are too low. Ignore these
809         // lifetimes for the purpose of filter lifetime calculations.
shouldIgnoreLifetime(int optionType, long lifetime)810         private boolean shouldIgnoreLifetime(int optionType, long lifetime) {
811             return optionType == ICMP6_RDNSS_OPTION_TYPE
812                     && lifetime != 0 && lifetime < mMinRdnssLifetimeSec;
813         }
814 
isRelevantLifetime(PacketSection section)815         private boolean isRelevantLifetime(PacketSection section) {
816             return section.type == PacketSection.Type.LIFETIME
817                     && !shouldIgnoreLifetime(section.option, section.lifetime);
818         }
819 
820         // Note that this parses RA and may throw InvalidRaException (from
821         // Buffer.position(int) or due to an invalid-length option) or IndexOutOfBoundsException
822         // (from ByteBuffer.get(int) ) if parsing encounters something non-compliant with
823         // specifications.
824         @VisibleForTesting
Ra(byte[] packet, int length)825         public Ra(byte[] packet, int length) throws InvalidRaException {
826             if (length < ICMP6_RA_OPTION_OFFSET) {
827                 throw new InvalidRaException("Not an ICMP6 router advertisement: too short");
828             }
829 
830             mPacket = ByteBuffer.wrap(Arrays.copyOf(packet, length));
831             mLastSeen = currentTimeSeconds();
832 
833             // Check packet in case a packet arrives before we attach RA filter
834             // to our packet socket. b/29586253
835             if (getUint16(mPacket, ETH_ETHERTYPE_OFFSET) != ETH_P_IPV6 ||
836                     getUint8(mPacket, IPV6_NEXT_HEADER_OFFSET) != IPPROTO_ICMPV6 ||
837                     getUint8(mPacket, ICMP6_TYPE_OFFSET) != ICMPV6_ROUTER_ADVERTISEMENT) {
838                 throw new InvalidRaException("Not an ICMP6 router advertisement");
839             }
840 
841 
842             RaEvent.Builder builder = new RaEvent.Builder();
843 
844             // Ignore the flow label and low 4 bits of traffic class.
845             addMatchUntil(IPV6_FLOW_LABEL_OFFSET);
846             addIgnoreSection(IPV6_FLOW_LABEL_LEN);
847 
848             // Ignore checksum.
849             addMatchUntil(ICMP6_RA_CHECKSUM_OFFSET);
850             addIgnoreSection(ICMP6_RA_CHECKSUM_LEN);
851 
852             // Parse router lifetime
853             addMatchUntil(ICMP6_RA_ROUTER_LIFETIME_OFFSET);
854             final long routerLifetime = getUint16(mPacket, ICMP6_RA_ROUTER_LIFETIME_OFFSET);
855             addLifetimeSection(ICMP6_RA_ROUTER_LIFETIME_LEN, 0, routerLifetime);
856             builder.updateRouterLifetime(routerLifetime);
857 
858             // Add remaining fields (reachable time and retransmission timer) to match section.
859             addMatchUntil(ICMP6_RA_OPTION_OFFSET);
860 
861             while (mPacket.hasRemaining()) {
862                 final int position = mPacket.position();
863                 final int optionType = getUint8(mPacket, position);
864                 final int optionLength = getUint8(mPacket, position + 1) * 8;
865                 long lifetime;
866                 switch (optionType) {
867                     case ICMP6_PREFIX_OPTION_TYPE:
868                         mPrefixOptionOffsets.add(position);
869 
870                         // Parse valid lifetime
871                         addMatchSection(ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET);
872                         lifetime = getUint32(mPacket, mPacket.position());
873                         addLifetimeSection(ICMP6_PREFIX_OPTION_VALID_LIFETIME_LEN,
874                                 ICMP6_PREFIX_OPTION_TYPE, lifetime);
875                         builder.updatePrefixValidLifetime(lifetime);
876 
877                         // Parse preferred lifetime
878                         lifetime = getUint32(mPacket, mPacket.position());
879                         addLifetimeSection(ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_LEN,
880                                 ICMP6_PREFIX_OPTION_TYPE, lifetime);
881                         builder.updatePrefixPreferredLifetime(lifetime);
882 
883                         addMatchSection(4);       // Reserved bytes
884                         addMatchSection(IPV6_ADDR_LEN);  // The prefix itself
885                         break;
886                     // These three options have the same lifetime offset and size, and
887                     // are processed with the same specialized add4ByteLifetimeOption:
888                     case ICMP6_RDNSS_OPTION_TYPE:
889                         mRdnssOptionOffsets.add(position);
890                         lifetime = add4ByteLifetimeOption(optionType, optionLength);
891                         builder.updateRdnssLifetime(lifetime);
892                         break;
893                     case ICMP6_ROUTE_INFO_OPTION_TYPE:
894                         mRioOptionOffsets.add(position);
895                         lifetime = add4ByteLifetimeOption(optionType, optionLength);
896                         builder.updateRouteInfoLifetime(lifetime);
897                         break;
898                     case ICMP6_DNSSL_OPTION_TYPE:
899                         lifetime = add4ByteLifetimeOption(optionType, optionLength);
900                         builder.updateDnsslLifetime(lifetime);
901                         break;
902                     default:
903                         // RFC4861 section 4.2 dictates we ignore unknown options for forwards
904                         // compatibility.
905                         mPacket.position(position + optionLength);
906                         break;
907                 }
908                 if (optionLength <= 0) {
909                     throw new InvalidRaException(String.format(
910                         "Invalid option length opt=%d len=%d", optionType, optionLength));
911                 }
912             }
913             mMinLifetime = minLifetime();
914             mMetricsLog.log(builder.build());
915         }
916 
917         // Considering only the MATCH sections, does {@code packet} match this RA?
matches(byte[] packet, int length)918         boolean matches(byte[] packet, int length) {
919             if (length != mPacket.capacity()) return false;
920             byte[] referencePacket = mPacket.array();
921             for (PacketSection section : mPacketSections) {
922                 if (section.type != PacketSection.Type.MATCH) continue;
923                 for (int i = section.start; i < (section.start + section.length); i++) {
924                     if (packet[i] != referencePacket[i]) return false;
925                 }
926             }
927             return true;
928         }
929 
930         // What is the minimum of all lifetimes within {@code packet} in seconds?
931         // Precondition: matches(packet, length) already returned true.
minLifetime()932         long minLifetime() {
933             long minLifetime = Long.MAX_VALUE;
934             for (PacketSection section : mPacketSections) {
935                 if (isRelevantLifetime(section)) {
936                     minLifetime = Math.min(minLifetime, section.lifetime);
937                 }
938             }
939             return minLifetime;
940         }
941 
942         // How many seconds does this RA's have to live, taking into account the fact
943         // that we might have seen it a while ago.
currentLifetime()944         long currentLifetime() {
945             return mMinLifetime - (currentTimeSeconds() - mLastSeen);
946         }
947 
isExpired()948         boolean isExpired() {
949             // TODO: We may want to handle 0 lifetime RAs differently, if they are common. We'll
950             // have to calculate the filter lifetime specially as a fraction of 0 is still 0.
951             return currentLifetime() <= 0;
952         }
953 
954         // Filter for a fraction of the lifetime and adjust for the age of the RA.
955         @GuardedBy("ApfFilter.this")
filterLifetime()956         int filterLifetime() {
957             // Use a flag from device config to toggle on/off the use of lifetime calculation fix
958             // in aosp/2276160. The old buggy behavior drops more RAs in some circumstances which
959             // probably use less battery. We can change it immediately if any OEM complains about
960             // additional battery usage after the fix.
961             if (mUseLifetimeCalculationFix) {
962                 return (int) (mMinLifetime / FRACTION_OF_LIFETIME_TO_FILTER)
963                         - (int) (mProgramBaseTime - mLastSeen);
964             } else {
965                 // The old buggy formula, always filter a fraction of the remaining lifetime.
966                 return (int) (currentLifetime() / FRACTION_OF_LIFETIME_TO_FILTER);
967             }
968         }
969 
970         @GuardedBy("ApfFilter.this")
shouldFilter()971         boolean shouldFilter() {
972             return filterLifetime() > 0;
973         }
974 
975         // Append a filter for this RA to {@code gen}. Jump to DROP_LABEL if it should be dropped.
976         // Jump to the next filter if packet doesn't match this RA.
977         // Return Long.MAX_VALUE if we don't install any filter program for this RA. As the return
978         // value of this function is used to calculate the program min lifetime (which corresponds
979         // to the smallest generated filter lifetime). Returning Long.MAX_VALUE in the case no
980         // filter gets generated makes sure the program lifetime stays unaffected.
981         @GuardedBy("ApfFilter.this")
generateFilterLocked(ApfGenerator gen)982         long generateFilterLocked(ApfGenerator gen) throws IllegalInstructionException {
983             String nextFilterLabel = "Ra" + getUniqueNumberLocked();
984             // Skip if packet is not the right size
985             gen.addLoadFromMemory(Register.R0, gen.PACKET_SIZE_MEMORY_SLOT);
986             gen.addJumpIfR0NotEquals(mPacket.capacity(), nextFilterLabel);
987             // Skip filter if expired
988             gen.addLoadFromMemory(Register.R0, gen.FILTER_AGE_MEMORY_SLOT);
989             gen.addJumpIfR0GreaterThan(filterLifetime(), nextFilterLabel);
990             for (PacketSection section : mPacketSections) {
991                 // Generate code to match the packet bytes.
992                 if (section.type == PacketSection.Type.MATCH) {
993                     gen.addLoadImmediate(Register.R0, section.start);
994                     gen.addJumpIfBytesNotEqual(Register.R0,
995                             Arrays.copyOfRange(mPacket.array(), section.start,
996                                     section.start + section.length),
997                             nextFilterLabel);
998                 }
999 
1000                 // Generate code to test the lifetimes haven't gone down too far.
1001                 // The packet is accepted if any non-ignored lifetime is lower than filterLifetime.
1002                 if (isRelevantLifetime(section)) {
1003                     switch (section.length) {
1004                         case 4: gen.addLoad32(Register.R0, section.start); break;
1005                         case 2: gen.addLoad16(Register.R0, section.start); break;
1006                         default:
1007                             throw new IllegalStateException(
1008                                     "bogus lifetime size " + section.length);
1009                     }
1010                     gen.addJumpIfR0LessThan(filterLifetime(), nextFilterLabel);
1011                 }
1012             }
1013             maybeSetupCounter(gen, Counter.DROPPED_RA);
1014             gen.addJump(mCountAndDropLabel);
1015             gen.defineLabel(nextFilterLabel);
1016             return filterLifetime();
1017         }
1018     }
1019 
1020     // TODO: Refactor these subclasses to avoid so much repetition.
1021     private abstract static class KeepalivePacket {
1022         // Note that the offset starts from IP header.
1023         // These must be added ether header length when generating program.
1024         static final int IP_HEADER_OFFSET = 0;
1025         static final int IPV4_SRC_ADDR_OFFSET = IP_HEADER_OFFSET + 12;
1026 
1027         // Append a filter for this keepalive ack to {@code gen}.
1028         // Jump to drop if it matches the keepalive ack.
1029         // Jump to the next filter if packet doesn't match the keepalive ack.
generateFilterLocked(ApfGenerator gen)1030         abstract void generateFilterLocked(ApfGenerator gen) throws IllegalInstructionException;
1031     }
1032 
1033     // A class to hold NAT-T keepalive ack information.
1034     private class NattKeepaliveResponse extends KeepalivePacket {
1035         static final int UDP_LENGTH_OFFSET = 4;
1036         static final int UDP_HEADER_LEN = 8;
1037 
1038         protected class NattKeepaliveResponseData {
1039             public final byte[] srcAddress;
1040             public final int srcPort;
1041             public final byte[] dstAddress;
1042             public final int dstPort;
1043 
NattKeepaliveResponseData(final NattKeepalivePacketDataParcelable sentKeepalivePacket)1044             NattKeepaliveResponseData(final NattKeepalivePacketDataParcelable sentKeepalivePacket) {
1045                 srcAddress = sentKeepalivePacket.dstAddress;
1046                 srcPort = sentKeepalivePacket.dstPort;
1047                 dstAddress = sentKeepalivePacket.srcAddress;
1048                 dstPort = sentKeepalivePacket.srcPort;
1049             }
1050         }
1051 
1052         protected final NattKeepaliveResponseData mPacket;
1053         protected final byte[] mSrcDstAddr;
1054         protected final byte[] mPortFingerprint;
1055         // NAT-T keepalive packet
1056         protected final byte[] mPayload = {(byte) 0xff};
1057 
NattKeepaliveResponse(final NattKeepalivePacketDataParcelable sentKeepalivePacket)1058         NattKeepaliveResponse(final NattKeepalivePacketDataParcelable sentKeepalivePacket) {
1059             mPacket = new NattKeepaliveResponseData(sentKeepalivePacket);
1060             mSrcDstAddr = concatArrays(mPacket.srcAddress, mPacket.dstAddress);
1061             mPortFingerprint = generatePortFingerprint(mPacket.srcPort, mPacket.dstPort);
1062         }
1063 
generatePortFingerprint(int srcPort, int dstPort)1064         byte[] generatePortFingerprint(int srcPort, int dstPort) {
1065             final ByteBuffer fp = ByteBuffer.allocate(4);
1066             fp.order(ByteOrder.BIG_ENDIAN);
1067             fp.putShort((short) srcPort);
1068             fp.putShort((short) dstPort);
1069             return fp.array();
1070         }
1071 
1072         @Override
generateFilterLocked(ApfGenerator gen)1073         void generateFilterLocked(ApfGenerator gen) throws IllegalInstructionException {
1074             final String nextFilterLabel = "natt_keepalive_filter" + getUniqueNumberLocked();
1075 
1076             gen.addLoadImmediate(Register.R0, ETH_HEADER_LEN + IPV4_SRC_ADDR_OFFSET);
1077             gen.addJumpIfBytesNotEqual(Register.R0, mSrcDstAddr, nextFilterLabel);
1078 
1079             // A NAT-T keepalive packet contains 1 byte payload with the value 0xff
1080             // Check payload length is 1
1081             gen.addLoadFromMemory(Register.R0, gen.IPV4_HEADER_SIZE_MEMORY_SLOT);
1082             gen.addAdd(UDP_HEADER_LEN);
1083             gen.addSwap();
1084             gen.addLoad16(Register.R0, IPV4_TOTAL_LENGTH_OFFSET);
1085             gen.addNeg(Register.R1);
1086             gen.addAddR1();
1087             gen.addJumpIfR0NotEquals(1, nextFilterLabel);
1088 
1089             // Check that the ports match
1090             gen.addLoadFromMemory(Register.R0, gen.IPV4_HEADER_SIZE_MEMORY_SLOT);
1091             gen.addAdd(ETH_HEADER_LEN);
1092             gen.addJumpIfBytesNotEqual(Register.R0, mPortFingerprint, nextFilterLabel);
1093 
1094             // Payload offset = R0 + UDP header length
1095             gen.addAdd(UDP_HEADER_LEN);
1096             gen.addJumpIfBytesNotEqual(Register.R0, mPayload, nextFilterLabel);
1097 
1098             maybeSetupCounter(gen, Counter.DROPPED_IPV4_NATT_KEEPALIVE);
1099             gen.addJump(mCountAndDropLabel);
1100             gen.defineLabel(nextFilterLabel);
1101         }
1102 
toString()1103         public String toString() {
1104             try {
1105                 return String.format("%s -> %s",
1106                         ConnectivityUtils.addressAndPortToString(
1107                                 InetAddress.getByAddress(mPacket.srcAddress), mPacket.srcPort),
1108                         ConnectivityUtils.addressAndPortToString(
1109                                 InetAddress.getByAddress(mPacket.dstAddress), mPacket.dstPort));
1110             } catch (UnknownHostException e) {
1111                 return "Unknown host";
1112             }
1113         }
1114     }
1115 
1116     // A class to hold TCP keepalive ack information.
1117     private abstract static class TcpKeepaliveAck extends KeepalivePacket {
1118         protected static class TcpKeepaliveAckData {
1119             public final byte[] srcAddress;
1120             public final int srcPort;
1121             public final byte[] dstAddress;
1122             public final int dstPort;
1123             public final int seq;
1124             public final int ack;
1125 
1126             // Create the characteristics of the ack packet from the sent keepalive packet.
TcpKeepaliveAckData(final TcpKeepalivePacketDataParcelable sentKeepalivePacket)1127             TcpKeepaliveAckData(final TcpKeepalivePacketDataParcelable sentKeepalivePacket) {
1128                 srcAddress = sentKeepalivePacket.dstAddress;
1129                 srcPort = sentKeepalivePacket.dstPort;
1130                 dstAddress = sentKeepalivePacket.srcAddress;
1131                 dstPort = sentKeepalivePacket.srcPort;
1132                 seq = sentKeepalivePacket.ack;
1133                 ack = sentKeepalivePacket.seq + 1;
1134             }
1135         }
1136 
1137         protected final TcpKeepaliveAckData mPacket;
1138         protected final byte[] mSrcDstAddr;
1139         protected final byte[] mPortSeqAckFingerprint;
1140 
TcpKeepaliveAck(final TcpKeepaliveAckData packet, final byte[] srcDstAddr)1141         TcpKeepaliveAck(final TcpKeepaliveAckData packet, final byte[] srcDstAddr) {
1142             mPacket = packet;
1143             mSrcDstAddr = srcDstAddr;
1144             mPortSeqAckFingerprint = generatePortSeqAckFingerprint(mPacket.srcPort,
1145                     mPacket.dstPort, mPacket.seq, mPacket.ack);
1146         }
1147 
generatePortSeqAckFingerprint(int srcPort, int dstPort, int seq, int ack)1148         static byte[] generatePortSeqAckFingerprint(int srcPort, int dstPort, int seq, int ack) {
1149             final ByteBuffer fp = ByteBuffer.allocate(12);
1150             fp.order(ByteOrder.BIG_ENDIAN);
1151             fp.putShort((short) srcPort);
1152             fp.putShort((short) dstPort);
1153             fp.putInt(seq);
1154             fp.putInt(ack);
1155             return fp.array();
1156         }
1157 
toString()1158         public String toString() {
1159             try {
1160                 return String.format("%s -> %s , seq=%d, ack=%d",
1161                         ConnectivityUtils.addressAndPortToString(
1162                                 InetAddress.getByAddress(mPacket.srcAddress), mPacket.srcPort),
1163                         ConnectivityUtils.addressAndPortToString(
1164                                 InetAddress.getByAddress(mPacket.dstAddress), mPacket.dstPort),
1165                         Integer.toUnsignedLong(mPacket.seq),
1166                         Integer.toUnsignedLong(mPacket.ack));
1167             } catch (UnknownHostException e) {
1168                 return "Unknown host";
1169             }
1170         }
1171 
1172         // Append a filter for this keepalive ack to {@code gen}.
1173         // Jump to drop if it matches the keepalive ack.
1174         // Jump to the next filter if packet doesn't match the keepalive ack.
generateFilterLocked(ApfGenerator gen)1175         abstract void generateFilterLocked(ApfGenerator gen) throws IllegalInstructionException;
1176     }
1177 
1178     private class TcpKeepaliveAckV4 extends TcpKeepaliveAck {
1179 
TcpKeepaliveAckV4(final TcpKeepalivePacketDataParcelable sentKeepalivePacket)1180         TcpKeepaliveAckV4(final TcpKeepalivePacketDataParcelable sentKeepalivePacket) {
1181             this(new TcpKeepaliveAckData(sentKeepalivePacket));
1182         }
TcpKeepaliveAckV4(final TcpKeepaliveAckData packet)1183         TcpKeepaliveAckV4(final TcpKeepaliveAckData packet) {
1184             super(packet, concatArrays(packet.srcAddress, packet.dstAddress) /* srcDstAddr */);
1185         }
1186 
1187         @Override
generateFilterLocked(ApfGenerator gen)1188         void generateFilterLocked(ApfGenerator gen) throws IllegalInstructionException {
1189             final String nextFilterLabel = "keepalive_ack" + getUniqueNumberLocked();
1190 
1191             gen.addLoadImmediate(Register.R0, ETH_HEADER_LEN + IPV4_SRC_ADDR_OFFSET);
1192             gen.addJumpIfBytesNotEqual(Register.R0, mSrcDstAddr, nextFilterLabel);
1193 
1194             // Skip to the next filter if it's not zero-sized :
1195             // TCP_HEADER_SIZE + IPV4_HEADER_SIZE - ipv4_total_length == 0
1196             // Load the IP header size into R1
1197             gen.addLoadFromMemory(Register.R1, gen.IPV4_HEADER_SIZE_MEMORY_SLOT);
1198             // Load the TCP header size into R0 (it's indexed by R1)
1199             gen.addLoad8Indexed(Register.R0, ETH_HEADER_LEN + TCP_HEADER_SIZE_OFFSET);
1200             // Size offset is in the top nibble, but it must be multiplied by 4, and the two
1201             // top bits of the low nibble are guaranteed to be zeroes. Right-shift R0 by 2.
1202             gen.addRightShift(2);
1203             // R0 += R1 -> R0 contains TCP + IP headers length
1204             gen.addAddR1();
1205             // Load IPv4 total length
1206             gen.addLoad16(Register.R1, IPV4_TOTAL_LENGTH_OFFSET);
1207             gen.addNeg(Register.R0);
1208             gen.addAddR1();
1209             gen.addJumpIfR0NotEquals(0, nextFilterLabel);
1210             // Add IPv4 header length
1211             gen.addLoadFromMemory(Register.R1, gen.IPV4_HEADER_SIZE_MEMORY_SLOT);
1212             gen.addLoadImmediate(Register.R0, ETH_HEADER_LEN);
1213             gen.addAddR1();
1214             gen.addJumpIfBytesNotEqual(Register.R0, mPortSeqAckFingerprint, nextFilterLabel);
1215 
1216             maybeSetupCounter(gen, Counter.DROPPED_IPV4_KEEPALIVE_ACK);
1217             gen.addJump(mCountAndDropLabel);
1218             gen.defineLabel(nextFilterLabel);
1219         }
1220     }
1221 
1222     private class TcpKeepaliveAckV6 extends TcpKeepaliveAck {
TcpKeepaliveAckV6(final TcpKeepalivePacketDataParcelable sentKeepalivePacket)1223         TcpKeepaliveAckV6(final TcpKeepalivePacketDataParcelable sentKeepalivePacket) {
1224             this(new TcpKeepaliveAckData(sentKeepalivePacket));
1225         }
TcpKeepaliveAckV6(final TcpKeepaliveAckData packet)1226         TcpKeepaliveAckV6(final TcpKeepaliveAckData packet) {
1227             super(packet, concatArrays(packet.srcAddress, packet.dstAddress) /* srcDstAddr */);
1228         }
1229 
1230         @Override
generateFilterLocked(ApfGenerator gen)1231         void generateFilterLocked(ApfGenerator gen) throws IllegalInstructionException {
1232             throw new UnsupportedOperationException("IPv6 TCP Keepalive is not supported yet");
1233         }
1234     }
1235 
1236     // Maximum number of RAs to filter for.
1237     private static final int MAX_RAS = 10;
1238 
1239     @GuardedBy("this")
1240     private ArrayList<Ra> mRas = new ArrayList<>();
1241     @GuardedBy("this")
1242     private SparseArray<KeepalivePacket> mKeepalivePackets = new SparseArray<>();
1243     @GuardedBy("this")
1244     private final List<String[]> mMdnsAllowList = new ArrayList<>();
1245 
1246     // There is always some marginal benefit to updating the installed APF program when an RA is
1247     // seen because we can extend the program's lifetime slightly, but there is some cost to
1248     // updating the program, so don't bother unless the program is going to expire soon. This
1249     // constant defines "soon" in seconds.
1250     private static final long MAX_PROGRAM_LIFETIME_WORTH_REFRESHING = 30;
1251     // We don't want to filter an RA for it's whole lifetime as it'll be expired by the time we ever
1252     // see a refresh.  Using half the lifetime might be a good idea except for the fact that
1253     // packets may be dropped, so let's use 6.
1254     private static final int FRACTION_OF_LIFETIME_TO_FILTER = 6;
1255 
1256     // The base time for this filter program. In seconds since Unix Epoch.
1257     // This is the time when the APF program was generated. All filters in the program should use
1258     // this base time as their current time for consistency purposes.
1259     @GuardedBy("this")
1260     private long mProgramBaseTime;
1261     // When did we last install a filter program? In seconds since Unix Epoch.
1262     @GuardedBy("this")
1263     private long mLastTimeInstalledProgram;
1264     // How long should the last installed filter program live for? In seconds.
1265     @GuardedBy("this")
1266     private long mLastInstalledProgramMinLifetime;
1267     @GuardedBy("this")
1268     private ApfProgramEvent.Builder mLastInstallEvent;
1269 
1270     // For debugging only. The last program installed.
1271     @GuardedBy("this")
1272     private byte[] mLastInstalledProgram;
1273 
1274     /**
1275      * For debugging only. Contains the latest APF buffer snapshot captured from the firmware.
1276      *
1277      * A typical size for this buffer is 4KB. It is present only if the WiFi HAL supports
1278      * IWifiStaIface#readApfPacketFilterData(), and the APF interpreter advertised support for
1279      * the opcodes to access the data buffer (LDDW and STDW).
1280      */
1281     @GuardedBy("this") @Nullable
1282     private byte[] mDataSnapshot;
1283 
1284     // How many times the program was updated since we started.
1285     @GuardedBy("this")
1286     private int mNumProgramUpdates = 0;
1287     // How many times the program was updated since we started for allowing multicast traffic.
1288     @GuardedBy("this")
1289     private int mNumProgramUpdatesAllowingMulticast = 0;
1290 
1291     /**
1292      * Generate filter code to process ARP packets. Execution of this code ends in either the
1293      * DROP_LABEL or PASS_LABEL and does not fall off the end.
1294      * Preconditions:
1295      *  - Packet being filtered is ARP
1296      */
1297     @GuardedBy("this")
generateArpFilterLocked(ApfGenerator gen)1298     private void generateArpFilterLocked(ApfGenerator gen) throws IllegalInstructionException {
1299         // Here's a basic summary of what the ARP filter program does:
1300         //
1301         // if not ARP IPv4
1302         //   pass
1303         // if not ARP IPv4 reply or request
1304         //   pass
1305         // if ARP reply source ip is 0.0.0.0
1306         //   drop
1307         // if unicast ARP reply
1308         //   pass
1309         // if interface has no IPv4 address
1310         //   if target ip is 0.0.0.0
1311         //      drop
1312         // else
1313         //   if target ip is not the interface ip
1314         //      drop
1315         // pass
1316 
1317         final String checkTargetIPv4 = "checkTargetIPv4";
1318 
1319         // Pass if not ARP IPv4.
1320         gen.addLoadImmediate(Register.R0, ARP_HEADER_OFFSET);
1321         maybeSetupCounter(gen, Counter.PASSED_ARP_NON_IPV4);
1322         gen.addJumpIfBytesNotEqual(Register.R0, ARP_IPV4_HEADER, mCountAndPassLabel);
1323 
1324         // Pass if unknown ARP opcode.
1325         gen.addLoad16(Register.R0, ARP_OPCODE_OFFSET);
1326         gen.addJumpIfR0Equals(ARP_OPCODE_REQUEST, checkTargetIPv4); // Skip to unicast check
1327         maybeSetupCounter(gen, Counter.PASSED_ARP_UNKNOWN);
1328         gen.addJumpIfR0NotEquals(ARP_OPCODE_REPLY, mCountAndPassLabel);
1329 
1330         // Drop if ARP reply source IP is 0.0.0.0
1331         gen.addLoad32(Register.R0, ARP_SOURCE_IP_ADDRESS_OFFSET);
1332         maybeSetupCounter(gen, Counter.DROPPED_ARP_REPLY_SPA_NO_HOST);
1333         gen.addJumpIfR0Equals(IPV4_ANY_HOST_ADDRESS, mCountAndDropLabel);
1334 
1335         // Pass if unicast reply.
1336         gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET);
1337         maybeSetupCounter(gen, Counter.PASSED_ARP_UNICAST_REPLY);
1338         gen.addJumpIfBytesNotEqual(Register.R0, ETHER_BROADCAST, mCountAndPassLabel);
1339 
1340         // Either a unicast request, a unicast reply, or a broadcast reply.
1341         gen.defineLabel(checkTargetIPv4);
1342         if (mIPv4Address == null) {
1343             // When there is no IPv4 address, drop GARP replies (b/29404209).
1344             gen.addLoad32(Register.R0, ARP_TARGET_IP_ADDRESS_OFFSET);
1345             maybeSetupCounter(gen, Counter.DROPPED_GARP_REPLY);
1346             gen.addJumpIfR0Equals(IPV4_ANY_HOST_ADDRESS, mCountAndDropLabel);
1347         } else {
1348             // When there is an IPv4 address, drop unicast/broadcast requests
1349             // and broadcast replies with a different target IPv4 address.
1350             gen.addLoadImmediate(Register.R0, ARP_TARGET_IP_ADDRESS_OFFSET);
1351             maybeSetupCounter(gen, Counter.DROPPED_ARP_OTHER_HOST);
1352             gen.addJumpIfBytesNotEqual(Register.R0, mIPv4Address, mCountAndDropLabel);
1353         }
1354 
1355         maybeSetupCounter(gen, Counter.PASSED_ARP);
1356         gen.addJump(mCountAndPassLabel);
1357     }
1358 
1359     /**
1360      * Generate filter code to process IPv4 packets. Execution of this code ends in either the
1361      * DROP_LABEL or PASS_LABEL and does not fall off the end.
1362      * Preconditions:
1363      *  - Packet being filtered is IPv4
1364      */
1365     @GuardedBy("this")
generateIPv4FilterLocked(ApfGenerator gen)1366     private void generateIPv4FilterLocked(ApfGenerator gen) throws IllegalInstructionException {
1367         // Here's a basic summary of what the IPv4 filter program does:
1368         //
1369         // if filtering multicast (i.e. multicast lock not held):
1370         //   if it's DHCP destined to our MAC:
1371         //     pass
1372         //   if it's L2 broadcast:
1373         //     drop
1374         //   if it's IPv4 multicast:
1375         //     drop
1376         //   if it's IPv4 broadcast:
1377         //     drop
1378         // if keepalive ack
1379         //   drop
1380         // pass
1381 
1382         if (mMulticastFilter) {
1383             final String skipDhcpv4Filter = "skip_dhcp_v4_filter";
1384 
1385             // Pass DHCP addressed to us.
1386             // Check it's UDP.
1387             gen.addLoad8(Register.R0, IPV4_PROTOCOL_OFFSET);
1388             gen.addJumpIfR0NotEquals(IPPROTO_UDP, skipDhcpv4Filter);
1389             // Check it's not a fragment. This matches the BPF filter installed by the DHCP client.
1390             gen.addLoad16(Register.R0, IPV4_FRAGMENT_OFFSET_OFFSET);
1391             gen.addJumpIfR0AnyBitsSet(IPV4_FRAGMENT_OFFSET_MASK, skipDhcpv4Filter);
1392             // Check it's addressed to DHCP client port.
1393             gen.addLoadFromMemory(Register.R1, gen.IPV4_HEADER_SIZE_MEMORY_SLOT);
1394             gen.addLoad16Indexed(Register.R0, UDP_DESTINATION_PORT_OFFSET);
1395             gen.addJumpIfR0NotEquals(DHCP_CLIENT_PORT, skipDhcpv4Filter);
1396             // Check it's DHCP to our MAC address.
1397             gen.addLoadImmediate(Register.R0, DHCP_CLIENT_MAC_OFFSET);
1398             // NOTE: Relies on R1 containing IPv4 header offset.
1399             gen.addAddR1();
1400             gen.addJumpIfBytesNotEqual(Register.R0, mHardwareAddress, skipDhcpv4Filter);
1401             maybeSetupCounter(gen, Counter.PASSED_DHCP);
1402             gen.addJump(mCountAndPassLabel);
1403 
1404             // Drop all multicasts/broadcasts.
1405             gen.defineLabel(skipDhcpv4Filter);
1406 
1407             // If IPv4 destination address is in multicast range, drop.
1408             gen.addLoad8(Register.R0, IPV4_DEST_ADDR_OFFSET);
1409             gen.addAnd(0xf0);
1410             maybeSetupCounter(gen, Counter.DROPPED_IPV4_MULTICAST);
1411             gen.addJumpIfR0Equals(0xe0, mCountAndDropLabel);
1412 
1413             // If IPv4 broadcast packet, drop regardless of L2 (b/30231088).
1414             maybeSetupCounter(gen, Counter.DROPPED_IPV4_BROADCAST_ADDR);
1415             gen.addLoad32(Register.R0, IPV4_DEST_ADDR_OFFSET);
1416             gen.addJumpIfR0Equals(IPV4_BROADCAST_ADDRESS, mCountAndDropLabel);
1417             if (mIPv4Address != null && mIPv4PrefixLength < 31) {
1418                 maybeSetupCounter(gen, Counter.DROPPED_IPV4_BROADCAST_NET);
1419                 int broadcastAddr = ipv4BroadcastAddress(mIPv4Address, mIPv4PrefixLength);
1420                 gen.addJumpIfR0Equals(broadcastAddr, mCountAndDropLabel);
1421             }
1422 
1423             // If any TCP keepalive filter matches, drop
1424             generateV4KeepaliveFilters(gen);
1425 
1426             // If any NAT-T keepalive filter matches, drop
1427             generateV4NattKeepaliveFilters(gen);
1428 
1429             // Otherwise, this is an IPv4 unicast, pass
1430             // If L2 broadcast packet, drop.
1431             // TODO: can we invert this condition to fall through to the common pass case below?
1432             maybeSetupCounter(gen, Counter.PASSED_IPV4_UNICAST);
1433             gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET);
1434             gen.addJumpIfBytesNotEqual(Register.R0, ETHER_BROADCAST, mCountAndPassLabel);
1435             maybeSetupCounter(gen, Counter.DROPPED_IPV4_L2_BROADCAST);
1436             gen.addJump(mCountAndDropLabel);
1437         } else {
1438             generateV4KeepaliveFilters(gen);
1439             generateV4NattKeepaliveFilters(gen);
1440         }
1441 
1442         // Otherwise, pass
1443         maybeSetupCounter(gen, Counter.PASSED_IPV4);
1444         gen.addJump(mCountAndPassLabel);
1445     }
1446 
generateKeepaliveFilters(ApfGenerator gen, Class<?> filterType, int proto, int offset, String label)1447     private void generateKeepaliveFilters(ApfGenerator gen, Class<?> filterType, int proto,
1448             int offset, String label) throws IllegalInstructionException {
1449         final boolean haveKeepaliveResponses = CollectionUtils.any(mKeepalivePackets,
1450                 ack -> filterType.isInstance(ack));
1451 
1452         // If no keepalive packets of this type
1453         if (!haveKeepaliveResponses) return;
1454 
1455         // If not the right proto, skip keepalive filters
1456         gen.addLoad8(Register.R0, offset);
1457         gen.addJumpIfR0NotEquals(proto, label);
1458 
1459         // Drop Keepalive responses
1460         for (int i = 0; i < mKeepalivePackets.size(); ++i) {
1461             final KeepalivePacket response = mKeepalivePackets.valueAt(i);
1462             if (filterType.isInstance(response)) response.generateFilterLocked(gen);
1463         }
1464 
1465         gen.defineLabel(label);
1466     }
1467 
generateV4KeepaliveFilters(ApfGenerator gen)1468     private void generateV4KeepaliveFilters(ApfGenerator gen) throws IllegalInstructionException {
1469         generateKeepaliveFilters(gen, TcpKeepaliveAckV4.class, IPPROTO_TCP, IPV4_PROTOCOL_OFFSET,
1470                 "skip_v4_keepalive_filter");
1471     }
1472 
generateV4NattKeepaliveFilters(ApfGenerator gen)1473     private void generateV4NattKeepaliveFilters(ApfGenerator gen)
1474             throws IllegalInstructionException {
1475         generateKeepaliveFilters(gen, NattKeepaliveResponse.class,
1476                 IPPROTO_UDP, IPV4_PROTOCOL_OFFSET, "skip_v4_nattkeepalive_filter");
1477     }
1478 
1479     /**
1480      * Generate filter code to process IPv6 packets. Execution of this code ends in either the
1481      * DROP_LABEL or PASS_LABEL, or falls off the end for ICMPv6 packets.
1482      * Preconditions:
1483      *  - Packet being filtered is IPv6
1484      */
1485     @GuardedBy("this")
generateIPv6FilterLocked(ApfGenerator gen)1486     private void generateIPv6FilterLocked(ApfGenerator gen) throws IllegalInstructionException {
1487         // Here's a basic summary of what the IPv6 filter program does:
1488         //
1489         // if we're dropping multicast
1490         //   if it's not IPCMv6 or it's ICMPv6 but we're in doze mode:
1491         //     if it's multicast:
1492         //       drop
1493         //     pass
1494         // if it's ICMPv6 RS to any:
1495         //   drop
1496         // if it's ICMPv6 NA to anything in ff02::/120
1497         //   drop
1498         // if keepalive ack
1499         //   drop
1500 
1501         gen.addLoad8(Register.R0, IPV6_NEXT_HEADER_OFFSET);
1502 
1503         // Drop multicast if the multicast filter is enabled.
1504         if (mMulticastFilter) {
1505             final String skipIPv6MulticastFilterLabel = "skipIPv6MulticastFilter";
1506             final String dropAllIPv6MulticastsLabel = "dropAllIPv6Multicast";
1507 
1508             // While in doze mode, drop ICMPv6 multicast pings, let the others pass.
1509             // While awake, let all ICMPv6 multicasts through.
1510             if (mInDozeMode) {
1511                 // Not ICMPv6? -> Proceed to multicast filtering
1512                 gen.addJumpIfR0NotEquals(IPPROTO_ICMPV6, dropAllIPv6MulticastsLabel);
1513 
1514                 // ICMPv6 but not ECHO? -> Skip the multicast filter.
1515                 // (ICMPv6 ECHO requests will go through the multicast filter below).
1516                 gen.addLoad8(Register.R0, ICMP6_TYPE_OFFSET);
1517                 gen.addJumpIfR0NotEquals(ICMPV6_ECHO_REQUEST_TYPE, skipIPv6MulticastFilterLabel);
1518             } else {
1519                 gen.addJumpIfR0Equals(IPPROTO_ICMPV6, skipIPv6MulticastFilterLabel);
1520             }
1521 
1522             // Drop all other packets sent to ff00::/8 (multicast prefix).
1523             gen.defineLabel(dropAllIPv6MulticastsLabel);
1524             maybeSetupCounter(gen, Counter.DROPPED_IPV6_NON_ICMP_MULTICAST);
1525             gen.addLoad8(Register.R0, IPV6_DEST_ADDR_OFFSET);
1526             gen.addJumpIfR0Equals(0xff, mCountAndDropLabel);
1527             // If any keepalive filter matches, drop
1528             generateV6KeepaliveFilters(gen);
1529             // Not multicast. Pass.
1530             maybeSetupCounter(gen, Counter.PASSED_IPV6_UNICAST_NON_ICMP);
1531             gen.addJump(mCountAndPassLabel);
1532             gen.defineLabel(skipIPv6MulticastFilterLabel);
1533         } else {
1534             generateV6KeepaliveFilters(gen);
1535             // If not ICMPv6, pass.
1536             maybeSetupCounter(gen, Counter.PASSED_IPV6_NON_ICMP);
1537             gen.addJumpIfR0NotEquals(IPPROTO_ICMPV6, mCountAndPassLabel);
1538         }
1539 
1540         // If we got this far, the packet is ICMPv6.  Drop some specific types.
1541 
1542         // Add unsolicited multicast neighbor announcements filter
1543         String skipUnsolicitedMulticastNALabel = "skipUnsolicitedMulticastNA";
1544         gen.addLoad8(Register.R0, ICMP6_TYPE_OFFSET);
1545         // Drop all router solicitations (b/32833400)
1546         maybeSetupCounter(gen, Counter.DROPPED_IPV6_ROUTER_SOLICITATION);
1547         gen.addJumpIfR0Equals(ICMPV6_ROUTER_SOLICITATION, mCountAndDropLabel);
1548         // If not neighbor announcements, skip filter.
1549         gen.addJumpIfR0NotEquals(ICMPV6_NEIGHBOR_ADVERTISEMENT, skipUnsolicitedMulticastNALabel);
1550         // Drop all multicast NA to ff02::/120.
1551         // This is a way to cover ff02::1 and ff02::2 with a single JNEBS.
1552         // TODO: Drop only if they don't contain the address of on-link neighbours.
1553         final byte[] unsolicitedNaDropPrefix = Arrays.copyOf(IPV6_ALL_NODES_ADDRESS, 15);
1554         gen.addLoadImmediate(Register.R0, IPV6_DEST_ADDR_OFFSET);
1555         gen.addJumpIfBytesNotEqual(Register.R0, unsolicitedNaDropPrefix,
1556                 skipUnsolicitedMulticastNALabel);
1557 
1558         maybeSetupCounter(gen, Counter.DROPPED_IPV6_MULTICAST_NA);
1559         gen.addJump(mCountAndDropLabel);
1560         gen.defineLabel(skipUnsolicitedMulticastNALabel);
1561     }
1562 
1563     /** Encodes qname in TLV pattern. */
1564     @VisibleForTesting
encodeQname(String[] labels)1565     public static byte[] encodeQname(String[] labels) {
1566         final ByteArrayOutputStream out = new ByteArrayOutputStream();
1567         for (String label : labels) {
1568             byte[] labelBytes = label.getBytes(StandardCharsets.UTF_8);
1569             out.write(labelBytes.length);
1570             out.write(labelBytes, 0, labelBytes.length);
1571         }
1572         out.write(0);
1573         return out.toByteArray();
1574     }
1575 
1576     /**
1577      * Generate filter code to process mDNS packets. Execution of this code ends in * DROP_LABEL
1578      * or PASS_LABEL if the packet is mDNS packets. Otherwise, skip this check.
1579      */
1580     @GuardedBy("this")
generateMdnsFilterLocked(ApfGenerator gen)1581     private void generateMdnsFilterLocked(ApfGenerator gen)
1582             throws IllegalInstructionException {
1583         final String skipMdnsv4Filter = "skip_mdns_v4_filter";
1584         final String skipMdnsFilter = "skip_mdns_filter";
1585         final String checkMdnsUdpPort = "check_mdns_udp_port";
1586         final String mDnsAcceptPacket = "mdns_accept_packet";
1587         final String mDnsDropPacket = "mdns_drop_packet";
1588 
1589         // Only turn on the filter if multicast filter is on and the qname allowlist is non-empty.
1590         if (!mMulticastFilter || mMdnsAllowList.isEmpty()) {
1591             return;
1592         }
1593 
1594         // Here's a basic summary of what the mDNS filter program does:
1595         //
1596         // if it is a multicast mDNS packet
1597         //    if QDCOUNT > 1 and the first QNAME is in the allowlist
1598         //       pass
1599         //    else:
1600         //       drop
1601         //
1602         // A packet is considered as a multicast mDNS packet if it matches all the following
1603         // conditions
1604         //   1. its destination MAC address matches 01:00:5E:00:00:FB or 33:33:00:00:00:FB, for
1605         //   v4 and v6 respectively.
1606         //   2. it is an IPv4/IPv6 packet
1607         //   3. it is a UDP packet with port 5353
1608 
1609         // Check it's L2 mDNS multicast address.
1610         gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET);
1611         gen.addJumpIfBytesNotEqual(Register.R0, ETH_MULTICAST_MDNS_V4_MAC_ADDRESS,
1612                 skipMdnsv4Filter);
1613 
1614         // Checks it's IPv4.
1615         gen.addLoad16(Register.R0, ETH_ETHERTYPE_OFFSET);
1616         gen.addJumpIfR0NotEquals(ETH_P_IP, skipMdnsFilter);
1617 
1618         // Checks it's UDP.
1619         gen.addLoad8(Register.R0, IPV4_PROTOCOL_OFFSET);
1620         gen.addJumpIfR0NotEquals(IPPROTO_UDP, skipMdnsFilter);
1621         // Set R1 to IPv4 header.
1622         gen.addLoadFromMemory(Register.R1, gen.IPV4_HEADER_SIZE_MEMORY_SLOT);
1623         gen.addJump(checkMdnsUdpPort);
1624 
1625         gen.defineLabel(skipMdnsv4Filter);
1626 
1627         // Checks it's L2 mDNS multicast address.
1628         // Relies on R0 containing the ethernet destination mac address offset.
1629         gen.addJumpIfBytesNotEqual(Register.R0, ETH_MULTICAST_MDNS_V6_MAC_ADDRESS,
1630                 skipMdnsFilter);
1631 
1632         // Checks it's IPv6.
1633         gen.addLoad16(Register.R0, ETH_ETHERTYPE_OFFSET);
1634         gen.addJumpIfR0NotEquals(ETH_P_IPV6, skipMdnsFilter);
1635 
1636         // Checks it's UDP.
1637         gen.addLoad8(Register.R0, IPV6_NEXT_HEADER_OFFSET);
1638         gen.addJumpIfR0NotEquals(IPPROTO_UDP, skipMdnsFilter);
1639 
1640         // Set R1 to IPv6 header.
1641         gen.addLoadImmediate(Register.R1, IPV6_HEADER_LEN);
1642 
1643         // Checks it's mDNS UDP port
1644         gen.defineLabel(checkMdnsUdpPort);
1645         gen.addLoad16Indexed(Register.R0, UDP_DESTINATION_PORT_OFFSET);
1646         gen.addJumpIfR0NotEquals(MDNS_PORT, skipMdnsFilter);
1647 
1648         // Only do the QNAME check if the QDCOUNT is more than 0.
1649         // If there is more than one query (QDCOUNT > 1), we only matches the first QNAME.
1650         gen.addLoad16Indexed(Register.R0, MDNS_QDCOUNT_OFFSET);
1651         gen.addJumpIfR0Equals(0, mDnsDropPacket);
1652 
1653         // Load offset for the first QNAME.
1654         gen.addLoadImmediate(Register.R0, MDNS_QNAME_OFFSET);
1655         gen.addAddR1();
1656 
1657         // Check first QNAME against allowlist
1658         for (int i = 0; i < mMdnsAllowList.size(); ++i) {
1659             final String mDnsNextAllowedQnameCheck = "mdns_next_allowed_qname_check" + i;
1660             final byte[] encodedQname = encodeQname(mMdnsAllowList.get(i));
1661             gen.addJumpIfBytesNotEqual(Register.R0, encodedQname, mDnsNextAllowedQnameCheck);
1662             // QNAME matched
1663             gen.addJump(mDnsAcceptPacket);
1664             // QNAME not matched
1665             gen.defineLabel(mDnsNextAllowedQnameCheck);
1666         }
1667         // If QNAME doesn't match any entries in allowlist, drop the packet.
1668         gen.defineLabel(mDnsDropPacket);
1669         maybeSetupCounter(gen, Counter.DROPPED_MDNS);
1670         gen.addJump(mCountAndDropLabel);
1671 
1672         gen.defineLabel(mDnsAcceptPacket);
1673         maybeSetupCounter(gen, Counter.PASSED_MDNS);
1674         gen.addJump(mCountAndPassLabel);
1675 
1676 
1677         gen.defineLabel(skipMdnsFilter);
1678     }
1679 
1680 
generateV6KeepaliveFilters(ApfGenerator gen)1681     private void generateV6KeepaliveFilters(ApfGenerator gen) throws IllegalInstructionException {
1682         generateKeepaliveFilters(gen, TcpKeepaliveAckV6.class, IPPROTO_TCP, IPV6_NEXT_HEADER_OFFSET,
1683                 "skip_v6_keepalive_filter");
1684     }
1685 
1686     /**
1687      * Begin generating an APF program to:
1688      * <ul>
1689      * <li>Drop/Pass 802.3 frames (based on policy)
1690      * <li>Drop packets with EtherType within the Black List
1691      * <li>Drop ARP requests not for us, if mIPv4Address is set,
1692      * <li>Drop IPv4 broadcast packets, except DHCP destined to our MAC,
1693      * <li>Drop IPv4 multicast packets, if mMulticastFilter,
1694      * <li>Pass all other IPv4 packets,
1695      * <li>Drop all broadcast non-IP non-ARP packets.
1696      * <li>Pass all non-ICMPv6 IPv6 packets,
1697      * <li>Pass all non-IPv4 and non-IPv6 packets,
1698      * <li>Drop IPv6 ICMPv6 NAs to anything in ff02::/120.
1699      * <li>Drop IPv6 ICMPv6 RSs.
1700      * <li>Filter IPv4 packets (see generateIPv4FilterLocked())
1701      * <li>Filter IPv6 packets (see generateIPv6FilterLocked())
1702      * <li>Let execution continue off the end of the program for IPv6 ICMPv6 packets. This allows
1703      *     insertion of RA filters here, or if there aren't any, just passes the packets.
1704      * </ul>
1705      */
1706     @GuardedBy("this")
emitPrologueLocked()1707     private ApfGenerator emitPrologueLocked() throws IllegalInstructionException {
1708         // This is guaranteed to succeed because of the check in maybeCreate.
1709         ApfGenerator gen = new ApfGenerator(mApfCapabilities.apfVersionSupported);
1710 
1711         if (mApfCapabilities.hasDataAccess()) {
1712             // Increment TOTAL_PACKETS
1713             maybeSetupCounter(gen, Counter.TOTAL_PACKETS);
1714             gen.addLoadData(Register.R0, 0);  // load counter
1715             gen.addAdd(1);
1716             gen.addStoreData(Register.R0, 0);  // write-back counter
1717         }
1718 
1719         // Here's a basic summary of what the initial program does:
1720         //
1721         // if it's a 802.3 Frame (ethtype < 0x0600):
1722         //    drop or pass based on configurations
1723         // if it has a ether-type that belongs to the black list
1724         //    drop
1725         // if it's ARP:
1726         //   insert ARP filter to drop or pass these appropriately
1727         // if it's IPv4:
1728         //   insert IPv4 filter to drop or pass these appropriately
1729         // if it's not IPv6:
1730         //   if it's broadcast:
1731         //     drop
1732         //   pass
1733         // insert IPv6 filter to drop, pass, or fall off the end for ICMPv6 packets
1734 
1735         gen.addLoad16(Register.R0, ETH_ETHERTYPE_OFFSET);
1736 
1737         if (mDrop802_3Frames) {
1738             // drop 802.3 frames (ethtype < 0x0600)
1739             maybeSetupCounter(gen, Counter.DROPPED_802_3_FRAME);
1740             gen.addJumpIfR0LessThan(ETH_TYPE_MIN, mCountAndDropLabel);
1741         }
1742 
1743         // Handle ether-type black list
1744         maybeSetupCounter(gen, Counter.DROPPED_ETHERTYPE_BLACKLISTED);
1745         for (int p : mEthTypeBlackList) {
1746             gen.addJumpIfR0Equals(p, mCountAndDropLabel);
1747         }
1748 
1749         // Add ARP filters:
1750         String skipArpFiltersLabel = "skipArpFilters";
1751         gen.addJumpIfR0NotEquals(ETH_P_ARP, skipArpFiltersLabel);
1752         generateArpFilterLocked(gen);
1753         gen.defineLabel(skipArpFiltersLabel);
1754 
1755         // Add mDNS filter:
1756         generateMdnsFilterLocked(gen);
1757         gen.addLoad16(Register.R0, ETH_ETHERTYPE_OFFSET);
1758 
1759         // Add IPv4 filters:
1760         String skipIPv4FiltersLabel = "skipIPv4Filters";
1761         gen.addJumpIfR0NotEquals(ETH_P_IP, skipIPv4FiltersLabel);
1762         generateIPv4FilterLocked(gen);
1763         gen.defineLabel(skipIPv4FiltersLabel);
1764 
1765         // Check for IPv6:
1766         // NOTE: Relies on R0 containing ethertype. This is safe because if we got here, we did
1767         // not execute the IPv4 filter, since this filter do not fall through, but either drop or
1768         // pass.
1769         String ipv6FilterLabel = "IPv6Filters";
1770         gen.addJumpIfR0Equals(ETH_P_IPV6, ipv6FilterLabel);
1771 
1772         // Drop non-IP non-ARP broadcasts, pass the rest
1773         gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET);
1774         maybeSetupCounter(gen, Counter.PASSED_NON_IP_UNICAST);
1775         gen.addJumpIfBytesNotEqual(Register.R0, ETHER_BROADCAST, mCountAndPassLabel);
1776         maybeSetupCounter(gen, Counter.DROPPED_ETH_BROADCAST);
1777         gen.addJump(mCountAndDropLabel);
1778 
1779         // Add IPv6 filters:
1780         gen.defineLabel(ipv6FilterLabel);
1781         generateIPv6FilterLocked(gen);
1782         return gen;
1783     }
1784 
1785     /**
1786      * Append packet counting epilogue to the APF program.
1787      *
1788      * Currently, the epilogue consists of two trampolines which count passed and dropped packets
1789      * before jumping to the actual PASS and DROP labels.
1790      */
1791     @GuardedBy("this")
emitEpilogue(ApfGenerator gen)1792     private void emitEpilogue(ApfGenerator gen) throws IllegalInstructionException {
1793         // If APFv4 is unsupported, no epilogue is necessary: if execution reached this far, it
1794         // will just fall-through to the PASS label.
1795         if (!mApfCapabilities.hasDataAccess()) return;
1796 
1797         // Execution will reach the bottom of the program if none of the filters match,
1798         // which will pass the packet to the application processor.
1799         maybeSetupCounter(gen, Counter.PASSED_IPV6_ICMP);
1800 
1801         // Append the count & pass trampoline, which increments the counter at the data address
1802         // pointed to by R1, then jumps to the pass label. This saves a few bytes over inserting
1803         // the entire sequence inline for every counter.
1804         gen.defineLabel(mCountAndPassLabel);
1805         gen.addLoadData(Register.R0, 0);   // R0 = *(R1 + 0)
1806         gen.addAdd(1);                     // R0++
1807         gen.addStoreData(Register.R0, 0);  // *(R1 + 0) = R0
1808         gen.addJump(gen.PASS_LABEL);
1809 
1810         // Same as above for the count & drop trampoline.
1811         gen.defineLabel(mCountAndDropLabel);
1812         gen.addLoadData(Register.R0, 0);   // R0 = *(R1 + 0)
1813         gen.addAdd(1);                     // R0++
1814         gen.addStoreData(Register.R0, 0);  // *(R1 + 0) = R0
1815         gen.addJump(gen.DROP_LABEL);
1816     }
1817 
1818     /**
1819      * Generate and install a new filter program.
1820      */
1821     @GuardedBy("this")
1822     @VisibleForTesting
installNewProgramLocked()1823     public void installNewProgramLocked() {
1824         purgeExpiredRasLocked();
1825         ArrayList<Ra> rasToFilter = new ArrayList<>();
1826         final byte[] program;
1827         long programMinLifetime = Long.MAX_VALUE;
1828         long maximumApfProgramSize = mApfCapabilities.maximumApfProgramSize;
1829         if (mApfCapabilities.hasDataAccess()) {
1830             // Reserve space for the counters.
1831             maximumApfProgramSize -= Counter.totalSize();
1832         }
1833 
1834         mProgramBaseTime = currentTimeSeconds();
1835         try {
1836             // Step 1: Determine how many RA filters we can fit in the program.
1837             ApfGenerator gen = emitPrologueLocked();
1838 
1839             // The epilogue normally goes after the RA filters, but add it early to include its
1840             // length when estimating the total.
1841             emitEpilogue(gen);
1842 
1843             // Can't fit the program even without any RA filters?
1844             if (gen.programLengthOverEstimate() > maximumApfProgramSize) {
1845                 Log.e(TAG, "Program exceeds maximum size " + maximumApfProgramSize);
1846                 return;
1847             }
1848 
1849             for (Ra ra : mRas) {
1850                 if (!ra.shouldFilter()) continue;
1851                 ra.generateFilterLocked(gen);
1852                 // Stop if we get too big.
1853                 if (gen.programLengthOverEstimate() > maximumApfProgramSize) {
1854                     if (VDBG) Log.d(TAG, "Past maximum program size, skipping RAs");
1855                     break;
1856                 }
1857 
1858                 rasToFilter.add(ra);
1859             }
1860 
1861             // Step 2: Actually generate the program
1862             gen = emitPrologueLocked();
1863             for (Ra ra : rasToFilter) {
1864                 programMinLifetime = Math.min(programMinLifetime, ra.generateFilterLocked(gen));
1865             }
1866             emitEpilogue(gen);
1867             program = gen.generate();
1868         } catch (IllegalInstructionException|IllegalStateException e) {
1869             Log.e(TAG, "Failed to generate APF program.", e);
1870             return;
1871         }
1872         mIpClientCallback.installPacketFilter(program);
1873         mLastTimeInstalledProgram = mProgramBaseTime;
1874         mLastInstalledProgramMinLifetime = programMinLifetime;
1875         mLastInstalledProgram = program;
1876         mNumProgramUpdates++;
1877 
1878         if (VDBG) {
1879             hexDump("Installing filter: ", program, program.length);
1880         }
1881         logApfProgramEventLocked(mProgramBaseTime);
1882         mLastInstallEvent = new ApfProgramEvent.Builder()
1883                 .setLifetime(programMinLifetime)
1884                 .setFilteredRas(rasToFilter.size())
1885                 .setCurrentRas(mRas.size())
1886                 .setProgramLength(program.length)
1887                 .setFlags(mIPv4Address != null, mMulticastFilter);
1888     }
1889 
1890     @GuardedBy("this")
logApfProgramEventLocked(long now)1891     private void logApfProgramEventLocked(long now) {
1892         if (mLastInstallEvent == null) {
1893             return;
1894         }
1895         ApfProgramEvent.Builder ev = mLastInstallEvent;
1896         mLastInstallEvent = null;
1897         final long actualLifetime = now - mLastTimeInstalledProgram;
1898         ev.setActualLifetime(actualLifetime);
1899         if (actualLifetime < APF_PROGRAM_EVENT_LIFETIME_THRESHOLD) {
1900             return;
1901         }
1902         mMetricsLog.log(ev.build());
1903     }
1904 
1905     /**
1906      * Returns {@code true} if a new program should be installed because the current one dies soon.
1907      */
shouldInstallnewProgram()1908     private boolean shouldInstallnewProgram() {
1909         long expiry = mLastTimeInstalledProgram + mLastInstalledProgramMinLifetime;
1910         return expiry < currentTimeSeconds() + MAX_PROGRAM_LIFETIME_WORTH_REFRESHING;
1911     }
1912 
hexDump(String msg, byte[] packet, int length)1913     private void hexDump(String msg, byte[] packet, int length) {
1914         log(msg + HexDump.toHexString(packet, 0, length, false /* lowercase */));
1915     }
1916 
1917     @GuardedBy("this")
purgeExpiredRasLocked()1918     private void purgeExpiredRasLocked() {
1919         for (int i = 0; i < mRas.size();) {
1920             if (mRas.get(i).isExpired()) {
1921                 log("Expiring " + mRas.get(i));
1922                 mRas.remove(i);
1923             } else {
1924                 i++;
1925             }
1926         }
1927     }
1928 
1929     /**
1930      * Process an RA packet, updating the list of known RAs and installing a new APF program
1931      * if the current APF program should be updated.
1932      * @return a ProcessRaResult enum describing what action was performed.
1933      */
1934     @VisibleForTesting
processRa(byte[] packet, int length)1935     public synchronized ProcessRaResult processRa(byte[] packet, int length) {
1936         if (VDBG) hexDump("Read packet = ", packet, length);
1937 
1938         // Have we seen this RA before?
1939         for (int i = 0; i < mRas.size(); i++) {
1940             Ra ra = mRas.get(i);
1941             if (ra.matches(packet, length)) {
1942                 if (VDBG) log("matched RA " + ra);
1943                 // Update lifetimes.
1944                 ra.mLastSeen = currentTimeSeconds();
1945                 ra.seenCount++;
1946 
1947                 // Keep mRas in LRU order so as to prioritize generating filters for recently seen
1948                 // RAs. LRU prioritizes this because RA filters are generated in order from mRas
1949                 // until the filter program exceeds the maximum filter program size allowed by the
1950                 // chipset, so RAs appearing earlier in mRas are more likely to make it into the
1951                 // filter program.
1952                 // TODO: consider sorting the RAs in order of increasing expiry time as well.
1953                 // Swap to front of array.
1954                 mRas.add(0, mRas.remove(i));
1955 
1956                 // If the current program doesn't expire for a while, don't update.
1957                 if (shouldInstallnewProgram()) {
1958                     installNewProgramLocked();
1959                     return ProcessRaResult.UPDATE_EXPIRY;
1960                 }
1961                 return ProcessRaResult.MATCH;
1962             }
1963         }
1964         purgeExpiredRasLocked();
1965         // TODO: figure out how to proceed when we've received more then MAX_RAS RAs.
1966         if (mRas.size() >= MAX_RAS) {
1967             return ProcessRaResult.DROPPED;
1968         }
1969         final Ra ra;
1970         try {
1971             ra = new Ra(packet, length);
1972         } catch (Exception e) {
1973             Log.e(TAG, "Error parsing RA", e);
1974             return ProcessRaResult.PARSE_ERROR;
1975         }
1976         // Ignore 0 lifetime RAs.
1977         if (ra.isExpired()) {
1978             return ProcessRaResult.ZERO_LIFETIME;
1979         }
1980         log("Adding " + ra);
1981         mRas.add(ra);
1982         installNewProgramLocked();
1983         return ProcessRaResult.UPDATE_NEW_RA;
1984     }
1985 
1986     /**
1987      * Create an {@link ApfFilter} if {@code apfCapabilities} indicates support for packet
1988      * filtering using APF programs.
1989      */
maybeCreate(Context context, ApfConfiguration config, InterfaceParams ifParams, IpClientCallbacksWrapper ipClientCallback)1990     public static ApfFilter maybeCreate(Context context, ApfConfiguration config,
1991             InterfaceParams ifParams, IpClientCallbacksWrapper ipClientCallback) {
1992         if (context == null || config == null || ifParams == null) return null;
1993         ApfCapabilities apfCapabilities =  config.apfCapabilities;
1994         if (apfCapabilities == null) return null;
1995         if (apfCapabilities.apfVersionSupported == 0) return null;
1996         if (apfCapabilities.maximumApfProgramSize < 512) {
1997             Log.e(TAG, "Unacceptably small APF limit: " + apfCapabilities.maximumApfProgramSize);
1998             return null;
1999         }
2000         // For now only support generating programs for Ethernet frames. If this restriction is
2001         // lifted:
2002         //   1. the program generator will need its offsets adjusted.
2003         //   2. the packet filter attached to our packet socket will need its offset adjusted.
2004         if (apfCapabilities.apfPacketFormat != ARPHRD_ETHER) return null;
2005         if (!ApfGenerator.supportsVersion(apfCapabilities.apfVersionSupported)) {
2006             Log.e(TAG, "Unsupported APF version: " + apfCapabilities.apfVersionSupported);
2007             return null;
2008         }
2009 
2010         return new ApfFilter(context, config, ifParams, ipClientCallback, new IpConnectivityLog());
2011     }
2012 
shutdown()2013     public synchronized void shutdown() {
2014         if (mReceiveThread != null) {
2015             log("shutting down");
2016             mReceiveThread.halt();  // Also closes socket.
2017             mReceiveThread = null;
2018         }
2019         mRas.clear();
2020         mContext.unregisterReceiver(mDeviceIdleReceiver);
2021     }
2022 
setMulticastFilter(boolean isEnabled)2023     public synchronized void setMulticastFilter(boolean isEnabled) {
2024         if (mMulticastFilter == isEnabled) return;
2025         mMulticastFilter = isEnabled;
2026         if (!isEnabled) {
2027             mNumProgramUpdatesAllowingMulticast++;
2028         }
2029         installNewProgramLocked();
2030     }
2031 
2032     /** Adds qname to the mDNS allowlist */
addToMdnsAllowList(String[] labels)2033     public synchronized void addToMdnsAllowList(String[] labels) {
2034         mMdnsAllowList.add(labels);
2035         if (mMulticastFilter) {
2036             installNewProgramLocked();
2037         }
2038     }
2039 
2040     /** Removes qname from the mDNS allowlist */
removeFromAllowList(String[] labels)2041     public synchronized void removeFromAllowList(String[] labels) {
2042         mMdnsAllowList.removeIf(e -> Arrays.equals(labels, e));
2043         if (mMulticastFilter) {
2044             installNewProgramLocked();
2045         }
2046     }
2047 
2048     @VisibleForTesting
setDozeMode(boolean isEnabled)2049     public synchronized void setDozeMode(boolean isEnabled) {
2050         if (mInDozeMode == isEnabled) return;
2051         mInDozeMode = isEnabled;
2052         installNewProgramLocked();
2053     }
2054 
2055     /** Find the single IPv4 LinkAddress if there is one, otherwise return null. */
findIPv4LinkAddress(LinkProperties lp)2056     private static LinkAddress findIPv4LinkAddress(LinkProperties lp) {
2057         LinkAddress ipv4Address = null;
2058         for (LinkAddress address : lp.getLinkAddresses()) {
2059             if (!(address.getAddress() instanceof Inet4Address)) {
2060                 continue;
2061             }
2062             if (ipv4Address != null && !ipv4Address.isSameAddressAs(address)) {
2063                 // More than one IPv4 address, abort.
2064                 return null;
2065             }
2066             ipv4Address = address;
2067         }
2068         return ipv4Address;
2069     }
2070 
setLinkProperties(LinkProperties lp)2071     public synchronized void setLinkProperties(LinkProperties lp) {
2072         // NOTE: Do not keep a copy of LinkProperties as it would further duplicate state.
2073         final LinkAddress ipv4Address = findIPv4LinkAddress(lp);
2074         final byte[] addr = (ipv4Address != null) ? ipv4Address.getAddress().getAddress() : null;
2075         final int prefix = (ipv4Address != null) ? ipv4Address.getPrefixLength() : 0;
2076         if ((prefix == mIPv4PrefixLength) && Arrays.equals(addr, mIPv4Address)) {
2077             return;
2078         }
2079         mIPv4Address = addr;
2080         mIPv4PrefixLength = prefix;
2081         installNewProgramLocked();
2082     }
2083 
2084     /**
2085      * Add TCP keepalive ack packet filter.
2086      * This will add a filter to drop acks to the keepalive packet passed as an argument.
2087      *
2088      * @param slot The index used to access the filter.
2089      * @param sentKeepalivePacket The attributes of the sent keepalive packet.
2090      */
addTcpKeepalivePacketFilter(final int slot, final TcpKeepalivePacketDataParcelable sentKeepalivePacket)2091     public synchronized void addTcpKeepalivePacketFilter(final int slot,
2092             final TcpKeepalivePacketDataParcelable sentKeepalivePacket) {
2093         log("Adding keepalive ack(" + slot + ")");
2094         if (null != mKeepalivePackets.get(slot)) {
2095             throw new IllegalArgumentException("Keepalive slot " + slot + " is occupied");
2096         }
2097         final int ipVersion = sentKeepalivePacket.srcAddress.length == 4 ? 4 : 6;
2098         mKeepalivePackets.put(slot, (ipVersion == 4)
2099                 ? new TcpKeepaliveAckV4(sentKeepalivePacket)
2100                 : new TcpKeepaliveAckV6(sentKeepalivePacket));
2101         installNewProgramLocked();
2102     }
2103 
2104     /**
2105      * Add NAT-T keepalive packet filter.
2106      * This will add a filter to drop NAT-T keepalive packet which is passed as an argument.
2107      *
2108      * @param slot The index used to access the filter.
2109      * @param sentKeepalivePacket The attributes of the sent keepalive packet.
2110      */
addNattKeepalivePacketFilter(final int slot, final NattKeepalivePacketDataParcelable sentKeepalivePacket)2111     public synchronized void addNattKeepalivePacketFilter(final int slot,
2112             final NattKeepalivePacketDataParcelable sentKeepalivePacket) {
2113         log("Adding NAT-T keepalive packet(" + slot + ")");
2114         if (null != mKeepalivePackets.get(slot)) {
2115             throw new IllegalArgumentException("NAT-T Keepalive slot " + slot + " is occupied");
2116         }
2117         if (sentKeepalivePacket.srcAddress.length != 4) {
2118             throw new IllegalArgumentException("NAT-T keepalive is only supported on IPv4");
2119         }
2120         mKeepalivePackets.put(slot, new NattKeepaliveResponse(sentKeepalivePacket));
2121         installNewProgramLocked();
2122     }
2123 
2124     /**
2125      * Remove keepalive packet filter.
2126      *
2127      * @param slot The index used to access the filter.
2128      */
removeKeepalivePacketFilter(int slot)2129     public synchronized void removeKeepalivePacketFilter(int slot) {
2130         log("Removing keepalive packet(" + slot + ")");
2131         mKeepalivePackets.remove(slot);
2132         installNewProgramLocked();
2133     }
2134 
counterValue(byte[] data, Counter counter)2135     static public long counterValue(byte[] data, Counter counter)
2136             throws ArrayIndexOutOfBoundsException {
2137         // Follow the same wrap-around addressing scheme of the interpreter.
2138         int offset = counter.offset();
2139         if (offset < 0) {
2140             offset = data.length + offset;
2141         }
2142 
2143         // Decode 32bit big-endian integer into a long so we can count up beyond 2^31.
2144         long value = 0;
2145         for (int i = 0; i < 4; i++) {
2146             value = value << 8 | (data[offset] & 0xFF);
2147             offset++;
2148         }
2149         return value;
2150     }
2151 
dump(IndentingPrintWriter pw)2152     public synchronized void dump(IndentingPrintWriter pw) {
2153         pw.println("Capabilities: " + mApfCapabilities);
2154         pw.println("Receive thread: " + (mReceiveThread != null ? "RUNNING" : "STOPPED"));
2155         pw.println("Multicast: " + (mMulticastFilter ? "DROP" : "ALLOW"));
2156         pw.println("Minimum RDNSS lifetime: " + mMinRdnssLifetimeSec);
2157         try {
2158             pw.println("IPv4 address: " + InetAddress.getByAddress(mIPv4Address).getHostAddress());
2159         } catch (UnknownHostException|NullPointerException e) {}
2160 
2161         if (mLastTimeInstalledProgram == 0) {
2162             pw.println("No program installed.");
2163             return;
2164         }
2165         pw.println("Program updates: " + mNumProgramUpdates);
2166         pw.println(String.format(
2167                 "Last program length %d, installed %ds ago, lifetime %ds",
2168                 mLastInstalledProgram.length, currentTimeSeconds() - mLastTimeInstalledProgram,
2169                 mLastInstalledProgramMinLifetime));
2170 
2171         pw.print("Denylisted Ethertypes:");
2172         for (int p : mEthTypeBlackList) {
2173             pw.print(String.format(" %04x", p));
2174         }
2175         pw.println();
2176         pw.println("RA filters:");
2177         pw.increaseIndent();
2178         for (Ra ra: mRas) {
2179             pw.println(ra);
2180             pw.increaseIndent();
2181             pw.println(String.format(
2182                     "Seen: %d, last %ds ago", ra.seenCount, currentTimeSeconds() - ra.mLastSeen));
2183             if (DBG) {
2184                 pw.println("Last match:");
2185                 pw.increaseIndent();
2186                 pw.println(ra.getLastMatchingPacket());
2187                 pw.decreaseIndent();
2188             }
2189             pw.decreaseIndent();
2190         }
2191         pw.decreaseIndent();
2192 
2193         pw.println("TCP Keepalive filters:");
2194         pw.increaseIndent();
2195         for (int i = 0; i < mKeepalivePackets.size(); ++i) {
2196             final KeepalivePacket keepalivePacket = mKeepalivePackets.valueAt(i);
2197             if (keepalivePacket instanceof TcpKeepaliveAck) {
2198                 pw.print("Slot ");
2199                 pw.print(mKeepalivePackets.keyAt(i));
2200                 pw.print(": ");
2201                 pw.println(keepalivePacket);
2202             }
2203         }
2204         pw.decreaseIndent();
2205 
2206         pw.println("NAT-T Keepalive filters:");
2207         pw.increaseIndent();
2208         for (int i = 0; i < mKeepalivePackets.size(); ++i) {
2209             final KeepalivePacket keepalivePacket = mKeepalivePackets.valueAt(i);
2210             if (keepalivePacket instanceof NattKeepaliveResponse) {
2211                 pw.print("Slot ");
2212                 pw.print(mKeepalivePackets.keyAt(i));
2213                 pw.print(": ");
2214                 pw.println(keepalivePacket);
2215             }
2216         }
2217         pw.decreaseIndent();
2218 
2219         if (DBG) {
2220             pw.println("Last program:");
2221             pw.increaseIndent();
2222             pw.println(HexDump.toHexString(mLastInstalledProgram, false /* lowercase */));
2223             pw.decreaseIndent();
2224         }
2225 
2226         pw.println("APF packet counters: ");
2227         pw.increaseIndent();
2228         if (!mApfCapabilities.hasDataAccess()) {
2229             pw.println("APF counters not supported");
2230         } else if (mDataSnapshot == null) {
2231             pw.println("No last snapshot.");
2232         } else {
2233             try {
2234                 Counter[] counters = Counter.class.getEnumConstants();
2235                 for (Counter c : Arrays.asList(counters).subList(1, counters.length)) {
2236                     long value = counterValue(mDataSnapshot, c);
2237                     // Only print non-zero counters
2238                     if (value != 0) {
2239                         pw.println(c.toString() + ": " + value);
2240                     }
2241                 }
2242             } catch (ArrayIndexOutOfBoundsException e) {
2243                 pw.println("Uh-oh: " + e);
2244             }
2245             if (VDBG) {
2246                 pw.println("Raw data dump: ");
2247                 pw.println(HexDump.dumpHexString(mDataSnapshot));
2248             }
2249         }
2250         pw.decreaseIndent();
2251     }
2252 
2253     // TODO: move to android.net.NetworkUtils
2254     @VisibleForTesting
ipv4BroadcastAddress(byte[] addrBytes, int prefixLength)2255     public static int ipv4BroadcastAddress(byte[] addrBytes, int prefixLength) {
2256         return bytesToBEInt(addrBytes) | (int) (Integer.toUnsignedLong(-1) >>> prefixLength);
2257     }
2258 
uint8(byte b)2259     private static int uint8(byte b) {
2260         return b & 0xff;
2261     }
2262 
getUint16(ByteBuffer buffer, int position)2263     private static int getUint16(ByteBuffer buffer, int position) {
2264         return buffer.getShort(position) & 0xffff;
2265     }
2266 
getUint32(ByteBuffer buffer, int position)2267     private static long getUint32(ByteBuffer buffer, int position) {
2268         return Integer.toUnsignedLong(buffer.getInt(position));
2269     }
2270 
getUint8(ByteBuffer buffer, int position)2271     private static int getUint8(ByteBuffer buffer, int position) {
2272         return uint8(buffer.get(position));
2273     }
2274 
bytesToBEInt(byte[] bytes)2275     private static int bytesToBEInt(byte[] bytes) {
2276         return (uint8(bytes[0]) << 24)
2277                 + (uint8(bytes[1]) << 16)
2278                 + (uint8(bytes[2]) << 8)
2279                 + (uint8(bytes[3]));
2280     }
2281 
concatArrays(final byte[]... arr)2282     private static byte[] concatArrays(final byte[]... arr) {
2283         int size = 0;
2284         for (byte[] a : arr) {
2285             size += a.length;
2286         }
2287         final byte[] result = new byte[size];
2288         int offset = 0;
2289         for (byte[] a : arr) {
2290             System.arraycopy(a, 0, result, offset, a.length);
2291             offset += a.length;
2292         }
2293         return result;
2294     }
2295 }
2296