DnsPinger.java revision bc7dfb58bffea133ccf6d94470a26f8d193f4890
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> 41bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * TODO : More general API. Wifi is currently hard coded 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; 61bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 62bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy private String TAG; 63bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 64bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy public DnsPinger(String TAG, Context context) { 65bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy mContext = context; 66bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy mContentResolver = context.getContentResolver(); 67bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy this.TAG = TAG; 68bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy } 69bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 70bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy /** 71bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * Gets the first DNS of the current Wifi AP. 72bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * @return The first DNS of the current AP. 73bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy */ 74bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy public InetAddress getDns() { 75bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy if (mConnectivityManager == null) { 76bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy mConnectivityManager = (ConnectivityManager) mContext.getSystemService( 77bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy Context.CONNECTIVITY_SERVICE); 78bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy } 79bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 80bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy LinkProperties linkProperties = mConnectivityManager.getLinkProperties( 81bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy ConnectivityManager.TYPE_WIFI); 82bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy if (linkProperties == null) 83bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy return null; 84bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 85bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy Collection<InetAddress> dnses = linkProperties.getDnses(); 86bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy if (dnses == null || dnses.size() == 0) 87bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy return null; 88bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 89bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy return dnses.iterator().next(); 90bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy } 91bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 92bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy /** 93bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * @return time to response. Negative value on error. 94bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy */ 95bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy public long pingDns(InetAddress dnsAddress, int timeout) { 96bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy DatagramSocket socket = null; 97bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy try { 98bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy socket = new DatagramSocket(); 99bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 100bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy // Set some socket properties 101bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy socket.setSoTimeout(timeout); 102bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 103bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy byte[] buf = new byte[DNS_QUERY_BASE_SIZE]; 104bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy fillQuery(buf); 105bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 106bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy // Send the DNS query 107bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 108bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy DatagramPacket packet = new DatagramPacket(buf, 109bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy buf.length, dnsAddress, DNS_PORT); 110bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy long start = SystemClock.elapsedRealtime(); 111bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy socket.send(packet); 112bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 113bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy // Wait for reply (blocks for the above timeout) 114bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy DatagramPacket replyPacket = new DatagramPacket(buf, buf.length); 115bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy socket.receive(replyPacket); 116bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 117bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy // If a timeout occurred, an exception would have been thrown. We 118bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy // got a reply! 119bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy return SystemClock.elapsedRealtime() - start; 120bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 121bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy } catch (SocketTimeoutException e) { 122bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy // Squelch this exception. 123bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy return -1; 124bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy } catch (Exception e) { 125bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy if (V) { 126bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy Slog.v(TAG, "DnsPinger.pingDns got socket exception: ", e); 127bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy } 128bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy return -2; 129bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy } finally { 130bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy if (socket != null) { 131bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy socket.close(); 132bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy } 133bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy } 134bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 135bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy } 136bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 137bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy private static void fillQuery(byte[] buf) { 138bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 139bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy /* 140bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * See RFC2929 (though the bit tables in there are misleading for us. 141bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * For example, the recursion desired bit is the 0th bit for us, but 142bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy * looking there it would appear as the 7th bit of the byte 143bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy */ 144bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 145bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy // Make sure it's all zeroed out 146bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy for (int i = 0; i < buf.length; i++) 147bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy buf[i] = 0; 148bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 149bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy // Form a query for www.android.com 150bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 151bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy // [0-1] bytes are an ID, generate random ID for this query 152bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy buf[0] = (byte) sRandom.nextInt(256); 153bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy buf[1] = (byte) sRandom.nextInt(256); 154bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 155bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy // [2-3] bytes are for flags. 156bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy buf[2] = 1; // Recursion desired 157bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 158bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy // [4-5] bytes are for the query count 159bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy buf[5] = 1; // One query 160bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 161bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy // [6-7] [8-9] [10-11] are all counts of other fields we don't use 162bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 163bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy // [12-15] for www 164bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy writeString(buf, 12, "www"); 165bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 166bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy // [16-23] for android 167bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy writeString(buf, 16, "android"); 168bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 169bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy // [24-27] for com 170bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy writeString(buf, 24, "com"); 171bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 172bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy // [29-30] bytes are for QTYPE, set to 1 173bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy buf[30] = 1; 174bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 175bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy // [31-32] bytes are for QCLASS, set to 1 176bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy buf[32] = 1; 177bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy } 178bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 179bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy private static void writeString(byte[] buf, int startPos, String string) { 180bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy int pos = startPos; 181bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy 182bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy // Write the length first 183bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy buf[pos++] = (byte) string.length(); 184bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy for (int i = 0; i < string.length(); i++) { 185bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy buf[pos++] = (byte) string.charAt(i); 186bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy } 187bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy } 188bc7dfb58bffea133ccf6d94470a26f8d193f4890Isaac Levy} 189