Home | History | Annotate | Download | only in ip
      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