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.AF_INET6; 22 import static android.system.OsConstants.IPPROTO_ICMPV6; 23 import static android.system.OsConstants.SOCK_RAW; 24 import static android.system.OsConstants.SOL_SOCKET; 25 import static android.system.OsConstants.SO_SNDTIMEO; 26 27 import android.net.IpPrefix; 28 import android.net.LinkAddress; 29 import android.net.TrafficStats; 30 import android.net.util.InterfaceParams; 31 import android.net.util.SocketUtils; 32 import android.net.util.TetheringUtils; 33 import android.system.ErrnoException; 34 import android.system.Os; 35 import android.system.StructTimeval; 36 import android.util.Log; 37 38 import com.android.internal.annotations.GuardedBy; 39 import com.android.internal.util.TrafficStatsConstants; 40 41 import java.io.FileDescriptor; 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.HashMap; 52 import java.util.HashSet; 53 import java.util.Iterator; 54 import java.util.Map; 55 import java.util.Random; 56 import java.util.Set; 57 import 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 */ 70 public 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 RaParams()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 RaParams(RaParams other)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 */ getDeprecatedRaParams(RaParams oldRa, RaParams newRa)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 getPrefixes()183 Set<IpPrefix> getPrefixes() { 184 return mPrefixes.keySet(); 185 } 186 putPrefixes(Set<IpPrefix> prefixes)187 void putPrefixes(Set<IpPrefix> prefixes) { 188 for (IpPrefix ipp : prefixes) { 189 mPrefixes.put(ipp, MAX_URGENT_RTR_ADVERTISEMENTS); 190 } 191 } 192 removePrefixes(Set<IpPrefix> prefixes)193 void removePrefixes(Set<IpPrefix> prefixes) { 194 for (IpPrefix ipp : prefixes) { 195 mPrefixes.remove(ipp); 196 } 197 } 198 getDnses()199 Set<Inet6Address> getDnses() { 200 return mDnses.keySet(); 201 } 202 putDnses(Set<Inet6Address> dnses)203 void putDnses(Set<Inet6Address> dnses) { 204 for (Inet6Address dns : dnses) { 205 mDnses.put(dns, MAX_URGENT_RTR_ADVERTISEMENTS); 206 } 207 } 208 removeDnses(Set<Inet6Address> dnses)209 void removeDnses(Set<Inet6Address> dnses) { 210 for (Inet6Address dns : dnses) { 211 mDnses.remove(dns); 212 } 213 } 214 isEmpty()215 boolean isEmpty() { 216 return mPrefixes.isEmpty() && mDnses.isEmpty(); 217 } 218 decrementCounters()219 private boolean decrementCounters() { 220 boolean removed = decrementCounter(mPrefixes); 221 removed |= decrementCounter(mDnses); 222 return removed; 223 } 224 decrementCounter(HashMap<T, Integer> map)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 RouterAdvertisementDaemon(InterfaceParams ifParams)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.*/ buildNewRa(RaParams deprecatedParams, RaParams newParams)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. */ start()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. */ stop()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") assembleRaLocked()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 maybeNotifyMulticastTransmitter()359 private void maybeNotifyMulticastTransmitter() { 360 final MulticastTransmitter m = mMulticastTransmitter; 361 if (m != null) { 362 m.hup(); 363 } 364 } 365 getAllNodesForScopeId(int scopeId)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 asByte(int value)375 private static byte asByte(int value) { 376 return (byte) value; 377 } asShort(int value)378 private static short asShort(int value) { 379 return (short) value; 380 } 381 putHeader(ByteBuffer ra, boolean hasDefaultRoute, byte hopLimit)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 putSlla(ByteBuffer ra, byte[] slla)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 putExpandedFlagsOption(ByteBuffer ra)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 putMtu(ByteBuffer ra, int mtu)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)); 612 SocketUtils.bindSocketToInterface(mSocket, mInterface.name); 613 TetheringUtils.setupRaSocket(mSocket, mInterface.index); 614 } 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 { 627 SocketUtils.closeSocket(mSocket); 628 } 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(0); 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 } 759