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