1/*
2 * Copyright (C) 2018 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 com.android.server.connectivity.tethering;
18
19import android.annotation.Nullable;
20import android.net.LinkProperties;
21import android.net.NetworkCapabilities;
22import android.net.NetworkState;
23import android.net.RouteInfo;
24import android.net.util.InterfaceSet;
25
26import java.net.Inet4Address;
27import java.net.Inet6Address;
28import java.net.InetAddress;
29
30/**
31 * @hide
32 */
33public final class TetheringInterfaceUtils {
34    /**
35     * Get upstream interfaces for tethering based on default routes for IPv4/IPv6.
36     * @return null if there is no usable interface, or a set of at least one interface otherwise.
37     */
38    public static @Nullable InterfaceSet getTetheringInterfaces(NetworkState ns) {
39        if (ns == null) {
40            return null;
41        }
42
43        final LinkProperties lp = ns.linkProperties;
44        final String if4 = getInterfaceForDestination(lp, Inet4Address.ANY);
45        final String if6 = getIPv6Interface(ns);
46
47        return (if4 == null && if6 == null) ? null : new InterfaceSet(if4, if6);
48    }
49
50    /**
51     * Get the upstream interface for IPv6 tethering.
52     * @return null if there is no usable interface, or the interface name otherwise.
53     */
54    public static @Nullable String getIPv6Interface(NetworkState ns) {
55        // Broadly speaking:
56        //
57        //     [1] does the upstream have an IPv6 default route?
58        //
59        // and
60        //
61        //     [2] does the upstream have one or more global IPv6 /64s
62        //         dedicated to this device?
63        //
64        // In lieu of Prefix Delegation and other evaluation of whether a
65        // prefix may or may not be dedicated to this device, for now just
66        // check whether the upstream is TRANSPORT_CELLULAR. This works
67        // because "[t]he 3GPP network allocates each default bearer a unique
68        // /64 prefix", per RFC 6459, Section 5.2.
69        final boolean canTether =
70                (ns != null) && (ns.network != null) &&
71                (ns.linkProperties != null) && (ns.networkCapabilities != null) &&
72                // At least one upstream DNS server:
73                ns.linkProperties.hasIPv6DnsServer() &&
74                // Minimal amount of IPv6 provisioning:
75                ns.linkProperties.hasGlobalIPv6Address() &&
76                // Temporary approximation of "dedicated prefix":
77                ns.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR);
78
79        return canTether
80                ? getInterfaceForDestination(ns.linkProperties, Inet6Address.ANY)
81                : null;
82    }
83
84    private static String getInterfaceForDestination(LinkProperties lp, InetAddress dst) {
85        final RouteInfo ri = (lp != null)
86                ? RouteInfo.selectBestRoute(lp.getAllRoutes(), dst)
87                : null;
88        return (ri != null) ? ri.getInterface() : null;
89    }
90}
91