blob: f05431968684c7cfcea4973b5df9806f14285424 [file] [log] [blame]
Paul Jensen578a76e2016-01-14 14:54:39 -05001/*
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
Paul Jensenf21b4dc2016-03-18 12:22:09 -040017package android.net.apf;
Paul Jensen578a76e2016-01-14 14:54:39 -050018
Remi NGUYEN VAN811f6382019-01-20 12:08:21 +090019import static android.net.util.SocketUtils.makePacketSocketAddress;
Remi NGUYEN VANa5d31f52019-01-12 15:36:47 +090020import static android.system.OsConstants.AF_PACKET;
21import static android.system.OsConstants.ARPHRD_ETHER;
22import static android.system.OsConstants.ETH_P_ARP;
23import static android.system.OsConstants.ETH_P_IP;
24import static android.system.OsConstants.ETH_P_IPV6;
25import static android.system.OsConstants.IPPROTO_ICMPV6;
Aaron Huanga63c40e2019-01-15 16:53:51 +080026import static android.system.OsConstants.IPPROTO_TCP;
Remi NGUYEN VANa5d31f52019-01-12 15:36:47 +090027import static android.system.OsConstants.IPPROTO_UDP;
28import static android.system.OsConstants.SOCK_RAW;
29
Remi NGUYEN VAN3c600a12019-01-10 19:12:46 +090030import static com.android.server.util.NetworkStackConstants.ICMPV6_ECHO_REQUEST_TYPE;
31import static com.android.server.util.NetworkStackConstants.ICMPV6_NEIGHBOR_ADVERTISEMENT;
32import static com.android.server.util.NetworkStackConstants.ICMPV6_ROUTER_ADVERTISEMENT;
33import static com.android.server.util.NetworkStackConstants.ICMPV6_ROUTER_SOLICITATION;
Hugo Benichi495a17b2017-01-12 15:31:05 +090034
Bernie Innocenti3cc40ea2018-04-24 01:25:42 +090035import android.annotation.Nullable;
Bernie Innocenti5be71dc2018-03-28 20:11:49 +090036import android.content.BroadcastReceiver;
37import android.content.Context;
38import android.content.Intent;
39import android.content.IntentFilter;
Hugo Benichi7d21eae2016-09-02 14:00:29 +090040import android.net.LinkAddress;
Paul Jensena8458c02016-03-25 11:25:57 -040041import android.net.LinkProperties;
Mark Chiend0f8ca82019-04-29 09:46:04 -070042import android.net.NattKeepalivePacketDataParcelable;
junyulai352dc2f2019-01-08 20:04:33 +080043import android.net.TcpKeepalivePacketDataParcelable;
Paul Jensen578a76e2016-01-14 14:54:39 -050044import android.net.apf.ApfGenerator.IllegalInstructionException;
45import android.net.apf.ApfGenerator.Register;
Remi NGUYEN VAN3c600a12019-01-10 19:12:46 +090046import android.net.ip.IpClient.IpClientCallbacksWrapper;
Hugo Benichi4fc3ee52016-06-02 11:20:27 +090047import android.net.metrics.ApfProgramEvent;
Hugo Benichi647c86d2016-06-07 15:35:16 +090048import android.net.metrics.ApfStats;
Hugo Benichi4fc3ee52016-06-02 11:20:27 +090049import android.net.metrics.IpConnectivityLog;
Hugo Benichicfbf7412016-06-23 10:41:30 +090050import android.net.metrics.RaEvent;
Erik Kline8bd00d52017-12-08 17:47:50 +090051import android.net.util.InterfaceParams;
Remi NGUYEN VAN231b52b2019-01-29 15:38:52 +090052import android.net.util.NetworkStackUtils;
Bernie Innocenti5be71dc2018-03-28 20:11:49 +090053import android.os.PowerManager;
54import android.os.SystemClock;
Paul Jensen578a76e2016-01-14 14:54:39 -050055import android.system.ErrnoException;
56import android.system.Os;
Hugo Benichi4fc3ee52016-06-02 11:20:27 +090057import android.text.format.DateUtils;
Paul Jensen578a76e2016-01-14 14:54:39 -050058import android.util.Log;
59import android.util.Pair;
Aaron Huanga63c40e2019-01-15 16:53:51 +080060import android.util.SparseArray;
Remi NGUYEN VANa5d31f52019-01-12 15:36:47 +090061
Paul Jensendfd5a942016-03-17 13:22:29 -040062import com.android.internal.annotations.GuardedBy;
Paul Jensen9132f342016-04-13 15:00:26 -040063import com.android.internal.annotations.VisibleForTesting;
Paul Jensen578a76e2016-01-14 14:54:39 -050064import com.android.internal.util.HexDump;
Lorenzo Colitti5ff640d2016-03-03 17:53:46 +090065import com.android.internal.util.IndentingPrintWriter;
Remi NGUYEN VANa5d31f52019-01-12 15:36:47 +090066
Paul Jensen578a76e2016-01-14 14:54:39 -050067import java.io.FileDescriptor;
68import java.io.IOException;
Hugo Benichi7d21eae2016-09-02 14:00:29 +090069import java.net.Inet4Address;
Lorenzo Colitti5ff640d2016-03-03 17:53:46 +090070import java.net.Inet6Address;
71import java.net.InetAddress;
Remi NGUYEN VAN811f6382019-01-20 12:08:21 +090072import java.net.SocketAddress;
Paul Jensen578a76e2016-01-14 14:54:39 -050073import java.net.SocketException;
Lorenzo Colitti5ff640d2016-03-03 17:53:46 +090074import java.net.UnknownHostException;
Lorenzo Colitti5ff640d2016-03-03 17:53:46 +090075import java.nio.BufferUnderflowException;
Bernie Innocenti5be71dc2018-03-28 20:11:49 +090076import java.nio.ByteBuffer;
Aaron Huang75a60432019-02-20 17:14:02 +080077import java.nio.ByteOrder;
Paul Jensen578a76e2016-01-14 14:54:39 -050078import java.util.ArrayList;
79import java.util.Arrays;
Paul Jensen578a76e2016-01-14 14:54:39 -050080
81/**
82 * For networks that support packet filtering via APF programs, {@code ApfFilter}
83 * listens for IPv6 ICMPv6 router advertisements (RAs) and generates APF programs to
84 * filter out redundant duplicate ones.
85 *
Paul Jensendfd5a942016-03-17 13:22:29 -040086 * Threading model:
87 * A collection of RAs we've received is kept in mRas. Generating APF programs uses mRas to
88 * know what RAs to filter for, thus generating APF programs is dependent on mRas.
89 * mRas can be accessed by multiple threads:
90 * - ReceiveThread, which listens for RAs and adds them to mRas, and generates APF programs.
91 * - callers of:
92 * - setMulticastFilter(), which can cause an APF program to be generated.
93 * - dump(), which dumps mRas among other things.
94 * - shutdown(), which clears mRas.
95 * So access to mRas is synchronized.
96 *
Paul Jensen578a76e2016-01-14 14:54:39 -050097 * @hide
98 */
99public class ApfFilter {
Hugo Benichi647c86d2016-06-07 15:35:16 +0900100
Hugo Benichi72166362017-10-13 16:32:20 +0900101 // Helper class for specifying functional filter parameters.
102 public static class ApfConfiguration {
103 public ApfCapabilities apfCapabilities;
104 public boolean multicastFilter;
105 public boolean ieee802_3Filter;
106 public int[] ethTypeBlackList;
107 }
108
Hugo Benichi647c86d2016-06-07 15:35:16 +0900109 // Enums describing the outcome of receiving an RA packet.
110 private static enum ProcessRaResult {
111 MATCH, // Received RA matched a known RA
112 DROPPED, // Received RA ignored due to MAX_RAS
113 PARSE_ERROR, // Received RA could not be parsed
114 ZERO_LIFETIME, // Received RA had 0 lifetime
115 UPDATE_NEW_RA, // APF program updated for new RA
116 UPDATE_EXPIRY // APF program updated for expiry
117 }
118
Bernie Innocenti3cc40ea2018-04-24 01:25:42 +0900119 /**
120 * APF packet counters.
121 *
122 * Packet counters are 32bit big-endian values, and allocated near the end of the APF data
123 * buffer, using negative byte offsets, where -4 is equivalent to maximumApfProgramSize - 4,
124 * the last writable 32bit word.
125 */
126 @VisibleForTesting
Aaron Huang785e5f12018-10-31 15:57:48 +0800127 public static enum Counter {
Bernie Innocenti3cc40ea2018-04-24 01:25:42 +0900128 RESERVED_OOB, // Points to offset 0 from the end of the buffer (out-of-bounds)
129 TOTAL_PACKETS,
130 PASSED_ARP,
131 PASSED_DHCP,
132 PASSED_IPV4,
133 PASSED_IPV6_NON_ICMP,
134 PASSED_IPV4_UNICAST,
135 PASSED_IPV6_ICMP,
136 PASSED_IPV6_UNICAST_NON_ICMP,
137 PASSED_ARP_NON_IPV4,
138 PASSED_ARP_UNKNOWN,
139 PASSED_ARP_UNICAST_REPLY,
140 PASSED_NON_IP_UNICAST,
141 DROPPED_ETH_BROADCAST,
142 DROPPED_RA,
143 DROPPED_GARP_REPLY,
144 DROPPED_ARP_OTHER_HOST,
145 DROPPED_IPV4_L2_BROADCAST,
146 DROPPED_IPV4_BROADCAST_ADDR,
147 DROPPED_IPV4_BROADCAST_NET,
148 DROPPED_IPV4_MULTICAST,
149 DROPPED_IPV6_ROUTER_SOLICITATION,
150 DROPPED_IPV6_MULTICAST_NA,
151 DROPPED_IPV6_MULTICAST,
152 DROPPED_IPV6_MULTICAST_PING,
153 DROPPED_IPV6_NON_ICMP_MULTICAST,
154 DROPPED_802_3_FRAME,
Aaron Huang04ed6a32018-11-15 20:30:46 +0800155 DROPPED_ETHERTYPE_BLACKLISTED,
Aaron Huanga63c40e2019-01-15 16:53:51 +0800156 DROPPED_ARP_REPLY_SPA_NO_HOST,
157 DROPPED_IPV4_KEEPALIVE_ACK,
Aaron Huang56f9e412019-05-13 05:13:09 -0700158 DROPPED_IPV6_KEEPALIVE_ACK,
Aaron Huang4a40e912019-05-15 00:17:35 -0700159 DROPPED_IPV4_NATT_KEEPALIVE;
Bernie Innocenti3cc40ea2018-04-24 01:25:42 +0900160
161 // Returns the negative byte offset from the end of the APF data segment for
162 // a given counter.
163 public int offset() {
164 return - this.ordinal() * 4; // Currently, all counters are 32bit long.
165 }
166
167 // Returns the total size of the data segment in bytes.
168 public static int totalSize() {
169 return (Counter.class.getEnumConstants().length - 1) * 4;
170 }
171 }
172
173 /**
174 * When APFv4 is supported, loads R1 with the offset of the specified counter.
175 */
Aaron Huang04ed6a32018-11-15 20:30:46 +0800176 private void maybeSetupCounter(ApfGenerator gen, Counter c) {
Bernie Innocenti3cc40ea2018-04-24 01:25:42 +0900177 if (mApfCapabilities.hasDataAccess()) {
178 gen.addLoadImmediate(Register.R1, c.offset());
179 }
180 }
181
182 // When APFv4 is supported, these point to the trampolines generated by emitEpilogue().
183 // Otherwise, they're just aliases for PASS_LABEL and DROP_LABEL.
184 private final String mCountAndPassLabel;
185 private final String mCountAndDropLabel;
186
Paul Jensen578a76e2016-01-14 14:54:39 -0500187 // Thread to listen for RAs.
Paul Jensen9132f342016-04-13 15:00:26 -0400188 @VisibleForTesting
189 class ReceiveThread extends Thread {
Paul Jensen578a76e2016-01-14 14:54:39 -0500190 private final byte[] mPacket = new byte[1514];
191 private final FileDescriptor mSocket;
Hugo Benichi647c86d2016-06-07 15:35:16 +0900192 private final long mStart = SystemClock.elapsedRealtime();
Remi NGUYEN VAN7b84fb32019-01-19 21:13:24 +0900193
194 private int mReceivedRas = 0;
195 private int mMatchingRas = 0;
196 private int mDroppedRas = 0;
197 private int mParseErrors = 0;
198 private int mZeroLifetimeRas = 0;
199 private int mProgramUpdates = 0;
Hugo Benichi647c86d2016-06-07 15:35:16 +0900200
Hugo Benichi22d9b2d2017-02-22 13:02:27 +0900201 private volatile boolean mStopped;
Hugo Benichi647c86d2016-06-07 15:35:16 +0900202
Paul Jensen578a76e2016-01-14 14:54:39 -0500203 public ReceiveThread(FileDescriptor socket) {
204 mSocket = socket;
205 }
206
207 public void halt() {
208 mStopped = true;
Remi NGUYEN VAN231b52b2019-01-29 15:38:52 +0900209 // Interrupts the read() call the thread is blocked in.
210 NetworkStackUtils.closeSocketQuietly(mSocket);
Paul Jensen578a76e2016-01-14 14:54:39 -0500211 }
212
213 @Override
214 public void run() {
215 log("begin monitoring");
216 while (!mStopped) {
217 try {
218 int length = Os.read(mSocket, mPacket, 0, mPacket.length);
Hugo Benichi647c86d2016-06-07 15:35:16 +0900219 updateStats(processRa(mPacket, length));
Paul Jensen578a76e2016-01-14 14:54:39 -0500220 } catch (IOException|ErrnoException e) {
221 if (!mStopped) {
222 Log.e(TAG, "Read error", e);
223 }
224 }
225 }
Hugo Benichi647c86d2016-06-07 15:35:16 +0900226 logStats();
227 }
228
229 private void updateStats(ProcessRaResult result) {
Remi NGUYEN VAN7b84fb32019-01-19 21:13:24 +0900230 mReceivedRas++;
Hugo Benichi647c86d2016-06-07 15:35:16 +0900231 switch(result) {
232 case MATCH:
Remi NGUYEN VAN7b84fb32019-01-19 21:13:24 +0900233 mMatchingRas++;
Hugo Benichi647c86d2016-06-07 15:35:16 +0900234 return;
235 case DROPPED:
Remi NGUYEN VAN7b84fb32019-01-19 21:13:24 +0900236 mDroppedRas++;
Hugo Benichi647c86d2016-06-07 15:35:16 +0900237 return;
238 case PARSE_ERROR:
Remi NGUYEN VAN7b84fb32019-01-19 21:13:24 +0900239 mParseErrors++;
Hugo Benichi647c86d2016-06-07 15:35:16 +0900240 return;
241 case ZERO_LIFETIME:
Remi NGUYEN VAN7b84fb32019-01-19 21:13:24 +0900242 mZeroLifetimeRas++;
Hugo Benichi647c86d2016-06-07 15:35:16 +0900243 return;
244 case UPDATE_EXPIRY:
Remi NGUYEN VAN7b84fb32019-01-19 21:13:24 +0900245 mMatchingRas++;
246 mProgramUpdates++;
Hugo Benichi647c86d2016-06-07 15:35:16 +0900247 return;
248 case UPDATE_NEW_RA:
Remi NGUYEN VAN7b84fb32019-01-19 21:13:24 +0900249 mProgramUpdates++;
Hugo Benichi647c86d2016-06-07 15:35:16 +0900250 return;
251 }
252 }
253
254 private void logStats() {
Hugo Benichi22d9b2d2017-02-22 13:02:27 +0900255 final long nowMs = SystemClock.elapsedRealtime();
256 synchronized (this) {
Remi NGUYEN VAN7b84fb32019-01-19 21:13:24 +0900257 final ApfStats stats = new ApfStats.Builder()
258 .setReceivedRas(mReceivedRas)
259 .setMatchingRas(mMatchingRas)
260 .setDroppedRas(mDroppedRas)
261 .setParseErrors(mParseErrors)
262 .setZeroLifetimeRas(mZeroLifetimeRas)
263 .setProgramUpdates(mProgramUpdates)
264 .setDurationMs(nowMs - mStart)
265 .setMaxProgramSize(mApfCapabilities.maximumApfProgramSize)
266 .setProgramUpdatesAll(mNumProgramUpdates)
267 .setProgramUpdatesAllowingMulticast(mNumProgramUpdatesAllowingMulticast)
268 .build();
269 mMetricsLog.log(stats);
Hugo Benichi22d9b2d2017-02-22 13:02:27 +0900270 logApfProgramEventLocked(nowMs / DateUtils.SECOND_IN_MILLIS);
271 }
Paul Jensen578a76e2016-01-14 14:54:39 -0500272 }
273 }
274
275 private static final String TAG = "ApfFilter";
Lorenzo Colitti39c0d422016-03-23 00:23:29 +0900276 private static final boolean DBG = true;
Joe Onorato7a8797f2016-03-17 13:41:23 -0700277 private static final boolean VDBG = false;
Paul Jensen578a76e2016-01-14 14:54:39 -0500278
Paul Jensendfd5a942016-03-17 13:22:29 -0400279 private static final int ETH_HEADER_LEN = 14;
Paul Jensen91723d72016-04-14 14:51:02 -0400280 private static final int ETH_DEST_ADDR_OFFSET = 0;
Paul Jensendfd5a942016-03-17 13:22:29 -0400281 private static final int ETH_ETHERTYPE_OFFSET = 12;
Ahmed ElArabawy8537c582017-06-12 18:01:11 -0700282 private static final int ETH_TYPE_MIN = 0x0600;
Ahmed ElArabawyfd424162017-08-02 13:31:05 -0700283 private static final int ETH_TYPE_MAX = 0xFFFF;
Hugo Benichi961ca492016-09-02 11:04:34 +0900284 private static final byte[] ETH_BROADCAST_MAC_ADDRESS =
285 {(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
Paul Jensendfd5a942016-03-17 13:22:29 -0400286 // TODO: Make these offsets relative to end of link-layer header; don't include ETH_HEADER_LEN.
Aaron Huang75a60432019-02-20 17:14:02 +0800287 private static final int IPV4_TOTAL_LENGTH_OFFSET = ETH_HEADER_LEN + 2;
Paul Jensendfd5a942016-03-17 13:22:29 -0400288 private static final int IPV4_FRAGMENT_OFFSET_OFFSET = ETH_HEADER_LEN + 6;
289 // Endianness is not an issue for this constant because the APF interpreter always operates in
290 // network byte order.
291 private static final int IPV4_FRAGMENT_OFFSET_MASK = 0x1fff;
292 private static final int IPV4_PROTOCOL_OFFSET = ETH_HEADER_LEN + 9;
293 private static final int IPV4_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 16;
Hugo Benichi38db9762016-07-12 15:08:50 +0900294 private static final int IPV4_ANY_HOST_ADDRESS = 0;
Hugo Benichi0dc1d312016-09-02 12:40:31 +0900295 private static final int IPV4_BROADCAST_ADDRESS = -1; // 255.255.255.255
Aaron Huanga63c40e2019-01-15 16:53:51 +0800296 private static final int IPV4_HEADER_LEN = 20; // Without options
Paul Jensendfd5a942016-03-17 13:22:29 -0400297
Joel Scherpelz967dec72017-05-24 15:08:39 +0900298 // Traffic class and Flow label are not byte aligned. Luckily we
299 // don't care about either value so we'll consider bytes 1-3 of the
300 // IPv6 header as don't care.
301 private static final int IPV6_FLOW_LABEL_OFFSET = ETH_HEADER_LEN + 1;
302 private static final int IPV6_FLOW_LABEL_LEN = 3;
Paul Jensendfd5a942016-03-17 13:22:29 -0400303 private static final int IPV6_NEXT_HEADER_OFFSET = ETH_HEADER_LEN + 6;
304 private static final int IPV6_SRC_ADDR_OFFSET = ETH_HEADER_LEN + 8;
305 private static final int IPV6_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 24;
306 private static final int IPV6_HEADER_LEN = 40;
307 // The IPv6 all nodes address ff02::1
308 private static final byte[] IPV6_ALL_NODES_ADDRESS =
Hugo Benichi961ca492016-09-02 11:04:34 +0900309 { (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
Paul Jensendfd5a942016-03-17 13:22:29 -0400310
311 private static final int ICMP6_TYPE_OFFSET = ETH_HEADER_LEN + IPV6_HEADER_LEN;
Paul Jensendfd5a942016-03-17 13:22:29 -0400312
313 // NOTE: this must be added to the IPv4 header length in IPV4_HEADER_SIZE_MEMORY_SLOT
314 private static final int UDP_DESTINATION_PORT_OFFSET = ETH_HEADER_LEN + 2;
315 private static final int UDP_HEADER_LEN = 8;
316
Aaron Huanga63c40e2019-01-15 16:53:51 +0800317 private static final int TCP_HEADER_SIZE_OFFSET = 12;
318
Paul Jensendfd5a942016-03-17 13:22:29 -0400319 private static final int DHCP_CLIENT_PORT = 68;
320 // NOTE: this must be added to the IPv4 header length in IPV4_HEADER_SIZE_MEMORY_SLOT
321 private static final int DHCP_CLIENT_MAC_OFFSET = ETH_HEADER_LEN + UDP_HEADER_LEN + 28;
322
Hugo Benichi4fc3ee52016-06-02 11:20:27 +0900323 private static final int ARP_HEADER_OFFSET = ETH_HEADER_LEN;
Hugo Benichi961ca492016-09-02 11:04:34 +0900324 private static final byte[] ARP_IPV4_HEADER = {
Paul Jensena8458c02016-03-25 11:25:57 -0400325 0, 1, // Hardware type: Ethernet (1)
326 8, 0, // Protocol type: IP (0x0800)
327 6, // Hardware size: 6
328 4, // Protocol size: 4
Paul Jensena8458c02016-03-25 11:25:57 -0400329 };
Aaron Huang04ed6a32018-11-15 20:30:46 +0800330 private static final int ARP_OPCODE_OFFSET = ARP_HEADER_OFFSET + 6;
331 // Opcode: ARP request (0x0001), ARP reply (0x0002)
332 private static final short ARP_OPCODE_REQUEST = 1;
333 private static final short ARP_OPCODE_REPLY = 2;
334 private static final int ARP_SOURCE_IP_ADDRESS_OFFSET = ARP_HEADER_OFFSET + 14;
335 private static final int ARP_TARGET_IP_ADDRESS_OFFSET = ARP_HEADER_OFFSET + 24;
Hugo Benichi22d9b2d2017-02-22 13:02:27 +0900336 // Do not log ApfProgramEvents whose actual lifetimes was less than this.
337 private static final int APF_PROGRAM_EVENT_LIFETIME_THRESHOLD = 2;
Ahmed ElArabawyfd424162017-08-02 13:31:05 -0700338 // Limit on the Black List size to cap on program usage for this
339 // TODO: Select a proper max length
340 private static final int APF_MAX_ETH_TYPE_BLACK_LIST_LEN = 20;
Paul Jensena8458c02016-03-25 11:25:57 -0400341
Paul Jensenf21b4dc2016-03-18 12:22:09 -0400342 private final ApfCapabilities mApfCapabilities;
Remi NGUYEN VAN3c600a12019-01-10 19:12:46 +0900343 private final IpClientCallbacksWrapper mIpClientCallback;
Erik Kline8bd00d52017-12-08 17:47:50 +0900344 private final InterfaceParams mInterfaceParams;
Hugo Benichi6ccd51a2016-07-04 09:22:30 +0900345 private final IpConnectivityLog mMetricsLog;
Ahmed ElArabawy8537c582017-06-12 18:01:11 -0700346
Paul Jensen9132f342016-04-13 15:00:26 -0400347 @VisibleForTesting
348 byte[] mHardwareAddress;
349 @VisibleForTesting
350 ReceiveThread mReceiveThread;
Paul Jensendfd5a942016-03-17 13:22:29 -0400351 @GuardedBy("this")
Paul Jensen578a76e2016-01-14 14:54:39 -0500352 private long mUniqueCounter;
Paul Jensendfd5a942016-03-17 13:22:29 -0400353 @GuardedBy("this")
354 private boolean mMulticastFilter;
Bernie Innocenti5be71dc2018-03-28 20:11:49 +0900355 @GuardedBy("this")
356 private boolean mInDozeMode;
Ahmed ElArabawy8537c582017-06-12 18:01:11 -0700357 private final boolean mDrop802_3Frames;
Ahmed ElArabawyfd424162017-08-02 13:31:05 -0700358 private final int[] mEthTypeBlackList;
359
Bernie Innocenti5be71dc2018-03-28 20:11:49 +0900360 // Detects doze mode state transitions.
361 private final BroadcastReceiver mDeviceIdleReceiver = new BroadcastReceiver() {
362 @Override
363 public void onReceive(Context context, Intent intent) {
364 String action = intent.getAction();
365 if (action.equals(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED)) {
366 PowerManager powerManager =
367 (PowerManager) context.getSystemService(Context.POWER_SERVICE);
368 final boolean deviceIdle = powerManager.isDeviceIdleMode();
369 setDozeMode(deviceIdle);
370 }
371 }
372 };
373 private final Context mContext;
374
Paul Jensena8458c02016-03-25 11:25:57 -0400375 // Our IPv4 address, if we have just one, otherwise null.
376 @GuardedBy("this")
377 private byte[] mIPv4Address;
Hugo Benichi7d21eae2016-09-02 14:00:29 +0900378 // The subnet prefix length of our IPv4 network. Only valid if mIPv4Address is not null.
379 @GuardedBy("this")
380 private int mIPv4PrefixLength;
Paul Jensen578a76e2016-01-14 14:54:39 -0500381
Paul Jensen9132f342016-04-13 15:00:26 -0400382 @VisibleForTesting
Bernie Innocenti5be71dc2018-03-28 20:11:49 +0900383 ApfFilter(Context context, ApfConfiguration config, InterfaceParams ifParams,
Remi NGUYEN VAN3c600a12019-01-10 19:12:46 +0900384 IpClientCallbacksWrapper ipClientCallback, IpConnectivityLog log) {
Hugo Benichi72166362017-10-13 16:32:20 +0900385 mApfCapabilities = config.apfCapabilities;
Erik Kline1b293582017-10-11 19:43:10 +0900386 mIpClientCallback = ipClientCallback;
Erik Kline8bd00d52017-12-08 17:47:50 +0900387 mInterfaceParams = ifParams;
Hugo Benichi72166362017-10-13 16:32:20 +0900388 mMulticastFilter = config.multicastFilter;
389 mDrop802_3Frames = config.ieee802_3Filter;
Bernie Innocenti5be71dc2018-03-28 20:11:49 +0900390 mContext = context;
Ahmed ElArabawyfd424162017-08-02 13:31:05 -0700391
Bernie Innocenti3cc40ea2018-04-24 01:25:42 +0900392 if (mApfCapabilities.hasDataAccess()) {
393 mCountAndPassLabel = "countAndPass";
394 mCountAndDropLabel = "countAndDrop";
395 } else {
396 // APFv4 unsupported: turn jumps to the counter trampolines to immediately PASS or DROP,
397 // preserving the original pre-APFv4 behavior.
398 mCountAndPassLabel = ApfGenerator.PASS_LABEL;
399 mCountAndDropLabel = ApfGenerator.DROP_LABEL;
400 }
401
Ahmed ElArabawyfd424162017-08-02 13:31:05 -0700402 // Now fill the black list from the passed array
Hugo Benichi72166362017-10-13 16:32:20 +0900403 mEthTypeBlackList = filterEthTypeBlackList(config.ethTypeBlackList);
Ahmed ElArabawyfd424162017-08-02 13:31:05 -0700404
Hugo Benichi6ccd51a2016-07-04 09:22:30 +0900405 mMetricsLog = log;
Paul Jensenf21b4dc2016-03-18 12:22:09 -0400406
Erik Kline1b293582017-10-11 19:43:10 +0900407 // TODO: ApfFilter should not generate programs until IpClient sends provisioning success.
Paul Jensen578a76e2016-01-14 14:54:39 -0500408 maybeStartFilter();
Bernie Innocenti5be71dc2018-03-28 20:11:49 +0900409
410 // Listen for doze-mode transition changes to enable/disable the IPv6 multicast filter.
411 mContext.registerReceiver(mDeviceIdleReceiver,
412 new IntentFilter(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED));
Paul Jensen578a76e2016-01-14 14:54:39 -0500413 }
414
Bernie Innocenti3cc40ea2018-04-24 01:25:42 +0900415 public synchronized void setDataSnapshot(byte[] data) {
416 mDataSnapshot = data;
417 }
418
Paul Jensen578a76e2016-01-14 14:54:39 -0500419 private void log(String s) {
Erik Kline8bd00d52017-12-08 17:47:50 +0900420 Log.d(TAG, "(" + mInterfaceParams.name + "): " + s);
Paul Jensen578a76e2016-01-14 14:54:39 -0500421 }
422
Paul Jensendfd5a942016-03-17 13:22:29 -0400423 @GuardedBy("this")
424 private long getUniqueNumberLocked() {
Paul Jensen578a76e2016-01-14 14:54:39 -0500425 return mUniqueCounter++;
426 }
427
Ahmed ElArabawyfd424162017-08-02 13:31:05 -0700428 @GuardedBy("this")
429 private static int[] filterEthTypeBlackList(int[] ethTypeBlackList) {
430 ArrayList<Integer> bl = new ArrayList<Integer>();
431
432 for (int p : ethTypeBlackList) {
433 // Check if the protocol is a valid ether type
434 if ((p < ETH_TYPE_MIN) || (p > ETH_TYPE_MAX)) {
435 continue;
436 }
437
438 // Check if the protocol is not repeated in the passed array
439 if (bl.contains(p)) {
440 continue;
441 }
442
443 // Check if list reach its max size
444 if (bl.size() == APF_MAX_ETH_TYPE_BLACK_LIST_LEN) {
445 Log.w(TAG, "Passed EthType Black List size too large (" + bl.size() +
446 ") using top " + APF_MAX_ETH_TYPE_BLACK_LIST_LEN + " protocols");
447 break;
448 }
449
450 // Now add the protocol to the list
451 bl.add(p);
452 }
453
454 return bl.stream().mapToInt(Integer::intValue).toArray();
455 }
456
Paul Jensen578a76e2016-01-14 14:54:39 -0500457 /**
458 * Attempt to start listening for RAs and, if RAs are received, generating and installing
459 * filters to ignore useless RAs.
460 */
Paul Jensen9132f342016-04-13 15:00:26 -0400461 @VisibleForTesting
462 void maybeStartFilter() {
Paul Jensen578a76e2016-01-14 14:54:39 -0500463 FileDescriptor socket;
464 try {
Erik Kline8bd00d52017-12-08 17:47:50 +0900465 mHardwareAddress = mInterfaceParams.macAddr.toByteArray();
Paul Jensendfd5a942016-03-17 13:22:29 -0400466 synchronized(this) {
Bernie Innocenti8d65db32018-05-09 17:58:50 +0900467 // Clear the APF memory to reset all counters upon connecting to the first AP
468 // in an SSID. This is limited to APFv4 devices because this large write triggers
469 // a crash on some older devices (b/78905546).
470 if (mApfCapabilities.hasDataAccess()) {
471 byte[] zeroes = new byte[mApfCapabilities.maximumApfProgramSize];
472 mIpClientCallback.installPacketFilter(zeroes);
473 }
Bernie Innocenti3cc40ea2018-04-24 01:25:42 +0900474
Paul Jensendfd5a942016-03-17 13:22:29 -0400475 // Install basic filters
476 installNewProgramLocked();
477 }
Paul Jensen578a76e2016-01-14 14:54:39 -0500478 socket = Os.socket(AF_PACKET, SOCK_RAW, ETH_P_IPV6);
Remi NGUYEN VAN811f6382019-01-20 12:08:21 +0900479 SocketAddress addr = makePacketSocketAddress(
Erik Kline8bd00d52017-12-08 17:47:50 +0900480 (short) ETH_P_IPV6, mInterfaceParams.index);
Remi NGUYEN VANb7bda392019-03-06 18:02:34 +0900481 Os.bind(socket, addr);
Remi NGUYEN VAN995aada2019-04-05 04:44:45 -0700482 NetworkStackUtils.attachRaFilter(socket, mApfCapabilities.apfPacketFormat);
Paul Jensen578a76e2016-01-14 14:54:39 -0500483 } catch(SocketException|ErrnoException e) {
Paul Jensendfd5a942016-03-17 13:22:29 -0400484 Log.e(TAG, "Error starting filter", e);
Paul Jensen578a76e2016-01-14 14:54:39 -0500485 return;
486 }
487 mReceiveThread = new ReceiveThread(socket);
488 mReceiveThread.start();
489 }
490
Hugo Benichidafc44e2016-10-17 14:21:33 +0900491 // Returns seconds since device boot.
Hugo Benichi4456f332016-12-19 14:50:52 +0900492 @VisibleForTesting
493 protected long currentTimeSeconds() {
Hugo Benichidafc44e2016-10-17 14:21:33 +0900494 return SystemClock.elapsedRealtime() / DateUtils.SECOND_IN_MILLIS;
Paul Jensen578a76e2016-01-14 14:54:39 -0500495 }
496
Hugo Benichi0668a612016-10-06 15:19:36 +0900497 public static class InvalidRaException extends Exception {
498 public InvalidRaException(String m) {
499 super(m);
500 }
501 }
502
Paul Jensen578a76e2016-01-14 14:54:39 -0500503 // A class to hold information about an RA.
Hugo Benichi0668a612016-10-06 15:19:36 +0900504 @VisibleForTesting
505 class Ra {
Paul Jensen578a76e2016-01-14 14:54:39 -0500506 // From RFC4861:
507 private static final int ICMP6_RA_HEADER_LEN = 16;
Lorenzo Colittie6dfc172016-03-03 17:53:33 +0900508 private static final int ICMP6_RA_CHECKSUM_OFFSET =
509 ETH_HEADER_LEN + IPV6_HEADER_LEN + 2;
510 private static final int ICMP6_RA_CHECKSUM_LEN = 2;
Paul Jensen578a76e2016-01-14 14:54:39 -0500511 private static final int ICMP6_RA_OPTION_OFFSET =
512 ETH_HEADER_LEN + IPV6_HEADER_LEN + ICMP6_RA_HEADER_LEN;
513 private static final int ICMP6_RA_ROUTER_LIFETIME_OFFSET =
514 ETH_HEADER_LEN + IPV6_HEADER_LEN + 6;
515 private static final int ICMP6_RA_ROUTER_LIFETIME_LEN = 2;
516 // Prefix information option.
517 private static final int ICMP6_PREFIX_OPTION_TYPE = 3;
518 private static final int ICMP6_PREFIX_OPTION_LEN = 32;
519 private static final int ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET = 4;
520 private static final int ICMP6_PREFIX_OPTION_VALID_LIFETIME_LEN = 4;
521 private static final int ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET = 8;
522 private static final int ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_LEN = 4;
523
524 // From RFC6106: Recursive DNS Server option
525 private static final int ICMP6_RDNSS_OPTION_TYPE = 25;
526 // From RFC6106: DNS Search List option
527 private static final int ICMP6_DNSSL_OPTION_TYPE = 31;
528
529 // From RFC4191: Route Information option
530 private static final int ICMP6_ROUTE_INFO_OPTION_TYPE = 24;
531 // Above three options all have the same format:
532 private static final int ICMP6_4_BYTE_LIFETIME_OFFSET = 4;
533 private static final int ICMP6_4_BYTE_LIFETIME_LEN = 4;
534
Paul Jensen1c71cb32016-03-25 11:39:58 -0400535 // Note: mPacket's position() cannot be assumed to be reset.
Paul Jensen578a76e2016-01-14 14:54:39 -0500536 private final ByteBuffer mPacket;
537 // List of binary ranges that include the whole packet except the lifetimes.
538 // Pairs consist of offset and length.
539 private final ArrayList<Pair<Integer, Integer>> mNonLifetimes =
540 new ArrayList<Pair<Integer, Integer>>();
541 // Minimum lifetime in packet
542 long mMinLifetime;
543 // When the packet was last captured, in seconds since Unix Epoch
544 long mLastSeen;
545
Lorenzo Colitti5ff640d2016-03-03 17:53:46 +0900546 // For debugging only. Offsets into the packet where PIOs are.
Lorenzo Colitti059e2bb2016-04-08 20:51:39 +0900547 private final ArrayList<Integer> mPrefixOptionOffsets = new ArrayList<>();
548
549 // For debugging only. Offsets into the packet where RDNSS options are.
550 private final ArrayList<Integer> mRdnssOptionOffsets = new ArrayList<>();
551
Lorenzo Colitti5ff640d2016-03-03 17:53:46 +0900552 // For debugging only. How many times this RA was seen.
553 int seenCount = 0;
554
Lorenzo Colitti39c0d422016-03-23 00:23:29 +0900555 // For debugging only. Returns the hex representation of the last matching packet.
556 String getLastMatchingPacket() {
Lorenzo Colitti059e2bb2016-04-08 20:51:39 +0900557 return HexDump.toHexString(mPacket.array(), 0, mPacket.capacity(),
558 false /* lowercase */);
Lorenzo Colitti39c0d422016-03-23 00:23:29 +0900559 }
Lorenzo Colitti5ff640d2016-03-03 17:53:46 +0900560
Lorenzo Colitti059e2bb2016-04-08 20:51:39 +0900561 // For debugging only. Returns the string representation of the IPv6 address starting at
562 // position pos in the packet.
Lorenzo Colitti5ff640d2016-03-03 17:53:46 +0900563 private String IPv6AddresstoString(int pos) {
564 try {
565 byte[] array = mPacket.array();
566 // Can't just call copyOfRange() and see if it throws, because if it reads past the
567 // end it pads with zeros instead of throwing.
568 if (pos < 0 || pos + 16 > array.length || pos + 16 < pos) {
569 return "???";
570 }
571 byte[] addressBytes = Arrays.copyOfRange(array, pos, pos + 16);
572 InetAddress address = (Inet6Address) InetAddress.getByAddress(addressBytes);
573 return address.getHostAddress();
574 } catch (UnsupportedOperationException e) {
575 // array() failed. Cannot happen, mPacket is array-backed and read-write.
576 return "???";
Hugo Benichi0668a612016-10-06 15:19:36 +0900577 } catch (ClassCastException|UnknownHostException e) {
Lorenzo Colitti5ff640d2016-03-03 17:53:46 +0900578 // Cannot happen.
579 return "???";
580 }
581 }
582
583 // Can't be static because it's in a non-static inner class.
Hugo Benichicfbf7412016-06-23 10:41:30 +0900584 // TODO: Make this static once RA is its own class.
Lorenzo Colitti059e2bb2016-04-08 20:51:39 +0900585 private void prefixOptionToString(StringBuffer sb, int offset) {
586 String prefix = IPv6AddresstoString(offset + 16);
Hugo Benichi4104ff92016-10-13 09:26:01 +0900587 int length = getUint8(mPacket, offset + 2);
588 long valid = getUint32(mPacket, offset + 4);
589 long preferred = getUint32(mPacket, offset + 8);
Lorenzo Colitti059e2bb2016-04-08 20:51:39 +0900590 sb.append(String.format("%s/%d %ds/%ds ", prefix, length, valid, preferred));
591 }
592
593 private void rdnssOptionToString(StringBuffer sb, int offset) {
Hugo Benichi4104ff92016-10-13 09:26:01 +0900594 int optLen = getUint8(mPacket, offset + 1) * 8;
Lorenzo Colitti059e2bb2016-04-08 20:51:39 +0900595 if (optLen < 24) return; // Malformed or empty.
Hugo Benichi4104ff92016-10-13 09:26:01 +0900596 long lifetime = getUint32(mPacket, offset + 4);
Lorenzo Colitti059e2bb2016-04-08 20:51:39 +0900597 int numServers = (optLen - 8) / 16;
598 sb.append("DNS ").append(lifetime).append("s");
599 for (int server = 0; server < numServers; server++) {
600 sb.append(" ").append(IPv6AddresstoString(offset + 8 + 16 * server));
601 }
602 }
603
Lorenzo Colitti5ff640d2016-03-03 17:53:46 +0900604 public String toString() {
605 try {
606 StringBuffer sb = new StringBuffer();
Lorenzo Colitti059e2bb2016-04-08 20:51:39 +0900607 sb.append(String.format("RA %s -> %s %ds ",
Lorenzo Colitti5ff640d2016-03-03 17:53:46 +0900608 IPv6AddresstoString(IPV6_SRC_ADDR_OFFSET),
Paul Jensendfd5a942016-03-17 13:22:29 -0400609 IPv6AddresstoString(IPV6_DEST_ADDR_OFFSET),
Hugo Benichi4104ff92016-10-13 09:26:01 +0900610 getUint16(mPacket, ICMP6_RA_ROUTER_LIFETIME_OFFSET)));
Lorenzo Colitti5ff640d2016-03-03 17:53:46 +0900611 for (int i: mPrefixOptionOffsets) {
Lorenzo Colitti059e2bb2016-04-08 20:51:39 +0900612 prefixOptionToString(sb, i);
613 }
614 for (int i: mRdnssOptionOffsets) {
615 rdnssOptionToString(sb, i);
Lorenzo Colitti5ff640d2016-03-03 17:53:46 +0900616 }
617 return sb.toString();
Hugo Benichi0668a612016-10-06 15:19:36 +0900618 } catch (BufferUnderflowException|IndexOutOfBoundsException e) {
Lorenzo Colitti5ff640d2016-03-03 17:53:46 +0900619 return "<Malformed RA>";
620 }
621 }
622
Paul Jensen578a76e2016-01-14 14:54:39 -0500623 /**
624 * Add a binary range of the packet that does not include a lifetime to mNonLifetimes.
625 * Assumes mPacket.position() is as far as we've parsed the packet.
626 * @param lastNonLifetimeStart offset within packet of where the last binary range of
627 * data not including a lifetime.
628 * @param lifetimeOffset offset from mPacket.position() to the next lifetime data.
629 * @param lifetimeLength length of the next lifetime data.
630 * @return offset within packet of where the next binary range of data not including
Hugo Benichi6ccd51a2016-07-04 09:22:30 +0900631 * a lifetime. This can be passed into the next invocation of this function
Paul Jensen578a76e2016-01-14 14:54:39 -0500632 * via {@code lastNonLifetimeStart}.
633 */
634 private int addNonLifetime(int lastNonLifetimeStart, int lifetimeOffset,
635 int lifetimeLength) {
636 lifetimeOffset += mPacket.position();
637 mNonLifetimes.add(new Pair<Integer, Integer>(lastNonLifetimeStart,
638 lifetimeOffset - lastNonLifetimeStart));
639 return lifetimeOffset + lifetimeLength;
640 }
641
Hugo Benichicfbf7412016-06-23 10:41:30 +0900642 private int addNonLifetimeU32(int lastNonLifetimeStart) {
643 return addNonLifetime(lastNonLifetimeStart,
644 ICMP6_4_BYTE_LIFETIME_OFFSET, ICMP6_4_BYTE_LIFETIME_LEN);
645 }
646
Bernie Innocenti408dbda2018-03-22 23:07:47 +0900647 // Note that this parses RA and may throw InvalidRaException (from
Lorenzo Colitti8995d852016-06-23 15:24:46 +0900648 // Buffer.position(int) or due to an invalid-length option) or IndexOutOfBoundsException
649 // (from ByteBuffer.get(int) ) if parsing encounters something non-compliant with
650 // specifications.
Hugo Benichi0668a612016-10-06 15:19:36 +0900651 Ra(byte[] packet, int length) throws InvalidRaException {
652 if (length < ICMP6_RA_OPTION_OFFSET) {
653 throw new InvalidRaException("Not an ICMP6 router advertisement");
654 }
655
Hugo Benichi6ccd51a2016-07-04 09:22:30 +0900656 mPacket = ByteBuffer.wrap(Arrays.copyOf(packet, length));
Hugo Benichi4456f332016-12-19 14:50:52 +0900657 mLastSeen = currentTimeSeconds();
Paul Jensen4b545b02016-07-20 15:01:17 -0400658
659 // Sanity check packet in case a packet arrives before we attach RA filter
660 // to our packet socket. b/29586253
661 if (getUint16(mPacket, ETH_ETHERTYPE_OFFSET) != ETH_P_IPV6 ||
Hugo Benichi4104ff92016-10-13 09:26:01 +0900662 getUint8(mPacket, IPV6_NEXT_HEADER_OFFSET) != IPPROTO_ICMPV6 ||
Bernie Innocenti5be71dc2018-03-28 20:11:49 +0900663 getUint8(mPacket, ICMP6_TYPE_OFFSET) != ICMPV6_ROUTER_ADVERTISEMENT) {
Hugo Benichi0668a612016-10-06 15:19:36 +0900664 throw new InvalidRaException("Not an ICMP6 router advertisement");
Paul Jensen4b545b02016-07-20 15:01:17 -0400665 }
666
667
Hugo Benichi6ccd51a2016-07-04 09:22:30 +0900668 RaEvent.Builder builder = new RaEvent.Builder();
Paul Jensen578a76e2016-01-14 14:54:39 -0500669
Joel Scherpelz967dec72017-05-24 15:08:39 +0900670 // Ignore the flow label and low 4 bits of traffic class.
Lorenzo Colittie6dfc172016-03-03 17:53:33 +0900671 int lastNonLifetimeStart = addNonLifetime(0,
Joel Scherpelz967dec72017-05-24 15:08:39 +0900672 IPV6_FLOW_LABEL_OFFSET,
673 IPV6_FLOW_LABEL_LEN);
674
675 // Ignore the checksum.
676 lastNonLifetimeStart = addNonLifetime(lastNonLifetimeStart,
Lorenzo Colittie6dfc172016-03-03 17:53:33 +0900677 ICMP6_RA_CHECKSUM_OFFSET,
678 ICMP6_RA_CHECKSUM_LEN);
679
Paul Jensen578a76e2016-01-14 14:54:39 -0500680 // Parse router lifetime
Lorenzo Colittie6dfc172016-03-03 17:53:33 +0900681 lastNonLifetimeStart = addNonLifetime(lastNonLifetimeStart,
682 ICMP6_RA_ROUTER_LIFETIME_OFFSET,
Paul Jensen578a76e2016-01-14 14:54:39 -0500683 ICMP6_RA_ROUTER_LIFETIME_LEN);
Hugo Benichi6ccd51a2016-07-04 09:22:30 +0900684 builder.updateRouterLifetime(getUint16(mPacket, ICMP6_RA_ROUTER_LIFETIME_OFFSET));
Hugo Benichicfbf7412016-06-23 10:41:30 +0900685
Lorenzo Colitti059e2bb2016-04-08 20:51:39 +0900686 // Ensures that the RA is not truncated.
Paul Jensen578a76e2016-01-14 14:54:39 -0500687 mPacket.position(ICMP6_RA_OPTION_OFFSET);
688 while (mPacket.hasRemaining()) {
Hugo Benichicfbf7412016-06-23 10:41:30 +0900689 final int position = mPacket.position();
Hugo Benichi4104ff92016-10-13 09:26:01 +0900690 final int optionType = getUint8(mPacket, position);
691 final int optionLength = getUint8(mPacket, position + 1) * 8;
Hugo Benichi6ccd51a2016-07-04 09:22:30 +0900692 long lifetime;
Paul Jensen578a76e2016-01-14 14:54:39 -0500693 switch (optionType) {
694 case ICMP6_PREFIX_OPTION_TYPE:
695 // Parse valid lifetime
696 lastNonLifetimeStart = addNonLifetime(lastNonLifetimeStart,
697 ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET,
698 ICMP6_PREFIX_OPTION_VALID_LIFETIME_LEN);
Hugo Benichi6ccd51a2016-07-04 09:22:30 +0900699 lifetime = getUint32(mPacket,
700 position + ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET);
701 builder.updatePrefixValidLifetime(lifetime);
Paul Jensen578a76e2016-01-14 14:54:39 -0500702 // Parse preferred lifetime
703 lastNonLifetimeStart = addNonLifetime(lastNonLifetimeStart,
704 ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET,
705 ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_LEN);
Hugo Benichi6ccd51a2016-07-04 09:22:30 +0900706 lifetime = getUint32(mPacket,
707 position + ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET);
708 builder.updatePrefixPreferredLifetime(lifetime);
Hugo Benichicfbf7412016-06-23 10:41:30 +0900709 mPrefixOptionOffsets.add(position);
Paul Jensen578a76e2016-01-14 14:54:39 -0500710 break;
Hugo Benichicfbf7412016-06-23 10:41:30 +0900711 // These three options have the same lifetime offset and size, and
Hugo Benichi6ccd51a2016-07-04 09:22:30 +0900712 // are processed with the same specialized addNonLifetimeU32:
Paul Jensen578a76e2016-01-14 14:54:39 -0500713 case ICMP6_RDNSS_OPTION_TYPE:
Hugo Benichicfbf7412016-06-23 10:41:30 +0900714 mRdnssOptionOffsets.add(position);
715 lastNonLifetimeStart = addNonLifetimeU32(lastNonLifetimeStart);
Hugo Benichi6ccd51a2016-07-04 09:22:30 +0900716 lifetime = getUint32(mPacket, position + ICMP6_4_BYTE_LIFETIME_OFFSET);
717 builder.updateRdnssLifetime(lifetime);
Hugo Benichicfbf7412016-06-23 10:41:30 +0900718 break;
Lorenzo Colitti059e2bb2016-04-08 20:51:39 +0900719 case ICMP6_ROUTE_INFO_OPTION_TYPE:
Hugo Benichicfbf7412016-06-23 10:41:30 +0900720 lastNonLifetimeStart = addNonLifetimeU32(lastNonLifetimeStart);
Hugo Benichi6ccd51a2016-07-04 09:22:30 +0900721 lifetime = getUint32(mPacket, position + ICMP6_4_BYTE_LIFETIME_OFFSET);
722 builder.updateRouteInfoLifetime(lifetime);
Hugo Benichicfbf7412016-06-23 10:41:30 +0900723 break;
Paul Jensen578a76e2016-01-14 14:54:39 -0500724 case ICMP6_DNSSL_OPTION_TYPE:
Hugo Benichicfbf7412016-06-23 10:41:30 +0900725 lastNonLifetimeStart = addNonLifetimeU32(lastNonLifetimeStart);
Hugo Benichi6ccd51a2016-07-04 09:22:30 +0900726 lifetime = getUint32(mPacket, position + ICMP6_4_BYTE_LIFETIME_OFFSET);
727 builder.updateDnsslLifetime(lifetime);
Paul Jensen578a76e2016-01-14 14:54:39 -0500728 break;
729 default:
730 // RFC4861 section 4.2 dictates we ignore unknown options for fowards
731 // compatibility.
732 break;
733 }
Lorenzo Colitti8995d852016-06-23 15:24:46 +0900734 if (optionLength <= 0) {
Hugo Benichi0668a612016-10-06 15:19:36 +0900735 throw new InvalidRaException(String.format(
Lorenzo Colitti8995d852016-06-23 15:24:46 +0900736 "Invalid option length opt=%d len=%d", optionType, optionLength));
737 }
Hugo Benichicfbf7412016-06-23 10:41:30 +0900738 mPacket.position(position + optionLength);
Paul Jensen578a76e2016-01-14 14:54:39 -0500739 }
740 // Mark non-lifetime bytes since last lifetime.
741 addNonLifetime(lastNonLifetimeStart, 0, 0);
742 mMinLifetime = minLifetime(packet, length);
Hugo Benichi6ccd51a2016-07-04 09:22:30 +0900743 mMetricsLog.log(builder.build());
Paul Jensen578a76e2016-01-14 14:54:39 -0500744 }
745
746 // Ignoring lifetimes (which may change) does {@code packet} match this RA?
747 boolean matches(byte[] packet, int length) {
Paul Jensen1c71cb32016-03-25 11:39:58 -0400748 if (length != mPacket.capacity()) return false;
749 byte[] referencePacket = mPacket.array();
Paul Jensen578a76e2016-01-14 14:54:39 -0500750 for (Pair<Integer, Integer> nonLifetime : mNonLifetimes) {
Paul Jensen1c71cb32016-03-25 11:39:58 -0400751 for (int i = nonLifetime.first; i < (nonLifetime.first + nonLifetime.second); i++) {
752 if (packet[i] != referencePacket[i]) return false;
753 }
Paul Jensen578a76e2016-01-14 14:54:39 -0500754 }
755 return true;
756 }
757
758 // What is the minimum of all lifetimes within {@code packet} in seconds?
759 // Precondition: matches(packet, length) already returned true.
760 long minLifetime(byte[] packet, int length) {
761 long minLifetime = Long.MAX_VALUE;
762 // Wrap packet in ByteBuffer so we can read big-endian values easily
763 ByteBuffer byteBuffer = ByteBuffer.wrap(packet);
764 for (int i = 0; (i + 1) < mNonLifetimes.size(); i++) {
765 int offset = mNonLifetimes.get(i).first + mNonLifetimes.get(i).second;
Lorenzo Colittie6dfc172016-03-03 17:53:33 +0900766
Joel Scherpelz967dec72017-05-24 15:08:39 +0900767 // The flow label is in mNonLifetimes, but it's not a lifetime.
768 if (offset == IPV6_FLOW_LABEL_OFFSET) {
769 continue;
770 }
771
Lorenzo Colittie6dfc172016-03-03 17:53:33 +0900772 // The checksum is in mNonLifetimes, but it's not a lifetime.
773 if (offset == ICMP6_RA_CHECKSUM_OFFSET) {
Joel Scherpelz967dec72017-05-24 15:08:39 +0900774 continue;
Lorenzo Colittie6dfc172016-03-03 17:53:33 +0900775 }
776
Hugo Benichicfbf7412016-06-23 10:41:30 +0900777 final int lifetimeLength = mNonLifetimes.get(i+1).first - offset;
778 final long optionLifetime;
Paul Jensen578a76e2016-01-14 14:54:39 -0500779 switch (lifetimeLength) {
Hugo Benichicfbf7412016-06-23 10:41:30 +0900780 case 2:
Hugo Benichi4104ff92016-10-13 09:26:01 +0900781 optionLifetime = getUint16(byteBuffer, offset);
Hugo Benichicfbf7412016-06-23 10:41:30 +0900782 break;
783 case 4:
Hugo Benichi4104ff92016-10-13 09:26:01 +0900784 optionLifetime = getUint32(byteBuffer, offset);
Hugo Benichicfbf7412016-06-23 10:41:30 +0900785 break;
786 default:
787 throw new IllegalStateException("bogus lifetime size " + lifetimeLength);
Paul Jensen578a76e2016-01-14 14:54:39 -0500788 }
Hugo Benichicfbf7412016-06-23 10:41:30 +0900789 minLifetime = Math.min(minLifetime, optionLifetime);
Paul Jensen578a76e2016-01-14 14:54:39 -0500790 }
791 return minLifetime;
792 }
793
794 // How many seconds does this RA's have to live, taking into account the fact
795 // that we might have seen it a while ago.
796 long currentLifetime() {
Hugo Benichi4456f332016-12-19 14:50:52 +0900797 return mMinLifetime - (currentTimeSeconds() - mLastSeen);
Paul Jensen578a76e2016-01-14 14:54:39 -0500798 }
799
800 boolean isExpired() {
Paul Jensendfd5a942016-03-17 13:22:29 -0400801 // TODO: We may want to handle 0 lifetime RAs differently, if they are common. We'll
Aaron Huanga63c40e2019-01-15 16:53:51 +0800802 // have to calculate the filter lifetime specially as a fraction of 0 is still 0.
Paul Jensendfd5a942016-03-17 13:22:29 -0400803 return currentLifetime() <= 0;
Paul Jensen578a76e2016-01-14 14:54:39 -0500804 }
805
806 // Append a filter for this RA to {@code gen}. Jump to DROP_LABEL if it should be dropped.
807 // Jump to the next filter if packet doesn't match this RA.
Paul Jensendfd5a942016-03-17 13:22:29 -0400808 @GuardedBy("ApfFilter.this")
809 long generateFilterLocked(ApfGenerator gen) throws IllegalInstructionException {
810 String nextFilterLabel = "Ra" + getUniqueNumberLocked();
Paul Jensen578a76e2016-01-14 14:54:39 -0500811 // Skip if packet is not the right size
812 gen.addLoadFromMemory(Register.R0, gen.PACKET_SIZE_MEMORY_SLOT);
Paul Jensen1c71cb32016-03-25 11:39:58 -0400813 gen.addJumpIfR0NotEquals(mPacket.capacity(), nextFilterLabel);
Paul Jensen578a76e2016-01-14 14:54:39 -0500814 int filterLifetime = (int)(currentLifetime() / FRACTION_OF_LIFETIME_TO_FILTER);
815 // Skip filter if expired
816 gen.addLoadFromMemory(Register.R0, gen.FILTER_AGE_MEMORY_SLOT);
817 gen.addJumpIfR0GreaterThan(filterLifetime, nextFilterLabel);
818 for (int i = 0; i < mNonLifetimes.size(); i++) {
819 // Generate code to match the packet bytes
820 Pair<Integer, Integer> nonLifetime = mNonLifetimes.get(i);
Paul Jensen7c34b152016-03-22 14:23:46 -0400821 // Don't generate JNEBS instruction for 0 bytes as it always fails the
822 // ASSERT_FORWARD_IN_PROGRAM(pc + cmp_imm - 1) check where cmp_imm is
823 // the number of bytes to compare. nonLifetime is zero between the
824 // valid and preferred lifetimes in the prefix option.
825 if (nonLifetime.second != 0) {
826 gen.addLoadImmediate(Register.R0, nonLifetime.first);
827 gen.addJumpIfBytesNotEqual(Register.R0,
828 Arrays.copyOfRange(mPacket.array(), nonLifetime.first,
829 nonLifetime.first + nonLifetime.second),
830 nextFilterLabel);
831 }
Paul Jensen578a76e2016-01-14 14:54:39 -0500832 // Generate code to test the lifetimes haven't gone down too far
833 if ((i + 1) < mNonLifetimes.size()) {
834 Pair<Integer, Integer> nextNonLifetime = mNonLifetimes.get(i + 1);
835 int offset = nonLifetime.first + nonLifetime.second;
Joel Scherpelz967dec72017-05-24 15:08:39 +0900836
837 // Skip the Flow label.
838 if (offset == IPV6_FLOW_LABEL_OFFSET) {
839 continue;
840 }
Lorenzo Colittie6dfc172016-03-03 17:53:33 +0900841 // Skip the checksum.
842 if (offset == ICMP6_RA_CHECKSUM_OFFSET) {
843 continue;
844 }
Paul Jensen578a76e2016-01-14 14:54:39 -0500845 int length = nextNonLifetime.first - offset;
846 switch (length) {
847 case 4: gen.addLoad32(Register.R0, offset); break;
848 case 2: gen.addLoad16(Register.R0, offset); break;
849 default: throw new IllegalStateException("bogus lifetime size " + length);
850 }
851 gen.addJumpIfR0LessThan(filterLifetime, nextFilterLabel);
852 }
853 }
Aaron Huang04ed6a32018-11-15 20:30:46 +0800854 maybeSetupCounter(gen, Counter.DROPPED_RA);
Bernie Innocenti3cc40ea2018-04-24 01:25:42 +0900855 gen.addJump(mCountAndDropLabel);
Paul Jensen578a76e2016-01-14 14:54:39 -0500856 gen.defineLabel(nextFilterLabel);
857 return filterLifetime;
858 }
859 }
860
Aaron Huang56f9e412019-05-13 05:13:09 -0700861 // TODO: Refactor these subclasses to avoid so much repetition.
862 private abstract static class KeepalivePacket {
Aaron Huanga63c40e2019-01-15 16:53:51 +0800863 // Note that the offset starts from IP header.
864 // These must be added ether header length when generating program.
865 static final int IP_HEADER_OFFSET = 0;
Aaron Huang56f9e412019-05-13 05:13:09 -0700866 static final int IPV4_SRC_ADDR_OFFSET = IP_HEADER_OFFSET + 12;
Aaron Huanga63c40e2019-01-15 16:53:51 +0800867
Aaron Huang56f9e412019-05-13 05:13:09 -0700868 // Append a filter for this keepalive ack to {@code gen}.
869 // Jump to drop if it matches the keepalive ack.
870 // Jump to the next filter if packet doesn't match the keepalive ack.
871 abstract void generateFilterLocked(ApfGenerator gen) throws IllegalInstructionException;
872 }
873
874 // A class to hold NAT-T keepalive ack information.
Aaron Huang4a40e912019-05-15 00:17:35 -0700875 private class NattKeepaliveResponse extends KeepalivePacket {
Aaron Huang56f9e412019-05-13 05:13:09 -0700876 static final int UDP_LENGTH_OFFSET = 4;
877 static final int UDP_HEADER_LEN = 8;
878
Aaron Huang4a40e912019-05-15 00:17:35 -0700879 protected class NattKeepaliveResponseData {
Aaron Huang56f9e412019-05-13 05:13:09 -0700880 public final byte[] srcAddress;
881 public final int srcPort;
882 public final byte[] dstAddress;
883 public final int dstPort;
884
Aaron Huang4a40e912019-05-15 00:17:35 -0700885 NattKeepaliveResponseData(final NattKeepalivePacketDataParcelable sentKeepalivePacket) {
Aaron Huang56f9e412019-05-13 05:13:09 -0700886 srcAddress = sentKeepalivePacket.dstAddress;
887 srcPort = sentKeepalivePacket.dstPort;
888 dstAddress = sentKeepalivePacket.srcAddress;
889 dstPort = sentKeepalivePacket.srcPort;
890 }
891 }
892
Aaron Huang4a40e912019-05-15 00:17:35 -0700893 protected final NattKeepaliveResponseData mPacket;
Aaron Huang56f9e412019-05-13 05:13:09 -0700894 protected final byte[] mSrcDstAddr;
895 protected final byte[] mPortFingerprint;
896 // NAT-T keepalive packet
897 protected final byte[] mPayload = {(byte) 0xff};
898
Aaron Huang4a40e912019-05-15 00:17:35 -0700899 NattKeepaliveResponse(final NattKeepalivePacketDataParcelable sentKeepalivePacket) {
900 mPacket = new NattKeepaliveResponseData(sentKeepalivePacket);
901 mSrcDstAddr = concatArrays(mPacket.srcAddress, mPacket.dstAddress);
Aaron Huang56f9e412019-05-13 05:13:09 -0700902 mPortFingerprint = generatePortFingerprint(mPacket.srcPort, mPacket.dstPort);
903 }
904
Aaron Huang4a40e912019-05-15 00:17:35 -0700905 byte[] generatePortFingerprint(int srcPort, int dstPort) {
Aaron Huang56f9e412019-05-13 05:13:09 -0700906 final ByteBuffer fp = ByteBuffer.allocate(4);
907 fp.order(ByteOrder.BIG_ENDIAN);
908 fp.putShort((short) srcPort);
909 fp.putShort((short) dstPort);
910 return fp.array();
911 }
912
Aaron Huang56f9e412019-05-13 05:13:09 -0700913 @Override
914 void generateFilterLocked(ApfGenerator gen) throws IllegalInstructionException {
915 final String nextFilterLabel = "natt_keepalive_filter" + getUniqueNumberLocked();
916
917 gen.addLoadImmediate(Register.R0, ETH_HEADER_LEN + IPV4_SRC_ADDR_OFFSET);
918 gen.addJumpIfBytesNotEqual(Register.R0, mSrcDstAddr, nextFilterLabel);
919
920 // A NAT-T keepalive packet contains 1 byte payload with the value 0xff
921 // Check payload length is 1
922 gen.addLoadFromMemory(Register.R0, gen.IPV4_HEADER_SIZE_MEMORY_SLOT);
923 gen.addAdd(UDP_HEADER_LEN);
924 gen.addSwap();
925 gen.addLoad16(Register.R0, IPV4_TOTAL_LENGTH_OFFSET);
926 gen.addNeg(Register.R1);
927 gen.addAddR1();
928 gen.addJumpIfR0NotEquals(1, nextFilterLabel);
929
Aaron Huang4a40e912019-05-15 00:17:35 -0700930 // Check that the ports match
931 gen.addLoadFromMemory(Register.R0, gen.IPV4_HEADER_SIZE_MEMORY_SLOT);
932 gen.addAdd(ETH_HEADER_LEN);
Aaron Huang56f9e412019-05-13 05:13:09 -0700933 gen.addJumpIfBytesNotEqual(Register.R0, mPortFingerprint, nextFilterLabel);
934
935 // Payload offset = R0 + UDP header length
936 gen.addAdd(UDP_HEADER_LEN);
937 gen.addJumpIfBytesNotEqual(Register.R0, mPayload, nextFilterLabel);
938
939 maybeSetupCounter(gen, Counter.DROPPED_IPV4_NATT_KEEPALIVE);
940 gen.addJump(mCountAndDropLabel);
941 gen.defineLabel(nextFilterLabel);
942 }
Aaron Huang56f9e412019-05-13 05:13:09 -0700943
Aaron Huang4a40e912019-05-15 00:17:35 -0700944 public String toString() {
945 try {
946 return String.format("%s -> %s",
947 NetworkStackUtils.addressAndPortToString(
948 InetAddress.getByAddress(mPacket.srcAddress), mPacket.srcPort),
949 NetworkStackUtils.addressAndPortToString(
950 InetAddress.getByAddress(mPacket.dstAddress), mPacket.dstPort));
951 } catch (UnknownHostException e) {
952 return "Unknown host";
953 }
Aaron Huang56f9e412019-05-13 05:13:09 -0700954 }
955 }
956
957 // A class to hold TCP keepalive ack information.
958 private abstract static class TcpKeepaliveAck extends KeepalivePacket {
Aaron Huanga63c40e2019-01-15 16:53:51 +0800959 protected static class TcpKeepaliveAckData {
960 public final byte[] srcAddress;
961 public final int srcPort;
962 public final byte[] dstAddress;
963 public final int dstPort;
964 public final int seq;
965 public final int ack;
Aaron Huang56f9e412019-05-13 05:13:09 -0700966
Aaron Huanga63c40e2019-01-15 16:53:51 +0800967 // Create the characteristics of the ack packet from the sent keepalive packet.
968 TcpKeepaliveAckData(final TcpKeepalivePacketDataParcelable sentKeepalivePacket) {
969 srcAddress = sentKeepalivePacket.dstAddress;
970 srcPort = sentKeepalivePacket.dstPort;
971 dstAddress = sentKeepalivePacket.srcAddress;
972 dstPort = sentKeepalivePacket.srcPort;
973 seq = sentKeepalivePacket.ack;
974 ack = sentKeepalivePacket.seq + 1;
975 }
976 }
977
978 protected final TcpKeepaliveAckData mPacket;
979 protected final byte[] mSrcDstAddr;
Aaron Huang75a60432019-02-20 17:14:02 +0800980 protected final byte[] mPortSeqAckFingerprint;
Aaron Huanga63c40e2019-01-15 16:53:51 +0800981
982 TcpKeepaliveAck(final TcpKeepaliveAckData packet, final byte[] srcDstAddr) {
983 mPacket = packet;
984 mSrcDstAddr = srcDstAddr;
Aaron Huang75a60432019-02-20 17:14:02 +0800985 mPortSeqAckFingerprint = generatePortSeqAckFingerprint(mPacket.srcPort,
986 mPacket.dstPort, mPacket.seq, mPacket.ack);
987 }
988
989 static byte[] generatePortSeqAckFingerprint(int srcPort, int dstPort, int seq, int ack) {
990 final ByteBuffer fp = ByteBuffer.allocate(12);
991 fp.order(ByteOrder.BIG_ENDIAN);
992 fp.putShort((short) srcPort);
993 fp.putShort((short) dstPort);
994 fp.putInt(seq);
995 fp.putInt(ack);
996 return fp.array();
Aaron Huanga63c40e2019-01-15 16:53:51 +0800997 }
998
Aaron Huanga63c40e2019-01-15 16:53:51 +0800999 public String toString() {
Aaron Huang56f9e412019-05-13 05:13:09 -07001000 try {
1001 return String.format("%s -> %s , seq=%d, ack=%d",
1002 NetworkStackUtils.addressAndPortToString(
1003 InetAddress.getByAddress(mPacket.srcAddress), mPacket.srcPort),
1004 NetworkStackUtils.addressAndPortToString(
1005 InetAddress.getByAddress(mPacket.dstAddress), mPacket.dstPort),
1006 Integer.toUnsignedLong(mPacket.seq),
1007 Integer.toUnsignedLong(mPacket.ack));
1008 } catch (UnknownHostException e) {
1009 return "Unknown host";
1010 }
Aaron Huanga63c40e2019-01-15 16:53:51 +08001011 }
1012
1013 // Append a filter for this keepalive ack to {@code gen}.
1014 // Jump to drop if it matches the keepalive ack.
1015 // Jump to the next filter if packet doesn't match the keepalive ack.
1016 abstract void generateFilterLocked(ApfGenerator gen) throws IllegalInstructionException;
1017 }
1018
1019 private class TcpKeepaliveAckV4 extends TcpKeepaliveAck {
Aaron Huanga63c40e2019-01-15 16:53:51 +08001020
1021 TcpKeepaliveAckV4(final TcpKeepalivePacketDataParcelable sentKeepalivePacket) {
1022 this(new TcpKeepaliveAckData(sentKeepalivePacket));
1023 }
1024 TcpKeepaliveAckV4(final TcpKeepaliveAckData packet) {
1025 super(packet, concatArrays(packet.srcAddress, packet.dstAddress) /* srcDstAddr */);
1026 }
1027
1028 @Override
1029 void generateFilterLocked(ApfGenerator gen) throws IllegalInstructionException {
1030 final String nextFilterLabel = "keepalive_ack" + getUniqueNumberLocked();
Aaron Huang75a60432019-02-20 17:14:02 +08001031
Aaron Huanga63c40e2019-01-15 16:53:51 +08001032 gen.addLoadImmediate(Register.R0, ETH_HEADER_LEN + IPV4_SRC_ADDR_OFFSET);
1033 gen.addJumpIfBytesNotEqual(Register.R0, mSrcDstAddr, nextFilterLabel);
1034
Aaron Huang75a60432019-02-20 17:14:02 +08001035 // Skip to the next filter if it's not zero-sized :
1036 // TCP_HEADER_SIZE + IPV4_HEADER_SIZE - ipv4_total_length == 0
Aaron Huanga63c40e2019-01-15 16:53:51 +08001037 // Load the IP header size into R1
1038 gen.addLoadFromMemory(Register.R1, gen.IPV4_HEADER_SIZE_MEMORY_SLOT);
1039 // Load the TCP header size into R0 (it's indexed by R1)
1040 gen.addLoad8Indexed(Register.R0, ETH_HEADER_LEN + TCP_HEADER_SIZE_OFFSET);
1041 // Size offset is in the top nibble, but it must be multiplied by 4, and the two
1042 // top bits of the low nibble are guaranteed to be zeroes. Right-shift R0 by 2.
1043 gen.addRightShift(2);
Aaron Huang75a60432019-02-20 17:14:02 +08001044 // R0 += R1 -> R0 contains TCP + IP headers length
Aaron Huanga63c40e2019-01-15 16:53:51 +08001045 gen.addAddR1();
Aaron Huang75a60432019-02-20 17:14:02 +08001046 // Load IPv4 total length
1047 gen.addLoad16(Register.R1, IPV4_TOTAL_LENGTH_OFFSET);
Aaron Huanga63c40e2019-01-15 16:53:51 +08001048 gen.addNeg(Register.R0);
1049 gen.addAddR1();
1050 gen.addJumpIfR0NotEquals(0, nextFilterLabel);
Aaron Huanga63c40e2019-01-15 16:53:51 +08001051 // Add IPv4 header length
1052 gen.addLoadFromMemory(Register.R1, gen.IPV4_HEADER_SIZE_MEMORY_SLOT);
Aaron Huang75a60432019-02-20 17:14:02 +08001053 gen.addLoadImmediate(Register.R0, ETH_HEADER_LEN);
1054 gen.addAddR1();
1055 gen.addJumpIfBytesNotEqual(Register.R0, mPortSeqAckFingerprint, nextFilterLabel);
Aaron Huanga63c40e2019-01-15 16:53:51 +08001056
1057 maybeSetupCounter(gen, Counter.DROPPED_IPV4_KEEPALIVE_ACK);
1058 gen.addJump(mCountAndDropLabel);
1059 gen.defineLabel(nextFilterLabel);
1060 }
1061 }
1062
1063 private class TcpKeepaliveAckV6 extends TcpKeepaliveAck {
1064 TcpKeepaliveAckV6(final TcpKeepalivePacketDataParcelable sentKeepalivePacket) {
1065 this(new TcpKeepaliveAckData(sentKeepalivePacket));
1066 }
1067 TcpKeepaliveAckV6(final TcpKeepaliveAckData packet) {
1068 super(packet, concatArrays(packet.srcAddress, packet.dstAddress) /* srcDstAddr */);
1069 }
1070
1071 @Override
1072 void generateFilterLocked(ApfGenerator gen) throws IllegalInstructionException {
Aaron Huang56f9e412019-05-13 05:13:09 -07001073 throw new UnsupportedOperationException("IPv6 TCP Keepalive is not supported yet");
Aaron Huanga63c40e2019-01-15 16:53:51 +08001074 }
1075 }
1076
Paul Jensen578a76e2016-01-14 14:54:39 -05001077 // Maximum number of RAs to filter for.
1078 private static final int MAX_RAS = 10;
Paul Jensendfd5a942016-03-17 13:22:29 -04001079
1080 @GuardedBy("this")
Aaron Huanga63c40e2019-01-15 16:53:51 +08001081 private ArrayList<Ra> mRas = new ArrayList<>();
1082 @GuardedBy("this")
Aaron Huang56f9e412019-05-13 05:13:09 -07001083 private SparseArray<KeepalivePacket> mKeepalivePackets = new SparseArray<>();
Paul Jensen578a76e2016-01-14 14:54:39 -05001084
1085 // There is always some marginal benefit to updating the installed APF program when an RA is
1086 // seen because we can extend the program's lifetime slightly, but there is some cost to
1087 // updating the program, so don't bother unless the program is going to expire soon. This
1088 // constant defines "soon" in seconds.
1089 private static final long MAX_PROGRAM_LIFETIME_WORTH_REFRESHING = 30;
1090 // We don't want to filter an RA for it's whole lifetime as it'll be expired by the time we ever
1091 // see a refresh. Using half the lifetime might be a good idea except for the fact that
1092 // packets may be dropped, so let's use 6.
1093 private static final int FRACTION_OF_LIFETIME_TO_FILTER = 6;
1094
1095 // When did we last install a filter program? In seconds since Unix Epoch.
Paul Jensendfd5a942016-03-17 13:22:29 -04001096 @GuardedBy("this")
Paul Jensen578a76e2016-01-14 14:54:39 -05001097 private long mLastTimeInstalledProgram;
1098 // How long should the last installed filter program live for? In seconds.
Paul Jensendfd5a942016-03-17 13:22:29 -04001099 @GuardedBy("this")
Paul Jensen578a76e2016-01-14 14:54:39 -05001100 private long mLastInstalledProgramMinLifetime;
Hugo Benichi22d9b2d2017-02-22 13:02:27 +09001101 @GuardedBy("this")
Remi NGUYEN VAN7b84fb32019-01-19 21:13:24 +09001102 private ApfProgramEvent.Builder mLastInstallEvent;
Paul Jensen578a76e2016-01-14 14:54:39 -05001103
Paul Jensendfd5a942016-03-17 13:22:29 -04001104 // For debugging only. The last program installed.
1105 @GuardedBy("this")
Lorenzo Colitti39c0d422016-03-23 00:23:29 +09001106 private byte[] mLastInstalledProgram;
Lorenzo Colitti5ff640d2016-03-03 17:53:46 +09001107
Bernie Innocenti3cc40ea2018-04-24 01:25:42 +09001108 /**
1109 * For debugging only. Contains the latest APF buffer snapshot captured from the firmware.
1110 *
1111 * A typical size for this buffer is 4KB. It is present only if the WiFi HAL supports
1112 * IWifiStaIface#readApfPacketFilterData(), and the APF interpreter advertised support for
1113 * the opcodes to access the data buffer (LDDW and STDW).
1114 */
1115 @GuardedBy("this") @Nullable
1116 private byte[] mDataSnapshot;
1117
Hugo Benichi22d9b2d2017-02-22 13:02:27 +09001118 // How many times the program was updated since we started.
Lorenzo Colitti059e2bb2016-04-08 20:51:39 +09001119 @GuardedBy("this")
Hugo Benichi22d9b2d2017-02-22 13:02:27 +09001120 private int mNumProgramUpdates = 0;
1121 // How many times the program was updated since we started for allowing multicast traffic.
1122 @GuardedBy("this")
1123 private int mNumProgramUpdatesAllowingMulticast = 0;
Lorenzo Colitti059e2bb2016-04-08 20:51:39 +09001124
Paul Jensendfd5a942016-03-17 13:22:29 -04001125 /**
Paul Jensena8458c02016-03-25 11:25:57 -04001126 * Generate filter code to process ARP packets. Execution of this code ends in either the
1127 * DROP_LABEL or PASS_LABEL and does not fall off the end.
1128 * Preconditions:
1129 * - Packet being filtered is ARP
1130 */
1131 @GuardedBy("this")
1132 private void generateArpFilterLocked(ApfGenerator gen) throws IllegalInstructionException {
1133 // Here's a basic summary of what the ARP filter program does:
1134 //
Hugo Benichi38db9762016-07-12 15:08:50 +09001135 // if not ARP IPv4
1136 // pass
1137 // if not ARP IPv4 reply or request
1138 // pass
Aaron Huang04ed6a32018-11-15 20:30:46 +08001139 // if ARP reply source ip is 0.0.0.0
1140 // drop
Hugo Benichi38db9762016-07-12 15:08:50 +09001141 // if unicast ARP reply
1142 // pass
1143 // if interface has no IPv4 address
1144 // if target ip is 0.0.0.0
1145 // drop
1146 // else
1147 // if target ip is not the interface ip
1148 // drop
Paul Jensena8458c02016-03-25 11:25:57 -04001149 // pass
1150
Hugo Benichi38db9762016-07-12 15:08:50 +09001151 final String checkTargetIPv4 = "checkTargetIPv4";
1152
1153 // Pass if not ARP IPv4.
1154 gen.addLoadImmediate(Register.R0, ARP_HEADER_OFFSET);
Aaron Huang04ed6a32018-11-15 20:30:46 +08001155 maybeSetupCounter(gen, Counter.PASSED_ARP_NON_IPV4);
Bernie Innocenti3cc40ea2018-04-24 01:25:42 +09001156 gen.addJumpIfBytesNotEqual(Register.R0, ARP_IPV4_HEADER, mCountAndPassLabel);
Hugo Benichi38db9762016-07-12 15:08:50 +09001157
1158 // Pass if unknown ARP opcode.
1159 gen.addLoad16(Register.R0, ARP_OPCODE_OFFSET);
1160 gen.addJumpIfR0Equals(ARP_OPCODE_REQUEST, checkTargetIPv4); // Skip to unicast check
Aaron Huang04ed6a32018-11-15 20:30:46 +08001161 maybeSetupCounter(gen, Counter.PASSED_ARP_UNKNOWN);
Bernie Innocenti3cc40ea2018-04-24 01:25:42 +09001162 gen.addJumpIfR0NotEquals(ARP_OPCODE_REPLY, mCountAndPassLabel);
Hugo Benichi38db9762016-07-12 15:08:50 +09001163
Aaron Huang04ed6a32018-11-15 20:30:46 +08001164 // Drop if ARP reply source IP is 0.0.0.0
1165 gen.addLoad32(Register.R0, ARP_SOURCE_IP_ADDRESS_OFFSET);
1166 maybeSetupCounter(gen, Counter.DROPPED_ARP_REPLY_SPA_NO_HOST);
1167 gen.addJumpIfR0Equals(IPV4_ANY_HOST_ADDRESS, mCountAndDropLabel);
1168
Hugo Benichi38db9762016-07-12 15:08:50 +09001169 // Pass if unicast reply.
1170 gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET);
Aaron Huang04ed6a32018-11-15 20:30:46 +08001171 maybeSetupCounter(gen, Counter.PASSED_ARP_UNICAST_REPLY);
Bernie Innocenti3cc40ea2018-04-24 01:25:42 +09001172 gen.addJumpIfBytesNotEqual(Register.R0, ETH_BROADCAST_MAC_ADDRESS, mCountAndPassLabel);
Hugo Benichi38db9762016-07-12 15:08:50 +09001173
1174 // Either a unicast request, a unicast reply, or a broadcast reply.
1175 gen.defineLabel(checkTargetIPv4);
1176 if (mIPv4Address == null) {
1177 // When there is no IPv4 address, drop GARP replies (b/29404209).
1178 gen.addLoad32(Register.R0, ARP_TARGET_IP_ADDRESS_OFFSET);
Aaron Huang04ed6a32018-11-15 20:30:46 +08001179 maybeSetupCounter(gen, Counter.DROPPED_GARP_REPLY);
Bernie Innocenti3cc40ea2018-04-24 01:25:42 +09001180 gen.addJumpIfR0Equals(IPV4_ANY_HOST_ADDRESS, mCountAndDropLabel);
Hugo Benichi38db9762016-07-12 15:08:50 +09001181 } else {
1182 // When there is an IPv4 address, drop unicast/broadcast requests
1183 // and broadcast replies with a different target IPv4 address.
Paul Jensendd7bee82016-05-06 10:27:56 -04001184 gen.addLoadImmediate(Register.R0, ARP_TARGET_IP_ADDRESS_OFFSET);
Aaron Huang04ed6a32018-11-15 20:30:46 +08001185 maybeSetupCounter(gen, Counter.DROPPED_ARP_OTHER_HOST);
Bernie Innocenti3cc40ea2018-04-24 01:25:42 +09001186 gen.addJumpIfBytesNotEqual(Register.R0, mIPv4Address, mCountAndDropLabel);
Paul Jensendd7bee82016-05-06 10:27:56 -04001187 }
Paul Jensena8458c02016-03-25 11:25:57 -04001188
Aaron Huang04ed6a32018-11-15 20:30:46 +08001189 maybeSetupCounter(gen, Counter.PASSED_ARP);
Bernie Innocenti3cc40ea2018-04-24 01:25:42 +09001190 gen.addJump(mCountAndPassLabel);
Paul Jensena8458c02016-03-25 11:25:57 -04001191 }
1192
1193 /**
Paul Jensendfd5a942016-03-17 13:22:29 -04001194 * Generate filter code to process IPv4 packets. Execution of this code ends in either the
1195 * DROP_LABEL or PASS_LABEL and does not fall off the end.
1196 * Preconditions:
1197 * - Packet being filtered is IPv4
Paul Jensendfd5a942016-03-17 13:22:29 -04001198 */
1199 @GuardedBy("this")
1200 private void generateIPv4FilterLocked(ApfGenerator gen) throws IllegalInstructionException {
1201 // Here's a basic summary of what the IPv4 filter program does:
1202 //
Paul Jensenf8a01e82016-05-26 09:16:11 -04001203 // if filtering multicast (i.e. multicast lock not held):
Hugo Benichi0dc1d312016-09-02 12:40:31 +09001204 // if it's DHCP destined to our MAC:
Paul Jensenf8a01e82016-05-26 09:16:11 -04001205 // pass
Hugo Benichi0dc1d312016-09-02 12:40:31 +09001206 // if it's L2 broadcast:
1207 // drop
1208 // if it's IPv4 multicast:
1209 // drop
1210 // if it's IPv4 broadcast:
Paul Jensenf8a01e82016-05-26 09:16:11 -04001211 // drop
Aaron Huanga63c40e2019-01-15 16:53:51 +08001212 // if keepalive ack
1213 // drop
Paul Jensendfd5a942016-03-17 13:22:29 -04001214 // pass
1215
1216 if (mMulticastFilter) {
Hugo Benichi0dc1d312016-09-02 12:40:31 +09001217 final String skipDhcpv4Filter = "skip_dhcp_v4_filter";
1218
1219 // Pass DHCP addressed to us.
1220 // Check it's UDP.
1221 gen.addLoad8(Register.R0, IPV4_PROTOCOL_OFFSET);
1222 gen.addJumpIfR0NotEquals(IPPROTO_UDP, skipDhcpv4Filter);
1223 // Check it's not a fragment. This matches the BPF filter installed by the DHCP client.
1224 gen.addLoad16(Register.R0, IPV4_FRAGMENT_OFFSET_OFFSET);
1225 gen.addJumpIfR0AnyBitsSet(IPV4_FRAGMENT_OFFSET_MASK, skipDhcpv4Filter);
1226 // Check it's addressed to DHCP client port.
1227 gen.addLoadFromMemory(Register.R1, gen.IPV4_HEADER_SIZE_MEMORY_SLOT);
1228 gen.addLoad16Indexed(Register.R0, UDP_DESTINATION_PORT_OFFSET);
1229 gen.addJumpIfR0NotEquals(DHCP_CLIENT_PORT, skipDhcpv4Filter);
1230 // Check it's DHCP to our MAC address.
1231 gen.addLoadImmediate(Register.R0, DHCP_CLIENT_MAC_OFFSET);
1232 // NOTE: Relies on R1 containing IPv4 header offset.
1233 gen.addAddR1();
1234 gen.addJumpIfBytesNotEqual(Register.R0, mHardwareAddress, skipDhcpv4Filter);
Aaron Huang04ed6a32018-11-15 20:30:46 +08001235 maybeSetupCounter(gen, Counter.PASSED_DHCP);
Bernie Innocenti3cc40ea2018-04-24 01:25:42 +09001236 gen.addJump(mCountAndPassLabel);
Hugo Benichi0dc1d312016-09-02 12:40:31 +09001237
1238 // Drop all multicasts/broadcasts.
1239 gen.defineLabel(skipDhcpv4Filter);
1240
1241 // If IPv4 destination address is in multicast range, drop.
Paul Jensendfd5a942016-03-17 13:22:29 -04001242 gen.addLoad8(Register.R0, IPV4_DEST_ADDR_OFFSET);
1243 gen.addAnd(0xf0);
Aaron Huang04ed6a32018-11-15 20:30:46 +08001244 maybeSetupCounter(gen, Counter.DROPPED_IPV4_MULTICAST);
Bernie Innocenti3cc40ea2018-04-24 01:25:42 +09001245 gen.addJumpIfR0Equals(0xe0, mCountAndDropLabel);
Paul Jensendfd5a942016-03-17 13:22:29 -04001246
Hugo Benichi0dc1d312016-09-02 12:40:31 +09001247 // If IPv4 broadcast packet, drop regardless of L2 (b/30231088).
Aaron Huang04ed6a32018-11-15 20:30:46 +08001248 maybeSetupCounter(gen, Counter.DROPPED_IPV4_BROADCAST_ADDR);
Hugo Benichi0dc1d312016-09-02 12:40:31 +09001249 gen.addLoad32(Register.R0, IPV4_DEST_ADDR_OFFSET);
Bernie Innocenti3cc40ea2018-04-24 01:25:42 +09001250 gen.addJumpIfR0Equals(IPV4_BROADCAST_ADDRESS, mCountAndDropLabel);
Hugo Benichi7d21eae2016-09-02 14:00:29 +09001251 if (mIPv4Address != null && mIPv4PrefixLength < 31) {
Aaron Huang04ed6a32018-11-15 20:30:46 +08001252 maybeSetupCounter(gen, Counter.DROPPED_IPV4_BROADCAST_NET);
Hugo Benichi7d21eae2016-09-02 14:00:29 +09001253 int broadcastAddr = ipv4BroadcastAddress(mIPv4Address, mIPv4PrefixLength);
Bernie Innocenti3cc40ea2018-04-24 01:25:42 +09001254 gen.addJumpIfR0Equals(broadcastAddr, mCountAndDropLabel);
Hugo Benichi7d21eae2016-09-02 14:00:29 +09001255 }
Hugo Benichi0dc1d312016-09-02 12:40:31 +09001256
Aaron Huang56f9e412019-05-13 05:13:09 -07001257 // If any TCP keepalive filter matches, drop
Aaron Huang75a60432019-02-20 17:14:02 +08001258 generateV4KeepaliveFilters(gen);
Aaron Huanga63c40e2019-01-15 16:53:51 +08001259
Aaron Huang56f9e412019-05-13 05:13:09 -07001260 // If any NAT-T keepalive filter matches, drop
1261 generateV4NattKeepaliveFilters(gen);
1262
Aaron Huang75a60432019-02-20 17:14:02 +08001263 // Otherwise, this is an IPv4 unicast, pass
Hugo Benichi0dc1d312016-09-02 12:40:31 +09001264 // If L2 broadcast packet, drop.
Bernie Innocenti3cc40ea2018-04-24 01:25:42 +09001265 // TODO: can we invert this condition to fall through to the common pass case below?
Aaron Huang04ed6a32018-11-15 20:30:46 +08001266 maybeSetupCounter(gen, Counter.PASSED_IPV4_UNICAST);
Paul Jensenf8a01e82016-05-26 09:16:11 -04001267 gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET);
Bernie Innocenti3cc40ea2018-04-24 01:25:42 +09001268 gen.addJumpIfBytesNotEqual(Register.R0, ETH_BROADCAST_MAC_ADDRESS, mCountAndPassLabel);
Aaron Huang04ed6a32018-11-15 20:30:46 +08001269 maybeSetupCounter(gen, Counter.DROPPED_IPV4_L2_BROADCAST);
Bernie Innocenti3cc40ea2018-04-24 01:25:42 +09001270 gen.addJump(mCountAndDropLabel);
Aaron Huanga63c40e2019-01-15 16:53:51 +08001271 } else {
Aaron Huang75a60432019-02-20 17:14:02 +08001272 generateV4KeepaliveFilters(gen);
Aaron Huang4a40e912019-05-15 00:17:35 -07001273 generateV4NattKeepaliveFilters(gen);
Paul Jensenf8a01e82016-05-26 09:16:11 -04001274 }
Paul Jensendfd5a942016-03-17 13:22:29 -04001275
1276 // Otherwise, pass
Aaron Huang04ed6a32018-11-15 20:30:46 +08001277 maybeSetupCounter(gen, Counter.PASSED_IPV4);
Bernie Innocenti3cc40ea2018-04-24 01:25:42 +09001278 gen.addJump(mCountAndPassLabel);
Paul Jensendfd5a942016-03-17 13:22:29 -04001279 }
1280
Aaron Huang4a40e912019-05-15 00:17:35 -07001281 private void generateKeepaliveFilters(ApfGenerator gen, Class<?> filterType, int proto,
1282 int offset, String label) throws IllegalInstructionException {
1283 final boolean haveKeepaliveResponses = NetworkStackUtils.any(mKeepalivePackets,
Aaron Huang56f9e412019-05-13 05:13:09 -07001284 ack -> filterType.isInstance(ack));
Aaron Huang75a60432019-02-20 17:14:02 +08001285
Aaron Huang56f9e412019-05-13 05:13:09 -07001286 // If no keepalive packets of this type
Aaron Huang4a40e912019-05-15 00:17:35 -07001287 if (!haveKeepaliveResponses) return;
Aaron Huang75a60432019-02-20 17:14:02 +08001288
Aaron Huang56f9e412019-05-13 05:13:09 -07001289 // If not the right proto, skip keepalive filters
1290 gen.addLoad8(Register.R0, offset);
1291 gen.addJumpIfR0NotEquals(proto, label);
Aaron Huang75a60432019-02-20 17:14:02 +08001292
Aaron Huang4a40e912019-05-15 00:17:35 -07001293 // Drop Keepalive responses
Aaron Huang56f9e412019-05-13 05:13:09 -07001294 for (int i = 0; i < mKeepalivePackets.size(); ++i) {
Aaron Huang4a40e912019-05-15 00:17:35 -07001295 final KeepalivePacket response = mKeepalivePackets.valueAt(i);
1296 if (filterType.isInstance(response)) response.generateFilterLocked(gen);
Aaron Huanga63c40e2019-01-15 16:53:51 +08001297 }
Aaron Huang75a60432019-02-20 17:14:02 +08001298
Aaron Huang56f9e412019-05-13 05:13:09 -07001299 gen.defineLabel(label);
1300 }
1301
1302 private void generateV4KeepaliveFilters(ApfGenerator gen) throws IllegalInstructionException {
Aaron Huang4a40e912019-05-15 00:17:35 -07001303 generateKeepaliveFilters(gen, TcpKeepaliveAckV4.class, IPPROTO_TCP, IPV4_PROTOCOL_OFFSET,
Aaron Huang56f9e412019-05-13 05:13:09 -07001304 "skip_v4_keepalive_filter");
1305 }
1306
1307 private void generateV4NattKeepaliveFilters(ApfGenerator gen)
1308 throws IllegalInstructionException {
Aaron Huang4a40e912019-05-15 00:17:35 -07001309 generateKeepaliveFilters(gen, NattKeepaliveResponse.class,
1310 IPPROTO_UDP, IPV4_PROTOCOL_OFFSET, "skip_v4_nattkeepalive_filter");
Aaron Huanga63c40e2019-01-15 16:53:51 +08001311 }
Paul Jensendfd5a942016-03-17 13:22:29 -04001312
1313 /**
1314 * Generate filter code to process IPv6 packets. Execution of this code ends in either the
1315 * DROP_LABEL or PASS_LABEL, or falls off the end for ICMPv6 packets.
1316 * Preconditions:
1317 * - Packet being filtered is IPv6
Paul Jensendfd5a942016-03-17 13:22:29 -04001318 */
1319 @GuardedBy("this")
1320 private void generateIPv6FilterLocked(ApfGenerator gen) throws IllegalInstructionException {
1321 // Here's a basic summary of what the IPv6 filter program does:
1322 //
Bernie Innocenti5be71dc2018-03-28 20:11:49 +09001323 // if we're dropping multicast
1324 // if it's not IPCMv6 or it's ICMPv6 but we're in doze mode:
1325 // if it's multicast:
1326 // drop
1327 // pass
Hugo Benichi02428982016-12-03 02:41:05 +09001328 // if it's ICMPv6 RS to any:
1329 // drop
Paul Jensendfd5a942016-03-17 13:22:29 -04001330 // if it's ICMPv6 NA to ff02::1:
1331 // drop
Aaron Huanga63c40e2019-01-15 16:53:51 +08001332 // if keepalive ack
1333 // drop
Paul Jensendfd5a942016-03-17 13:22:29 -04001334
Paul Jensendfd5a942016-03-17 13:22:29 -04001335 gen.addLoad8(Register.R0, IPV6_NEXT_HEADER_OFFSET);
Lorenzo Colitti11e13e22016-05-20 00:04:43 +09001336
1337 // Drop multicast if the multicast filter is enabled.
1338 if (mMulticastFilter) {
Bernie Innocenti5be71dc2018-03-28 20:11:49 +09001339 final String skipIPv6MulticastFilterLabel = "skipIPv6MulticastFilter";
1340 final String dropAllIPv6MulticastsLabel = "dropAllIPv6Multicast";
Lorenzo Colitti11e13e22016-05-20 00:04:43 +09001341
Bernie Innocenti5be71dc2018-03-28 20:11:49 +09001342 // While in doze mode, drop ICMPv6 multicast pings, let the others pass.
1343 // While awake, let all ICMPv6 multicasts through.
1344 if (mInDozeMode) {
1345 // Not ICMPv6? -> Proceed to multicast filtering
1346 gen.addJumpIfR0NotEquals(IPPROTO_ICMPV6, dropAllIPv6MulticastsLabel);
1347
1348 // ICMPv6 but not ECHO? -> Skip the multicast filter.
1349 // (ICMPv6 ECHO requests will go through the multicast filter below).
1350 gen.addLoad8(Register.R0, ICMP6_TYPE_OFFSET);
1351 gen.addJumpIfR0NotEquals(ICMPV6_ECHO_REQUEST_TYPE, skipIPv6MulticastFilterLabel);
1352 } else {
1353 gen.addJumpIfR0Equals(IPPROTO_ICMPV6, skipIPv6MulticastFilterLabel);
1354 }
1355
1356 // Drop all other packets sent to ff00::/8 (multicast prefix).
1357 gen.defineLabel(dropAllIPv6MulticastsLabel);
Aaron Huang04ed6a32018-11-15 20:30:46 +08001358 maybeSetupCounter(gen, Counter.DROPPED_IPV6_NON_ICMP_MULTICAST);
Lorenzo Colitti11e13e22016-05-20 00:04:43 +09001359 gen.addLoad8(Register.R0, IPV6_DEST_ADDR_OFFSET);
Bernie Innocenti3cc40ea2018-04-24 01:25:42 +09001360 gen.addJumpIfR0Equals(0xff, mCountAndDropLabel);
Aaron Huang75a60432019-02-20 17:14:02 +08001361 // If any keepalive filter matches, drop
1362 generateV6KeepaliveFilters(gen);
Bernie Innocenti5be71dc2018-03-28 20:11:49 +09001363 // Not multicast. Pass.
Aaron Huang04ed6a32018-11-15 20:30:46 +08001364 maybeSetupCounter(gen, Counter.PASSED_IPV6_UNICAST_NON_ICMP);
Bernie Innocenti3cc40ea2018-04-24 01:25:42 +09001365 gen.addJump(mCountAndPassLabel);
Bernie Innocenti5be71dc2018-03-28 20:11:49 +09001366 gen.defineLabel(skipIPv6MulticastFilterLabel);
Lorenzo Colitti11e13e22016-05-20 00:04:43 +09001367 } else {
Aaron Huang75a60432019-02-20 17:14:02 +08001368 generateV6KeepaliveFilters(gen);
Lorenzo Colitti11e13e22016-05-20 00:04:43 +09001369 // If not ICMPv6, pass.
Aaron Huang04ed6a32018-11-15 20:30:46 +08001370 maybeSetupCounter(gen, Counter.PASSED_IPV6_NON_ICMP);
Bernie Innocenti3cc40ea2018-04-24 01:25:42 +09001371 gen.addJumpIfR0NotEquals(IPPROTO_ICMPV6, mCountAndPassLabel);
Lorenzo Colitti11e13e22016-05-20 00:04:43 +09001372 }
1373
Bernie Innocenti5be71dc2018-03-28 20:11:49 +09001374 // If we got this far, the packet is ICMPv6. Drop some specific types.
1375
Paul Jensendfd5a942016-03-17 13:22:29 -04001376 // Add unsolicited multicast neighbor announcements filter
1377 String skipUnsolicitedMulticastNALabel = "skipUnsolicitedMulticastNA";
Paul Jensendfd5a942016-03-17 13:22:29 -04001378 gen.addLoad8(Register.R0, ICMP6_TYPE_OFFSET);
Hugo Benichi02428982016-12-03 02:41:05 +09001379 // Drop all router solicitations (b/32833400)
Aaron Huang04ed6a32018-11-15 20:30:46 +08001380 maybeSetupCounter(gen, Counter.DROPPED_IPV6_ROUTER_SOLICITATION);
Bernie Innocenti3cc40ea2018-04-24 01:25:42 +09001381 gen.addJumpIfR0Equals(ICMPV6_ROUTER_SOLICITATION, mCountAndDropLabel);
Hugo Benichi02428982016-12-03 02:41:05 +09001382 // If not neighbor announcements, skip filter.
Bernie Innocenti5be71dc2018-03-28 20:11:49 +09001383 gen.addJumpIfR0NotEquals(ICMPV6_NEIGHBOR_ADVERTISEMENT, skipUnsolicitedMulticastNALabel);
Hugo Benichi02428982016-12-03 02:41:05 +09001384 // If to ff02::1, drop.
Paul Jensendfd5a942016-03-17 13:22:29 -04001385 // TODO: Drop only if they don't contain the address of on-link neighbours.
1386 gen.addLoadImmediate(Register.R0, IPV6_DEST_ADDR_OFFSET);
1387 gen.addJumpIfBytesNotEqual(Register.R0, IPV6_ALL_NODES_ADDRESS,
1388 skipUnsolicitedMulticastNALabel);
Aaron Huang04ed6a32018-11-15 20:30:46 +08001389 maybeSetupCounter(gen, Counter.DROPPED_IPV6_MULTICAST_NA);
Bernie Innocenti3cc40ea2018-04-24 01:25:42 +09001390 gen.addJump(mCountAndDropLabel);
Paul Jensendfd5a942016-03-17 13:22:29 -04001391 gen.defineLabel(skipUnsolicitedMulticastNALabel);
Aaron Huang75a60432019-02-20 17:14:02 +08001392 }
1393
1394 private void generateV6KeepaliveFilters(ApfGenerator gen) throws IllegalInstructionException {
Aaron Huang4a40e912019-05-15 00:17:35 -07001395 generateKeepaliveFilters(gen, TcpKeepaliveAckV6.class, IPPROTO_TCP, IPV6_NEXT_HEADER_OFFSET,
Aaron Huang56f9e412019-05-13 05:13:09 -07001396 "skip_v6_keepalive_filter");
Paul Jensendfd5a942016-03-17 13:22:29 -04001397 }
1398
1399 /**
1400 * Begin generating an APF program to:
1401 * <ul>
Ahmed ElArabawy8537c582017-06-12 18:01:11 -07001402 * <li>Drop/Pass 802.3 frames (based on policy)
Ahmed ElArabawyfd424162017-08-02 13:31:05 -07001403 * <li>Drop packets with EtherType within the Black List
Paul Jensena8458c02016-03-25 11:25:57 -04001404 * <li>Drop ARP requests not for us, if mIPv4Address is set,
Paul Jensendfd5a942016-03-17 13:22:29 -04001405 * <li>Drop IPv4 broadcast packets, except DHCP destined to our MAC,
1406 * <li>Drop IPv4 multicast packets, if mMulticastFilter,
1407 * <li>Pass all other IPv4 packets,
Paul Jensendd7bee82016-05-06 10:27:56 -04001408 * <li>Drop all broadcast non-IP non-ARP packets.
Paul Jensendfd5a942016-03-17 13:22:29 -04001409 * <li>Pass all non-ICMPv6 IPv6 packets,
1410 * <li>Pass all non-IPv4 and non-IPv6 packets,
1411 * <li>Drop IPv6 ICMPv6 NAs to ff02::1.
Hugo Benichi02428982016-12-03 02:41:05 +09001412 * <li>Drop IPv6 ICMPv6 RSs.
Aaron Huang75a60432019-02-20 17:14:02 +08001413 * <li>Filter IPv4 packets (see generateIPv4FilterLocked())
1414 * <li>Filter IPv6 packets (see generateIPv6FilterLocked())
Paul Jensendfd5a942016-03-17 13:22:29 -04001415 * <li>Let execution continue off the end of the program for IPv6 ICMPv6 packets. This allows
1416 * insertion of RA filters here, or if there aren't any, just passes the packets.
1417 * </ul>
1418 */
1419 @GuardedBy("this")
Bernie Innocenti3cc40ea2018-04-24 01:25:42 +09001420 private ApfGenerator emitPrologueLocked() throws IllegalInstructionException {
Bernie Innocenti408dbda2018-03-22 23:07:47 +09001421 // This is guaranteed to succeed because of the check in maybeCreate.
1422 ApfGenerator gen = new ApfGenerator(mApfCapabilities.apfVersionSupported);
Paul Jensendfd5a942016-03-17 13:22:29 -04001423
Bernie Innocenti3cc40ea2018-04-24 01:25:42 +09001424 if (mApfCapabilities.hasDataAccess()) {
1425 // Increment TOTAL_PACKETS
Aaron Huang04ed6a32018-11-15 20:30:46 +08001426 maybeSetupCounter(gen, Counter.TOTAL_PACKETS);
Bernie Innocenti3cc40ea2018-04-24 01:25:42 +09001427 gen.addLoadData(Register.R0, 0); // load counter
1428 gen.addAdd(1);
1429 gen.addStoreData(Register.R0, 0); // write-back counter
1430 }
1431
Paul Jensendfd5a942016-03-17 13:22:29 -04001432 // Here's a basic summary of what the initial program does:
1433 //
Ahmed ElArabawy8537c582017-06-12 18:01:11 -07001434 // if it's a 802.3 Frame (ethtype < 0x0600):
1435 // drop or pass based on configurations
Ahmed ElArabawyfd424162017-08-02 13:31:05 -07001436 // if it has a ether-type that belongs to the black list
1437 // drop
Paul Jensena8458c02016-03-25 11:25:57 -04001438 // if it's ARP:
Paul Jensendd7bee82016-05-06 10:27:56 -04001439 // insert ARP filter to drop or pass these appropriately
Paul Jensendfd5a942016-03-17 13:22:29 -04001440 // if it's IPv4:
1441 // insert IPv4 filter to drop or pass these appropriately
1442 // if it's not IPv6:
Paul Jensendd7bee82016-05-06 10:27:56 -04001443 // if it's broadcast:
1444 // drop
Paul Jensendfd5a942016-03-17 13:22:29 -04001445 // pass
1446 // insert IPv6 filter to drop, pass, or fall off the end for ICMPv6 packets
1447
Ahmed ElArabawy8537c582017-06-12 18:01:11 -07001448 gen.addLoad16(Register.R0, ETH_ETHERTYPE_OFFSET);
1449
1450 if (mDrop802_3Frames) {
1451 // drop 802.3 frames (ethtype < 0x0600)
Aaron Huang04ed6a32018-11-15 20:30:46 +08001452 maybeSetupCounter(gen, Counter.DROPPED_802_3_FRAME);
Bernie Innocenti3cc40ea2018-04-24 01:25:42 +09001453 gen.addJumpIfR0LessThan(ETH_TYPE_MIN, mCountAndDropLabel);
Ahmed ElArabawy8537c582017-06-12 18:01:11 -07001454 }
1455
Ahmed ElArabawyfd424162017-08-02 13:31:05 -07001456 // Handle ether-type black list
Aaron Huang04ed6a32018-11-15 20:30:46 +08001457 maybeSetupCounter(gen, Counter.DROPPED_ETHERTYPE_BLACKLISTED);
Ahmed ElArabawyfd424162017-08-02 13:31:05 -07001458 for (int p : mEthTypeBlackList) {
Bernie Innocenti3cc40ea2018-04-24 01:25:42 +09001459 gen.addJumpIfR0Equals(p, mCountAndDropLabel);
Ahmed ElArabawyfd424162017-08-02 13:31:05 -07001460 }
1461
Paul Jensendd7bee82016-05-06 10:27:56 -04001462 // Add ARP filters:
1463 String skipArpFiltersLabel = "skipArpFilters";
Paul Jensendd7bee82016-05-06 10:27:56 -04001464 gen.addJumpIfR0NotEquals(ETH_P_ARP, skipArpFiltersLabel);
1465 generateArpFilterLocked(gen);
1466 gen.defineLabel(skipArpFiltersLabel);
Paul Jensena8458c02016-03-25 11:25:57 -04001467
Paul Jensendfd5a942016-03-17 13:22:29 -04001468 // Add IPv4 filters:
1469 String skipIPv4FiltersLabel = "skipIPv4Filters";
Paul Jensena8458c02016-03-25 11:25:57 -04001470 // NOTE: Relies on R0 containing ethertype. This is safe because if we got here, we did not
1471 // execute the ARP filter, since that filter does not fall through, but either drops or
1472 // passes.
Paul Jensendfd5a942016-03-17 13:22:29 -04001473 gen.addJumpIfR0NotEquals(ETH_P_IP, skipIPv4FiltersLabel);
Paul Jensendfd5a942016-03-17 13:22:29 -04001474 generateIPv4FilterLocked(gen);
1475 gen.defineLabel(skipIPv4FiltersLabel);
1476
Paul Jensendd7bee82016-05-06 10:27:56 -04001477 // Check for IPv6:
Paul Jensendfd5a942016-03-17 13:22:29 -04001478 // NOTE: Relies on R0 containing ethertype. This is safe because if we got here, we did not
Paul Jensena8458c02016-03-25 11:25:57 -04001479 // execute the ARP or IPv4 filters, since those filters do not fall through, but either
1480 // drop or pass.
Paul Jensendd7bee82016-05-06 10:27:56 -04001481 String ipv6FilterLabel = "IPv6Filters";
1482 gen.addJumpIfR0Equals(ETH_P_IPV6, ipv6FilterLabel);
1483
1484 // Drop non-IP non-ARP broadcasts, pass the rest
1485 gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET);
Aaron Huang04ed6a32018-11-15 20:30:46 +08001486 maybeSetupCounter(gen, Counter.PASSED_NON_IP_UNICAST);
Bernie Innocenti3cc40ea2018-04-24 01:25:42 +09001487 gen.addJumpIfBytesNotEqual(Register.R0, ETH_BROADCAST_MAC_ADDRESS, mCountAndPassLabel);
Aaron Huang04ed6a32018-11-15 20:30:46 +08001488 maybeSetupCounter(gen, Counter.DROPPED_ETH_BROADCAST);
Bernie Innocenti3cc40ea2018-04-24 01:25:42 +09001489 gen.addJump(mCountAndDropLabel);
Paul Jensendd7bee82016-05-06 10:27:56 -04001490
1491 // Add IPv6 filters:
1492 gen.defineLabel(ipv6FilterLabel);
Paul Jensendfd5a942016-03-17 13:22:29 -04001493 generateIPv6FilterLocked(gen);
1494 return gen;
1495 }
1496
Hugo Benichi4fc3ee52016-06-02 11:20:27 +09001497 /**
Bernie Innocenti3cc40ea2018-04-24 01:25:42 +09001498 * Append packet counting epilogue to the APF program.
1499 *
1500 * Currently, the epilogue consists of two trampolines which count passed and dropped packets
1501 * before jumping to the actual PASS and DROP labels.
1502 */
1503 @GuardedBy("this")
1504 private void emitEpilogue(ApfGenerator gen) throws IllegalInstructionException {
1505 // If APFv4 is unsupported, no epilogue is necessary: if execution reached this far, it
1506 // will just fall-through to the PASS label.
1507 if (!mApfCapabilities.hasDataAccess()) return;
1508
1509 // Execution will reach the bottom of the program if none of the filters match,
1510 // which will pass the packet to the application processor.
Aaron Huang04ed6a32018-11-15 20:30:46 +08001511 maybeSetupCounter(gen, Counter.PASSED_IPV6_ICMP);
Bernie Innocenti3cc40ea2018-04-24 01:25:42 +09001512
1513 // Append the count & pass trampoline, which increments the counter at the data address
1514 // pointed to by R1, then jumps to the pass label. This saves a few bytes over inserting
1515 // the entire sequence inline for every counter.
1516 gen.defineLabel(mCountAndPassLabel);
1517 gen.addLoadData(Register.R0, 0); // R0 = *(R1 + 0)
1518 gen.addAdd(1); // R0++
1519 gen.addStoreData(Register.R0, 0); // *(R1 + 0) = R0
1520 gen.addJump(gen.PASS_LABEL);
1521
1522 // Same as above for the count & drop trampoline.
1523 gen.defineLabel(mCountAndDropLabel);
1524 gen.addLoadData(Register.R0, 0); // R0 = *(R1 + 0)
1525 gen.addAdd(1); // R0++
1526 gen.addStoreData(Register.R0, 0); // *(R1 + 0) = R0
1527 gen.addJump(gen.DROP_LABEL);
1528 }
1529
1530 /**
Hugo Benichi4fc3ee52016-06-02 11:20:27 +09001531 * Generate and install a new filter program.
1532 */
Paul Jensendfd5a942016-03-17 13:22:29 -04001533 @GuardedBy("this")
Paul Jensen9132f342016-04-13 15:00:26 -04001534 @VisibleForTesting
1535 void installNewProgramLocked() {
Paul Jensendfd5a942016-03-17 13:22:29 -04001536 purgeExpiredRasLocked();
Hugo Benichi4fc3ee52016-06-02 11:20:27 +09001537 ArrayList<Ra> rasToFilter = new ArrayList<>();
Paul Jensen578a76e2016-01-14 14:54:39 -05001538 final byte[] program;
1539 long programMinLifetime = Long.MAX_VALUE;
Bernie Innocenti3cc40ea2018-04-24 01:25:42 +09001540 long maximumApfProgramSize = mApfCapabilities.maximumApfProgramSize;
1541 if (mApfCapabilities.hasDataAccess()) {
1542 // Reserve space for the counters.
1543 maximumApfProgramSize -= Counter.totalSize();
1544 }
1545
Paul Jensen578a76e2016-01-14 14:54:39 -05001546 try {
Paul Jensen578a76e2016-01-14 14:54:39 -05001547 // Step 1: Determine how many RA filters we can fit in the program.
Bernie Innocenti3cc40ea2018-04-24 01:25:42 +09001548 ApfGenerator gen = emitPrologueLocked();
1549
1550 // The epilogue normally goes after the RA filters, but add it early to include its
1551 // length when estimating the total.
1552 emitEpilogue(gen);
1553
1554 // Can't fit the program even without any RA filters?
1555 if (gen.programLengthOverEstimate() > maximumApfProgramSize) {
1556 Log.e(TAG, "Program exceeds maximum size " + maximumApfProgramSize);
1557 return;
1558 }
1559
Paul Jensen578a76e2016-01-14 14:54:39 -05001560 for (Ra ra : mRas) {
Paul Jensendfd5a942016-03-17 13:22:29 -04001561 ra.generateFilterLocked(gen);
1562 // Stop if we get too big.
Bernie Innocenti3cc40ea2018-04-24 01:25:42 +09001563 if (gen.programLengthOverEstimate() > maximumApfProgramSize) break;
Paul Jensendfd5a942016-03-17 13:22:29 -04001564 rasToFilter.add(ra);
Paul Jensen578a76e2016-01-14 14:54:39 -05001565 }
Bernie Innocenti3cc40ea2018-04-24 01:25:42 +09001566
Paul Jensendfd5a942016-03-17 13:22:29 -04001567 // Step 2: Actually generate the program
Bernie Innocenti3cc40ea2018-04-24 01:25:42 +09001568 gen = emitPrologueLocked();
Paul Jensendfd5a942016-03-17 13:22:29 -04001569 for (Ra ra : rasToFilter) {
1570 programMinLifetime = Math.min(programMinLifetime, ra.generateFilterLocked(gen));
Paul Jensen578a76e2016-01-14 14:54:39 -05001571 }
Bernie Innocenti3cc40ea2018-04-24 01:25:42 +09001572 emitEpilogue(gen);
Paul Jensen578a76e2016-01-14 14:54:39 -05001573 program = gen.generate();
Hugo Benichi0668a612016-10-06 15:19:36 +09001574 } catch (IllegalInstructionException|IllegalStateException e) {
1575 Log.e(TAG, "Failed to generate APF program.", e);
Paul Jensen578a76e2016-01-14 14:54:39 -05001576 return;
1577 }
Hugo Benichi22d9b2d2017-02-22 13:02:27 +09001578 final long now = currentTimeSeconds();
1579 mLastTimeInstalledProgram = now;
Paul Jensen578a76e2016-01-14 14:54:39 -05001580 mLastInstalledProgramMinLifetime = programMinLifetime;
Lorenzo Colitti39c0d422016-03-23 00:23:29 +09001581 mLastInstalledProgram = program;
Lorenzo Colitti059e2bb2016-04-08 20:51:39 +09001582 mNumProgramUpdates++;
1583
Lorenzo Colitti5ff640d2016-03-03 17:53:46 +09001584 if (VDBG) {
1585 hexDump("Installing filter: ", program, program.length);
Lorenzo Colitti5ff640d2016-03-03 17:53:46 +09001586 }
Erik Kline1b293582017-10-11 19:43:10 +09001587 mIpClientCallback.installPacketFilter(program);
Hugo Benichi22d9b2d2017-02-22 13:02:27 +09001588 logApfProgramEventLocked(now);
Remi NGUYEN VAN7b84fb32019-01-19 21:13:24 +09001589 mLastInstallEvent = new ApfProgramEvent.Builder()
1590 .setLifetime(programMinLifetime)
1591 .setFilteredRas(rasToFilter.size())
1592 .setCurrentRas(mRas.size())
1593 .setProgramLength(program.length)
1594 .setFlags(mIPv4Address != null, mMulticastFilter);
Hugo Benichi22d9b2d2017-02-22 13:02:27 +09001595 }
1596
Andreas Gampebbab23f2018-02-07 15:34:27 -08001597 @GuardedBy("this")
Hugo Benichi22d9b2d2017-02-22 13:02:27 +09001598 private void logApfProgramEventLocked(long now) {
1599 if (mLastInstallEvent == null) {
1600 return;
1601 }
Remi NGUYEN VAN7b84fb32019-01-19 21:13:24 +09001602 ApfProgramEvent.Builder ev = mLastInstallEvent;
Hugo Benichi22d9b2d2017-02-22 13:02:27 +09001603 mLastInstallEvent = null;
Remi NGUYEN VAN7b84fb32019-01-19 21:13:24 +09001604 final long actualLifetime = now - mLastTimeInstalledProgram;
1605 ev.setActualLifetime(actualLifetime);
1606 if (actualLifetime < APF_PROGRAM_EVENT_LIFETIME_THRESHOLD) {
Hugo Benichi22d9b2d2017-02-22 13:02:27 +09001607 return;
1608 }
Remi NGUYEN VAN7b84fb32019-01-19 21:13:24 +09001609 mMetricsLog.log(ev.build());
Paul Jensen578a76e2016-01-14 14:54:39 -05001610 }
1611
Hugo Benichi647c86d2016-06-07 15:35:16 +09001612 /**
1613 * Returns {@code true} if a new program should be installed because the current one dies soon.
1614 */
1615 private boolean shouldInstallnewProgram() {
Paul Jensen578a76e2016-01-14 14:54:39 -05001616 long expiry = mLastTimeInstalledProgram + mLastInstalledProgramMinLifetime;
Hugo Benichi4456f332016-12-19 14:50:52 +09001617 return expiry < currentTimeSeconds() + MAX_PROGRAM_LIFETIME_WORTH_REFRESHING;
Paul Jensen578a76e2016-01-14 14:54:39 -05001618 }
1619
1620 private void hexDump(String msg, byte[] packet, int length) {
Lorenzo Colitti39c0d422016-03-23 00:23:29 +09001621 log(msg + HexDump.toHexString(packet, 0, length, false /* lowercase */));
Paul Jensen578a76e2016-01-14 14:54:39 -05001622 }
1623
Paul Jensendfd5a942016-03-17 13:22:29 -04001624 @GuardedBy("this")
1625 private void purgeExpiredRasLocked() {
1626 for (int i = 0; i < mRas.size();) {
1627 if (mRas.get(i).isExpired()) {
1628 log("Expiring " + mRas.get(i));
1629 mRas.remove(i);
1630 } else {
1631 i++;
1632 }
1633 }
1634 }
1635
Hugo Benichi647c86d2016-06-07 15:35:16 +09001636 /**
1637 * Process an RA packet, updating the list of known RAs and installing a new APF program
1638 * if the current APF program should be updated.
1639 * @return a ProcessRaResult enum describing what action was performed.
1640 */
Hugo Benichi0668a612016-10-06 15:19:36 +09001641 @VisibleForTesting
1642 synchronized ProcessRaResult processRa(byte[] packet, int length) {
Lorenzo Colitti5ff640d2016-03-03 17:53:46 +09001643 if (VDBG) hexDump("Read packet = ", packet, length);
Paul Jensen578a76e2016-01-14 14:54:39 -05001644
1645 // Have we seen this RA before?
1646 for (int i = 0; i < mRas.size(); i++) {
1647 Ra ra = mRas.get(i);
1648 if (ra.matches(packet, length)) {
Lorenzo Colitti5ff640d2016-03-03 17:53:46 +09001649 if (VDBG) log("matched RA " + ra);
Paul Jensen578a76e2016-01-14 14:54:39 -05001650 // Update lifetimes.
Hugo Benichi4456f332016-12-19 14:50:52 +09001651 ra.mLastSeen = currentTimeSeconds();
Paul Jensen578a76e2016-01-14 14:54:39 -05001652 ra.mMinLifetime = ra.minLifetime(packet, length);
Lorenzo Colitti5ff640d2016-03-03 17:53:46 +09001653 ra.seenCount++;
Paul Jensen578a76e2016-01-14 14:54:39 -05001654
1655 // Keep mRas in LRU order so as to prioritize generating filters for recently seen
1656 // RAs. LRU prioritizes this because RA filters are generated in order from mRas
1657 // until the filter program exceeds the maximum filter program size allowed by the
1658 // chipset, so RAs appearing earlier in mRas are more likely to make it into the
1659 // filter program.
1660 // TODO: consider sorting the RAs in order of increasing expiry time as well.
1661 // Swap to front of array.
1662 mRas.add(0, mRas.remove(i));
1663
Hugo Benichi647c86d2016-06-07 15:35:16 +09001664 // If the current program doesn't expire for a while, don't update.
1665 if (shouldInstallnewProgram()) {
1666 installNewProgramLocked();
1667 return ProcessRaResult.UPDATE_EXPIRY;
1668 }
1669 return ProcessRaResult.MATCH;
Paul Jensen578a76e2016-01-14 14:54:39 -05001670 }
1671 }
Paul Jensendfd5a942016-03-17 13:22:29 -04001672 purgeExpiredRasLocked();
Paul Jensen578a76e2016-01-14 14:54:39 -05001673 // TODO: figure out how to proceed when we've received more then MAX_RAS RAs.
Hugo Benichi647c86d2016-06-07 15:35:16 +09001674 if (mRas.size() >= MAX_RAS) {
1675 return ProcessRaResult.DROPPED;
1676 }
Paul Jensendfd5a942016-03-17 13:22:29 -04001677 final Ra ra;
Paul Jensen578a76e2016-01-14 14:54:39 -05001678 try {
Paul Jensendfd5a942016-03-17 13:22:29 -04001679 ra = new Ra(packet, length);
Paul Jensen578a76e2016-01-14 14:54:39 -05001680 } catch (Exception e) {
Hugo Benichi0668a612016-10-06 15:19:36 +09001681 Log.e(TAG, "Error parsing RA", e);
Hugo Benichi647c86d2016-06-07 15:35:16 +09001682 return ProcessRaResult.PARSE_ERROR;
Paul Jensen578a76e2016-01-14 14:54:39 -05001683 }
Paul Jensendfd5a942016-03-17 13:22:29 -04001684 // Ignore 0 lifetime RAs.
Hugo Benichi647c86d2016-06-07 15:35:16 +09001685 if (ra.isExpired()) {
1686 return ProcessRaResult.ZERO_LIFETIME;
1687 }
Paul Jensendfd5a942016-03-17 13:22:29 -04001688 log("Adding " + ra);
1689 mRas.add(ra);
1690 installNewProgramLocked();
Hugo Benichi647c86d2016-06-07 15:35:16 +09001691 return ProcessRaResult.UPDATE_NEW_RA;
Paul Jensen578a76e2016-01-14 14:54:39 -05001692 }
1693
1694 /**
Paul Jensenf21b4dc2016-03-18 12:22:09 -04001695 * Create an {@link ApfFilter} if {@code apfCapabilities} indicates support for packet
Paul Jensen578a76e2016-01-14 14:54:39 -05001696 * filtering using APF programs.
1697 */
Bernie Innocenti5be71dc2018-03-28 20:11:49 +09001698 public static ApfFilter maybeCreate(Context context, ApfConfiguration config,
Remi NGUYEN VAN3c600a12019-01-10 19:12:46 +09001699 InterfaceParams ifParams, IpClientCallbacksWrapper ipClientCallback) {
Bernie Innocenti5be71dc2018-03-28 20:11:49 +09001700 if (context == null || config == null || ifParams == null) return null;
Hugo Benichi72166362017-10-13 16:32:20 +09001701 ApfCapabilities apfCapabilities = config.apfCapabilities;
Erik Kline8bd00d52017-12-08 17:47:50 +09001702 if (apfCapabilities == null) return null;
Paul Jensenf21b4dc2016-03-18 12:22:09 -04001703 if (apfCapabilities.apfVersionSupported == 0) return null;
1704 if (apfCapabilities.maximumApfProgramSize < 512) {
1705 Log.e(TAG, "Unacceptably small APF limit: " + apfCapabilities.maximumApfProgramSize);
1706 return null;
Paul Jensen578a76e2016-01-14 14:54:39 -05001707 }
1708 // For now only support generating programs for Ethernet frames. If this restriction is
1709 // lifted:
1710 // 1. the program generator will need its offsets adjusted.
1711 // 2. the packet filter attached to our packet socket will need its offset adjusted.
Paul Jensenf21b4dc2016-03-18 12:22:09 -04001712 if (apfCapabilities.apfPacketFormat != ARPHRD_ETHER) return null;
Bernie Innocenti408dbda2018-03-22 23:07:47 +09001713 if (!ApfGenerator.supportsVersion(apfCapabilities.apfVersionSupported)) {
Paul Jensenf21b4dc2016-03-18 12:22:09 -04001714 Log.e(TAG, "Unsupported APF version: " + apfCapabilities.apfVersionSupported);
1715 return null;
Paul Jensen578a76e2016-01-14 14:54:39 -05001716 }
Bernie Innocenti5be71dc2018-03-28 20:11:49 +09001717
1718 return new ApfFilter(context, config, ifParams, ipClientCallback, new IpConnectivityLog());
Paul Jensen578a76e2016-01-14 14:54:39 -05001719 }
1720
Paul Jensendfd5a942016-03-17 13:22:29 -04001721 public synchronized void shutdown() {
Paul Jensen578a76e2016-01-14 14:54:39 -05001722 if (mReceiveThread != null) {
Lorenzo Colitti5ff640d2016-03-03 17:53:46 +09001723 log("shutting down");
Paul Jensen578a76e2016-01-14 14:54:39 -05001724 mReceiveThread.halt(); // Also closes socket.
1725 mReceiveThread = null;
1726 }
Paul Jensendfd5a942016-03-17 13:22:29 -04001727 mRas.clear();
Bernie Innocenti5be71dc2018-03-28 20:11:49 +09001728 mContext.unregisterReceiver(mDeviceIdleReceiver);
Paul Jensen578a76e2016-01-14 14:54:39 -05001729 }
Lorenzo Colitti5ff640d2016-03-03 17:53:46 +09001730
Hugo Benichi22d9b2d2017-02-22 13:02:27 +09001731 public synchronized void setMulticastFilter(boolean isEnabled) {
Bernie Innocenti5be71dc2018-03-28 20:11:49 +09001732 if (mMulticastFilter == isEnabled) return;
Hugo Benichi22d9b2d2017-02-22 13:02:27 +09001733 mMulticastFilter = isEnabled;
1734 if (!isEnabled) {
1735 mNumProgramUpdatesAllowingMulticast++;
1736 }
1737 installNewProgramLocked();
Paul Jensendfd5a942016-03-17 13:22:29 -04001738 }
1739
Bernie Innocenti5be71dc2018-03-28 20:11:49 +09001740 @VisibleForTesting
1741 public synchronized void setDozeMode(boolean isEnabled) {
1742 if (mInDozeMode == isEnabled) return;
1743 mInDozeMode = isEnabled;
1744 installNewProgramLocked();
1745 }
1746
Hugo Benichi7d21eae2016-09-02 14:00:29 +09001747 /** Find the single IPv4 LinkAddress if there is one, otherwise return null. */
1748 private static LinkAddress findIPv4LinkAddress(LinkProperties lp) {
1749 LinkAddress ipv4Address = null;
1750 for (LinkAddress address : lp.getLinkAddresses()) {
1751 if (!(address.getAddress() instanceof Inet4Address)) {
1752 continue;
1753 }
1754 if (ipv4Address != null && !ipv4Address.isSameAddressAs(address)) {
1755 // More than one IPv4 address, abort.
1756 return null;
1757 }
1758 ipv4Address = address;
Paul Jensena8458c02016-03-25 11:25:57 -04001759 }
1760 return ipv4Address;
1761 }
1762
1763 public synchronized void setLinkProperties(LinkProperties lp) {
1764 // NOTE: Do not keep a copy of LinkProperties as it would further duplicate state.
Hugo Benichi7d21eae2016-09-02 14:00:29 +09001765 final LinkAddress ipv4Address = findIPv4LinkAddress(lp);
1766 final byte[] addr = (ipv4Address != null) ? ipv4Address.getAddress().getAddress() : null;
1767 final int prefix = (ipv4Address != null) ? ipv4Address.getPrefixLength() : 0;
1768 if ((prefix == mIPv4PrefixLength) && Arrays.equals(addr, mIPv4Address)) {
1769 return;
1770 }
1771 mIPv4Address = addr;
1772 mIPv4PrefixLength = prefix;
Paul Jensena8458c02016-03-25 11:25:57 -04001773 installNewProgramLocked();
1774 }
1775
junyulai352dc2f2019-01-08 20:04:33 +08001776 /**
Mark Chiend0f8ca82019-04-29 09:46:04 -07001777 * Add TCP keepalive ack packet filter.
Aaron Huanga63c40e2019-01-15 16:53:51 +08001778 * This will add a filter to drop acks to the keepalive packet passed as an argument.
junyulai352dc2f2019-01-08 20:04:33 +08001779 *
1780 * @param slot The index used to access the filter.
Aaron Huanga63c40e2019-01-15 16:53:51 +08001781 * @param sentKeepalivePacket The attributes of the sent keepalive packet.
junyulai352dc2f2019-01-08 20:04:33 +08001782 */
Mark Chiend0f8ca82019-04-29 09:46:04 -07001783 public synchronized void addTcpKeepalivePacketFilter(final int slot,
Aaron Huanga63c40e2019-01-15 16:53:51 +08001784 final TcpKeepalivePacketDataParcelable sentKeepalivePacket) {
1785 log("Adding keepalive ack(" + slot + ")");
Aaron Huang56f9e412019-05-13 05:13:09 -07001786 if (null != mKeepalivePackets.get(slot)) {
Aaron Huanga63c40e2019-01-15 16:53:51 +08001787 throw new IllegalArgumentException("Keepalive slot " + slot + " is occupied");
1788 }
1789 final int ipVersion = sentKeepalivePacket.srcAddress.length == 4 ? 4 : 6;
Aaron Huang56f9e412019-05-13 05:13:09 -07001790 mKeepalivePackets.put(slot, (ipVersion == 4)
Aaron Huanga63c40e2019-01-15 16:53:51 +08001791 ? new TcpKeepaliveAckV4(sentKeepalivePacket)
1792 : new TcpKeepaliveAckV6(sentKeepalivePacket));
1793 installNewProgramLocked();
junyulai352dc2f2019-01-08 20:04:33 +08001794 }
1795
1796 /**
Aaron Huang4a40e912019-05-15 00:17:35 -07001797 * Add NAT-T keepalive packet filter.
1798 * This will add a filter to drop NAT-T keepalive packet which is passed as an argument.
Mark Chiend0f8ca82019-04-29 09:46:04 -07001799 *
1800 * @param slot The index used to access the filter.
1801 * @param sentKeepalivePacket The attributes of the sent keepalive packet.
1802 */
1803 public synchronized void addNattKeepalivePacketFilter(final int slot,
1804 final NattKeepalivePacketDataParcelable sentKeepalivePacket) {
Aaron Huang56f9e412019-05-13 05:13:09 -07001805 log("Adding NAT-T keepalive packet(" + slot + ")");
1806 if (null != mKeepalivePackets.get(slot)) {
Aaron Huang4a40e912019-05-15 00:17:35 -07001807 throw new IllegalArgumentException("NAT-T Keepalive slot " + slot + " is occupied");
Aaron Huang56f9e412019-05-13 05:13:09 -07001808 }
Aaron Huang4a40e912019-05-15 00:17:35 -07001809 if (sentKeepalivePacket.srcAddress.length != 4) {
1810 throw new IllegalArgumentException("NAT-T keepalive is only supported on IPv4");
1811 }
1812 mKeepalivePackets.put(slot, new NattKeepaliveResponse(sentKeepalivePacket));
Aaron Huang56f9e412019-05-13 05:13:09 -07001813 installNewProgramLocked();
Mark Chiend0f8ca82019-04-29 09:46:04 -07001814 }
1815
1816 /**
junyulai352dc2f2019-01-08 20:04:33 +08001817 * Remove keepalive packet filter.
1818 *
1819 * @param slot The index used to access the filter.
1820 */
1821 public synchronized void removeKeepalivePacketFilter(int slot) {
Aaron Huang56f9e412019-05-13 05:13:09 -07001822 log("Removing keepalive packet(" + slot + ")");
1823 mKeepalivePackets.remove(slot);
Aaron Huanga63c40e2019-01-15 16:53:51 +08001824 installNewProgramLocked();
junyulai352dc2f2019-01-08 20:04:33 +08001825 }
1826
Bernie Innocenti3cc40ea2018-04-24 01:25:42 +09001827 static public long counterValue(byte[] data, Counter counter)
1828 throws ArrayIndexOutOfBoundsException {
1829 // Follow the same wrap-around addressing scheme of the interpreter.
1830 int offset = counter.offset();
1831 if (offset < 0) {
1832 offset = data.length + offset;
1833 }
1834
1835 // Decode 32bit big-endian integer into a long so we can count up beyond 2^31.
1836 long value = 0;
1837 for (int i = 0; i < 4; i++) {
1838 value = value << 8 | (data[offset] & 0xFF);
1839 offset++;
1840 }
1841 return value;
1842 }
1843
Paul Jensendfd5a942016-03-17 13:22:29 -04001844 public synchronized void dump(IndentingPrintWriter pw) {
Lorenzo Colitti059e2bb2016-04-08 20:51:39 +09001845 pw.println("Capabilities: " + mApfCapabilities);
Lorenzo Colitti5ff640d2016-03-03 17:53:46 +09001846 pw.println("Receive thread: " + (mReceiveThread != null ? "RUNNING" : "STOPPED"));
Lorenzo Colitti059e2bb2016-04-08 20:51:39 +09001847 pw.println("Multicast: " + (mMulticastFilter ? "DROP" : "ALLOW"));
Paul Jensena8458c02016-03-25 11:25:57 -04001848 try {
Lorenzo Colitti059e2bb2016-04-08 20:51:39 +09001849 pw.println("IPv4 address: " + InetAddress.getByAddress(mIPv4Address).getHostAddress());
Paul Jensena8458c02016-03-25 11:25:57 -04001850 } catch (UnknownHostException|NullPointerException e) {}
Lorenzo Colitti059e2bb2016-04-08 20:51:39 +09001851
Lorenzo Colitti5ff640d2016-03-03 17:53:46 +09001852 if (mLastTimeInstalledProgram == 0) {
1853 pw.println("No program installed.");
1854 return;
1855 }
Lorenzo Colitti059e2bb2016-04-08 20:51:39 +09001856 pw.println("Program updates: " + mNumProgramUpdates);
Lorenzo Colitti5ff640d2016-03-03 17:53:46 +09001857 pw.println(String.format(
Lorenzo Colitti059e2bb2016-04-08 20:51:39 +09001858 "Last program length %d, installed %ds ago, lifetime %ds",
Hugo Benichi4456f332016-12-19 14:50:52 +09001859 mLastInstalledProgram.length, currentTimeSeconds() - mLastTimeInstalledProgram,
Lorenzo Colitti5ff640d2016-03-03 17:53:46 +09001860 mLastInstalledProgramMinLifetime));
1861
1862 pw.println("RA filters:");
1863 pw.increaseIndent();
1864 for (Ra ra: mRas) {
1865 pw.println(ra);
1866 pw.increaseIndent();
1867 pw.println(String.format(
Hugo Benichi4456f332016-12-19 14:50:52 +09001868 "Seen: %d, last %ds ago", ra.seenCount, currentTimeSeconds() - ra.mLastSeen));
Lorenzo Colitti39c0d422016-03-23 00:23:29 +09001869 if (DBG) {
1870 pw.println("Last match:");
1871 pw.increaseIndent();
1872 pw.println(ra.getLastMatchingPacket());
1873 pw.decreaseIndent();
1874 }
Lorenzo Colitti5ff640d2016-03-03 17:53:46 +09001875 pw.decreaseIndent();
1876 }
Lorenzo Colitti059e2bb2016-04-08 20:51:39 +09001877 pw.decreaseIndent();
Lorenzo Colitti39c0d422016-03-23 00:23:29 +09001878
Aaron Huang56f9e412019-05-13 05:13:09 -07001879 pw.println("TCP Keepalive filters:");
Aaron Huanga63c40e2019-01-15 16:53:51 +08001880 pw.increaseIndent();
Aaron Huang56f9e412019-05-13 05:13:09 -07001881 for (int i = 0; i < mKeepalivePackets.size(); ++i) {
1882 final KeepalivePacket keepalivePacket = mKeepalivePackets.valueAt(i);
1883 if (keepalivePacket instanceof TcpKeepaliveAck) {
1884 pw.print("Slot ");
1885 pw.print(mKeepalivePackets.keyAt(i));
Aaron Huang4a40e912019-05-15 00:17:35 -07001886 pw.print(": ");
Aaron Huang56f9e412019-05-13 05:13:09 -07001887 pw.println(keepalivePacket);
1888 }
1889 }
1890 pw.decreaseIndent();
1891
1892 pw.println("NAT-T Keepalive filters:");
1893 pw.increaseIndent();
1894 for (int i = 0; i < mKeepalivePackets.size(); ++i) {
1895 final KeepalivePacket keepalivePacket = mKeepalivePackets.valueAt(i);
Aaron Huang4a40e912019-05-15 00:17:35 -07001896 if (keepalivePacket instanceof NattKeepaliveResponse) {
Aaron Huang56f9e412019-05-13 05:13:09 -07001897 pw.print("Slot ");
1898 pw.print(mKeepalivePackets.keyAt(i));
Aaron Huang4a40e912019-05-15 00:17:35 -07001899 pw.print(": ");
Aaron Huang56f9e412019-05-13 05:13:09 -07001900 pw.println(keepalivePacket);
1901 }
Aaron Huanga63c40e2019-01-15 16:53:51 +08001902 }
1903 pw.decreaseIndent();
1904
Lorenzo Colitti39c0d422016-03-23 00:23:29 +09001905 if (DBG) {
1906 pw.println("Last program:");
1907 pw.increaseIndent();
1908 pw.println(HexDump.toHexString(mLastInstalledProgram, false /* lowercase */));
1909 pw.decreaseIndent();
1910 }
Bernie Innocenti3cc40ea2018-04-24 01:25:42 +09001911
1912 pw.println("APF packet counters: ");
1913 pw.increaseIndent();
1914 if (!mApfCapabilities.hasDataAccess()) {
1915 pw.println("APF counters not supported");
1916 } else if (mDataSnapshot == null) {
1917 pw.println("No last snapshot.");
1918 } else {
1919 try {
1920 Counter[] counters = Counter.class.getEnumConstants();
1921 for (Counter c : Arrays.asList(counters).subList(1, counters.length)) {
1922 long value = counterValue(mDataSnapshot, c);
1923 // Only print non-zero counters
1924 if (value != 0) {
1925 pw.println(c.toString() + ": " + value);
1926 }
1927 }
1928 } catch (ArrayIndexOutOfBoundsException e) {
1929 pw.println("Uh-oh: " + e);
1930 }
1931 if (VDBG) {
1932 pw.println("Raw data dump: ");
1933 pw.println(HexDump.dumpHexString(mDataSnapshot));
1934 }
1935 }
1936 pw.decreaseIndent();
Lorenzo Colitti5ff640d2016-03-03 17:53:46 +09001937 }
Hugo Benichi7d21eae2016-09-02 14:00:29 +09001938
Hugo Benichi7d21eae2016-09-02 14:00:29 +09001939 // TODO: move to android.net.NetworkUtils
1940 @VisibleForTesting
1941 public static int ipv4BroadcastAddress(byte[] addrBytes, int prefixLength) {
Remi NGUYEN VAN3ba6c0d2019-01-20 13:48:19 +09001942 return bytesToBEInt(addrBytes) | (int) (Integer.toUnsignedLong(-1) >>> prefixLength);
1943 }
1944
1945 private static int uint8(byte b) {
1946 return b & 0xff;
1947 }
1948
1949 private static int getUint16(ByteBuffer buffer, int position) {
1950 return buffer.getShort(position) & 0xffff;
1951 }
1952
1953 private static long getUint32(ByteBuffer buffer, int position) {
1954 return Integer.toUnsignedLong(buffer.getInt(position));
1955 }
1956
1957 private static int getUint8(ByteBuffer buffer, int position) {
1958 return uint8(buffer.get(position));
1959 }
1960
1961 private static int bytesToBEInt(byte[] bytes) {
1962 return (uint8(bytes[0]) << 24)
1963 + (uint8(bytes[1]) << 16)
1964 + (uint8(bytes[2]) << 8)
1965 + (uint8(bytes[3]));
Hugo Benichi7d21eae2016-09-02 14:00:29 +09001966 }
Aaron Huang56f9e412019-05-13 05:13:09 -07001967
1968 private static byte[] concatArrays(final byte[]... arr) {
1969 int size = 0;
1970 for (byte[] a : arr) {
1971 size += a.length;
1972 }
1973 final byte[] result = new byte[size];
1974 int offset = 0;
1975 for (byte[] a : arr) {
1976 System.arraycopy(a, 0, result, offset, a.length);
1977 offset += a.length;
1978 }
1979 return result;
1980 }
Paul Jensen578a76e2016-01-14 14:54:39 -05001981}