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