Home | History | Annotate | Download | only in tethering
      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 com.android.server.connectivity.tethering;
     18 
     19 import android.net.ConnectivityManager;
     20 import android.net.IpPrefix;
     21 import android.net.LinkAddress;
     22 import android.net.LinkProperties;
     23 import android.net.Network;
     24 import android.net.NetworkCapabilities;
     25 import android.net.NetworkState;
     26 import android.net.RouteInfo;
     27 import android.net.util.NetworkConstants;
     28 import android.net.util.SharedLog;
     29 import android.util.Log;
     30 
     31 import java.net.Inet6Address;
     32 import java.net.InetAddress;
     33 import java.net.UnknownHostException;
     34 import java.util.ArrayList;
     35 import java.util.Arrays;
     36 import java.util.HashMap;
     37 import java.util.LinkedList;
     38 import java.util.Random;
     39 
     40 
     41 /**
     42  * IPv6 tethering is rather different from IPv4 owing to the absence of NAT.
     43  * This coordinator is responsible for evaluating the dedicated prefixes
     44  * assigned to the device and deciding how to divvy them up among downstream
     45  * interfaces.
     46  *
     47  * @hide
     48  */
     49 public class IPv6TetheringCoordinator {
     50     private static final String TAG = IPv6TetheringCoordinator.class.getSimpleName();
     51     private static final boolean DBG = false;
     52     private static final boolean VDBG = false;
     53 
     54     private static class Downstream {
     55         public final TetherInterfaceStateMachine tism;
     56         public final int mode;  // IControlsTethering.STATE_*
     57         // Used to append to a ULA /48, constructing a ULA /64 for local use.
     58         public final short subnetId;
     59 
     60         Downstream(TetherInterfaceStateMachine tism, int mode, short subnetId) {
     61             this.tism = tism;
     62             this.mode = mode;
     63             this.subnetId = subnetId;
     64         }
     65     }
     66 
     67     private final ArrayList<TetherInterfaceStateMachine> mNotifyList;
     68     private final SharedLog mLog;
     69     // NOTE: mActiveDownstreams is a list and not a hash data structure because
     70     // we keep active downstreams in arrival order.  This is done so /64s can
     71     // be parceled out on a "first come, first served" basis and a /64 used by
     72     // a downstream that is no longer active can be redistributed to any next
     73     // waiting active downstream (again, in arrival order).
     74     private final LinkedList<Downstream> mActiveDownstreams;
     75     private final byte[] mUniqueLocalPrefix;
     76     private short mNextSubnetId;
     77     private NetworkState mUpstreamNetworkState;
     78 
     79     public IPv6TetheringCoordinator(ArrayList<TetherInterfaceStateMachine> notifyList,
     80                                     SharedLog log) {
     81         mNotifyList = notifyList;
     82         mLog = log.forSubComponent(TAG);
     83         mActiveDownstreams = new LinkedList<>();
     84         mUniqueLocalPrefix = generateUniqueLocalPrefix();
     85         mNextSubnetId = 0;
     86     }
     87 
     88     public void addActiveDownstream(TetherInterfaceStateMachine downstream, int mode) {
     89         if (findDownstream(downstream) == null) {
     90             // Adding a new downstream appends it to the list. Adding a
     91             // downstream a second time without first removing it has no effect.
     92             // We never change the mode of a downstream except by first removing
     93             // it and then re-adding it (with its new mode specified);
     94             if (mActiveDownstreams.offer(new Downstream(downstream, mode, mNextSubnetId))) {
     95                 // Make sure subnet IDs are always positive. They are appended
     96                 // to a ULA /48 to make a ULA /64 for local use.
     97                 mNextSubnetId = (short) Math.max(0, mNextSubnetId + 1);
     98             }
     99             updateIPv6TetheringInterfaces();
    100         }
    101     }
    102 
    103     public void removeActiveDownstream(TetherInterfaceStateMachine downstream) {
    104         stopIPv6TetheringOn(downstream);
    105         if (mActiveDownstreams.remove(findDownstream(downstream))) {
    106             updateIPv6TetheringInterfaces();
    107         }
    108 
    109         // When tethering is stopping we can reset the subnet counter.
    110         if (mNotifyList.isEmpty()) {
    111             if (!mActiveDownstreams.isEmpty()) {
    112                 Log.wtf(TAG, "Tethering notify list empty, IPv6 downstreams non-empty.");
    113             }
    114             mNextSubnetId = 0;
    115         }
    116     }
    117 
    118     public void updateUpstreamNetworkState(NetworkState ns) {
    119         if (VDBG) {
    120             Log.d(TAG, "updateUpstreamNetworkState: " + toDebugString(ns));
    121         }
    122         if (!canTetherIPv6(ns, mLog)) {
    123             stopIPv6TetheringOnAllInterfaces();
    124             setUpstreamNetworkState(null);
    125             return;
    126         }
    127 
    128         if (mUpstreamNetworkState != null &&
    129             !ns.network.equals(mUpstreamNetworkState.network)) {
    130             stopIPv6TetheringOnAllInterfaces();
    131         }
    132 
    133         setUpstreamNetworkState(ns);
    134         updateIPv6TetheringInterfaces();
    135     }
    136 
    137     private void stopIPv6TetheringOnAllInterfaces() {
    138         for (TetherInterfaceStateMachine sm : mNotifyList) {
    139             stopIPv6TetheringOn(sm);
    140         }
    141     }
    142 
    143     private void setUpstreamNetworkState(NetworkState ns) {
    144         if (ns == null) {
    145             mUpstreamNetworkState = null;
    146         } else {
    147             // Make a deep copy of the parts we need.
    148             mUpstreamNetworkState = new NetworkState(
    149                     null,
    150                     new LinkProperties(ns.linkProperties),
    151                     new NetworkCapabilities(ns.networkCapabilities),
    152                     new Network(ns.network),
    153                     null,
    154                     null);
    155         }
    156 
    157         mLog.log("setUpstreamNetworkState: " + toDebugString(mUpstreamNetworkState));
    158     }
    159 
    160     private void updateIPv6TetheringInterfaces() {
    161         for (TetherInterfaceStateMachine sm : mNotifyList) {
    162             final LinkProperties lp = getInterfaceIPv6LinkProperties(sm);
    163             sm.sendMessage(TetherInterfaceStateMachine.CMD_IPV6_TETHER_UPDATE, 0, 0, lp);
    164             break;
    165         }
    166     }
    167 
    168     private LinkProperties getInterfaceIPv6LinkProperties(TetherInterfaceStateMachine sm) {
    169         if (sm.interfaceType() == ConnectivityManager.TETHERING_BLUETOOTH) {
    170             // TODO: Figure out IPv6 support on PAN interfaces.
    171             return null;
    172         }
    173 
    174         final Downstream ds = findDownstream(sm);
    175         if (ds == null) return null;
    176 
    177         if (ds.mode == IControlsTethering.STATE_LOCAL_ONLY) {
    178             // Build a Unique Locally-assigned Prefix configuration.
    179             return getUniqueLocalConfig(mUniqueLocalPrefix, ds.subnetId);
    180         }
    181 
    182         // This downstream is in IControlsTethering.STATE_TETHERED mode.
    183         if (mUpstreamNetworkState == null || mUpstreamNetworkState.linkProperties == null) {
    184             return null;
    185         }
    186 
    187         // NOTE: Here, in future, we would have policies to decide how to divvy
    188         // up the available dedicated prefixes among downstream interfaces.
    189         // At this time we have no such mechanism--we only support tethering
    190         // IPv6 toward the oldest (first requested) active downstream.
    191 
    192         final Downstream currentActive = mActiveDownstreams.peek();
    193         if (currentActive != null && currentActive.tism == sm) {
    194             final LinkProperties lp = getIPv6OnlyLinkProperties(
    195                     mUpstreamNetworkState.linkProperties);
    196             if (lp.hasIPv6DefaultRoute() && lp.hasGlobalIPv6Address()) {
    197                 return lp;
    198             }
    199         }
    200 
    201         return null;
    202     }
    203 
    204     Downstream findDownstream(TetherInterfaceStateMachine tism) {
    205         for (Downstream ds : mActiveDownstreams) {
    206             if (ds.tism == tism) return ds;
    207         }
    208         return null;
    209     }
    210 
    211     private static boolean canTetherIPv6(NetworkState ns, SharedLog sharedLog) {
    212         // Broadly speaking:
    213         //
    214         //     [1] does the upstream have an IPv6 default route?
    215         //
    216         // and
    217         //
    218         //     [2] does the upstream have one or more global IPv6 /64s
    219         //         dedicated to this device?
    220         //
    221         // In lieu of Prefix Delegation and other evaluation of whether a
    222         // prefix may or may not be dedicated to this device, for now just
    223         // check whether the upstream is TRANSPORT_CELLULAR. This works
    224         // because "[t]he 3GPP network allocates each default bearer a unique
    225         // /64 prefix", per RFC 6459, Section 5.2.
    226 
    227         final boolean canTether =
    228                 (ns != null) && (ns.network != null) &&
    229                 (ns.linkProperties != null) && (ns.networkCapabilities != null) &&
    230                 // At least one upstream DNS server:
    231                 ns.linkProperties.isProvisioned() &&
    232                 // Minimal amount of IPv6 provisioning:
    233                 ns.linkProperties.hasIPv6DefaultRoute() &&
    234                 ns.linkProperties.hasGlobalIPv6Address() &&
    235                 // Temporary approximation of "dedicated prefix":
    236                 ns.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR);
    237 
    238         // For now, we do not support separate IPv4 and IPv6 upstreams (e.g.
    239         // tethering with 464xlat involved). TODO: Rectify this shortcoming,
    240         // likely by calling NetworkManagementService#startInterfaceForwarding()
    241         // for all upstream interfaces.
    242         RouteInfo v4default = null;
    243         RouteInfo v6default = null;
    244         if (canTether) {
    245             for (RouteInfo r : ns.linkProperties.getAllRoutes()) {
    246                 if (r.isIPv4Default()) {
    247                     v4default = r;
    248                 } else if (r.isIPv6Default()) {
    249                     v6default = r;
    250                 }
    251 
    252                 if (v4default != null && v6default != null) {
    253                     break;
    254                 }
    255             }
    256         }
    257 
    258         final boolean supportedConfiguration =
    259                 (v4default != null) && (v6default != null) &&
    260                 (v4default.getInterface() != null) &&
    261                 v4default.getInterface().equals(v6default.getInterface());
    262 
    263         final boolean outcome = canTether && supportedConfiguration;
    264 
    265         if (ns == null) {
    266             sharedLog.log("No available upstream.");
    267         } else {
    268             sharedLog.log(String.format("IPv6 tethering is %s for upstream: %s",
    269                     (outcome ? "available" : "not available"), toDebugString(ns)));
    270         }
    271 
    272         return outcome;
    273     }
    274 
    275     private static LinkProperties getIPv6OnlyLinkProperties(LinkProperties lp) {
    276         final LinkProperties v6only = new LinkProperties();
    277         if (lp == null) {
    278             return v6only;
    279         }
    280 
    281         // NOTE: At this time we don't copy over any information about any
    282         // stacked links. No current stacked link configuration has IPv6.
    283 
    284         v6only.setInterfaceName(lp.getInterfaceName());
    285 
    286         v6only.setMtu(lp.getMtu());
    287 
    288         for (LinkAddress linkAddr : lp.getLinkAddresses()) {
    289             if (linkAddr.isGlobalPreferred() && linkAddr.getPrefixLength() == 64) {
    290                 v6only.addLinkAddress(linkAddr);
    291             }
    292         }
    293 
    294         for (RouteInfo routeInfo : lp.getRoutes()) {
    295             final IpPrefix destination = routeInfo.getDestination();
    296             if ((destination.getAddress() instanceof Inet6Address) &&
    297                 (destination.getPrefixLength() <= 64)) {
    298                 v6only.addRoute(routeInfo);
    299             }
    300         }
    301 
    302         for (InetAddress dnsServer : lp.getDnsServers()) {
    303             if (isIPv6GlobalAddress(dnsServer)) {
    304                 // For now we include ULAs.
    305                 v6only.addDnsServer(dnsServer);
    306             }
    307         }
    308 
    309         v6only.setDomains(lp.getDomains());
    310 
    311         return v6only;
    312     }
    313 
    314     // TODO: Delete this and switch to LinkAddress#isGlobalPreferred once we
    315     // announce our own IPv6 address as DNS server.
    316     private static boolean isIPv6GlobalAddress(InetAddress ip) {
    317         return (ip instanceof Inet6Address) &&
    318                !ip.isAnyLocalAddress() &&
    319                !ip.isLoopbackAddress() &&
    320                !ip.isLinkLocalAddress() &&
    321                !ip.isSiteLocalAddress() &&
    322                !ip.isMulticastAddress();
    323     }
    324 
    325     private static LinkProperties getUniqueLocalConfig(byte[] ulp, short subnetId) {
    326         final LinkProperties lp = new LinkProperties();
    327 
    328         final IpPrefix local48 = makeUniqueLocalPrefix(ulp, (short) 0, 48);
    329         lp.addRoute(new RouteInfo(local48, null, null));
    330 
    331         final IpPrefix local64 = makeUniqueLocalPrefix(ulp, subnetId, 64);
    332         // Because this is a locally-generated ULA, we don't have an upstream
    333         // address. But because the downstream IP address management code gets
    334         // its prefix from the upstream's IP address, we create a fake one here.
    335         lp.addLinkAddress(new LinkAddress(local64.getAddress(), 64));
    336 
    337         lp.setMtu(NetworkConstants.ETHER_MTU);
    338         return lp;
    339     }
    340 
    341     private static IpPrefix makeUniqueLocalPrefix(byte[] in6addr, short subnetId, int prefixlen) {
    342         final byte[] bytes = Arrays.copyOf(in6addr, in6addr.length);
    343         bytes[7] = (byte) (subnetId >> 8);
    344         bytes[8] = (byte) subnetId;
    345         return new IpPrefix(bytes, prefixlen);
    346     }
    347 
    348     // Generates a Unique Locally-assigned Prefix:
    349     //
    350     //     https://tools.ietf.org/html/rfc4193#section-3.1
    351     //
    352     // The result is a /48 that can be used for local-only communications.
    353     private static byte[] generateUniqueLocalPrefix() {
    354         final byte[] ulp = new byte[6];  // 6 = 48bits / 8bits/byte
    355         (new Random()).nextBytes(ulp);
    356 
    357         final byte[] in6addr = Arrays.copyOf(ulp, NetworkConstants.IPV6_ADDR_LEN);
    358         in6addr[0] = (byte) 0xfd;  // fc00::/7 and L=1
    359 
    360         return in6addr;
    361     }
    362 
    363     private static String toDebugString(NetworkState ns) {
    364         if (ns == null) {
    365             return "NetworkState{null}";
    366         }
    367         return String.format("NetworkState{%s, %s, %s}",
    368                 ns.network,
    369                 ns.networkCapabilities,
    370                 ns.linkProperties);
    371     }
    372 
    373     private static void stopIPv6TetheringOn(TetherInterfaceStateMachine sm) {
    374         sm.sendMessage(TetherInterfaceStateMachine.CMD_IPV6_TETHER_UPDATE, 0, 0, null);
    375     }
    376 }
    377