110accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti/*
210accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti * Copyright (C) 2014 The Android Open Source Project
310accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti *
410accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti * Licensed under the Apache License, Version 2.0 (the "License");
510accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti * you may not use this file except in compliance with the License.
610accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti * You may obtain a copy of the License at
710accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti *
810accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti *      http://www.apache.org/licenses/LICENSE-2.0
910accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti *
1010accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti * Unless required by applicable law or agreed to in writing, software
1110accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti * distributed under the License is distributed on an "AS IS" BASIS,
1210accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1310accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti * See the License for the specific language governing permissions and
1410accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti * limitations under the License.
1510accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti */
1610accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti
1710accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colittipackage com.android.server.net;
1810accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti
1910accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colittiimport android.net.LinkAddress;
2010accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colittiimport android.net.LinkProperties;
21c18cbfdf8d40e7a526a088225cb32341e1ea0920Lorenzo Colittiimport android.net.RouteInfo;
2210accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colittiimport android.util.Log;
2310accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti
2493e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colittiimport java.net.InetAddress;
2593e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colittiimport java.util.ArrayList;
2693e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colittiimport java.util.Arrays;
2793e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colittiimport java.util.Collections;
2893e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colittiimport java.util.HashMap;
2993e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colittiimport java.util.HashSet;
3093e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colittiimport java.util.Set;
3193e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti
3210accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti/**
3310accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti * Keeps track of link configuration received from Netlink.
3410accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti *
3510accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti * Instances of this class are expected to be owned by subsystems such as Wi-Fi
3610accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti * or Ethernet that manage one or more network interfaces. Each interface to be
3710accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti * tracked needs its own {@code NetlinkTracker}.
3810accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti *
3910accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti * An instance of this class is constructed by passing in an interface name and
4010accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti * a callback. The owner is then responsible for registering the tracker with
4110accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti * NetworkManagementService. When the class receives update notifications from
4210accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti * the NetworkManagementService notification threads, it applies the update to
4310accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti * its local LinkProperties, and if something has changed, notifies its owner of
4410accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti * the update via the callback.
4510accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti *
4610accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti * The owner can then call {@code getLinkProperties()} in order to find out
4710accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti * what changed. If in the meantime the LinkProperties stored here have changed,
4810accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti * this class will return the current LinkProperties. Because each change
4910accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti * triggers an update callback after the change is made, the owner may get more
5010accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti * callbacks than strictly necessary (some of which may be no-ops), but will not
5110accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti * be out of sync once all callbacks have been processed.
5210accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti *
5310accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti * Threading model:
5410accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti *
5510accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti * - The owner of this class is expected to create it, register it, and call
5610accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti *   getLinkProperties or clearLinkProperties on its thread.
5710accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti * - Most of the methods in the class are inherited from BaseNetworkObserver
5810accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti *   and are called by NetworkManagementService notification threads.
5910accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti * - All accesses to mLinkProperties must be synchronized(this). All the other
6010accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti *   member variables are immutable once the object is constructed.
6110accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti *
6210accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti * This class currently tracks IPv4 and IPv6 addresses. In the future it will
6310accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti * track routes and DNS servers.
6410accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti *
6510accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti * @hide
6610accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti */
6710accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colittipublic class NetlinkTracker extends BaseNetworkObserver {
6810accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti
6910accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti    private final String TAG;
7010accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti
7110accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti    public interface Callback {
7210accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti        public void update();
7310accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti    }
7410accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti
7510accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti    private final String mInterfaceName;
7610accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti    private final Callback mCallback;
7710accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti    private final LinkProperties mLinkProperties;
7893e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti    private DnsServerRepository mDnsServerRepository;
7910accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti
8020ceb903731bc732eb063b1bbee3bac806a5d5efLorenzo Colitti    private static final boolean DBG = false;
8110accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti
8210accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti    public NetlinkTracker(String iface, Callback callback) {
8310accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti        TAG = "NetlinkTracker/" + iface;
8410accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti        mInterfaceName = iface;
8510accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti        mCallback = callback;
8610accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti        mLinkProperties = new LinkProperties();
8710accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti        mLinkProperties.setInterfaceName(mInterfaceName);
8893e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti        mDnsServerRepository = new DnsServerRepository();
8910accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti    }
9010accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti
9110accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti    private void maybeLog(String operation, String iface, LinkAddress address) {
9210accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti        if (DBG) {
9310accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti            Log.d(TAG, operation + ": " + address + " on " + iface +
9410accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti                    " flags " + address.getFlags() + " scope " + address.getScope());
9510accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti        }
9610accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti    }
9710accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti
98c18cbfdf8d40e7a526a088225cb32341e1ea0920Lorenzo Colitti    private void maybeLog(String operation, Object o) {
99c18cbfdf8d40e7a526a088225cb32341e1ea0920Lorenzo Colitti        if (DBG) {
100c18cbfdf8d40e7a526a088225cb32341e1ea0920Lorenzo Colitti            Log.d(TAG, operation + ": " + o.toString());
101c18cbfdf8d40e7a526a088225cb32341e1ea0920Lorenzo Colitti        }
102c18cbfdf8d40e7a526a088225cb32341e1ea0920Lorenzo Colitti    }
103c18cbfdf8d40e7a526a088225cb32341e1ea0920Lorenzo Colitti
10410accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti    @Override
105a3d5948c3764c071211d2943d5407ce0459483a0Lorenzo Colitti    public void interfaceRemoved(String iface) {
106a3d5948c3764c071211d2943d5407ce0459483a0Lorenzo Colitti        maybeLog("interfaceRemoved", iface);
107a3d5948c3764c071211d2943d5407ce0459483a0Lorenzo Colitti        if (mInterfaceName.equals(iface)) {
108a3d5948c3764c071211d2943d5407ce0459483a0Lorenzo Colitti            // Our interface was removed. Clear our LinkProperties and tell our owner that they are
109a3d5948c3764c071211d2943d5407ce0459483a0Lorenzo Colitti            // now empty. Note that from the moment that the interface is removed, any further
110a3d5948c3764c071211d2943d5407ce0459483a0Lorenzo Colitti            // interface-specific messages (e.g., RTM_DELADDR) will not reach us, because the netd
111a3d5948c3764c071211d2943d5407ce0459483a0Lorenzo Colitti            // code that parses them will not be able to resolve the ifindex to an interface name.
112a3d5948c3764c071211d2943d5407ce0459483a0Lorenzo Colitti            clearLinkProperties();
113a3d5948c3764c071211d2943d5407ce0459483a0Lorenzo Colitti            mCallback.update();
114a3d5948c3764c071211d2943d5407ce0459483a0Lorenzo Colitti        }
115a3d5948c3764c071211d2943d5407ce0459483a0Lorenzo Colitti    }
116a3d5948c3764c071211d2943d5407ce0459483a0Lorenzo Colitti
117a3d5948c3764c071211d2943d5407ce0459483a0Lorenzo Colitti    @Override
11810accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti    public void addressUpdated(String iface, LinkAddress address) {
11910accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti        if (mInterfaceName.equals(iface)) {
12010accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti            maybeLog("addressUpdated", iface, address);
12110accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti            boolean changed;
12210accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti            synchronized (this) {
12310accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti                changed = mLinkProperties.addLinkAddress(address);
12410accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti            }
12510accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti            if (changed) {
12610accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti                mCallback.update();
12710accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti            }
12810accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti        }
12910accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti    }
13010accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti
13110accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti    @Override
13210accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti    public void addressRemoved(String iface, LinkAddress address) {
13310accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti        if (mInterfaceName.equals(iface)) {
13410accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti            maybeLog("addressRemoved", iface, address);
13510accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti            boolean changed;
13610accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti            synchronized (this) {
13710accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti                changed = mLinkProperties.removeLinkAddress(address);
13810accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti            }
13910accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti            if (changed) {
14010accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti                mCallback.update();
14110accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti            }
14210accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti        }
14310accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti    }
14410accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti
145c18cbfdf8d40e7a526a088225cb32341e1ea0920Lorenzo Colitti    @Override
146c18cbfdf8d40e7a526a088225cb32341e1ea0920Lorenzo Colitti    public void routeUpdated(RouteInfo route) {
147c18cbfdf8d40e7a526a088225cb32341e1ea0920Lorenzo Colitti        if (mInterfaceName.equals(route.getInterface())) {
148c18cbfdf8d40e7a526a088225cb32341e1ea0920Lorenzo Colitti            maybeLog("routeUpdated", route);
149c18cbfdf8d40e7a526a088225cb32341e1ea0920Lorenzo Colitti            boolean changed;
150c18cbfdf8d40e7a526a088225cb32341e1ea0920Lorenzo Colitti            synchronized (this) {
151c18cbfdf8d40e7a526a088225cb32341e1ea0920Lorenzo Colitti                changed = mLinkProperties.addRoute(route);
152c18cbfdf8d40e7a526a088225cb32341e1ea0920Lorenzo Colitti            }
153c18cbfdf8d40e7a526a088225cb32341e1ea0920Lorenzo Colitti            if (changed) {
154c18cbfdf8d40e7a526a088225cb32341e1ea0920Lorenzo Colitti                mCallback.update();
155c18cbfdf8d40e7a526a088225cb32341e1ea0920Lorenzo Colitti            }
156c18cbfdf8d40e7a526a088225cb32341e1ea0920Lorenzo Colitti        }
157c18cbfdf8d40e7a526a088225cb32341e1ea0920Lorenzo Colitti    }
158c18cbfdf8d40e7a526a088225cb32341e1ea0920Lorenzo Colitti
159c18cbfdf8d40e7a526a088225cb32341e1ea0920Lorenzo Colitti    @Override
160c18cbfdf8d40e7a526a088225cb32341e1ea0920Lorenzo Colitti    public void routeRemoved(RouteInfo route) {
161c18cbfdf8d40e7a526a088225cb32341e1ea0920Lorenzo Colitti        if (mInterfaceName.equals(route.getInterface())) {
162c18cbfdf8d40e7a526a088225cb32341e1ea0920Lorenzo Colitti            maybeLog("routeRemoved", route);
163c18cbfdf8d40e7a526a088225cb32341e1ea0920Lorenzo Colitti            boolean changed;
164c18cbfdf8d40e7a526a088225cb32341e1ea0920Lorenzo Colitti            synchronized (this) {
165c18cbfdf8d40e7a526a088225cb32341e1ea0920Lorenzo Colitti                changed = mLinkProperties.removeRoute(route);
166c18cbfdf8d40e7a526a088225cb32341e1ea0920Lorenzo Colitti            }
167c18cbfdf8d40e7a526a088225cb32341e1ea0920Lorenzo Colitti            if (changed) {
168c18cbfdf8d40e7a526a088225cb32341e1ea0920Lorenzo Colitti                mCallback.update();
169c18cbfdf8d40e7a526a088225cb32341e1ea0920Lorenzo Colitti            }
170c18cbfdf8d40e7a526a088225cb32341e1ea0920Lorenzo Colitti        }
171c18cbfdf8d40e7a526a088225cb32341e1ea0920Lorenzo Colitti    }
172c18cbfdf8d40e7a526a088225cb32341e1ea0920Lorenzo Colitti
17393e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti    @Override
17493e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti    public void interfaceDnsServerInfo(String iface, long lifetime, String[] addresses) {
17593e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti        if (mInterfaceName.equals(iface)) {
17693e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti            maybeLog("interfaceDnsServerInfo", Arrays.toString(addresses));
17793e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti            boolean changed = mDnsServerRepository.addServers(lifetime, addresses);
17893e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti            if (changed) {
17993e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti                synchronized (this) {
18093e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti                    mDnsServerRepository.setDnsServersOn(mLinkProperties);
18193e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti                }
18293e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti                mCallback.update();
18393e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti            }
18493e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti        }
18593e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti    }
18693e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti
18710accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti    /**
18810accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti     * Returns a copy of this object's LinkProperties.
18910accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti     */
19010accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti    public synchronized LinkProperties getLinkProperties() {
19110accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti        return new LinkProperties(mLinkProperties);
19210accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti    }
19310accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti
19410accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti    public synchronized void clearLinkProperties() {
19593e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti        // Clear the repository before clearing mLinkProperties. That way, if a clear() happens
19693e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti        // while interfaceDnsServerInfo() is being called, we'll end up with no DNS servers in
19793e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti        // mLinkProperties, as desired.
19893e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti        mDnsServerRepository = new DnsServerRepository();
19910accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti        mLinkProperties.clear();
20010accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti        mLinkProperties.setInterfaceName(mInterfaceName);
20110accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti    }
20210accbb46e82b3178ff26124041f3ab7d6c1802dLorenzo Colitti}
20393e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti
20493e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti/**
20593e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti * Represents a DNS server entry with an expiry time.
20693e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti *
20793e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti * Implements Comparable so DNS server entries can be sorted by lifetime, longest-lived first.
20893e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti * The ordering of entries with the same lifetime is unspecified, because given two servers with
20993e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti * identical lifetimes, we don't care which one we use, and only comparing the lifetime is much
21093e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti * faster than comparing the IP address as well.
21193e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti *
21293e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti * Note: this class has a natural ordering that is inconsistent with equals.
21393e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti */
21493e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitticlass DnsServerEntry implements Comparable<DnsServerEntry> {
21593e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti    /** The IP address of the DNS server. */
21693e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti    public final InetAddress address;
21793e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti    /** The time until which the DNS server may be used. A Java millisecond time as might be
21893e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti      * returned by currentTimeMillis(). */
21993e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti    public long expiry;
22093e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti
22193e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti    public DnsServerEntry(InetAddress address, long expiry) throws IllegalArgumentException {
22293e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti        this.address = address;
22393e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti        this.expiry = expiry;
22493e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti    }
22593e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti
22693e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti    public int compareTo(DnsServerEntry other) {
22793e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti        return Long.compare(other.expiry, this.expiry);
22893e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti    }
22993e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti}
23093e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti
23193e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti/**
23293e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti * Tracks DNS server updates received from Netlink.
23393e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti *
23493e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti * The network may announce an arbitrary number of DNS servers in Router Advertisements at any
23593e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti * time. Each announcement has a lifetime; when the lifetime expires, the servers should not be used
23693e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti * any more. In this way, the network can gracefully migrate clients from one set of DNS servers to
23793e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti * another. Announcements can both raise and lower the lifetime, and an announcement can expire
23893e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti * servers by announcing them with a lifetime of zero.
23993e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti *
24093e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti * Typically the system will only use a small number (2 or 3; {@code NUM_CURRENT_SERVERS}) of DNS
24193e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti * servers at any given time. These are referred to as the current servers. In case all the
24293e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti * current servers expire, the class also keeps track of a larger (but limited) number of servers
24393e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti * that are promoted to current servers when the current ones expire. In order to minimize updates
24493e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti * to the rest of the system (and potentially expensive cache flushes) this class attempts to keep
24593e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti * the list of current servers constant where possible. More specifically, the list of current
24693e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti * servers is only updated if a new server is learned and there are not yet {@code
24793e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti * NUM_CURRENT_SERVERS} current servers, or if one or more of the current servers expires or is
24893e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti * pushed out of the set. Therefore, the current servers will not necessarily be the ones with the
24993e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti * highest lifetime, but the ones learned first.
25093e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti *
25193e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti * This is by design: if instead the class always preferred the servers with the highest lifetime, a
25293e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti * (misconfigured?) network where two or more routers announce more than {@code NUM_CURRENT_SERVERS}
25393e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti * unique servers would cause persistent oscillations.
25493e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti *
25593e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti * TODO: Currently servers are only expired when a new DNS update is received.
25693e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti * Update them using timers, or possibly on every notification received by NetlinkTracker.
25793e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti *
25893e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti * Threading model: run by NetlinkTracker. Methods are synchronized(this) just in case netlink
25993e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti * notifications are sent by multiple threads. If future threads use alarms to expire, those
26093e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti * alarms must also be synchronized(this).
26193e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti *
26293e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti */
26393e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitticlass DnsServerRepository {
26493e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti
26593e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti    /** How many DNS servers we will use. 3 is suggested by RFC 6106. */
26693e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti    public static final int NUM_CURRENT_SERVERS = 3;
26793e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti
26893e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti    /** How many DNS servers we'll keep track of, in total. */
26993e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti    public static final int NUM_SERVERS = 12;
27093e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti
27193e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti    /** Stores up to {@code NUM_CURRENT_SERVERS} DNS servers we're currently using. */
27293e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti    private Set<InetAddress> mCurrentServers;
27393e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti
27493e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti    public static final String TAG = "DnsServerRepository";
27593e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti
27693e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti    /**
27793e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti     * Stores all the DNS servers we know about, for use when the current servers expire.
27893e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti     * Always sorted in order of decreasing expiry. The elements in this list are also the values
27993e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti     * of mIndex, and may be elements in mCurrentServers.
28093e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti     */
28193e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti    private ArrayList<DnsServerEntry> mAllServers;
28293e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti
28393e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti    /**
28493e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti     * Indexes the servers so we can update their lifetimes more quickly in the common case where
28593e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti     * servers are not being added, but only being refreshed.
28693e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti     */
28793e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti    private HashMap<InetAddress, DnsServerEntry> mIndex;
28893e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti
28993e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti    public DnsServerRepository() {
29093e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti        mCurrentServers = new HashSet();
29193e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti        mAllServers = new ArrayList<DnsServerEntry>(NUM_SERVERS);
29293e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti        mIndex = new HashMap<InetAddress, DnsServerEntry>(NUM_SERVERS);
29393e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti    }
29493e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti
29593e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti    /** Sets the DNS servers of the provided LinkProperties object to the current servers. */
29693e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti    public synchronized void setDnsServersOn(LinkProperties lp) {
29793e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti        lp.setDnsServers(mCurrentServers);
29893e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti    }
29993e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti
30093e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti    /**
30193e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti     * Notifies the class of new DNS server information.
30293e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti     * @param lifetime the time in seconds that the DNS servers are valid.
30393e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti     * @param addresses the string representations of the IP addresses of the DNS servers to use.
30493e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti     */
30593e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti    public synchronized boolean addServers(long lifetime, String[] addresses) {
30693e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti        // The lifetime is actually an unsigned 32-bit number, but Java doesn't have unsigned.
30793e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti        // Technically 0xffffffff (the maximum) is special and means "forever", but 2^32 seconds
30893e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti        // (136 years) is close enough.
30993e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti        long now = System.currentTimeMillis();
31093e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti        long expiry = now + 1000 * lifetime;
31193e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti
31293e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti        // Go through the list of servers. For each one, update the entry if one exists, and
31393e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti        // create one if it doesn't.
31493e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti        for (String addressString : addresses) {
31593e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti            InetAddress address;
31693e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti            try {
31793e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti                address = InetAddress.parseNumericAddress(addressString);
31893e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti            } catch (IllegalArgumentException ex) {
31993e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti                continue;
32093e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti            }
32193e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti
32293e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti            if (!updateExistingEntry(address, expiry)) {
32393e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti                // There was no entry for this server. Create one, unless it's already expired
32493e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti                // (i.e., if the lifetime is zero; it cannot be < 0 because it's unsigned).
32593e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti                if (expiry > now) {
32693e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti                    DnsServerEntry entry = new DnsServerEntry(address, expiry);
32793e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti                    mAllServers.add(entry);
32893e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti                    mIndex.put(address, entry);
32993e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti                }
33093e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti            }
33193e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti        }
33293e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti
33393e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti        // Sort the servers by expiry.
33493e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti        Collections.sort(mAllServers);
33593e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti
33693e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti        // Prune excess entries and update the current server list.
33793e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti        return updateCurrentServers();
33893e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti    }
33993e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti
34093e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti    private synchronized boolean updateExistingEntry(InetAddress address, long expiry) {
34193e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti        DnsServerEntry existing = mIndex.get(address);
34293e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti        if (existing != null) {
34393e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti            existing.expiry = expiry;
34493e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti            return true;
34593e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti        }
34693e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti        return false;
34793e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti    }
34893e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti
34993e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti    private synchronized boolean updateCurrentServers() {
35093e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti        long now = System.currentTimeMillis();
35193e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti        boolean changed = false;
35293e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti
35393e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti        // Prune excess or expired entries.
35493e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti        for (int i = mAllServers.size() - 1; i >= 0; i--) {
35593e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti            if (i >= NUM_SERVERS || mAllServers.get(i).expiry < now) {
35693e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti                DnsServerEntry removed = mAllServers.remove(i);
35793e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti                mIndex.remove(removed.address);
35893e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti                changed |= mCurrentServers.remove(removed.address);
35993e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti            } else {
36093e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti                break;
36193e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti            }
36293e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti        }
36393e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti
36493e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti        // Add servers to the current set, in order of decreasing lifetime, until it has enough.
36593e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti        // Prefer existing servers over new servers in order to minimize updates to the rest of the
36693e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti        // system and avoid persistent oscillations.
36793e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti        for (DnsServerEntry entry : mAllServers) {
36893e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti            if (mCurrentServers.size() < NUM_CURRENT_SERVERS) {
36993e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti                changed |= mCurrentServers.add(entry.address);
37093e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti            } else {
37193e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti                break;
37293e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti            }
37393e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti        }
37493e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti        return changed;
37593e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti    }
37693e6d9db7848a6efe823def6f480c8f4ea74ba85Lorenzo Colitti}
377