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.net.util.InterfaceParams;
29import android.system.ErrnoException;
30import android.system.Os;
31import android.system.StructGroupReq;
32import android.system.StructTimeval;
33import android.util.Log;
34
35import com.android.internal.annotations.GuardedBy;
36
37import libcore.io.IoBridge;
38import libcore.util.HexEncoding;
39
40import java.io.FileDescriptor;
41import java.io.InterruptedIOException;
42import java.io.IOException;
43import java.net.Inet6Address;
44import java.net.InetAddress;
45import java.net.InetSocketAddress;
46import java.net.SocketException;
47import java.net.UnknownHostException;
48import java.nio.BufferOverflowException;
49import java.nio.ByteBuffer;
50import java.nio.ByteOrder;
51import java.util.ArrayList;
52import java.util.HashMap;
53import java.util.HashSet;
54import java.util.Iterator;
55import java.util.Map;
56import java.util.Random;
57import java.util.Set;
58import 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 */
71public 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