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