下面列出了 io.netty.handler.codec.dns.DefaultDnsQuestion #io.netty.handler.codec.dns.DnsRecord 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
DnsQueryContext(DnsNameResolver parent,
InetSocketAddress nameServerAddr,
DnsQuestion question,
DnsRecord[] additionals,
Promise<AddressedEnvelope<DnsResponse, InetSocketAddress>> promise) {
this.parent = checkNotNull(parent, "parent");
this.nameServerAddr = checkNotNull(nameServerAddr, "nameServerAddr");
this.question = checkNotNull(question, "question");
this.additionals = checkNotNull(additionals, "additionals");
this.promise = checkNotNull(promise, "promise");
recursionDesired = parent.isRecursionDesired();
id = parent.queryContextManager.add(this);
if (parent.isOptResourceEnabled()) {
optResource = new AbstractDnsOptPseudoRrRecord(parent.maxPayloadSize(), 0, 0) {
// We may want to remove this in the future and let the user just specify the opt record in the query.
};
} else {
optResource = null;
}
}
private InetAddress parseAddress(DnsRecord r, String name) {
if (!(r instanceof DnsRawRecord)) {
return null;
}
final ByteBuf content = ((ByteBufHolder) r).content();
final int contentLen = content.readableBytes();
if (contentLen != INADDRSZ4 && contentLen != INADDRSZ6) {
return null;
}
final byte[] addrBytes = new byte[contentLen];
content.getBytes(content.readerIndex(), addrBytes);
try {
return InetAddress.getByAddress(
parent.isDecodeIdn() ? IDN.toUnicode(name) : name, addrBytes);
} catch (UnknownHostException e) {
// Should never reach here.
throw new Error(e);
}
}
private static Map<String, String> buildAliasMap(DnsResponse response) {
final int answerCount = response.count(DnsSection.ANSWER);
Map<String, String> cnames = null;
for (int i = 0; i < answerCount; i ++) {
final DnsRecord r = response.recordAt(DnsSection.ANSWER, i);
final DnsRecordType type = r.type();
if (type != DnsRecordType.CNAME) {
continue;
}
if (!(r instanceof DnsRawRecord)) {
continue;
}
final ByteBuf recordContent = ((ByteBufHolder) r).content();
final String domainName = decodeDomainName(recordContent);
if (domainName == null) {
continue;
}
if (cnames == null) {
cnames = new HashMap<String, String>(min(8, answerCount));
}
cnames.put(r.name().toLowerCase(Locale.US), domainName.toLowerCase(Locale.US));
}
return cnames != null? cnames : Collections.<String, String>emptyMap();
}
final Future<AddressedEnvelope<DnsResponse, InetSocketAddress>> query0(
InetSocketAddress nameServerAddr, DnsQuestion question,
DnsRecord[] additionals,
ChannelPromise writePromise,
Promise<AddressedEnvelope<? extends DnsResponse, InetSocketAddress>> promise) {
assert !writePromise.isVoid();
final Promise<AddressedEnvelope<DnsResponse, InetSocketAddress>> castPromise = cast(
checkNotNull(promise, "promise"));
try {
new DnsQueryContext(this, nameServerAddr, question, additionals, castPromise).query(writePromise);
return castPromise;
} catch (Exception e) {
return castPromise.setFailure(e);
}
}
@Ignore
@Test
public void testSubnetQuery() throws Exception {
EventLoopGroup group = new NioEventLoopGroup(1);
DnsNameResolver resolver = newResolver(group).build();
try {
// Same as:
// # /.bind-9.9.3-edns/bin/dig @ns1.google.com www.google.es +client=157.88.0.0/24
Future<List<InetAddress>> future = resolver.resolveAll("www.google.es",
Collections.<DnsRecord>singleton(
// Suggest max payload size of 1024
// 157.88.0.0 / 24
new DefaultDnsOptEcsRecord(1024, 24,
SocketUtils.addressByName("157.88.0.0").getAddress())));
for (InetAddress address: future.syncUninterruptibly().getNow()) {
System.err.println(address);
}
} finally {
resolver.close();
group.shutdownGracefully(0, 0, TimeUnit.SECONDS);
}
}
@Nullable
public static byte[] extractAddressBytes(DnsRecord record, Logger logger, String logPrefix) {
final DnsRecordType type = record.type();
final ByteBuf content = ((ByteBufHolder) record).content();
final int contentLen = content.readableBytes();
// Skip invalid records.
if (type == DnsRecordType.A) {
if (contentLen != 4) {
warnInvalidRecord(logger, logPrefix, type, content);
return null;
}
} else if (type == DnsRecordType.AAAA) {
if (contentLen != 16) {
warnInvalidRecord(logger, logPrefix, type, content);
return null;
}
} else {
return null;
}
final byte[] addrBytes = new byte[contentLen];
content.getBytes(content.readerIndex(), addrBytes);
return addrBytes;
}
private void configureTimeout(List<DnsQuestion> questions, String logPrefix,
Promise<List<DnsRecord>> result,
List<Promise<List<DnsRecord>>> promises) {
if (queryTimeoutMillis == 0) {
return;
}
eventLoop.schedule(() -> {
if (result.isDone()) {
// Received a response before the query times out.
return;
}
// Return DnsTimeoutException if we can cancel all of the queries.
if (promises.stream().noneMatch(Promise::isDone)) {
result.setFailure(new DnsTimeoutException(
'[' + logPrefix + "] " + questions + " are timed out after " +
queryTimeoutMillis + " milliseconds."));
}
promises.forEach(promise -> promise.cancel(true));
}, queryTimeoutMillis, TimeUnit.MILLISECONDS);
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
if (msg instanceof DatagramDnsQuery) {
final DatagramDnsQuery dnsQuery = (DatagramDnsQuery) msg;
final DnsRecord dnsRecord = dnsQuery.recordAt(DnsSection.QUESTION, 0);
if (dnsRecord.type() == delayType) {
ctx.executor().schedule(() -> {
try {
super.channelRead(ctx, msg);
} catch (Exception ignore) {
}
}, 1, TimeUnit.SECONDS);
return;
}
}
super.channelRead(ctx, msg);
}
@Override
public List<TransportAddress> getSeedAddresses(HostsResolver hostsResolver) {
if (query == null) {
LOGGER.error("DNS query must not be null. Please set '{}'", DISCOVERY_SRV_QUERY);
return Collections.emptyList();
}
try {
List<DnsRecord> records = lookupRecords();
LOGGER.trace("Building dynamic unicast discovery nodes...");
if (records == null || records.size() == 0) {
LOGGER.debug("No nodes found");
} else {
List<TransportAddress> transportAddresses = parseRecords(records);
LOGGER.info("Using dynamic nodes {}", transportAddresses);
return transportAddresses;
}
} catch (InterruptedException | ExecutionException | TimeoutException e) {
LOGGER.error("DNS lookup exception:", e);
}
return Collections.emptyList();
}
@Override
public List<? extends DnsCacheEntry> get(String hostname, DnsRecord[] additionals) {
checkNotNull(hostname, "hostname");
if (!emptyAdditionals(additionals)) {
return Collections.<DnsCacheEntry>emptyList();
}
Entries entries = resolveCache.get(hostname);
return entries == null ? null : entries.get();
}
@Override
public DnsCacheEntry cache(String hostname, DnsRecord[] additionals,
InetAddress address, long originalTtl, EventLoop loop) {
checkNotNull(hostname, "hostname");
checkNotNull(address, "address");
checkNotNull(loop, "loop");
final DefaultDnsCacheEntry e = new DefaultDnsCacheEntry(hostname, address);
if (maxTtl == 0 || !emptyAdditionals(additionals)) {
return e;
}
cache0(e, Math.max(minTtl, (int) Math.min(maxTtl, originalTtl)), loop);
return e;
}
@Override
public DnsCacheEntry cache(String hostname, DnsRecord[] additionals, Throwable cause, EventLoop loop) {
checkNotNull(hostname, "hostname");
checkNotNull(cause, "cause");
checkNotNull(loop, "loop");
final DefaultDnsCacheEntry e = new DefaultDnsCacheEntry(hostname, cause);
if (negativeTtl == 0 || !emptyAdditionals(additionals)) {
return e;
}
cache0(e, negativeTtl, loop);
return e;
}
DnsNameResolverContext(DnsNameResolver parent,
String hostname,
DnsRecord[] additionals,
DnsCache resolveCache,
DnsServerAddressStream nameServerAddrs) {
this.parent = parent;
this.hostname = hostname;
this.additionals = additionals;
this.resolveCache = resolveCache;
this.nameServerAddrs = ObjectUtil.checkNotNull(nameServerAddrs, "nameServerAddrs");
maxAllowedQueries = parent.maxQueriesPerResolve();
resolvedInternetProtocolFamilies = parent.resolvedInternetProtocolFamiliesUnsafe();
allowedQueries = maxAllowedQueries;
}
/**
* Resolves the specified name into an address.
*
* @param inetHost the name to resolve
* @param additionals additional records ({@code OPT})
* @param promise the {@link Promise} which will be fulfilled when the name resolution is finished
*
* @return the address as the result of the resolution
*/
public final Future<InetAddress> resolve(String inetHost, Iterable<DnsRecord> additionals,
Promise<InetAddress> promise) {
checkNotNull(promise, "promise");
DnsRecord[] additionalsArray = toArray(additionals, true);
try {
doResolve(inetHost, additionalsArray, promise, resolveCache);
return promise;
} catch (Exception e) {
return promise.setFailure(e);
}
}
/**
* Resolves the specified host name and port into a list of address.
*
* @param inetHost the name to resolve
* @param additionals additional records ({@code OPT})
* @param promise the {@link Promise} which will be fulfilled when the name resolution is finished
*
* @return the list of the address as the result of the resolution
*/
public final Future<List<InetAddress>> resolveAll(String inetHost, Iterable<DnsRecord> additionals,
Promise<List<InetAddress>> promise) {
checkNotNull(promise, "promise");
DnsRecord[] additionalsArray = toArray(additionals, true);
try {
doResolveAll(inetHost, additionalsArray, promise, resolveCache);
return promise;
} catch (Exception e) {
return promise.setFailure(e);
}
}
/**
* Hook designed for extensibility so one can pass a different cache on each resolution attempt
* instead of using the global one.
*/
protected void doResolve(String inetHost,
DnsRecord[] additionals,
Promise<InetAddress> promise,
DnsCache resolveCache) throws Exception {
if (inetHost == null || inetHost.isEmpty()) {
// If an empty hostname is used we should use "localhost", just like InetAddress.getByName(...) does.
promise.setSuccess(loopbackAddress());
return;
}
final byte[] bytes = NetUtil.createByteArrayFromIpAddressString(inetHost);
if (bytes != null) {
// The inetHost is actually an ipaddress.
promise.setSuccess(InetAddress.getByAddress(bytes));
return;
}
final String hostname = hostname(inetHost);
InetAddress hostsFileEntry = resolveHostsFileEntry(hostname);
if (hostsFileEntry != null) {
promise.setSuccess(hostsFileEntry);
return;
}
if (!doResolveCached(hostname, additionals, promise, resolveCache)) {
doResolveUncached(hostname, additionals, promise, resolveCache);
}
}
private boolean doResolveCached(String hostname,
DnsRecord[] additionals,
Promise<InetAddress> promise,
DnsCache resolveCache) {
final List<? extends DnsCacheEntry> cachedEntries = resolveCache.get(hostname, additionals);
if (cachedEntries == null || cachedEntries.isEmpty()) {
return false;
}
Throwable cause = cachedEntries.get(0).cause();
if (cause == null) {
final int numEntries = cachedEntries.size();
// Find the first entry with the preferred address type.
for (InternetProtocolFamily f : resolvedInternetProtocolFamilies) {
for (int i = 0; i < numEntries; i++) {
final DnsCacheEntry e = cachedEntries.get(i);
if (f.addressType().isInstance(e.address())) {
trySuccess(promise, e.address());
return true;
}
}
}
return false;
} else {
tryFailure(promise, cause);
return true;
}
}
private void doResolveUncached(String hostname,
DnsRecord[] additionals,
Promise<InetAddress> promise,
DnsCache resolveCache) {
new SingleResolverContext(this, hostname, additionals, resolveCache,
dnsServerAddressStreamProvider.nameServerAddressStream(hostname)).resolve(promise);
}
/**
* Hook designed for extensibility so one can pass a different cache on each resolution attempt
* instead of using the global one.
*/
protected void doResolveAll(String inetHost,
DnsRecord[] additionals,
Promise<List<InetAddress>> promise,
DnsCache resolveCache) throws Exception {
if (inetHost == null || inetHost.isEmpty()) {
// If an empty hostname is used we should use "localhost", just like InetAddress.getAllByName(...) does.
promise.setSuccess(Collections.singletonList(loopbackAddress()));
return;
}
final byte[] bytes = NetUtil.createByteArrayFromIpAddressString(inetHost);
if (bytes != null) {
// The unresolvedAddress was created via a String that contains an ipaddress.
promise.setSuccess(Collections.singletonList(InetAddress.getByAddress(bytes)));
return;
}
final String hostname = hostname(inetHost);
InetAddress hostsFileEntry = resolveHostsFileEntry(hostname);
if (hostsFileEntry != null) {
promise.setSuccess(Collections.singletonList(hostsFileEntry));
return;
}
if (!doResolveAllCached(hostname, additionals, promise, resolveCache)) {
doResolveAllUncached(hostname, additionals, promise, resolveCache);
}
}
private boolean doResolveAllCached(String hostname,
DnsRecord[] additionals,
Promise<List<InetAddress>> promise,
DnsCache resolveCache) {
final List<? extends DnsCacheEntry> cachedEntries = resolveCache.get(hostname, additionals);
if (cachedEntries == null || cachedEntries.isEmpty()) {
return false;
}
Throwable cause = cachedEntries.get(0).cause();
if (cause == null) {
List<InetAddress> result = null;
final int numEntries = cachedEntries.size();
for (InternetProtocolFamily f : resolvedInternetProtocolFamilies) {
for (int i = 0; i < numEntries; i++) {
final DnsCacheEntry e = cachedEntries.get(i);
if (f.addressType().isInstance(e.address())) {
if (result == null) {
result = new ArrayList<InetAddress>(numEntries);
}
result.add(e.address());
}
}
}
if (result != null) {
trySuccess(promise, result);
return true;
}
return false;
} else {
tryFailure(promise, cause);
return true;
}
}
private void doResolveAllUncached(String hostname,
DnsRecord[] additionals,
Promise<List<InetAddress>> promise,
DnsCache resolveCache) {
new ListResolverContext(this, hostname, additionals, resolveCache,
dnsServerAddressStreamProvider.nameServerAddressStream(hostname)).resolve(promise);
}
/**
* Sends a DNS query with the specified question with additional records using the specified name server list.
*/
public Future<AddressedEnvelope<DnsResponse, InetSocketAddress>> query(
InetSocketAddress nameServerAddr, DnsQuestion question, Iterable<DnsRecord> additionals) {
return query0(nameServerAddr, question, toArray(additionals, false),
ch.eventLoop().<AddressedEnvelope<? extends DnsResponse, InetSocketAddress>>newPromise());
}
/**
* Sends a DNS query with the specified question with additional records using the specified name server list.
*/
public Future<AddressedEnvelope<DnsResponse, InetSocketAddress>> query(
InetSocketAddress nameServerAddr, DnsQuestion question,
Iterable<DnsRecord> additionals,
Promise<AddressedEnvelope<? extends DnsResponse, InetSocketAddress>> promise) {
return query0(nameServerAddr, question, toArray(additionals, false), promise);
}
@Nullable
@Override
public List<? extends DnsCacheEntry> get(final String hostname, final DnsRecord[] additionals) {
final List<? extends DnsCacheEntry> entries = cache.get(hostname, additionals);
if (entries != null) {
// This means that either:
// 1. there were multiple `discover` calls for the same hostname (on `DefaultDnsClient`), or
// 2. the scheduled lookup happened before the cache expired the entries.
// #1 is ok. #2 means that stale results will be returned until the next TTL scheduled lookup.
LOGGER.debug("Found cached entries for {}: {}", hostname, entries);
}
return entries;
}
@Override
public DnsCacheEntry cache(final String hostname, final DnsRecord[] additionals, final InetAddress address,
final long originalTtl, final EventLoop loop) {
final long currentTime = NANOSECONDS.toSeconds(System.nanoTime());
minExpiryMap.merge(hostname, currentTime + max(initialTtl, originalTtl), Math::min);
return cache.cache(hostname, additionals, address, originalTtl, loop);
}
private void sendQueries(List<DnsQuestion> questions) {
if (isClosing()) {
return;
}
final Future<List<DnsRecord>> future = resolver.sendQueries(questions, logPrefix);
attemptsSoFar++;
future.addListener(this::onDnsRecords);
}
private void onDnsRecords(Future<? super List<DnsRecord>> future) {
if (isClosing()) {
if (future.isSuccess()) {
@SuppressWarnings("unchecked")
final List<DnsRecord> result = (List<DnsRecord>) future.getNow();
result.forEach(ReferenceCountUtil::safeRelease);
}
return;
}
if (!future.isSuccess()) {
// Failed. Try again with the delay given by Backoff.
final long delayMillis = backoff.nextDelayMillis(attemptsSoFar);
logger.warn("{} DNS query failed; retrying in {} ms (attempts so far: {}):",
logPrefix, delayMillis, attemptsSoFar, future.cause());
scheduledFuture = eventLoop.schedule(() -> sendQueries(questions),
delayMillis, TimeUnit.MILLISECONDS);
return;
}
// Reset the counter so that Backoff is reset.
attemptsSoFar = 0;
@SuppressWarnings("unchecked")
final List<DnsRecord> records = (List<DnsRecord>) future.getNow();
final long serverTtl = records.stream().mapToLong(DnsRecord::timeToLive).min().orElse(minTtl);
final int effectiveTtl = (int) Math.max(Math.min(serverTtl, maxTtl), minTtl);
try {
setEndpoints(onDnsRecords(records, effectiveTtl));
} catch (Throwable t) {
logger.warn("{} Failed to process the DNS query result: {}", logPrefix, records, t);
} finally {
records.forEach(ReferenceCountUtil::safeRelease);
scheduledFuture = eventLoop.schedule(() -> sendQueries(questions), effectiveTtl, TimeUnit.SECONDS);
}
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
if (msg instanceof DatagramDnsQuery) {
final DatagramDnsQuery dnsQuery = (DatagramDnsQuery) msg;
final DnsRecord dnsRecord = dnsQuery.recordAt(DnsSection.QUESTION, 0);
if (dnsRecord.type() == A && recordACount++ == 0) {
// Just release the msg and return so that the client request is timed out.
ReferenceCountUtil.safeRelease(msg);
return;
}
}
super.channelRead(ctx, msg);
}
private static DnsRecord newSrvRecord(String hostname, int weight, int port, String target) {
final ByteBuf content = Unpooled.buffer();
content.writeShort(1); // priority unused
content.writeShort(weight);
content.writeShort(port);
DnsNameEncoder.encodeName(target, content);
return new DefaultDnsRawRecord(hostname, SRV, 60, content);
}
private static DnsRecord newMappedAddressRecord(String name, String ipV4Addr) {
final ByteBuf content = Unpooled.buffer();
content.writeZero(10);
content.writeShort(0xFFFF);
content.writeBytes(NetUtil.createByteArrayFromIpAddressString(ipV4Addr));
return new DefaultDnsRawRecord(name, AAAA, 60, content);
}