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