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.system.OsConstants.*; 20 21 import android.net.IpPrefix; 22 import android.net.LinkAddress; 23 import android.net.LinkProperties; 24 import android.net.NetworkUtils; 25 import android.system.ErrnoException; 26 import android.system.Os; 27 import android.system.StructGroupReq; 28 import android.system.StructTimeval; 29 import android.util.Log; 30 31 import com.android.internal.annotations.GuardedBy; 32 33 import libcore.io.IoBridge; 34 import libcore.util.HexEncoding; 35 36 import java.io.FileDescriptor; 37 import java.io.InterruptedIOException; 38 import java.io.IOException; 39 import java.net.Inet6Address; 40 import java.net.InetAddress; 41 import java.net.InetSocketAddress; 42 import java.net.SocketException; 43 import java.net.UnknownHostException; 44 import java.nio.BufferOverflowException; 45 import java.nio.ByteBuffer; 46 import java.nio.ByteOrder; 47 import java.util.ArrayList; 48 import java.util.HashMap; 49 import java.util.HashSet; 50 import java.util.Iterator; 51 import java.util.Map; 52 import java.util.Random; 53 import java.util.Set; 54 import java.util.concurrent.atomic.AtomicInteger; 55 56 57 /** 58 * Basic IPv6 Router Advertisement Daemon. 59 * 60 * TODO: 61 * 62 * - Rewrite using Handler (and friends) so that AlarmManager can deliver 63 * "kick" messages when it's time to send a multicast RA. 64 * 65 * @hide 66 */ 67 public class RouterAdvertisementDaemon { 68 private static final String TAG = RouterAdvertisementDaemon.class.getSimpleName(); 69 private static final byte ICMPV6_ND_ROUTER_SOLICIT = asByte(133); 70 private static final byte ICMPV6_ND_ROUTER_ADVERT = asByte(134); 71 private static final int IPV6_MIN_MTU = 1280; 72 private static final int MIN_RA_HEADER_SIZE = 16; 73 74 // Summary of various timers and lifetimes. 75 private static final int MIN_RTR_ADV_INTERVAL_SEC = 300; 76 private static final int MAX_RTR_ADV_INTERVAL_SEC = 600; 77 // In general, router, prefix, and DNS lifetimes are all advised to be 78 // greater than or equal to 3 * MAX_RTR_ADV_INTERVAL. Here, we double 79 // that to allow for multicast packet loss. 80 // 81 // This MAX_RTR_ADV_INTERVAL_SEC and DEFAULT_LIFETIME are also consistent 82 // with the https://tools.ietf.org/html/rfc7772#section-4 discussion of 83 // "approximately 7 RAs per hour". 84 private static final int DEFAULT_LIFETIME = 6 * MAX_RTR_ADV_INTERVAL_SEC; 85 // From https://tools.ietf.org/html/rfc4861#section-10 . 86 private static final int MIN_DELAY_BETWEEN_RAS_SEC = 3; 87 // Both initial and final RAs, but also for changes in RA contents. 88 // From https://tools.ietf.org/html/rfc4861#section-10 . 89 private static final int MAX_URGENT_RTR_ADVERTISEMENTS = 5; 90 91 private static final int DAY_IN_SECONDS = 86_400; 92 93 private static final byte[] ALL_NODES = new byte[] { 94 (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 95 }; 96 97 private final String mIfName; 98 private final int mIfIndex; 99 private final byte[] mHwAddr; 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 public static class RaParams { 121 public boolean hasDefaultRoute; 122 public int mtu; 123 public HashSet<IpPrefix> prefixes; 124 public HashSet<Inet6Address> dnses; 125 126 public RaParams() { 127 hasDefaultRoute = false; 128 mtu = IPV6_MIN_MTU; 129 prefixes = new HashSet<IpPrefix>(); 130 dnses = new HashSet<Inet6Address>(); 131 } 132 133 public RaParams(RaParams other) { 134 hasDefaultRoute = other.hasDefaultRoute; 135 mtu = other.mtu; 136 prefixes = (HashSet) other.prefixes.clone(); 137 dnses = (HashSet) other.dnses.clone(); 138 } 139 140 // Returns the subset of RA parameters that become deprecated when 141 // moving from announcing oldRa to announcing newRa. 142 // 143 // Currently only tracks differences in |prefixes| and |dnses|. 144 public static RaParams getDeprecatedRaParams(RaParams oldRa, RaParams newRa) { 145 RaParams newlyDeprecated = new RaParams(); 146 147 if (oldRa != null) { 148 for (IpPrefix ipp : oldRa.prefixes) { 149 if (newRa == null || !newRa.prefixes.contains(ipp)) { 150 newlyDeprecated.prefixes.add(ipp); 151 } 152 } 153 154 for (Inet6Address dns : oldRa.dnses) { 155 if (newRa == null || !newRa.dnses.contains(dns)) { 156 newlyDeprecated.dnses.add(dns); 157 } 158 } 159 } 160 161 return newlyDeprecated; 162 } 163 } 164 165 private static class DeprecatedInfoTracker { 166 private final HashMap<IpPrefix, Integer> mPrefixes = new HashMap<>(); 167 private final HashMap<Inet6Address, Integer> mDnses = new HashMap<>(); 168 169 Set<IpPrefix> getPrefixes() { return mPrefixes.keySet(); } 170 171 void putPrefixes(Set<IpPrefix> prefixes) { 172 for (IpPrefix ipp : prefixes) { 173 mPrefixes.put(ipp, MAX_URGENT_RTR_ADVERTISEMENTS); 174 } 175 } 176 177 void removePrefixes(Set<IpPrefix> prefixes) { 178 for (IpPrefix ipp : prefixes) { 179 mPrefixes.remove(ipp); 180 } 181 } 182 183 Set<Inet6Address> getDnses() { return mDnses.keySet(); } 184 185 void putDnses(Set<Inet6Address> dnses) { 186 for (Inet6Address dns : dnses) { 187 mDnses.put(dns, MAX_URGENT_RTR_ADVERTISEMENTS); 188 } 189 } 190 191 void removeDnses(Set<Inet6Address> dnses) { 192 for (Inet6Address dns : dnses) { 193 mDnses.remove(dns); 194 } 195 } 196 197 boolean isEmpty() { return mPrefixes.isEmpty() && mDnses.isEmpty(); } 198 199 private boolean decrementCounters() { 200 boolean removed = decrementCounter(mPrefixes); 201 removed |= decrementCounter(mDnses); 202 return removed; 203 } 204 205 private <T> boolean decrementCounter(HashMap<T, Integer> map) { 206 boolean removed = false; 207 208 for (Iterator<Map.Entry<T, Integer>> it = map.entrySet().iterator(); 209 it.hasNext();) { 210 Map.Entry<T, Integer> kv = it.next(); 211 if (kv.getValue() == 0) { 212 it.remove(); 213 removed = true; 214 } else { 215 kv.setValue(kv.getValue() - 1); 216 } 217 } 218 219 return removed; 220 } 221 } 222 223 224 public RouterAdvertisementDaemon(String ifname, int ifindex, byte[] hwaddr) { 225 mIfName = ifname; 226 mIfIndex = ifindex; 227 mHwAddr = hwaddr; 228 mAllNodes = new InetSocketAddress(getAllNodesForScopeId(mIfIndex), 0); 229 mDeprecatedInfoTracker = new DeprecatedInfoTracker(); 230 } 231 232 public void buildNewRa(RaParams deprecatedParams, RaParams newParams) { 233 synchronized (mLock) { 234 if (deprecatedParams != null) { 235 mDeprecatedInfoTracker.putPrefixes(deprecatedParams.prefixes); 236 mDeprecatedInfoTracker.putDnses(deprecatedParams.dnses); 237 } 238 239 if (newParams != null) { 240 // Process information that is no longer deprecated. 241 mDeprecatedInfoTracker.removePrefixes(newParams.prefixes); 242 mDeprecatedInfoTracker.removeDnses(newParams.dnses); 243 } 244 245 mRaParams = newParams; 246 assembleRaLocked(); 247 } 248 249 maybeNotifyMulticastTransmitter(); 250 } 251 252 public boolean start() { 253 if (!createSocket()) { 254 return false; 255 } 256 257 mMulticastTransmitter = new MulticastTransmitter(); 258 mMulticastTransmitter.start(); 259 260 mUnicastResponder = new UnicastResponder(); 261 mUnicastResponder.start(); 262 263 return true; 264 } 265 266 public void stop() { 267 closeSocket(); 268 mMulticastTransmitter = null; 269 mUnicastResponder = null; 270 } 271 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, mHwAddr); 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 byte ND_OPTION_RDNSS = 25; 546 final byte RDNSS_NUM_8OCTETS = asByte(dnses.size() * 2 + 1); 547 ra.put(ND_OPTION_RDNSS) 548 .put(RDNSS_NUM_8OCTETS) 549 .putShort(asShort(0)) 550 .putInt(lifetime); 551 552 for (Inet6Address dns : dnses) { 553 // NOTE: If the full of list DNS servers doesn't fit in the packet, 554 // this code will cause a buffer overflow and the RA won't include 555 // this instance of the option at all. 556 // 557 // TODO: Consider looking at ra.remaining() to determine how many 558 // DNS servers will fit, and adding only those. 559 ra.put(dns.getAddress()); 560 } 561 } 562 563 private boolean createSocket() { 564 final int SEND_TIMEOUT_MS = 300; 565 566 try { 567 mSocket = Os.socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); 568 // Setting SNDTIMEO is purely for defensive purposes. 569 Os.setsockoptTimeval( 570 mSocket, SOL_SOCKET, SO_SNDTIMEO, StructTimeval.fromMillis(SEND_TIMEOUT_MS)); 571 Os.setsockoptIfreq(mSocket, SOL_SOCKET, SO_BINDTODEVICE, mIfName); 572 NetworkUtils.protectFromVpn(mSocket); 573 NetworkUtils.setupRaSocket(mSocket, mIfIndex); 574 } catch (ErrnoException | IOException e) { 575 Log.e(TAG, "Failed to create RA daemon socket: " + e); 576 return false; 577 } 578 579 return true; 580 } 581 582 private void closeSocket() { 583 if (mSocket != null) { 584 try { 585 IoBridge.closeAndSignalBlockedThreads(mSocket); 586 } catch (IOException ignored) {} 587 } 588 mSocket = null; 589 } 590 591 private boolean isSocketValid() { 592 final FileDescriptor s = mSocket; 593 return (s != null) && s.valid(); 594 } 595 596 private boolean isSuitableDestination(InetSocketAddress dest) { 597 if (mAllNodes.equals(dest)) { 598 return true; 599 } 600 601 final InetAddress destip = dest.getAddress(); 602 return (destip instanceof Inet6Address) && 603 destip.isLinkLocalAddress() && 604 (((Inet6Address) destip).getScopeId() == mIfIndex); 605 } 606 607 private void maybeSendRA(InetSocketAddress dest) { 608 if (dest == null || !isSuitableDestination(dest)) { 609 dest = mAllNodes; 610 } 611 612 try { 613 synchronized (mLock) { 614 if (mRaLength < MIN_RA_HEADER_SIZE) { 615 // No actual RA to send. 616 return; 617 } 618 Os.sendto(mSocket, mRA, 0, mRaLength, 0, dest); 619 } 620 Log.d(TAG, "RA sendto " + dest.getAddress().getHostAddress()); 621 } catch (ErrnoException | SocketException e) { 622 if (isSocketValid()) { 623 Log.e(TAG, "sendto error: " + e); 624 } 625 } 626 } 627 628 private final class UnicastResponder extends Thread { 629 private final InetSocketAddress solicitor = new InetSocketAddress(); 630 // The recycled buffer for receiving Router Solicitations from clients. 631 // If the RS is larger than IPV6_MIN_MTU the packets are truncated. 632 // This is fine since currently only byte 0 is examined anyway. 633 private final byte mSolication[] = new byte[IPV6_MIN_MTU]; 634 635 @Override 636 public void run() { 637 while (isSocketValid()) { 638 try { 639 // Blocking receive. 640 final int rval = Os.recvfrom( 641 mSocket, mSolication, 0, mSolication.length, 0, solicitor); 642 // Do the least possible amount of validation. 643 if (rval < 1 || mSolication[0] != ICMPV6_ND_ROUTER_SOLICIT) { 644 continue; 645 } 646 } catch (ErrnoException | SocketException e) { 647 if (isSocketValid()) { 648 Log.e(TAG, "recvfrom error: " + e); 649 } 650 continue; 651 } 652 653 maybeSendRA(solicitor); 654 } 655 } 656 } 657 658 // TODO: Consider moving this to run on a provided Looper as a Handler, 659 // with WakeupMessage-style messages providing the timer driven input. 660 private final class MulticastTransmitter extends Thread { 661 private final Random mRandom = new Random(); 662 private final AtomicInteger mUrgentAnnouncements = new AtomicInteger(0); 663 664 @Override 665 public void run() { 666 while (isSocketValid()) { 667 try { 668 Thread.sleep(getNextMulticastTransmitDelayMs()); 669 } catch (InterruptedException ignored) { 670 // Stop sleeping, immediately send an RA, and continue. 671 } 672 673 maybeSendRA(mAllNodes); 674 synchronized (mLock) { 675 if (mDeprecatedInfoTracker.decrementCounters()) { 676 // At least one deprecated PIO has been removed; 677 // reassemble the RA. 678 assembleRaLocked(); 679 } 680 } 681 } 682 } 683 684 public void hup() { 685 // Set to one fewer that the desired number, because as soon as 686 // the thread interrupt is processed we immediately send an RA 687 // and mUrgentAnnouncements is not examined until the subsequent 688 // sleep interval computation (i.e. this way we send 3 and not 4). 689 mUrgentAnnouncements.set(MAX_URGENT_RTR_ADVERTISEMENTS - 1); 690 interrupt(); 691 } 692 693 private int getNextMulticastTransmitDelaySec() { 694 boolean deprecationInProgress = false; 695 synchronized (mLock) { 696 if (mRaLength < MIN_RA_HEADER_SIZE) { 697 // No actual RA to send; just sleep for 1 day. 698 return DAY_IN_SECONDS; 699 } 700 deprecationInProgress = !mDeprecatedInfoTracker.isEmpty(); 701 } 702 703 final int urgentPending = mUrgentAnnouncements.getAndDecrement(); 704 if ((urgentPending > 0) || deprecationInProgress) { 705 return MIN_DELAY_BETWEEN_RAS_SEC; 706 } 707 708 return MIN_RTR_ADV_INTERVAL_SEC + mRandom.nextInt( 709 MAX_RTR_ADV_INTERVAL_SEC - MIN_RTR_ADV_INTERVAL_SEC); 710 } 711 712 private long getNextMulticastTransmitDelayMs() { 713 return 1000 * (long) getNextMulticastTransmitDelaySec(); 714 } 715 } 716 } 717