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