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