Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@qeesung
Last active June 1, 2019 05:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save qeesung/7b5d5a42e7d8b97597d2baf55a83b43b to your computer and use it in GitHub Desktop.
Save qeesung/7b5d5a42e7d8b97597d2baf55a83b43b to your computer and use it in GitHub Desktop.
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufHolder;
import io.netty.channel.AddressedEnvelope;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.handler.codec.dns.DefaultDnsQuestion;
import io.netty.handler.codec.dns.DefaultDnsRecordDecoder;
import io.netty.handler.codec.dns.DnsRecord;
import io.netty.handler.codec.dns.DnsRecordType;
import io.netty.handler.codec.dns.DnsResponse;
import io.netty.handler.codec.dns.DnsSection;
import io.netty.resolver.dns.DefaultDnsCache;
import io.netty.resolver.dns.DnsNameResolver;
import io.netty.resolver.dns.DnsNameResolverBuilder;
import io.netty.resolver.dns.DnsNameResolverTimeoutException;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;
import io.netty.util.internal.StringUtil;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class DnsClient {
private static EventLoopGroup eventLoop = new NioEventLoopGroup();
private CompletableFuture<String> completableFuture;
private DnsNameResolver resolver;
private static DefaultDnsCache cache = new DefaultDnsCache();
public DnsClient() {
// eventLoop = new NioEventLoopGroup();
}
public CompletableFuture<String> call() throws Exception {
completableFuture = new CompletableFuture<String>();
try {
resolver = new DnsNameResolverBuilder(eventLoop.next())
.queryTimeoutMillis(5000)
.resolveCache(cache)
.maxQueriesPerResolve(5)
.channelType(NioDatagramChannel.class)
.build();
DefaultDnsQuestion defaultDnsQuestion = new DefaultDnsQuestion("gmail.com", DnsRecordType.MX);
InetSocketAddress dnsServerAddr = new InetSocketAddress("ns1.google.com", 53);
Future<AddressedEnvelope<DnsResponse, InetSocketAddress>> future = resolver.query(dnsServerAddr, defaultDnsQuestion);
// AddressEnvelopeListener listener = new AddressEnvelopeListener();
future.addListener(new GenericFutureListener<Future<AddressedEnvelope<DnsResponse, InetSocketAddress>>>() {
@Override
public void operationComplete(Future<AddressedEnvelope<DnsResponse, InetSocketAddress>> future)
throws Exception {
handleOperationComplete(future);
}
});
} catch (Exception e) {
System.out.println(e);
}
return completableFuture;
}
protected synchronized void handleOperationComplete(
Future<AddressedEnvelope<DnsResponse, InetSocketAddress>> future) {
List<MxDnsRecord> dnsRecords;
if (future.isSuccess()) {
try {
dnsRecords = new ArrayList<>();
AddressedEnvelope<DnsResponse, InetSocketAddress> answer = future.get();
DnsResponse content = answer.content();
final int count = content.count(DnsSection.ANSWER);
final List<MxDnsRecord> mxList = new ArrayList(count);
for (int i = 0; i < count; i++) {
final DnsRecord record = content.recordAt(DnsSection.ANSWER, i);
if (record.type() == DnsRecordType.MX) {
mxList.add(new MxDnsRecord(record));
}
}
answer.release();
sortRecordsByPriority(mxList);
StringBuilder stringBuilder = new StringBuilder();
mxList.forEach(m -> stringBuilder.append(m+"\n"));
stringBuilder.append("\n");
completableFuture.complete(stringBuilder.toString());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
else {
try {
AddressedEnvelope<DnsResponse, InetSocketAddress> answer = future.get();
} catch (InterruptedException | ExecutionException e1) {
completableFuture.completeExceptionally(e1.getCause());
}
}
}
private List<MxDnsRecord> sortRecordsByPriority(List<MxDnsRecord> dnsRecords) {
if (dnsRecords != null) {
Collections.sort(dnsRecords, new Comparator<MxDnsRecord>() {
@Override
public int compare(MxDnsRecord o1, MxDnsRecord o2) {
return ((Integer) o1.getPriority()).compareTo(o2.getPriority());
}
});
}
return dnsRecords;
}
public static void main(String[] args) throws Exception {
DnsClient client = new DnsClient();
for (int i = 0; i < 10000; i++) {
CompletableFuture<String> future = client.call();
try {
System.out.println("#"+i+" "+future.get());
} catch (Exception e) {
if (e.getCause() instanceof DnsNameResolverTimeoutException) {
continue;
}
e.printStackTrace();
}
}
}
}
class MxDnsRecord implements DnsRecord {
private String name;
private DnsRecordType recordType;
private int dnsClass;
private long timeToLive;
private int priority;
private String inetHost;
public MxDnsRecord(DnsRecord dnsRecord) {
this.name = dnsRecord.name();
this.recordType = dnsRecord.type();
this.dnsClass = dnsRecord.dnsClass();
this.timeToLive = dnsRecord.timeToLive();
ByteBuf recordContent = ((ByteBufHolder) dnsRecord).content();
this.priority = recordContent.readUnsignedShort();
this.inetHost = DefaultDnsRecordDecoder.decodeName(recordContent);
}
@Override
public String name() {
return name;
}
@Override
public DnsRecordType type() {
return recordType;
}
@Override
public int dnsClass() {
return dnsClass;
}
@Override
public long timeToLive() {
return timeToLive;
}
public int getPriority() {
return priority;
}
public String getInetHost() {
return inetHost;
}
public String toString() {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(StringUtil.NEWLINE);
stringBuilder.append('\t');
stringBuilder.append(name());
stringBuilder.append(' ');
stringBuilder.append(type().name());
stringBuilder.append(' ');
stringBuilder.append(getPriority());
stringBuilder.append(' ');
stringBuilder.append(getInetHost());
stringBuilder.append("\n");
return inetHost;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment