DnsPinger.java revision b1ef292b3d0c2b4b4c77bb7b442df8e73d1fbb5e
1bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy/* 2bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * Copyright (C) 2011 The Android Open Source Project 3bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * 4bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * Licensed under the Apache License, Version 2.0 (the "License"); 5bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * you may not use this file except in compliance with the License. 6bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * You may obtain a copy of the License at 7bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * 8bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * http://www.apache.org/licenses/LICENSE-2.0 9bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * 10bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * Unless required by applicable law or agreed to in writing, software 11bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * distributed under the License is distributed on an "AS IS" BASIS, 12bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * See the License for the specific language governing permissions and 14bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * limitations under the License. 15bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy */ 16bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 17bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levypackage com.android.server; 18bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 19bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levyimport android.content.ContentResolver; 20bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levyimport android.content.Context; 21bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levyimport android.net.ConnectivityManager; 22bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levyimport android.net.LinkProperties; 23bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levyimport android.os.SystemClock; 24bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levyimport android.util.Slog; 25bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 26bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levyimport java.net.DatagramPacket; 27bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levyimport java.net.DatagramSocket; 28bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levyimport java.net.InetAddress; 29bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levyimport java.net.SocketTimeoutException; 30bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levyimport java.util.Collection; 31bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levyimport java.util.Random; 32bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 33bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy/** 34bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * Performs a simple DNS "ping" by sending a "server status" query packet to the 35bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * DNS server. As long as the server replies, we consider it a success. 36bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * <p> 37bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * We do not use a simple hostname lookup because that could be cached and the 38bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * API may not differentiate between a time out and a failure lookup (which we 39bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * really care about). 40bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * <p> 41b1ef292b3d0c2b4b4c77bb7b442df8e73d1fbb5eIsaac Levy * TODO : More general API. Socket does not bind to specified connection type 42bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * TODO : Choice of DNS query location - current looks up www.android.com 43bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * 44bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * @hide 45bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy */ 46bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levypublic final class DnsPinger { 47bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy private static final boolean V = true; 48bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 49bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy /** Number of bytes for the query */ 50bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy private static final int DNS_QUERY_BASE_SIZE = 33; 51bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 52bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy /** The DNS port */ 53bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy private static final int DNS_PORT = 53; 54bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 55bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy /** Used to generate IDs */ 56bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy private static Random sRandom = new Random(); 57bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 58bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy private ConnectivityManager mConnectivityManager = null; 59bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy private ContentResolver mContentResolver; 60bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy private Context mContext; 61b1ef292b3d0c2b4b4c77bb7b442df8e73d1fbb5eIsaac Levy private int mConnectionType; 62bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 63bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy private String TAG; 64bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 65b1ef292b3d0c2b4b4c77bb7b442df8e73d1fbb5eIsaac Levy 66b1ef292b3d0c2b4b4c77bb7b442df8e73d1fbb5eIsaac Levy /** 67b1ef292b3d0c2b4b4c77bb7b442df8e73d1fbb5eIsaac Levy * @param connectionType The connection type from @link {@link ConnectivityManager} 68b1ef292b3d0c2b4b4c77bb7b442df8e73d1fbb5eIsaac Levy */ 69b1ef292b3d0c2b4b4c77bb7b442df8e73d1fbb5eIsaac Levy public DnsPinger(String TAG, Context context, int connectionType) { 70bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy mContext = context; 71bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy mContentResolver = context.getContentResolver(); 72b1ef292b3d0c2b4b4c77bb7b442df8e73d1fbb5eIsaac Levy mConnectionType = connectionType; 73bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy this.TAG = TAG; 74bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy } 75bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 76bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy /** 77b1ef292b3d0c2b4b4c77bb7b442df8e73d1fbb5eIsaac Levy * @return The first DNS in the link properties of the specified connection type 78bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy */ 79bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy public InetAddress getDns() { 80b1ef292b3d0c2b4b4c77bb7b442df8e73d1fbb5eIsaac Levy LinkProperties linkProperties = getCurLinkProperties(); 81bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy if (linkProperties == null) 82bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy return null; 83bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 84bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy Collection<InetAddress> dnses = linkProperties.getDnses(); 85bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy if (dnses == null || dnses.size() == 0) 86bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy return null; 87bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 88bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy return dnses.iterator().next(); 89bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy } 90bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 91b1ef292b3d0c2b4b4c77bb7b442df8e73d1fbb5eIsaac Levy private LinkProperties getCurLinkProperties() { 92b1ef292b3d0c2b4b4c77bb7b442df8e73d1fbb5eIsaac Levy if (mConnectivityManager == null) { 93b1ef292b3d0c2b4b4c77bb7b442df8e73d1fbb5eIsaac Levy mConnectivityManager = (ConnectivityManager) mContext.getSystemService( 94b1ef292b3d0c2b4b4c77bb7b442df8e73d1fbb5eIsaac Levy Context.CONNECTIVITY_SERVICE); 95b1ef292b3d0c2b4b4c77bb7b442df8e73d1fbb5eIsaac Levy } 96b1ef292b3d0c2b4b4c77bb7b442df8e73d1fbb5eIsaac Levy return mConnectivityManager.getLinkProperties(mConnectionType); 97b1ef292b3d0c2b4b4c77bb7b442df8e73d1fbb5eIsaac Levy } 98b1ef292b3d0c2b4b4c77bb7b442df8e73d1fbb5eIsaac Levy 99bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy /** 100bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * @return time to response. Negative value on error. 101bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy */ 102bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy public long pingDns(InetAddress dnsAddress, int timeout) { 103bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy DatagramSocket socket = null; 104bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy try { 105bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy socket = new DatagramSocket(); 106bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 107bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy // Set some socket properties 108bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy socket.setSoTimeout(timeout); 109bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 110bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy byte[] buf = new byte[DNS_QUERY_BASE_SIZE]; 111bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy fillQuery(buf); 112bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 113bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy // Send the DNS query 114bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 115bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy DatagramPacket packet = new DatagramPacket(buf, 116bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy buf.length, dnsAddress, DNS_PORT); 117bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy long start = SystemClock.elapsedRealtime(); 118bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy socket.send(packet); 119bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 120bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy // Wait for reply (blocks for the above timeout) 121bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy DatagramPacket replyPacket = new DatagramPacket(buf, buf.length); 122bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy socket.receive(replyPacket); 123bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 124bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy // If a timeout occurred, an exception would have been thrown. We 125bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy // got a reply! 126bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy return SystemClock.elapsedRealtime() - start; 127bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 128bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy } catch (SocketTimeoutException e) { 129bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy // Squelch this exception. 130bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy return -1; 131bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy } catch (Exception e) { 132bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy if (V) { 133bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy Slog.v(TAG, "DnsPinger.pingDns got socket exception: ", e); 134bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy } 135bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy return -2; 136bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy } finally { 137bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy if (socket != null) { 138bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy socket.close(); 139bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy } 140bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy } 141bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 142bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy } 143bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 144bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy private static void fillQuery(byte[] buf) { 145bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 146bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy /* 147bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * See RFC2929 (though the bit tables in there are misleading for us. 148bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * For example, the recursion desired bit is the 0th bit for us, but 149bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * looking there it would appear as the 7th bit of the byte 150bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy */ 151bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 152bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy // Make sure it's all zeroed out 153bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy for (int i = 0; i < buf.length; i++) 154bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy buf[i] = 0; 155bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 156bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy // Form a query for www.android.com 157bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 158bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy // [0-1] bytes are an ID, generate random ID for this query 159bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy buf[0] = (byte) sRandom.nextInt(256); 160bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy buf[1] = (byte) sRandom.nextInt(256); 161bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 162bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy // [2-3] bytes are for flags. 163bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy buf[2] = 1; // Recursion desired 164bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 165bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy // [4-5] bytes are for the query count 166bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy buf[5] = 1; // One query 167bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 168bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy // [6-7] [8-9] [10-11] are all counts of other fields we don't use 169bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 170bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy // [12-15] for www 171bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy writeString(buf, 12, "www"); 172bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 173bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy // [16-23] for android 174bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy writeString(buf, 16, "android"); 175bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 176bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy // [24-27] for com 177bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy writeString(buf, 24, "com"); 178bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 179bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy // [29-30] bytes are for QTYPE, set to 1 180bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy buf[30] = 1; 181bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 182bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy // [31-32] bytes are for QCLASS, set to 1 183bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy buf[32] = 1; 184bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy } 185bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 186bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy private static void writeString(byte[] buf, int startPos, String string) { 187bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy int pos = startPos; 188bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 189bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy // Write the length first 190bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy buf[pos++] = (byte) string.length(); 191bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy for (int i = 0; i < string.length(); i++) { 192bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy buf[pos++] = (byte) string.charAt(i); 193bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy } 194bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy } 195bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy} 196