package com.sina.util.dnscache.dnsp.impl; import com.sina.util.dnscache.dnsp.DnsConfig; import com.sina.util.dnscache.dnsp.IDnsProvider; import com.sina.util.dnscache.dnsp.impl.UdpDns.UdnDnsClient.UdpDnsInfo; import com.sina.util.dnscache.model.HttpDnsPack; import com.sina.util.dnscache.net.networktype.NetworkManager; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketTimeoutException; public class UdpDns implements IDnsProvider { @Override public HttpDnsPack requestDns(String domain) { try { UdpDnsInfo info = UdnDnsClient.query(DnsConfig.UDPDNS_SERVER_API, domain); if (null != info && info.ips.length > 0) { HttpDnsPack dnsPack = new HttpDnsPack(); String IPArr[] = info.ips; String TTL = String.valueOf(info.ttl); dnsPack.rawResult = "domain : " + domain + "\n" + info.toString(); dnsPack.domain = domain; dnsPack.device_ip = NetworkManager.Util.getLocalIpAddress(); dnsPack.device_sp = NetworkManager.getInstance().getSPID(); dnsPack.dns = new HttpDnsPack.IP[IPArr.length]; for (int i = 0; i < IPArr.length; i++) { dnsPack.dns[i] = new HttpDnsPack.IP(); dnsPack.dns[i].ip = IPArr[i]; dnsPack.dns[i].ttl = TTL; dnsPack.dns[i].priority = "0"; } return dnsPack; } } catch (Exception e) { e.printStackTrace(); } return null; } static class UdnDnsClient { private final static int TIME_OUT = 2000; private final static int PORT = 53; private final static int BUF_SIZE = 1024; static class UdpDnsInfo { public int ttl; public String[] ips; @Override public String toString() { StringBuilder info = new StringBuilder(); info.append("ttl : " + ttl + "\n"); info.append("ipArray : "); if (null != ips) { for (String ip : ips) { info.append(ip + ","); } } else { info.append("null "); } return info.toString(); } } private static UdpDnsInfo query(String dnsServerIP, String domainName) throws SocketTimeoutException, IOException { UdpDnsInfo info = new UdpDnsInfo(); DatagramSocket socket = new DatagramSocket(0); socket.setSoTimeout(TIME_OUT); ByteArrayOutputStream outBuf = new ByteArrayOutputStream(BUF_SIZE); DataOutputStream output = new DataOutputStream(outBuf); encodeDNSMessage(output, domainName); InetAddress host = InetAddress.getByName(dnsServerIP); DatagramPacket request = new DatagramPacket(outBuf.toByteArray(), outBuf.size(), host, PORT); socket.send(request); byte[] inBuf = new byte[BUF_SIZE]; ByteArrayInputStream inBufArray = new ByteArrayInputStream(inBuf); DataInputStream input = new DataInputStream(inBufArray); DatagramPacket response = new DatagramPacket(inBuf, inBuf.length); socket.receive(response); decodeDNSMessage(input, info); socket.close(); return info; } private static void encodeDNSMessage(DataOutputStream output, String domainName) throws IOException { // transaction id output.writeShort(1); // flags output.writeShort(0x100); // number of queries output.writeShort(1); // answer, auth, other output.writeShort(0); output.writeShort(0); output.writeShort(0); encodeDomainName(output, domainName); // query type output.writeShort(1); // query class output.writeShort(1); output.flush(); } private static void encodeDomainName(DataOutputStream output, String domainName) throws IOException { for (String label : domainName.split("\\.")) { output.writeByte((byte) label.length()); output.write(label.getBytes()); } output.writeByte(0); } private static void decodeDNSMessage(DataInputStream input, UdpDnsInfo info) throws IOException { // header // transaction id input.skip(2); // flags input.skip(2); // number of queries input.skip(2); // answer, auth, other short numberOfAnswer = input.readShort(); input.skip(2); input.skip(2); // question record skipDomainName(input); // query type input.skip(2); // query class input.skip(2); // answer records for (int i = 0; i < numberOfAnswer; i++) { input.mark(1); byte ahead = input.readByte(); input.reset(); if ((ahead & 0xc0) == 0xc0) { // compressed name input.skip(2); } else { skipDomainName(input); } // query type short type = input.readShort(); // query class input.skip(2); // ttl int ttl = input.readInt(); info.ttl = ttl; short addrLen = input.readShort(); info.ips = new String[1]; if (type == 1 && addrLen == 4) { int addr = input.readInt(); info.ips[0] = (longToIp(addr)); } else { input.skip(addrLen); } } } private static void skipDomainName(DataInputStream input) throws IOException { byte labelLength = 0; do { labelLength = input.readByte(); input.skip(labelLength); } while (labelLength != 0); } private static String longToIp(long ip) { return ((ip >> 24) & 0xFF) + "." + ((ip >> 16) & 0xFF) + "." + ((ip >> 8) & 0xFF) + "." + (ip & 0xFF); } } @Override public boolean isActivate() { return DnsConfig.enableUdpDns; } @Override public String getServerApi() { return DnsConfig.UDPDNS_SERVER_API; } @Override public int getPriority() { return 7; } }