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