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