use of io.netty.handler.codec.dns.DnsResponse in project netty by netty.
the class DnsNameResolverTest method testQueryMx.
@Test
public void testQueryMx() throws Exception {
DnsNameResolver resolver = newResolver().build();
try {
assertThat(resolver.isRecursionDesired(), is(true));
Map<String, Future<AddressedEnvelope<DnsResponse, InetSocketAddress>>> futures = new LinkedHashMap<String, Future<AddressedEnvelope<DnsResponse, InetSocketAddress>>>();
for (String name : DOMAINS) {
if (EXCLUSIONS_QUERY_MX.contains(name)) {
continue;
}
queryMx(resolver, futures, name);
}
for (Entry<String, Future<AddressedEnvelope<DnsResponse, InetSocketAddress>>> e : futures.entrySet()) {
String hostname = e.getKey();
Future<AddressedEnvelope<DnsResponse, InetSocketAddress>> f = e.getValue().awaitUninterruptibly();
DnsResponse response = f.getNow().content();
assertThat(response.code(), is(DnsResponseCode.NOERROR));
final int answerCount = response.count(DnsSection.ANSWER);
final List<DnsRecord> mxList = new ArrayList<DnsRecord>(answerCount);
for (int i = 0; i < answerCount; i++) {
final DnsRecord r = response.recordAt(DnsSection.ANSWER, i);
if (r.type() == DnsRecordType.MX) {
mxList.add(r);
}
}
assertThat(mxList.size(), is(greaterThan(0)));
StringBuilder buf = new StringBuilder();
for (DnsRecord r : mxList) {
ByteBuf recordContent = ((ByteBufHolder) r).content();
buf.append(StringUtil.NEWLINE);
buf.append('\t');
buf.append(r.name());
buf.append(' ');
buf.append(r.type().name());
buf.append(' ');
buf.append(recordContent.readUnsignedShort());
buf.append(' ');
buf.append(DnsNameResolverContext.decodeDomainName(recordContent));
}
logger.info("{} has the following MX records:{}", hostname, buf);
response.release();
}
} finally {
resolver.close();
}
}
use of io.netty.handler.codec.dns.DnsResponse in project netty by netty.
the class DnsNameResolverContext method onResponseAorAAAA.
private void onResponseAorAAAA(DnsRecordType qType, DnsQuestion question, AddressedEnvelope<DnsResponse, InetSocketAddress> envelope, Promise<T> promise) {
// We often get a bunch of CNAMES as well when we asked for A/AAAA.
final DnsResponse response = envelope.content();
final Map<String, String> cnames = buildAliasMap(response);
final int answerCount = response.count(DnsSection.ANSWER);
boolean found = false;
for (int i = 0; i < answerCount; i++) {
final DnsRecord r = response.recordAt(DnsSection.ANSWER, i);
final DnsRecordType type = r.type();
if (type != DnsRecordType.A && type != DnsRecordType.AAAA) {
continue;
}
final String questionName = question.name().toLowerCase(Locale.US);
final String recordName = r.name().toLowerCase(Locale.US);
// Make sure the record is for the questioned domain.
if (!recordName.equals(questionName)) {
// Even if the record's name is not exactly same, it might be an alias defined in the CNAME records.
String resolved = questionName;
do {
resolved = cnames.get(resolved);
if (recordName.equals(resolved)) {
break;
}
} while (resolved != null);
if (resolved == null) {
continue;
}
}
InetAddress resolved = parseAddress(r, hostname);
if (resolved == null) {
continue;
}
if (resolvedEntries == null) {
resolvedEntries = new ArrayList<DnsCacheEntry>(8);
}
final DnsCacheEntry e = new DnsCacheEntry(hostname, resolved);
resolveCache.cache(hostname, additionals, resolved, r.timeToLive(), parent.ch.eventLoop());
resolvedEntries.add(e);
found = true;
// Note that we do not break from the loop here, so we decode/cache all A/AAAA records.
}
if (found) {
return;
}
if (traceEnabled) {
addTrace(envelope.sender(), "no matching " + qType + " record found");
}
// We aked for A/AAAA but we got only CNAME.
if (!cnames.isEmpty()) {
onResponseCNAME(question, envelope, cnames, false, promise);
}
}
use of io.netty.handler.codec.dns.DnsResponse in project netty by netty.
the class DnsNameResolverContext method handleRedirect.
/**
* Handle redirects if needed and returns {@code true} if there was a redirect handled. If {@code true} is returned
* this method took ownership of the {@code promise} otherwise {@code false} is returned.
*/
private boolean handleRedirect(DnsQuestion question, AddressedEnvelope<DnsResponse, InetSocketAddress> envelope, Promise<T> promise) {
final DnsResponse res = envelope.content();
// Check if we have answers, if not this may be an non authority NS and so redirects must be handled.
if (res.count(DnsSection.ANSWER) == 0) {
AuthoritativeNameServerList serverNames = extractAuthoritativeNameServers(question.name(), res);
if (serverNames != null) {
List<InetSocketAddress> nameServers = new ArrayList<InetSocketAddress>(serverNames.size());
int additionalCount = res.count(DnsSection.ADDITIONAL);
for (int i = 0; i < additionalCount; i++) {
final DnsRecord r = res.recordAt(DnsSection.ADDITIONAL, i);
if ((r.type() == DnsRecordType.A && !parent.supportsARecords()) || r.type() == DnsRecordType.AAAA && !parent.supportsAAAARecords()) {
continue;
}
final String recordName = r.name();
AuthoritativeNameServer authoritativeNameServer = serverNames.remove(recordName);
if (authoritativeNameServer == null) {
// Not a server we are interested in.
continue;
}
InetAddress resolved = parseAddress(r, recordName);
if (resolved == null) {
// Could not parse it, move to the next.
continue;
}
nameServers.add(new InetSocketAddress(resolved, parent.dnsRedirectPort(resolved)));
addNameServerToCache(authoritativeNameServer, resolved, r.timeToLive());
}
if (nameServers.isEmpty()) {
promise.tryFailure(new UnknownHostException("Unable to find correct name server for " + hostname));
} else {
// Shuffle as we want to re-distribute the load across name servers.
query(DnsServerAddresses.shuffled(nameServers).stream(), question, promise);
}
return true;
}
}
return false;
}
use of io.netty.handler.codec.dns.DnsResponse in project netty by netty.
the class DnsNameResolverContext method onResponse.
void onResponse(final DnsServerAddressStream nameServerAddrStream, final DnsQuestion question, AddressedEnvelope<DnsResponse, InetSocketAddress> envelope, Promise<T> promise) {
try {
final DnsResponse res = envelope.content();
final DnsResponseCode code = res.code();
if (code == DnsResponseCode.NOERROR) {
if (handleRedirect(question, envelope, promise)) {
// Was a redirect so return here as everything else is handled in handleRedirect(...)
return;
}
final DnsRecordType type = question.type();
if (type == DnsRecordType.A || type == DnsRecordType.AAAA) {
onResponseAorAAAA(type, question, envelope, promise);
} else if (type == DnsRecordType.CNAME) {
onResponseCNAME(question, envelope, promise);
}
return;
}
if (traceEnabled) {
addTrace(envelope.sender(), "response code: " + code + " with " + res.count(DnsSection.ANSWER) + " answer(s) and " + res.count(DnsSection.AUTHORITY) + " authority resource(s)");
}
// Retry with the next server if the server did not tell us that the domain does not exist.
if (code != DnsResponseCode.NXDOMAIN) {
query(nameServerAddrStream, question, promise);
}
} finally {
ReferenceCountUtil.safeRelease(envelope);
}
}
use of io.netty.handler.codec.dns.DnsResponse in project netty by netty.
the class DnsQueryContext method finish.
void finish(AddressedEnvelope<? extends DnsResponse, InetSocketAddress> envelope) {
final DnsResponse res = envelope.content();
if (res.count(DnsSection.QUESTION) != 1) {
logger.warn("Received a DNS response with invalid number of questions: {}", envelope);
return;
}
if (!question().equals(res.recordAt(DnsSection.QUESTION))) {
logger.warn("Received a mismatching DNS response: {}", envelope);
return;
}
setSuccess(envelope);
}
Aggregations