package fq.router2.utils;
import net.sf.ivmaidns.dns.DNSConnection;
import net.sf.ivmaidns.dns.DNSMsgHeader;
import net.sf.ivmaidns.dns.DNSName;
import net.sf.ivmaidns.dns.DNSRecord;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.Inet4Address;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
public class DnsUtils {
private final static InetSocketAddress[] DNS_SERVERS = new InetSocketAddress[]{
new InetSocketAddress("8.8.8.8", 53),
new InetSocketAddress("208.67.222.222", 443),
new InetSocketAddress("208.67.220.220", 443),
new InetSocketAddress("199.91.73.222", 3389),
new InetSocketAddress("87.118.100.175", 110),
new InetSocketAddress("87.118.85.241", 110),
new InetSocketAddress("77.109.139.29", 110),
new InetSocketAddress("77.109.138.45", 110)
};
private final static HashSet<String> WRONG_ANSWERS = new HashSet<String>() {{
for (String ip : new String[]{
"4.36.66.178",
"8.7.198.45",
"37.61.54.158",
"46.82.174.68",
"59.24.3.173",
"64.33.88.161",
"64.33.99.47",
"64.66.163.251",
"65.104.202.252",
"65.160.219.113",
"66.45.252.237",
"72.14.205.99",
"72.14.205.104",
"78.16.49.15",
"93.46.8.89",
"128.121.126.139",
"159.106.121.75",
"169.132.13.103",
"192.67.198.6",
"202.106.1.2",
"202.181.7.85",
"203.161.230.171",
"203.98.7.65",
"207.12.88.98",
"208.56.31.43",
"209.36.73.33",
"209.145.54.50",
"209.220.30.174",
"211.94.66.147",
"213.169.251.35",
"216.221.188.182",
"216.234.179.13",
"243.185.187.39",
"74.125.127.102",
"74.125.155.102",
"74.125.39.113",
"74.125.39.102",
"209.85.229.138"
}) {
add(ip);
}
}};
public static List<Inet4Address> resolveA(String domain) throws Exception {
for (InetSocketAddress dnsServer : DNS_SERVERS) {
try {
return resolveA(domain, dnsServer);
} catch (Exception e) {
LogUtils.e("failed to resolve: " + domain, e);
}
}
return new ArrayList<Inet4Address>();
}
public static List<Inet4Address> resolveA(String domain, InetSocketAddress dnsServer) throws Exception {
DNSMsgHeader qHeader = DNSMsgHeader.construct(
DNSMsgHeader.QUERY, true, 1, 0, 0, 0, false);
DNSRecord[] records = new DNSRecord[1];
records[0] = new DNSRecord(new DNSName(domain, null), DNSRecord.A, DNSRecord.IN);
byte[] query = DNSConnection.encode(qHeader, records);
try {
return resolveAOverUdp(dnsServer, query);
} catch (Exception e) {
LogUtils.e("failed to resolve over udp", e);
return resolveAOverTcp(dnsServer, query);
}
}
private static List<Inet4Address> resolveAOverTcp(InetSocketAddress dnsServer, byte[] query) throws Exception {
DNSConnection dnsConnection = new DNSConnection();
try {
dnsConnection.open(dnsServer.getAddress());
dnsConnection.send(query);
return toIps(dnsConnection.receive(true));
} finally {
dnsConnection.close();
}
}
private static List<Inet4Address> resolveAOverUdp(InetSocketAddress dnsServer, byte[] query) throws Exception {
DatagramSocket datagramSocket = new DatagramSocket();
datagramSocket.setSoTimeout(1000);
try {
datagramSocket.connect(dnsServer.getAddress(), dnsServer.getPort());
datagramSocket.send(new DatagramPacket(query, query.length));
while (true) {
List<Inet4Address> ips = readIps(datagramSocket);
if (!isWrong(ips)) {
return ips;
}
}
} finally {
datagramSocket.close();
}
}
private static List<Inet4Address> readIps(DatagramSocket datagramSocket) throws Exception {
DatagramPacket packet = new DatagramPacket(new byte[2048], 2048);
datagramSocket.receive(packet);
return toIps(packet.getData());
}
private static List<Inet4Address> toIps(byte[] buffer) {
DNSRecord[] records = DNSConnection.decode(buffer);
List<Inet4Address> ips = new ArrayList<Inet4Address>();
for (DNSRecord record : records) {
if (DNSRecord.A == record.getRType()) {
if (record.getRData().length > 0) {
ips.add((Inet4Address) record.getRData()[0]);
}
}
}
return ips;
}
private static boolean isWrong(List<Inet4Address> ips) {
if (ips.isEmpty()) {
return true;
}
for (Inet4Address ip : ips) {
if (WRONG_ANSWERS.contains(ip.getHostAddress())) {
return true;
}
}
return false;
}
public static String resolveTXT(String domain) throws Exception {
for (InetSocketAddress dnsServer : DNS_SERVERS) {
try {
return resolveTXT(domain, dnsServer);
} catch (Exception e) {
LogUtils.e("failed to resolve: " + domain, e);
}
}
return "";
}
public static String resolveTXT(String domain, InetSocketAddress dnsServer) throws Exception {
DNSMsgHeader qHeader = DNSMsgHeader.construct(
DNSMsgHeader.QUERY, true, 1, 0, 0, 0, false);
DNSRecord[] records = new DNSRecord[1];
records[0] = new DNSRecord(new DNSName(domain, null), DNSRecord.TXT, DNSRecord.IN);
byte[] request = DNSConnection.encode(qHeader, records);
try {
return resolveTXTOverUdp(dnsServer, request);
} catch (Exception e) {
LogUtils.e("failed to resolve txt over udp at " + dnsServer, e);
return resolveTXTOverTcp(dnsServer, request);
}
}
private static String resolveTXTOverUdp(InetSocketAddress dnsServer, byte[] query) throws Exception {
DatagramSocket datagramSocket = new DatagramSocket();
datagramSocket.setSoTimeout(2000);
try {
datagramSocket.connect(dnsServer.getAddress(), dnsServer.getPort());
datagramSocket.send(new DatagramPacket(query, query.length));
DatagramPacket packet = new DatagramPacket(new byte[2048], 2048);
datagramSocket.receive(packet);
return toTXT(packet.getData());
} finally {
datagramSocket.close();
}
}
private static String resolveTXTOverTcp(InetSocketAddress dnsServer, byte[] request) throws IOException {
DNSConnection connection = new DNSConnection();
try {
connection.open(dnsServer.getAddress());
connection.send(request);
return toTXT(connection.receive(true));
} finally {
connection.close();
}
}
private static String toTXT(byte[] buffer) {
DNSRecord[] records = DNSConnection.decode(buffer);
for (DNSRecord record : records) {
if (DNSRecord.TXT == record.getRType() && record.getRData().length > 0) {
return (String) record.getRData()[0];
}
}
throw new RuntimeException("not found");
}
}