use of io.netty.handler.codec.dns.DnsRecord 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.DnsRecord in project netty by netty.
the class DnsNameResolver method toArray.
private static DnsRecord[] toArray(Iterable<DnsRecord> additionals, boolean validateType) {
checkNotNull(additionals, "additionals");
if (additionals instanceof Collection) {
Collection<DnsRecord> records = (Collection<DnsRecord>) additionals;
for (DnsRecord r : additionals) {
validateAdditional(r, validateType);
}
return records.toArray(new DnsRecord[records.size()]);
}
Iterator<DnsRecord> additionalsIt = additionals.iterator();
if (!additionalsIt.hasNext()) {
return EMPTY_ADDITIONALS;
}
List<DnsRecord> records = new ArrayList<DnsRecord>();
do {
DnsRecord r = additionalsIt.next();
validateAdditional(r, validateType);
records.add(r);
} while (additionalsIt.hasNext());
return records.toArray(new DnsRecord[records.size()]);
}
use of io.netty.handler.codec.dns.DnsRecord 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.DnsRecord 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.DnsRecord in project netty by netty.
the class DnsQueryContext method query.
void query() {
final DnsQuestion question = question();
final InetSocketAddress nameServerAddr = nameServerAddr();
final DatagramDnsQuery query = new DatagramDnsQuery(null, nameServerAddr, id);
query.setRecursionDesired(recursionDesired);
query.addRecord(DnsSection.QUESTION, question);
for (DnsRecord record : additionals) {
query.addRecord(DnsSection.ADDITIONAL, record);
}
if (optResource != null) {
query.addRecord(DnsSection.ADDITIONAL, optResource);
}
if (logger.isDebugEnabled()) {
logger.debug("{} WRITE: [{}: {}], {}", parent.ch, id, nameServerAddr, question);
}
sendQuery(query);
}
Aggregations