/** * @param ip, like "192.168.1.1" * @return the complete DNS record for that IP. */ @Converter public static Record toRecord(String ip) throws IOException { Resolver res = new ExtendedResolver(); Name name = ReverseMap.fromAddress(ip); int type = Type.PTR; int dclass = DClass.IN; Record rec = Record.newRecord(name, type, dclass); Message query = Message.newQuery(rec); Message response = res.send(query); Record[] answers = response.getSectionArray(Section.ANSWER); if (answers.length == 0) { return null; } else { return answers[0]; } }
private String resolveSrvByName(Resolver resolver, String name) { try { Lookup lookup = new Lookup(name, SRV); if (resolver != null) { lookup.setResolver(resolver); } Record[] records = lookup.run(); if (records == null) { return null; } return of(records) .filter(it -> it instanceof SRVRecord) .map(srv -> resolveHostByName(resolver, ((SRVRecord) srv).getTarget()) + ":" + ((SRVRecord) srv).getPort()) .distinct() .collect(joining(",")); } catch (TextParseException e) { log.warn("unable to resolve using SRV record " + name, e); return null; } }
private String resolveHostByName(Resolver resolver, Name target) { Lookup lookup = new Lookup(target, A); if (resolver != null) { lookup.setResolver(resolver); } Record[] records = lookup.run(); Optional<InetAddress> address = of(records) .filter(it -> it instanceof ARecord) .map(a -> ((ARecord) a).getAddress()) .findFirst(); if (address.isPresent()) { return address.get().getHostAddress(); } else { log.warn("unknown name: " + target); return null; } }
/** * Instantiate a set of default DNS <code>Resolver</code> by the provided Server. In case of * DNSSEC validation is needed, <code>ValidatingResolver</code> will be instantiated. * * @param dnsSec <code>true</code> iff DNSSEC is enabled * @param trustAnchor Public cryptographic to validate against * * @return A list of default <code>Resolver</code> * * @throws ConfigurationException * Exceptional circumstances in which no default <code>Resolver</code> can be created. */ public static Map<String, Resolver> getResolvers(boolean dnsSec, String trustAnchor) throws ConfigurationException { String[] servers = ResolverConfig.getCurrentConfig().servers(); Map<String, Resolver> resolvers = new LinkedHashMap<>(servers.length); for (String server : servers) { Resolver resolver = instantiateResolver(dnsSec, trustAnchor, server); if (resolver != null) { resolvers.put(server, resolver); } } if (resolvers.isEmpty()) { throw new ConfigurationException("Unable to retrieve Default Resolvers"); } return resolvers; }
/** * Private helper to instantiate a DNS <code>Resolver</code> by the provided Server. * * @param dnsSec <code>true</code> iff DNSSEC is enabled * @param trustAnchor Public cryptographic to validate against * @param server Server to use as DNS resolver * * @return <code>null</code> in case the <code>Resolver</code> cannot be instantiated */ private static Resolver instantiateResolver(boolean dnsSec, String trustAnchor, String server) { try { Resolver resolver = new SimpleResolver(server); if (!dnsSec) { return resolver; } ValidatingResolver validating = new ValidatingResolver(resolver); validating.loadTrustAnchors(new ByteArrayInputStream(trustAnchor.getBytes(StandardCharsets.UTF_8))); return validating; } catch (IOException e) { return null; } }
/** * Private helper to retrieve a set of one or more instances of <code>Resolver</code> to carry * out the lookup. * * @param secValidation <code>true</code> iff DNSSEC validation id needed * @return Instance(s) of <code>Resolver</code> * * @throws ConfigurationException * In case instance(s) of <code>Resolver</code> cannot he instantiated. */ private Map<String, Resolver> retrieveResolvers(boolean secValidation) throws ConfigurationException { Map<String, Resolver> resolvers = new LinkedHashMap<>(); for(InetAddress dnsServer: this.dnsServers) { if (dnsServer != null && (!dnsServer.getHostAddress().isEmpty() || !dnsServer.getCanonicalHostName().isEmpty())) { String server = ((dnsServer.getHostAddress().isEmpty()) ? dnsServer.getCanonicalHostName() : dnsServer.getHostAddress()); resolvers.put(server, DnsUtil.getResolver(secValidation, this.trustAnchorDefault, server)); } else { resolvers.putAll(DnsUtil.getResolvers(secValidation, this.trustAnchorDefault)); } } return resolvers; }
private void init() { if (mInitialized) return; else mInitialized = true; try { // configure the resolvers, starting with the default ones (based on the current network connection) Resolver defaultResolver = Lookup.getDefaultResolver(); // use Google's public DNS services Resolver googleFirstResolver = new SimpleResolver("8.8.8.8"); Resolver googleSecondResolver = new SimpleResolver("8.8.4.4"); // also try using Amazon Resolver amazonResolver = new SimpleResolver("205.251.198.30"); Lookup.setDefaultResolver(new ExtendedResolver(new Resolver[]{ googleFirstResolver, googleSecondResolver, amazonResolver, defaultResolver })); } catch (UnknownHostException e) { Log.w(TAG, "Couldn't initialize custom resolvers"); } }
private Resolver createResolver(String[] targets) throws IOException { // Shuffle input targets so we don't query the same all the time ArrayList<String> targetsList = new ArrayList<String>(); for (String target : targets) targetsList.add(target); Collections.shuffle(targetsList); Resolver resolver = new ExtendedResolver(targetsList.toArray(new String[targetsList.size()])); resolver.setTimeout(RECURSIVE_QUERY_TIMEOUT); if (port != null) resolver.setPort(port); if (tcp != null) resolver.setTCP(tcp); if (ignoreTruncation != null) resolver.setIgnoreTruncation(ignoreTruncation); if (ednsLevel != null) { if (ednsPayloadSize != null && ednsFlags != null && ednsOptions != null) resolver.setEDNS(ednsLevel, ednsPayloadSize, ednsFlags, ednsOptions); else resolver.setEDNS(ednsLevel); } if (key != null) resolver.setTSIGKey(key); return resolver; }
@Before public void setUp() throws Exception { lookupFactory = mock(LookupFactory.class); resolver = new XBillDnsSrvResolver(lookupFactory); xbillResolver = mock(Resolver.class); }
public boolean sendAdd() throws TextParseException, IOException { boolean rc = false; Resolver res = createResolver(); String revIp = buildReverseIpString(); Name owner = new Name(revIp.toString()); PTRRecord ptr = new PTRRecord(owner, DClass.IN, ttl, new Name(fqdn)); Name _zone = buildZoneName(revIp); Update update = new Update(_zone); update.delete(owner); update.add(ptr); if (log.isDebugEnabled()) { log.debug("Sending reverse DDNS update (replace) to server=" + server + ":\n" + update.toString()); } else if (log.isInfoEnabled()) { log.info("Sending reverse DDNS update (replace): " + ptr.toString()); } Message response = res.send(update); if (response.getRcode() == Rcode.NOERROR) { log.info("Reverse DDNS update (replace) succeeded: " + ptr.toString()); rc = true; } else { log.error("Reverse DDNS update (replace) failed (rcode=" + Rcode.string(response.getRcode()) + "): " + ptr.toString()); } return rc; }
public boolean sendDelete() throws TextParseException, IOException { boolean rc = false; Resolver res = createResolver(); String revIp = buildReverseIpString(); Name owner = new Name(revIp); PTRRecord ptr = new PTRRecord(owner, DClass.IN, 0, new Name(fqdn)); Name _zone = buildZoneName(revIp); Update update = new Update(_zone); update.delete(ptr); if (log.isDebugEnabled()) { log.debug("Sending reverse DDNS update (delete) to server=" + server + ":\n" + update.toString()); } else if (log.isInfoEnabled()) { log.info("Sending reverse DDNS update (delete): " + ptr.toString()); } Message response = res.send(update); if (response.getRcode() == Rcode.NOERROR) { log.info("Reverse DDNS update (delete) succeeded: " + ptr.toString()); rc = true; } else { log.error("Reverse DDNS update (delete) failed (rcode=" + Rcode.string(response.getRcode()) + "): " + ptr.toString()); } return rc; }
/** * Creates a new instance of this class. * * @param headResolver The resolver to which queries for DS, DNSKEY and * referring CNAME records are sent. */ public ValidatingResolver(Resolver headResolver) { this.headResolver = headResolver; headResolver.setEDNS(0, 0, ExtendedFlags.DO, null); headResolver.setIgnoreTruncation(false); this.keyCache = new KeyCache(); this.valUtils = new ValUtils(); this.n3valUtils = new NSEC3ValUtils(); this.trustAnchors = new TrustAnchorStore(); }
public DnsRequest(Message resp, Message req, Resolver res, long duration) { this.response = resp; this.request = req; this.resolver = res; this.duration = duration; }
public Resolver getResolver() { return resolver; }
public Resolver getResolver () { return this.resolver; }
public void setResolver ( Resolver resolver ) { this.resolver = resolver; }
public Resolver getValResolver () { return this.valResolver; }
public void setValResolver ( Resolver resolver ) { this.valResolver = resolver; }
/** * Validate the DNSSEC trust chain against the provided domain name (i.e. <code>Fqdn</code>). * * @param name A <code>Fqdn</code> representing the validating domain * @param resolver A DNS <code>Resovler</code> to be used in this validation * @param rType An integer representing the record type * * @return <code>true</code> iff the DNSSEC is valid * * @throws LookupException * Containing the specific <code>StatusCode</code> defining the error that has been raised. */ public static boolean checkDnsSec(Fqdn name, Resolver resolver, int rType) throws LookupException { try { ValidatingResolver validating = (ValidatingResolver) resolver; Record toValidate = Record.newRecord(Name.fromConstantString(name.fqdn()), rType, DClass.IN); Message dnsResponse = validating.send(Message.newQuery(toValidate)); RRset[] rrSets = dnsResponse.getSectionRRsets(Section.ADDITIONAL); StringBuilder reason = new StringBuilder(""); for (RRset rrset : rrSets) { if (rrset.getName().equals(Name.root) && rrset.getType() == Type.TXT && rrset.getDClass() == ValidatingResolver.VALIDATION_REASON_QCLASS) { reason.append(TextRecord.build((TXTRecord) rrset.first()).getRData()); } } StatusCode outcome = StatusCode.SUCCESSFUL_OPERATION; if (dnsResponse.getRcode() == Rcode.SERVFAIL) { if (reason.toString().toLowerCase().contains(CHAIN_OF_TRUST) || reason.toString().toLowerCase().contains(INSECURE)) { outcome = StatusCode.RESOURCE_INSECURE_ERROR; } else if (reason.toString().toLowerCase().contains(NO_DATA)) { outcome = StatusCode.NETWORK_ERROR; } else if (reason.toString().toLowerCase().contains(NO_SIGNATURE) || reason.toString().toLowerCase().contains(MISSING_KEY)) { outcome = StatusCode.RESOLUTION_NAME_ERROR; } } else if (dnsResponse.getRcode() == Rcode.NXDOMAIN) { if (reason.toString().toLowerCase().contains(NSEC3_NO_DS)) { outcome = StatusCode.RESOURCE_INSECURE_ERROR; } else { outcome = StatusCode.RESOLUTION_NAME_ERROR; } } else if (dnsResponse.getRcode() == Rcode.NOERROR && !dnsResponse.getHeader().getFlag(Flags.AD)) { outcome = StatusCode.RESOURCE_INSECURE_ERROR; } if (outcome != StatusCode.SUCCESSFUL_OPERATION) { throw ExceptionsUtil.build(outcome, "DNSSEC Validation Failed", new LinkedHashMap<String, StatusCode>()); } } catch (IOException e) { // it might be a transient error network: retry with next Resolver return false; } return true; }
@Override public boolean isDnsSecValid(Fqdn name) throws LookupException, ConfigurationException { try { ValidatorUtil.isValidDomainName(name); } catch(IllegalArgumentException exception) { throw new LookupException(StatusCode.ILLEGAL_FQDN, name.fqdn()); } validatedConf(); if (name == null || name.fqdn().isEmpty()) { name = new Fqdn(this.dnsSecDomain); } Map<String, Resolver> resolvers = retrieveResolvers(true); Iterator<String> itrResolvers = resolvers.keySet().iterator(); boolean validated = false; String server = null; do { server = itrResolvers.next(); statusChange(FormattingUtil.server(server)); statusChange(FormattingUtil.query(name, "", "SOA")); try { validated = DnsUtil.checkDnsSec(name, resolvers.get(server), Type.SOA); if (validated) { statusChange(FormattingUtil.response(FormattingUtil.authenticData(name.fqdn()))); } else { statusChange(FormattingUtil.response(FormattingUtil.networkError(name.fqdn()))); } } catch (LookupException le) { if (le.dnsError() == StatusCode.RESOURCE_LOOKUP_ERROR) { statusChange(FormattingUtil.response(FormattingUtil.unableToResolve(name.fqdn()))); } else { statusChange(FormattingUtil.response(FormattingUtil.unableToValidate(name.fqdn()))); } if (le.dnsError() == StatusCode.RESOURCE_INSECURE_ERROR) { throw ExceptionsUtil.build(StatusCode.DNSSEC_STATUS_ERROR, "DNSSEC Validation Failed", new LinkedHashMap<String, StatusCode>()); } throw le; } } while (itrResolvers.hasNext() && !validated); return validated; }
/** * Retrieve a set of Service Types from the browsing domain. * * @param browsingDomain <code>Fqdn</code> representing the browsing domain * @param secValidation <code>true</code> in case secure browsing is needed * * @return A set of <code>String</code> identifying the retrieved Service Types. * * @throws LookupException * In case of any unrecoverable error during the lookup process. * * @throws ConfigurationException * In case of wrong/faulty static and/or runtime configuration. */ public Set<String> serviceTypes(Fqdn browsingDomain, boolean secValidation) throws LookupException, ConfigurationException { statusChange(FormattingUtil.info((secValidation?"Secure Resolving mode":"Insecure Resolving mode"))); Map<String, Resolver> resolvers = retrieveResolvers(false); Map<String, Resolver> valResolvers = retrieveResolvers(true); RecordsContainer set = new RecordsContainer(); errorsTrace.get().clear(); Iterator<String> itrResolvers = resolvers.keySet().iterator(); LookupContext ctx = DnsUtil.context(browsingDomain, Constants.SERVICES_DNS_SD_UDP, "", "", Type.PTR, secValidation); String server = null; do { server = itrResolvers.next(); Resolver resolver = resolvers.get(server); ctx.setResolver(resolver); Resolver valResolver = valResolvers.get(server); ctx.setValResolver(valResolver); statusChange(FormattingUtil.server(server)); try { Record[] records = lookup(ctx); set.getLabels().addAll(DnsUtil.extractNamesFromRecords(records)); statusChange(StatusChangeEvent.build(browsingDomain.fqdn(), Type.string(Type.PTR), StatusChangeEvent.castedArray(records))); } catch (LookupException le) { if (le.dnsError().equals(StatusCode.NETWORK_ERROR) && !itrResolvers.hasNext()) { throw le; } else if (le.dnsError().equals(StatusCode.SERVER_ERROR) || le.dnsError().equals(StatusCode.RESOURCE_INSECURE_ERROR)) { throw le; } else { errorsTrace.get().put( ExceptionsUtil.traceKey(resolver, browsingDomain.fqdn(), "Retrieving-Types"), le.dnsError()); } } } while (itrResolvers.hasNext() && set.getLabels().isEmpty()); statusChange(FormattingUtil.answer()); return set.getLabels(); }
/** * Retrieve a set of Text Resource Records from the browsing domain for the specified * <i>label</i>. * * @param browsingDomain <code>Fqdn</code> representing the browsing domain * @param label A label to be looked up * @param secValidation <code>true</code> in case secure browsing is needed * * @return A set of <code>String</code> identifying the retrieved Text records * * @throws LookupException * In case of any unrecoverable error during the lookup process. * @throws ConfigurationException * In case of wrong/faulty static and/or runtime configuration. */ public Set<TextRecord> serviceTexts(Fqdn browsingDomain, String label, boolean secValidation) throws LookupException, ConfigurationException { statusChange(FormattingUtil.info((secValidation?"Secure Resolving mode":"Insecure Resolving mode"))); Map<String, Resolver> resolvers = retrieveResolvers(false); Map<String, Resolver> valResolvers = retrieveResolvers(true); RecordsContainer set = new RecordsContainer(); errorsTrace.get().clear(); Iterator<String> itrResolvers = resolvers.keySet().iterator(); LookupContext ctx = DnsUtil.context(browsingDomain, label, label, "", Type.TXT, secValidation); String server = null; do { server = itrResolvers.next(); Resolver resolver = resolvers.get(server); ctx.setResolver(resolver); Resolver valResolver = valResolvers.get(server); ctx.setValResolver(valResolver); statusChange(FormattingUtil.server(server)); try { Record[] records = lookup(ctx); parseRecords(records, set, RrHolderType.OTHER); statusChange(StatusChangeEvent.build(browsingDomain.fqdnWithPrefix(label), "", StatusChangeEvent.castedList(set.getTexts()))); } catch (LookupException le) { if (le.dnsError().equals(StatusCode.NETWORK_ERROR) && !itrResolvers.hasNext()) { throw le; } else if (le.dnsError().equals(StatusCode.SERVER_ERROR) || le.dnsError().equals(StatusCode.RESOURCE_INSECURE_ERROR)) { throw le; } else { errorsTrace.get().put( ExceptionsUtil.traceKey(resolver, browsingDomain.fqdnWithPrefix(label), "Retrieving-Texts"), le.dnsError()); } } } while (itrResolvers.hasNext() && set.getTexts().isEmpty()); statusChange(FormattingUtil.answer()); return set.getTexts(); }
/** * * Retrieve a set of TLSA Records from the browsing domain, according to the * specified <i>options</i>. * * @param browsingDomain <code>Fqdn</code> representing the browsing domain * @param tlsaPrefix A <code>String</code> defining the TLSA prefix as couple * <code>port:protocol</code> * @param secValidation <code>true</code> in case secure browsing is needed * * @return A set of <code>String</code> identifying the retrieve Service records. * * @throws LookupException * In case of any unrecoverable error during the lookup process. * @throws ConfigurationException * In case of wrong/faulty static and/or runtime configuration. */ public Set<CertRecord> tlsaRecords(Fqdn browsingDomain, DnsCertPrefix tlsaPrefix, boolean secValidation) throws LookupException, ConfigurationException { statusChange(FormattingUtil.info((secValidation?"Secure Resolving mode":"Insecure Resolving mode"))); Map<String, Resolver> resolvers = retrieveResolvers(false); Map<String, Resolver> valResolvers = retrieveResolvers(true); Set<CertRecord> tlsaDiscoveryRecords = new TreeSet<>(); errorsTrace.get().clear(); Iterator<String> itrResolvers = resolvers.keySet().iterator(); String tlsaFqdn = tlsaPrefix.toString() + Constants.DNS_LABEL_DELIMITER + browsingDomain.fqdn(); Fqdn browsingDomainWithTLSAPrefix = new Fqdn(tlsaFqdn); LookupContext ctx = DnsUtil.context(browsingDomainWithTLSAPrefix, "", "", "", Type.TLSA, secValidation); String server; do { server = itrResolvers.next(); Resolver resolver = resolvers.get(server); ctx.setResolver(resolver); Resolver valResolver = valResolvers.get(server); ctx.setValResolver(valResolver); statusChange(FormattingUtil.server(server)); try { Record[] records = lookup(ctx); for (Record record : records) { if (record instanceof TLSARecord) { tlsaDiscoveryRecords.add(new CertRecord((TLSARecord) record)); } } statusChange(StatusChangeEvent.build(ctx.getDomainName().fqdnWithPrefix(ctx.getPrefix()), "", StatusChangeEvent.castedList(tlsaDiscoveryRecords))); } catch (LookupException le) { if (le.dnsError().equals(StatusCode.NETWORK_ERROR) && !itrResolvers.hasNext()) { throw le; } else if (le.dnsError().equals(StatusCode.SERVER_ERROR) || le.dnsError().equals(StatusCode.RESOURCE_INSECURE_ERROR)) { throw le; } else { errorsTrace.get().put( ExceptionsUtil.traceKey(resolver, browsingDomain.domain(), "Retrieving-Instances"), le.dnsError()); } } } while (itrResolvers.hasNext() && tlsaDiscoveryRecords.isEmpty()); statusChange(FormattingUtil.answer()); return tlsaDiscoveryRecords; }
private Message lookup(Set<Name> stack, String[] addresses, Message query) throws IOException { Message msg = getCached(query); if (msg != null) return msg; if (addresses == null) return null; Resolver resolver = createResolver(addresses); try { msg = resolver.send(query); } catch (IOException e) { return null; } if (msg == null) return null; // Found the authoritative answer if (msg.getHeader().getFlag(Flags.AA)) return msg; Record[] authority = msg.getSectionArray(Section.AUTHORITY); for (Record record : authority) { if (Type.NS == record.getType()) { Name nameserver = ((NSRecord)record).getTarget(); // Try to find glue for the record first Record[] additional = msg.getSectionArray(Section.ADDITIONAL); addresses = findAddresses(nameserver, additional); if (stack.contains(nameserver)) // Loop - cannot go there continue; stack.add(nameserver); if (stack.size() > MAX_RECURSION_STACK) // Prevent recursion spinning out of control return null; // No glue found - lookup target recursively if (addresses == null) addresses = findAddressesRecursive(stack, nameserver); // Chase down to the next level Message resp = lookup(stack, addresses, query); if (resp != null) { addCached(resp); return resp; } } } return null; // Just couldn't do it }
public void setResolver(Resolver r) { resolver = r; }
/** * Instantiate a DNS <code>Resolver</code> by the provided Server. In case of DNSSEC validation * is needed, a <code>ValidatingResolver</code> is instantiated. * * @param dnsSec <code>true</code> iff DNSSEC is enabled * @param trustAnchor Public cryptographic to validate against * @param server Server to use as DNS resolver * * @return An instance of <code>Resolver</code> * * @throws ConfigurationException * Exceptional circumstances in which <code>Resolver</code> cannot be created. */ public static Resolver getResolver(boolean dnsSec, String trustAnchor, String server) throws ConfigurationException { Resolver resolver = instantiateResolver(dnsSec, trustAnchor, server); if (resolver == null) { throw new ConfigurationException(String.format("Unable to retrieve a Resolver from [%s]", server)); } return resolver; }