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.ip.IpServer;
28 import android.net.util.NetworkConstants;
29 import android.net.util.SharedLog;
30 import android.util.Log;
31 
32 import java.net.Inet6Address;
33 import java.net.InetAddress;
34 import java.util.ArrayList;
35 import java.util.Arrays;
36 import java.util.LinkedList;
37 import java.util.Random;
38 
39 
40 /**
41  * IPv6 tethering is rather different from IPv4 owing to the absence of NAT.
42  * This coordinator is responsible for evaluating the dedicated prefixes
43  * assigned to the device and deciding how to divvy them up among downstream
44  * interfaces.
45  *
46  * @hide
47  */
48 public class IPv6TetheringCoordinator {
49     private static final String TAG = IPv6TetheringCoordinator.class.getSimpleName();
50     private static final boolean DBG = false;
51     private static final boolean VDBG = false;
52 
53     private static class Downstream {
54         public final IpServer ipServer;
55         public final int mode;  // IpServer.STATE_*
56         // Used to append to a ULA /48, constructing a ULA /64 for local use.
57         public final short subnetId;
58 
Downstream(IpServer ipServer, int mode, short subnetId)59         Downstream(IpServer ipServer, int mode, short subnetId) {
60             this.ipServer = ipServer;
61             this.mode = mode;
62             this.subnetId = subnetId;
63         }
64     }
65 
66     private final ArrayList<IpServer> mNotifyList;
67     private final SharedLog mLog;
68     // NOTE: mActiveDownstreams is a list and not a hash data structure because
69     // we keep active downstreams in arrival order.  This is done so /64s can
70     // be parceled out on a "first come, first served" basis and a /64 used by
71     // a downstream that is no longer active can be redistributed to any next
72     // waiting active downstream (again, in arrival order).
73     private final LinkedList<Downstream> mActiveDownstreams;
74     private final byte[] mUniqueLocalPrefix;
75     private short mNextSubnetId;
76     private NetworkState mUpstreamNetworkState;
77 
IPv6TetheringCoordinator(ArrayList<IpServer> notifyList, SharedLog log)78     public IPv6TetheringCoordinator(ArrayList<IpServer> notifyList, SharedLog log) {
79         mNotifyList = notifyList;
80         mLog = log.forSubComponent(TAG);
81         mActiveDownstreams = new LinkedList<>();
82         mUniqueLocalPrefix = generateUniqueLocalPrefix();
83         mNextSubnetId = 0;
84     }
85 
addActiveDownstream(IpServer downstream, int mode)86     public void addActiveDownstream(IpServer downstream, int mode) {
87         if (findDownstream(downstream) == null) {
88             // Adding a new downstream appends it to the list. Adding a
89             // downstream a second time without first removing it has no effect.
90             // We never change the mode of a downstream except by first removing
91             // it and then re-adding it (with its new mode specified);
92             if (mActiveDownstreams.offer(new Downstream(downstream, mode, mNextSubnetId))) {
93                 // Make sure subnet IDs are always positive. They are appended
94                 // to a ULA /48 to make a ULA /64 for local use.
95                 mNextSubnetId = (short) Math.max(0, mNextSubnetId + 1);
96             }
97             updateIPv6TetheringInterfaces();
98         }
99     }
100 
removeActiveDownstream(IpServer downstream)101     public void removeActiveDownstream(IpServer downstream) {
102         stopIPv6TetheringOn(downstream);
103         if (mActiveDownstreams.remove(findDownstream(downstream))) {
104             updateIPv6TetheringInterfaces();
105         }
106 
107         // When tethering is stopping we can reset the subnet counter.
108         if (mNotifyList.isEmpty()) {
109             if (!mActiveDownstreams.isEmpty()) {
110                 Log.wtf(TAG, "Tethering notify list empty, IPv6 downstreams non-empty.");
111             }
112             mNextSubnetId = 0;
113         }
114     }
115 
updateUpstreamNetworkState(NetworkState ns)116     public void updateUpstreamNetworkState(NetworkState ns) {
117         if (VDBG) {
118             Log.d(TAG, "updateUpstreamNetworkState: " + toDebugString(ns));
119         }
120         if (TetheringInterfaceUtils.getIPv6Interface(ns) == null) {
121             stopIPv6TetheringOnAllInterfaces();
122             setUpstreamNetworkState(null);
123             return;
124         }
125 
126         if (mUpstreamNetworkState != null &&
127             !ns.network.equals(mUpstreamNetworkState.network)) {
128             stopIPv6TetheringOnAllInterfaces();
129         }
130 
131         setUpstreamNetworkState(ns);
132         updateIPv6TetheringInterfaces();
133     }
134 
stopIPv6TetheringOnAllInterfaces()135     private void stopIPv6TetheringOnAllInterfaces() {
136         for (IpServer ipServer : mNotifyList) {
137             stopIPv6TetheringOn(ipServer);
138         }
139     }
140 
setUpstreamNetworkState(NetworkState ns)141     private void setUpstreamNetworkState(NetworkState ns) {
142         if (ns == null) {
143             mUpstreamNetworkState = null;
144         } else {
145             // Make a deep copy of the parts we need.
146             mUpstreamNetworkState = new NetworkState(
147                     null,
148                     new LinkProperties(ns.linkProperties),
149                     new NetworkCapabilities(ns.networkCapabilities),
150                     new Network(ns.network),
151                     null,
152                     null);
153         }
154 
155         mLog.log("setUpstreamNetworkState: " + toDebugString(mUpstreamNetworkState));
156     }
157 
updateIPv6TetheringInterfaces()158     private void updateIPv6TetheringInterfaces() {
159         for (IpServer ipServer : mNotifyList) {
160             final LinkProperties lp = getInterfaceIPv6LinkProperties(ipServer);
161             ipServer.sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, 0, 0, lp);
162             break;
163         }
164     }
165 
getInterfaceIPv6LinkProperties(IpServer ipServer)166     private LinkProperties getInterfaceIPv6LinkProperties(IpServer ipServer) {
167         if (ipServer.interfaceType() == ConnectivityManager.TETHERING_BLUETOOTH) {
168             // TODO: Figure out IPv6 support on PAN interfaces.
169             return null;
170         }
171 
172         final Downstream ds = findDownstream(ipServer);
173         if (ds == null) return null;
174 
175         if (ds.mode == IpServer.STATE_LOCAL_ONLY) {
176             // Build a Unique Locally-assigned Prefix configuration.
177             return getUniqueLocalConfig(mUniqueLocalPrefix, ds.subnetId);
178         }
179 
180         // This downstream is in IpServer.STATE_TETHERED mode.
181         if (mUpstreamNetworkState == null || mUpstreamNetworkState.linkProperties == null) {
182             return null;
183         }
184 
185         // NOTE: Here, in future, we would have policies to decide how to divvy
186         // up the available dedicated prefixes among downstream interfaces.
187         // At this time we have no such mechanism--we only support tethering
188         // IPv6 toward the oldest (first requested) active downstream.
189 
190         final Downstream currentActive = mActiveDownstreams.peek();
191         if (currentActive != null && currentActive.ipServer == ipServer) {
192             final LinkProperties lp = getIPv6OnlyLinkProperties(
193                     mUpstreamNetworkState.linkProperties);
194             if (lp.hasIpv6DefaultRoute() && lp.hasGlobalIpv6Address()) {
195                 return lp;
196             }
197         }
198 
199         return null;
200     }
201 
findDownstream(IpServer ipServer)202     Downstream findDownstream(IpServer ipServer) {
203         for (Downstream ds : mActiveDownstreams) {
204             if (ds.ipServer == ipServer) return ds;
205         }
206         return null;
207     }
208 
getIPv6OnlyLinkProperties(LinkProperties lp)209     private static LinkProperties getIPv6OnlyLinkProperties(LinkProperties lp) {
210         final LinkProperties v6only = new LinkProperties();
211         if (lp == null) {
212             return v6only;
213         }
214 
215         // NOTE: At this time we don't copy over any information about any
216         // stacked links. No current stacked link configuration has IPv6.
217 
218         v6only.setInterfaceName(lp.getInterfaceName());
219 
220         v6only.setMtu(lp.getMtu());
221 
222         for (LinkAddress linkAddr : lp.getLinkAddresses()) {
223             if (linkAddr.isGlobalPreferred() && linkAddr.getPrefixLength() == 64) {
224                 v6only.addLinkAddress(linkAddr);
225             }
226         }
227 
228         for (RouteInfo routeInfo : lp.getRoutes()) {
229             final IpPrefix destination = routeInfo.getDestination();
230             if ((destination.getAddress() instanceof Inet6Address) &&
231                 (destination.getPrefixLength() <= 64)) {
232                 v6only.addRoute(routeInfo);
233             }
234         }
235 
236         for (InetAddress dnsServer : lp.getDnsServers()) {
237             if (isIPv6GlobalAddress(dnsServer)) {
238                 // For now we include ULAs.
239                 v6only.addDnsServer(dnsServer);
240             }
241         }
242 
243         v6only.setDomains(lp.getDomains());
244 
245         return v6only;
246     }
247 
248     // TODO: Delete this and switch to LinkAddress#isGlobalPreferred once we
249     // announce our own IPv6 address as DNS server.
isIPv6GlobalAddress(InetAddress ip)250     private static boolean isIPv6GlobalAddress(InetAddress ip) {
251         return (ip instanceof Inet6Address) &&
252                !ip.isAnyLocalAddress() &&
253                !ip.isLoopbackAddress() &&
254                !ip.isLinkLocalAddress() &&
255                !ip.isSiteLocalAddress() &&
256                !ip.isMulticastAddress();
257     }
258 
getUniqueLocalConfig(byte[] ulp, short subnetId)259     private static LinkProperties getUniqueLocalConfig(byte[] ulp, short subnetId) {
260         final LinkProperties lp = new LinkProperties();
261 
262         final IpPrefix local48 = makeUniqueLocalPrefix(ulp, (short) 0, 48);
263         lp.addRoute(new RouteInfo(local48, null, null));
264 
265         final IpPrefix local64 = makeUniqueLocalPrefix(ulp, subnetId, 64);
266         // Because this is a locally-generated ULA, we don't have an upstream
267         // address. But because the downstream IP address management code gets
268         // its prefix from the upstream's IP address, we create a fake one here.
269         lp.addLinkAddress(new LinkAddress(local64.getAddress(), 64));
270 
271         lp.setMtu(NetworkConstants.ETHER_MTU);
272         return lp;
273     }
274 
makeUniqueLocalPrefix(byte[] in6addr, short subnetId, int prefixlen)275     private static IpPrefix makeUniqueLocalPrefix(byte[] in6addr, short subnetId, int prefixlen) {
276         final byte[] bytes = Arrays.copyOf(in6addr, in6addr.length);
277         bytes[7] = (byte) (subnetId >> 8);
278         bytes[8] = (byte) subnetId;
279         return new IpPrefix(bytes, prefixlen);
280     }
281 
282     // Generates a Unique Locally-assigned Prefix:
283     //
284     //     https://tools.ietf.org/html/rfc4193#section-3.1
285     //
286     // The result is a /48 that can be used for local-only communications.
generateUniqueLocalPrefix()287     private static byte[] generateUniqueLocalPrefix() {
288         final byte[] ulp = new byte[6];  // 6 = 48bits / 8bits/byte
289         (new Random()).nextBytes(ulp);
290 
291         final byte[] in6addr = Arrays.copyOf(ulp, NetworkConstants.IPV6_ADDR_LEN);
292         in6addr[0] = (byte) 0xfd;  // fc00::/7 and L=1
293 
294         return in6addr;
295     }
296 
toDebugString(NetworkState ns)297     private static String toDebugString(NetworkState ns) {
298         if (ns == null) {
299             return "NetworkState{null}";
300         }
301         return String.format("NetworkState{%s, %s, %s}",
302                 ns.network,
303                 ns.networkCapabilities,
304                 ns.linkProperties);
305     }
306 
stopIPv6TetheringOn(IpServer ipServer)307     private static void stopIPv6TetheringOn(IpServer ipServer) {
308         ipServer.sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, 0, 0, null);
309     }
310 }
311