blob: 414741309ef05511593b292f0121dd5d6c0fccf5 [file] [log] [blame]
markchien74a4fa92019-09-09 20:50:49 +08001/*
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
17package android.net.ip;
18
19import static android.net.util.NetworkConstants.IPV6_MIN_MTU;
20import static android.net.util.NetworkConstants.RFC7421_PREFIX_LENGTH;
21import static android.system.OsConstants.AF_INET6;
22import static android.system.OsConstants.IPPROTO_ICMPV6;
23import static android.system.OsConstants.SOCK_RAW;
24import static android.system.OsConstants.SOL_SOCKET;
25import static android.system.OsConstants.SO_BINDTODEVICE;
26import static android.system.OsConstants.SO_SNDTIMEO;
27
28import android.net.IpPrefix;
29import android.net.LinkAddress;
30import android.net.NetworkUtils;
31import android.net.TrafficStats;
32import android.net.util.InterfaceParams;
33import android.system.ErrnoException;
34import android.system.Os;
35import android.system.StructTimeval;
36import android.util.Log;
37
38import com.android.internal.annotations.GuardedBy;
39import com.android.internal.util.TrafficStatsConstants;
40
41import libcore.io.IoBridge;
42
43import java.io.FileDescriptor;
44import java.io.IOException;
45import java.net.Inet6Address;
46import java.net.InetAddress;
47import java.net.InetSocketAddress;
48import java.net.SocketException;
49import java.net.UnknownHostException;
50import java.nio.BufferOverflowException;
51import java.nio.ByteBuffer;
52import java.nio.ByteOrder;
53import java.util.HashMap;
54import java.util.HashSet;
55import java.util.Iterator;
56import java.util.Map;
57import java.util.Random;
58import java.util.Set;
59import java.util.concurrent.atomic.AtomicInteger;
60
61
62/**
63 * Basic IPv6 Router Advertisement Daemon.
64 *
65 * TODO:
66 *
67 * - Rewrite using Handler (and friends) so that AlarmManager can deliver
68 * "kick" messages when it's time to send a multicast RA.
69 *
70 * @hide
71 */
72public class RouterAdvertisementDaemon {
73 private static final String TAG = RouterAdvertisementDaemon.class.getSimpleName();
74 private static final byte ICMPV6_ND_ROUTER_SOLICIT = asByte(133);
75 private static final byte ICMPV6_ND_ROUTER_ADVERT = asByte(134);
76 private static final int MIN_RA_HEADER_SIZE = 16;
77
78 // Summary of various timers and lifetimes.
79 private static final int MIN_RTR_ADV_INTERVAL_SEC = 300;
80 private static final int MAX_RTR_ADV_INTERVAL_SEC = 600;
81 // In general, router, prefix, and DNS lifetimes are all advised to be
82 // greater than or equal to 3 * MAX_RTR_ADV_INTERVAL. Here, we double
83 // that to allow for multicast packet loss.
84 //
85 // This MAX_RTR_ADV_INTERVAL_SEC and DEFAULT_LIFETIME are also consistent
86 // with the https://tools.ietf.org/html/rfc7772#section-4 discussion of
87 // "approximately 7 RAs per hour".
88 private static final int DEFAULT_LIFETIME = 6 * MAX_RTR_ADV_INTERVAL_SEC;
89 // From https://tools.ietf.org/html/rfc4861#section-10 .
90 private static final int MIN_DELAY_BETWEEN_RAS_SEC = 3;
91 // Both initial and final RAs, but also for changes in RA contents.
92 // From https://tools.ietf.org/html/rfc4861#section-10 .
93 private static final int MAX_URGENT_RTR_ADVERTISEMENTS = 5;
94
95 private static final int DAY_IN_SECONDS = 86_400;
96
97 private static final byte[] ALL_NODES = new byte[] {
98 (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
99 };
100
101 private final InterfaceParams mInterface;
102 private final InetSocketAddress mAllNodes;
103
104 // This lock is to protect the RA from being updated while being
105 // transmitted on another thread (multicast or unicast).
106 //
107 // TODO: This should be handled with a more RCU-like approach.
108 private final Object mLock = new Object();
109 @GuardedBy("mLock")
110 private final byte[] mRA = new byte[IPV6_MIN_MTU];
111 @GuardedBy("mLock")
112 private int mRaLength;
113 @GuardedBy("mLock")
114 private final DeprecatedInfoTracker mDeprecatedInfoTracker;
115 @GuardedBy("mLock")
116 private RaParams mRaParams;
117
118 private volatile FileDescriptor mSocket;
119 private volatile MulticastTransmitter mMulticastTransmitter;
120 private volatile UnicastResponder mUnicastResponder;
121
122 /** Encapsulate the RA parameters for RouterAdvertisementDaemon.*/
123 public static class RaParams {
124 // Tethered traffic will have the hop limit properly decremented.
125 // Consequently, set the hoplimit greater by one than the upstream
126 // unicast hop limit.
127 //
128 // TODO: Dynamically pass down the IPV6_UNICAST_HOPS value from the
129 // upstream interface for more correct behaviour.
130 static final byte DEFAULT_HOPLIMIT = 65;
131
132 public boolean hasDefaultRoute;
133 public byte hopLimit;
134 public int mtu;
135 public HashSet<IpPrefix> prefixes;
136 public HashSet<Inet6Address> dnses;
137
138 public RaParams() {
139 hasDefaultRoute = false;
140 hopLimit = DEFAULT_HOPLIMIT;
141 mtu = IPV6_MIN_MTU;
142 prefixes = new HashSet<IpPrefix>();
143 dnses = new HashSet<Inet6Address>();
144 }
145
146 public RaParams(RaParams other) {
147 hasDefaultRoute = other.hasDefaultRoute;
148 hopLimit = other.hopLimit;
149 mtu = other.mtu;
150 prefixes = (HashSet) other.prefixes.clone();
151 dnses = (HashSet) other.dnses.clone();
152 }
153
154 /**
155 * Returns the subset of RA parameters that become deprecated when
156 * moving from announcing oldRa to announcing newRa.
157 *
158 * Currently only tracks differences in |prefixes| and |dnses|.
159 */
160 public static RaParams getDeprecatedRaParams(RaParams oldRa, RaParams newRa) {
161 RaParams newlyDeprecated = new RaParams();
162
163 if (oldRa != null) {
164 for (IpPrefix ipp : oldRa.prefixes) {
165 if (newRa == null || !newRa.prefixes.contains(ipp)) {
166 newlyDeprecated.prefixes.add(ipp);
167 }
168 }
169
170 for (Inet6Address dns : oldRa.dnses) {
171 if (newRa == null || !newRa.dnses.contains(dns)) {
172 newlyDeprecated.dnses.add(dns);
173 }
174 }
175 }
176
177 return newlyDeprecated;
178 }
179 }
180
181 private static class DeprecatedInfoTracker {
182 private final HashMap<IpPrefix, Integer> mPrefixes = new HashMap<>();
183 private final HashMap<Inet6Address, Integer> mDnses = new HashMap<>();
184
185 Set<IpPrefix> getPrefixes() {
186 return mPrefixes.keySet();
187 }
188
189 void putPrefixes(Set<IpPrefix> prefixes) {
190 for (IpPrefix ipp : prefixes) {
191 mPrefixes.put(ipp, MAX_URGENT_RTR_ADVERTISEMENTS);
192 }
193 }
194
195 void removePrefixes(Set<IpPrefix> prefixes) {
196 for (IpPrefix ipp : prefixes) {
197 mPrefixes.remove(ipp);
198 }
199 }
200
201 Set<Inet6Address> getDnses() {
202 return mDnses.keySet();
203 }
204
205 void putDnses(Set<Inet6Address> dnses) {
206 for (Inet6Address dns : dnses) {
207 mDnses.put(dns, MAX_URGENT_RTR_ADVERTISEMENTS);
208 }
209 }
210
211 void removeDnses(Set<Inet6Address> dnses) {
212 for (Inet6Address dns : dnses) {
213 mDnses.remove(dns);
214 }
215 }
216
217 boolean isEmpty() {
218 return mPrefixes.isEmpty() && mDnses.isEmpty();
219 }
220
221 private boolean decrementCounters() {
222 boolean removed = decrementCounter(mPrefixes);
223 removed |= decrementCounter(mDnses);
224 return removed;
225 }
226
227 private <T> boolean decrementCounter(HashMap<T, Integer> map) {
228 boolean removed = false;
229
230 for (Iterator<Map.Entry<T, Integer>> it = map.entrySet().iterator();
231 it.hasNext();) {
232 Map.Entry<T, Integer> kv = it.next();
233 if (kv.getValue() == 0) {
234 it.remove();
235 removed = true;
236 } else {
237 kv.setValue(kv.getValue() - 1);
238 }
239 }
240
241 return removed;
242 }
243 }
244
245
246 public RouterAdvertisementDaemon(InterfaceParams ifParams) {
247 mInterface = ifParams;
248 mAllNodes = new InetSocketAddress(getAllNodesForScopeId(mInterface.index), 0);
249 mDeprecatedInfoTracker = new DeprecatedInfoTracker();
250 }
251
252 /** Build new RA.*/
253 public void buildNewRa(RaParams deprecatedParams, RaParams newParams) {
254 synchronized (mLock) {
255 if (deprecatedParams != null) {
256 mDeprecatedInfoTracker.putPrefixes(deprecatedParams.prefixes);
257 mDeprecatedInfoTracker.putDnses(deprecatedParams.dnses);
258 }
259
260 if (newParams != null) {
261 // Process information that is no longer deprecated.
262 mDeprecatedInfoTracker.removePrefixes(newParams.prefixes);
263 mDeprecatedInfoTracker.removeDnses(newParams.dnses);
264 }
265
266 mRaParams = newParams;
267 assembleRaLocked();
268 }
269
270 maybeNotifyMulticastTransmitter();
271 }
272
273 /** Start router advertisement daemon. */
274 public boolean start() {
275 if (!createSocket()) {
276 return false;
277 }
278
279 mMulticastTransmitter = new MulticastTransmitter();
280 mMulticastTransmitter.start();
281
282 mUnicastResponder = new UnicastResponder();
283 mUnicastResponder.start();
284
285 return true;
286 }
287
288 /** Stop router advertisement daemon. */
289 public void stop() {
290 closeSocket();
291 // Wake up mMulticastTransmitter thread to interrupt a potential 1 day sleep before
292 // the thread's termination.
293 maybeNotifyMulticastTransmitter();
294 mMulticastTransmitter = null;
295 mUnicastResponder = null;
296 }
297
298 @GuardedBy("mLock")
299 private void assembleRaLocked() {
300 final ByteBuffer ra = ByteBuffer.wrap(mRA);
301 ra.order(ByteOrder.BIG_ENDIAN);
302
303 final boolean haveRaParams = (mRaParams != null);
304 boolean shouldSendRA = false;
305
306 try {
307 putHeader(ra, haveRaParams && mRaParams.hasDefaultRoute,
308 haveRaParams ? mRaParams.hopLimit : RaParams.DEFAULT_HOPLIMIT);
309 putSlla(ra, mInterface.macAddr.toByteArray());
310 mRaLength = ra.position();
311
312 // https://tools.ietf.org/html/rfc5175#section-4 says:
313 //
314 // "MUST NOT be added to a Router Advertisement message
315 // if no flags in the option are set."
316 //
317 // putExpandedFlagsOption(ra);
318
319 if (haveRaParams) {
320 putMtu(ra, mRaParams.mtu);
321 mRaLength = ra.position();
322
323 for (IpPrefix ipp : mRaParams.prefixes) {
324 putPio(ra, ipp, DEFAULT_LIFETIME, DEFAULT_LIFETIME);
325 mRaLength = ra.position();
326 shouldSendRA = true;
327 }
328
329 if (mRaParams.dnses.size() > 0) {
330 putRdnss(ra, mRaParams.dnses, DEFAULT_LIFETIME);
331 mRaLength = ra.position();
332 shouldSendRA = true;
333 }
334 }
335
336 for (IpPrefix ipp : mDeprecatedInfoTracker.getPrefixes()) {
337 putPio(ra, ipp, 0, 0);
338 mRaLength = ra.position();
339 shouldSendRA = true;
340 }
341
342 final Set<Inet6Address> deprecatedDnses = mDeprecatedInfoTracker.getDnses();
343 if (!deprecatedDnses.isEmpty()) {
344 putRdnss(ra, deprecatedDnses, 0);
345 mRaLength = ra.position();
346 shouldSendRA = true;
347 }
348 } catch (BufferOverflowException e) {
349 // The packet up to mRaLength is valid, since it has been updated
350 // progressively as the RA was built. Log an error, and continue
351 // on as best as possible.
352 Log.e(TAG, "Could not construct new RA: " + e);
353 }
354
355 // We have nothing worth announcing; indicate as much to maybeSendRA().
356 if (!shouldSendRA) {
357 mRaLength = 0;
358 }
359 }
360
361 private void maybeNotifyMulticastTransmitter() {
362 final MulticastTransmitter m = mMulticastTransmitter;
363 if (m != null) {
364 m.hup();
365 }
366 }
367
368 private static Inet6Address getAllNodesForScopeId(int scopeId) {
369 try {
370 return Inet6Address.getByAddress("ff02::1", ALL_NODES, scopeId);
371 } catch (UnknownHostException uhe) {
372 Log.wtf(TAG, "Failed to construct ff02::1 InetAddress: " + uhe);
373 return null;
374 }
375 }
376
377 private static byte asByte(int value) {
378 return (byte) value;
379 }
380 private static short asShort(int value) {
381 return (short) value;
382 }
383
384 private static void putHeader(ByteBuffer ra, boolean hasDefaultRoute, byte hopLimit) {
385 /**
386 Router Advertisement Message Format
387
388 0 1 2 3
389 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
390 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
391 | Type | Code | Checksum |
392 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
393 | Cur Hop Limit |M|O|H|Prf|P|R|R| Router Lifetime |
394 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
395 | Reachable Time |
396 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
397 | Retrans Timer |
398 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
399 | Options ...
400 +-+-+-+-+-+-+-+-+-+-+-+-
401 */
402 ra.put(ICMPV6_ND_ROUTER_ADVERT)
403 .put(asByte(0))
404 .putShort(asShort(0))
405 .put(hopLimit)
406 // RFC 4191 "high" preference, iff. advertising a default route.
407 .put(hasDefaultRoute ? asByte(0x08) : asByte(0))
408 .putShort(hasDefaultRoute ? asShort(DEFAULT_LIFETIME) : asShort(0))
409 .putInt(0)
410 .putInt(0);
411 }
412
413 private static void putSlla(ByteBuffer ra, byte[] slla) {
414 /**
415 Source/Target Link-layer Address
416
417 0 1 2 3
418 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
419 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
420 | Type | Length | Link-Layer Address ...
421 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
422 */
423 if (slla == null || slla.length != 6) {
424 // Only IEEE 802.3 6-byte addresses are supported.
425 return;
426 }
427
428 final byte nd_option_slla = 1;
429 final byte slla_num_8octets = 1;
430 ra.put(nd_option_slla)
431 .put(slla_num_8octets)
432 .put(slla);
433 }
434
435 private static void putExpandedFlagsOption(ByteBuffer ra) {
436 /**
437 Router Advertisement Expanded Flags Option
438
439 0 1 2 3
440 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
441 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
442 | Type | Length | Bit fields available ..
443 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
444 ... for assignment |
445 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
446 */
447
448 final byte nd_option__efo = 26;
449 final byte efo_num_8octets = 1;
450
451 ra.put(nd_option__efo)
452 .put(efo_num_8octets)
453 .putShort(asShort(0))
454 .putInt(0);
455 }
456
457 private static void putMtu(ByteBuffer ra, int mtu) {
458 /**
459 MTU
460
461 0 1 2 3
462 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
463 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
464 | Type | Length | Reserved |
465 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
466 | MTU |
467 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
468 */
469 final byte nd_option_mtu = 5;
470 final byte mtu_num_8octs = 1;
471 ra.put(nd_option_mtu)
472 .put(mtu_num_8octs)
473 .putShort(asShort(0))
474 .putInt((mtu < IPV6_MIN_MTU) ? IPV6_MIN_MTU : mtu);
475 }
476
477 private static void putPio(ByteBuffer ra, IpPrefix ipp,
478 int validTime, int preferredTime) {
479 /**
480 Prefix Information
481
482 0 1 2 3
483 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
484 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
485 | Type | Length | Prefix Length |L|A| Reserved1 |
486 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
487 | Valid Lifetime |
488 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
489 | Preferred Lifetime |
490 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
491 | Reserved2 |
492 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
493 | |
494 + +
495 | |
496 + Prefix +
497 | |
498 + +
499 | |
500 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
501 */
502 final int prefixLength = ipp.getPrefixLength();
503 if (prefixLength != 64) {
504 return;
505 }
506 final byte nd_option_pio = 3;
507 final byte pio_num_8octets = 4;
508
509 if (validTime < 0) validTime = 0;
510 if (preferredTime < 0) preferredTime = 0;
511 if (preferredTime > validTime) preferredTime = validTime;
512
513 final byte[] addr = ipp.getAddress().getAddress();
514 ra.put(nd_option_pio)
515 .put(pio_num_8octets)
516 .put(asByte(prefixLength))
517 .put(asByte(0xc0)) /* L & A set */
518 .putInt(validTime)
519 .putInt(preferredTime)
520 .putInt(0)
521 .put(addr);
522 }
523
524 private static void putRio(ByteBuffer ra, IpPrefix ipp) {
525 /**
526 Route Information Option
527
528 0 1 2 3
529 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
530 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
531 | Type | Length | Prefix Length |Resvd|Prf|Resvd|
532 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
533 | Route Lifetime |
534 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
535 | Prefix (Variable Length) |
536 . .
537 . .
538 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
539 */
540 final int prefixLength = ipp.getPrefixLength();
541 if (prefixLength > 64) {
542 return;
543 }
544 final byte nd_option_rio = 24;
545 final byte rio_num_8octets = asByte(
546 (prefixLength == 0) ? 1 : (prefixLength <= 8) ? 2 : 3);
547
548 final byte[] addr = ipp.getAddress().getAddress();
549 ra.put(nd_option_rio)
550 .put(rio_num_8octets)
551 .put(asByte(prefixLength))
552 .put(asByte(0x18))
553 .putInt(DEFAULT_LIFETIME);
554
555 // Rely upon an IpPrefix's address being properly zeroed.
556 if (prefixLength > 0) {
557 ra.put(addr, 0, (prefixLength <= 64) ? 8 : 16);
558 }
559 }
560
561 private static void putRdnss(ByteBuffer ra, Set<Inet6Address> dnses, int lifetime) {
562 /**
563 Recursive DNS Server (RDNSS) Option
564
565 0 1 2 3
566 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
567 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
568 | Type | Length | Reserved |
569 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
570 | Lifetime |
571 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
572 | |
573 : Addresses of IPv6 Recursive DNS Servers :
574 | |
575 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
576 */
577
578 final HashSet<Inet6Address> filteredDnses = new HashSet<>();
579 for (Inet6Address dns : dnses) {
580 if ((new LinkAddress(dns, RFC7421_PREFIX_LENGTH)).isGlobalPreferred()) {
581 filteredDnses.add(dns);
582 }
583 }
584 if (filteredDnses.isEmpty()) return;
585
586 final byte nd_option_rdnss = 25;
587 final byte rdnss_num_8octets = asByte(dnses.size() * 2 + 1);
588 ra.put(nd_option_rdnss)
589 .put(rdnss_num_8octets)
590 .putShort(asShort(0))
591 .putInt(lifetime);
592
593 for (Inet6Address dns : filteredDnses) {
594 // NOTE: If the full of list DNS servers doesn't fit in the packet,
595 // this code will cause a buffer overflow and the RA won't include
596 // this instance of the option at all.
597 //
598 // TODO: Consider looking at ra.remaining() to determine how many
599 // DNS servers will fit, and adding only those.
600 ra.put(dns.getAddress());
601 }
602 }
603
604 private boolean createSocket() {
605 final int send_timout_ms = 300;
606
607 final int oldTag = TrafficStats.getAndSetThreadStatsTag(
608 TrafficStatsConstants.TAG_SYSTEM_NEIGHBOR);
609 try {
610 mSocket = Os.socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
611 // Setting SNDTIMEO is purely for defensive purposes.
612 Os.setsockoptTimeval(
613 mSocket, SOL_SOCKET, SO_SNDTIMEO, StructTimeval.fromMillis(send_timout_ms));
614 Os.setsockoptIfreq(mSocket, SOL_SOCKET, SO_BINDTODEVICE, mInterface.name);
615 NetworkUtils.protectFromVpn(mSocket);
616 NetworkUtils.setupRaSocket(mSocket, mInterface.index);
617 } catch (ErrnoException | IOException e) {
618 Log.e(TAG, "Failed to create RA daemon socket: " + e);
619 return false;
620 } finally {
621 TrafficStats.setThreadStatsTag(oldTag);
622 }
623
624 return true;
625 }
626
627 private void closeSocket() {
628 if (mSocket != null) {
629 try {
630 IoBridge.closeAndSignalBlockedThreads(mSocket);
631 } catch (IOException ignored) { }
632 }
633 mSocket = null;
634 }
635
636 private boolean isSocketValid() {
637 final FileDescriptor s = mSocket;
638 return (s != null) && s.valid();
639 }
640
641 private boolean isSuitableDestination(InetSocketAddress dest) {
642 if (mAllNodes.equals(dest)) {
643 return true;
644 }
645
646 final InetAddress destip = dest.getAddress();
647 return (destip instanceof Inet6Address)
648 && destip.isLinkLocalAddress()
649 && (((Inet6Address) destip).getScopeId() == mInterface.index);
650 }
651
652 private void maybeSendRA(InetSocketAddress dest) {
653 if (dest == null || !isSuitableDestination(dest)) {
654 dest = mAllNodes;
655 }
656
657 try {
658 synchronized (mLock) {
659 if (mRaLength < MIN_RA_HEADER_SIZE) {
660 // No actual RA to send.
661 return;
662 }
663 Os.sendto(mSocket, mRA, 0, mRaLength, 0, dest);
664 }
665 Log.d(TAG, "RA sendto " + dest.getAddress().getHostAddress());
666 } catch (ErrnoException | SocketException e) {
667 if (isSocketValid()) {
668 Log.e(TAG, "sendto error: " + e);
669 }
670 }
671 }
672
673 private final class UnicastResponder extends Thread {
674 private final InetSocketAddress mSolicitor = new InetSocketAddress();
675 // The recycled buffer for receiving Router Solicitations from clients.
676 // If the RS is larger than IPV6_MIN_MTU the packets are truncated.
677 // This is fine since currently only byte 0 is examined anyway.
678 private final byte[] mSolicitation = new byte[IPV6_MIN_MTU];
679
680 @Override
681 public void run() {
682 while (isSocketValid()) {
683 try {
684 // Blocking receive.
685 final int rval = Os.recvfrom(
686 mSocket, mSolicitation, 0, mSolicitation.length, 0, mSolicitor);
687 // Do the least possible amount of validation.
688 if (rval < 1 || mSolicitation[0] != ICMPV6_ND_ROUTER_SOLICIT) {
689 continue;
690 }
691 } catch (ErrnoException | SocketException e) {
692 if (isSocketValid()) {
693 Log.e(TAG, "recvfrom error: " + e);
694 }
695 continue;
696 }
697
698 maybeSendRA(mSolicitor);
699 }
700 }
701 }
702
703 // TODO: Consider moving this to run on a provided Looper as a Handler,
704 // with WakeupMessage-style messages providing the timer driven input.
705 private final class MulticastTransmitter extends Thread {
706 private final Random mRandom = new Random();
707 private final AtomicInteger mUrgentAnnouncements = new AtomicInteger(0);
708
709 @Override
710 public void run() {
711 while (isSocketValid()) {
712 try {
713 Thread.sleep(getNextMulticastTransmitDelayMs());
714 } catch (InterruptedException ignored) {
715 // Stop sleeping, immediately send an RA, and continue.
716 }
717
718 maybeSendRA(mAllNodes);
719 synchronized (mLock) {
720 if (mDeprecatedInfoTracker.decrementCounters()) {
721 // At least one deprecated PIO has been removed;
722 // reassemble the RA.
723 assembleRaLocked();
724 }
725 }
726 }
727 }
728
729 public void hup() {
730 // Set to one fewer that the desired number, because as soon as
731 // the thread interrupt is processed we immediately send an RA
732 // and mUrgentAnnouncements is not examined until the subsequent
733 // sleep interval computation (i.e. this way we send 3 and not 4).
734 mUrgentAnnouncements.set(MAX_URGENT_RTR_ADVERTISEMENTS - 1);
735 interrupt();
736 }
737
738 private int getNextMulticastTransmitDelaySec() {
739 boolean deprecationInProgress = false;
740 synchronized (mLock) {
741 if (mRaLength < MIN_RA_HEADER_SIZE) {
742 // No actual RA to send; just sleep for 1 day.
743 return DAY_IN_SECONDS;
744 }
745 deprecationInProgress = !mDeprecatedInfoTracker.isEmpty();
746 }
747
748 final int urgentPending = mUrgentAnnouncements.getAndDecrement();
749 if ((urgentPending > 0) || deprecationInProgress) {
750 return MIN_DELAY_BETWEEN_RAS_SEC;
751 }
752
753 return MIN_RTR_ADV_INTERVAL_SEC + mRandom.nextInt(
754 MAX_RTR_ADV_INTERVAL_SEC - MIN_RTR_ADV_INTERVAL_SEC);
755 }
756
757 private long getNextMulticastTransmitDelayMs() {
758 return 1000 * (long) getNextMulticastTransmitDelaySec();
759 }
760 }
761}