Search in sources :

Example 1 with SetResponse

use of org.xbill.DNS.SetResponse in project GNS by MobilityFirst.

the class NameResolution method lookupDnsCache.

/**
   * Look up the local dns server cache.
   * Returns a {@link Message}.
   *
   * @param query
   * @param dnsCache
   * @return a Message
   */
public static Message lookupDnsCache(Message query, Cache dnsCache) {
    // check for queries we can't handle
    int type = query.getQuestion().getType();
    // Was the query legitimate or implemented?
    if (!Type.isRR(type) && type != Type.ANY) {
        return errorMessage(query, Rcode.NOTIMP);
    }
    // extract the domain (guid) and field from the query
    final Name requestedName = query.getQuestion().getName();
    final byte[] rawName = requestedName.toWire();
    final String lookupName = querytoStringForGNS(rawName);
    NameResolution.getLogger().log(Level.FINER, "Looking up name in cache: {0}", lookupName);
    SetResponse lookupresult = dnsCache.lookupRecords(requestedName, Type.ANY, Credibility.NORMAL);
    if (lookupresult.isSuccessful()) {
        Message response = new Message(query.getHeader().getID());
        response.getHeader().setFlag(Flags.QR);
        if (query.getHeader().getFlag(Flags.RD)) {
            response.getHeader().setFlag(Flags.RA);
        }
        response.addRecord(query.getQuestion(), Section.QUESTION);
        response.getHeader().setFlag(Flags.AA);
        ArrayList<Name> cnameNames = new ArrayList<>();
        // Write the response
        for (RRset rrset : lookupresult.answers()) {
            NameResolution.getLogger().log(Level.FINE, "{0}\n", rrset.toString());
            Iterator<?> rrItr = rrset.rrs();
            while (rrItr.hasNext()) {
                Record curRecord = (Record) rrItr.next();
                response.addRecord(curRecord, Section.ANSWER);
                if (curRecord.getType() == Type.CNAME) {
                    cnameNames.add(((CNAMERecord) curRecord).getAlias());
                }
            }
        }
        if (cnameNames.isEmpty()) {
            return response;
        }
        // For all CNAMES in the response, add their A records
        for (Name cname : cnameNames) {
            NameResolution.getLogger().log(Level.FINE, "Looking up CNAME in cache: {0}", cname.toString());
            SetResponse lookUpResult = dnsCache.lookupRecords(cname, Type.ANY, Credibility.NORMAL);
            if (lookUpResult.isSuccessful()) {
                for (RRset rrset : lookUpResult.answers()) {
                    NameResolution.getLogger().log(Level.FINE, "{0}\n", rrset.toString());
                    Iterator<?> rrItr = rrset.rrs();
                    while (rrItr.hasNext()) {
                        Record curRecord = (Record) rrItr.next();
                        response.addRecord(curRecord, Section.ANSWER);
                    }
                }
            }
        }
        return response;
    } else {
        return errorMessage(query, Rcode.NOTIMP);
    }
}
Also used : SetResponse(org.xbill.DNS.SetResponse) Message(org.xbill.DNS.Message) ArrayList(java.util.ArrayList) RRset(org.xbill.DNS.RRset) CNAMERecord(org.xbill.DNS.CNAMERecord) ARecord(org.xbill.DNS.ARecord) Record(org.xbill.DNS.Record) NSRecord(org.xbill.DNS.NSRecord) MXRecord(org.xbill.DNS.MXRecord) Name(org.xbill.DNS.Name)

Example 2 with SetResponse

use of org.xbill.DNS.SetResponse in project GNS by MobilityFirst.

the class LookupWorker method generateReply.

/**
   * Queries DNS and/or GNS servers for DNS records.
   *
   * Note: a null return value means that the caller doesn't need to do
   * anything. Currently this only happens if this is an AXFR request over TCP.
   */
private Message generateReply(Message query) {
    long startTime = System.currentTimeMillis();
    NameResolution.getLogger().log(Level.FINE, "Incoming request:\n {0}", query.toString());
    // If it's not a query we just ignore it.
    if (query.getHeader().getFlag(Flags.QR)) {
        return null;
    }
    long checkStart = System.currentTimeMillis();
    // Check for wierd queries we can't handle.
    Message errorMessage;
    if ((errorMessage = NameResolution.checkForErroneousQueries(query)) != null) {
        return errorMessage;
    }
    DelayProfiler.updateDelay("checkForErroneousQueries", checkStart);
    // If we're not consulting the DNS server as well just send the query to GNS.
    if (dnsServer == null) {
        Message result = NameResolution.lookupGnsServer(incomingPacket.getAddress(), query, handler);
        DelayProfiler.updateDelay("generateReply", startTime);
        return result;
    }
    // Otherwise as a first step before performing GNS/DNS lookup we check our own local cache.
    if (dnsCache != null) {
        Message tempQuery = (Message) query.clone();
        Message result = NameResolution.lookupDnsCache(tempQuery, dnsCache);
        if (result.getHeader().getRcode() == Rcode.NOERROR) {
            NameResolution.getLogger().log(Level.FINE, "Responding the request from cache {0}", NameResolution.queryAndResponseToString(query, result));
            return result;
        }
    }
    // Create a clone of the query for duplicating the request to GNS and DNS
    Message dnsQuery = (Message) query.clone();
    List<LookupTask> tasks;
    if (gnsServer == null) {
        // We make two tasks to check the DNS and GNS in parallel
        tasks = Arrays.asList(// Create GNS lookup task
        new LookupTask(query, handler), // Create DNS lookup task
        new LookupTask(dnsQuery, dnsServer, handler));
    } else {
        tasks = Arrays.asList(// Create GNS lookup task
        new LookupTask(query, gnsServer, true, /* isGNS */
        handler), // Create DNS lookup task
        new LookupTask(dnsQuery, dnsServer, false, /* isGNS */
        handler));
    }
    // A little bit of overkill for two tasks, but it's really not that much longer (if any) than
    // the altenative. Plus it's cool and trendy to use futures.
    ExecutorService executor = Executors.newFixedThreadPool(2);
    ExecutorCompletionService<Message> completionService = new ExecutorCompletionService<>(executor);
    List<Future<Message>> futures = new ArrayList<>(2);
    for (Callable<Message> task : tasks) {
        futures.add(completionService.submit(task));
    }
    Message successResponse = null;
    Message errorResponse = null;
    // loop throught the tasks getting results as they complete
    for (LookupTask task : tasks) {
        // this is just doing things twice btw
        try {
            Message result = completionService.take().get();
            if (result.getHeader().getRcode() == Rcode.NOERROR) {
                successResponse = result;
                break;
            } else {
                // squirrel this away for later in case we get no successes
                errorResponse = result;
            }
        } catch (ExecutionException e) {
            NameResolution.getLogger().log(Level.WARNING, "Problem handling lookup task: {0}", e);
        } catch (InterruptedException e) {
            NameResolution.getLogger().log(Level.WARNING, "Lookup task interrupted: {0}", e);
        }
    }
    // Shutdown the executor threadpool
    executor.shutdown();
    if (successResponse != null) {
        // Cache the successful response
        try {
            SetResponse addMsgResponse = dnsCache.addMessage(successResponse);
            if (!addMsgResponse.isSuccessful()) {
                RRset[] answers = successResponse.getSectionRRsets(Section.ANSWER);
                boolean isAuth = successResponse.getHeader().getFlag(Flags.AA);
                int qClass = successResponse.getQuestion().getDClass();
                for (int i = 0; i < answers.length; i++) {
                    if (answers[i].getDClass() != qClass) {
                        continue;
                    }
                    int cred = getCred(Section.ANSWER, isAuth);
                    dnsCache.addRRset(answers[i], cred);
                    NameResolution.getLogger().log(Level.FINE, "Records added to cache {0}", answers[i].toString());
                }
            }
        } catch (NullPointerException e) {
            NameResolution.getLogger().log(Level.WARNING, "Failed to add a dns response to cache{0}", e);
        }
        return successResponse;
    } else if (errorResponse != null) {
        // currently this is returning the second error response... do we care?
        return errorResponse;
    } else {
        return NameResolution.errorMessage(query, Rcode.NXDOMAIN);
    }
}
Also used : Message(org.xbill.DNS.Message) ArrayList(java.util.ArrayList) RRset(org.xbill.DNS.RRset) ExecutorCompletionService(java.util.concurrent.ExecutorCompletionService) SetResponse(org.xbill.DNS.SetResponse) ExecutorService(java.util.concurrent.ExecutorService) Future(java.util.concurrent.Future) ExecutionException(java.util.concurrent.ExecutionException)

Example 3 with SetResponse

use of org.xbill.DNS.SetResponse in project opennms by OpenNMS.

the class DNSServer method addCacheNS.

private final void addCacheNS(final Message response, final Cache cache, final Name name) {
    final SetResponse sr = cache.lookupRecords(name, Type.NS, Credibility.HINT);
    if (!sr.isDelegation())
        return;
    final RRset nsRecords = sr.getNS();
    @SuppressWarnings("unchecked") final Iterator<Record> it = nsRecords.rrs();
    while (it.hasNext()) {
        final Record r = it.next();
        response.addRecord(r, Section.AUTHORITY);
    }
}
Also used : SetResponse(org.xbill.DNS.SetResponse) RRset(org.xbill.DNS.RRset) CNAMERecord(org.xbill.DNS.CNAMERecord) TSIGRecord(org.xbill.DNS.TSIGRecord) OPTRecord(org.xbill.DNS.OPTRecord) Record(org.xbill.DNS.Record) DNAMERecord(org.xbill.DNS.DNAMERecord)

Example 4 with SetResponse

use of org.xbill.DNS.SetResponse in project opennms by OpenNMS.

the class DNSServer method addAnswer.

byte addAnswer(final Message response, final Name name, int type, int dclass, int iterations, int flags) {
    SetResponse sr;
    byte rcode = Rcode.NOERROR;
    if (iterations > 6)
        return Rcode.NOERROR;
    if (type == Type.SIG || type == Type.RRSIG) {
        type = Type.ANY;
        flags |= FLAG_SIGONLY;
    }
    final Zone zone = findBestZone(name);
    if (zone != null)
        sr = zone.findRecords(name, type);
    else {
        sr = getCache(dclass).lookupRecords(name, type, Credibility.NORMAL);
    }
    if (sr.isUnknown()) {
        addCacheNS(response, getCache(dclass), name);
    }
    if (sr.isNXDOMAIN()) {
        response.getHeader().setRcode(Rcode.NXDOMAIN);
        if (zone != null) {
            addSOA(response, zone);
            if (iterations == 0)
                response.getHeader().setFlag(Flags.AA);
        }
        rcode = Rcode.NXDOMAIN;
    } else if (sr.isNXRRSET()) {
        if (zone != null) {
            addSOA(response, zone);
            if (iterations == 0)
                response.getHeader().setFlag(Flags.AA);
        }
    } else if (sr.isDelegation()) {
        final RRset nsRecords = sr.getNS();
        addRRset(nsRecords.getName(), response, nsRecords, Section.AUTHORITY, flags);
    } else if (sr.isCNAME()) {
        final CNAMERecord cname = sr.getCNAME();
        addRRset(name, response, new RRset(cname), Section.ANSWER, flags);
        if (zone != null && iterations == 0)
            response.getHeader().setFlag(Flags.AA);
        rcode = addAnswer(response, cname.getTarget(), type, dclass, iterations + 1, flags);
    } else if (sr.isDNAME()) {
        final DNAMERecord dname = sr.getDNAME();
        RRset rrset = new RRset(dname);
        addRRset(name, response, rrset, Section.ANSWER, flags);
        final Name newname;
        try {
            newname = name.fromDNAME(dname);
        } catch (final NameTooLongException e) {
            return Rcode.YXDOMAIN;
        }
        rrset = new RRset(new CNAMERecord(name, dclass, 0, newname));
        addRRset(name, response, rrset, Section.ANSWER, flags);
        if (zone != null && iterations == 0)
            response.getHeader().setFlag(Flags.AA);
        rcode = addAnswer(response, newname, type, dclass, iterations + 1, flags);
    } else if (sr.isSuccessful()) {
        final RRset[] rrsets = sr.answers();
        for (int i = 0; i < rrsets.length; i++) addRRset(name, response, rrsets[i], Section.ANSWER, flags);
        if (zone != null) {
            addNS(response, zone, flags);
            if (iterations == 0)
                response.getHeader().setFlag(Flags.AA);
        } else
            addCacheNS(response, getCache(dclass), name);
    }
    return rcode;
}
Also used : SetResponse(org.xbill.DNS.SetResponse) CNAMERecord(org.xbill.DNS.CNAMERecord) NameTooLongException(org.xbill.DNS.NameTooLongException) DNAMERecord(org.xbill.DNS.DNAMERecord) Zone(org.xbill.DNS.Zone) RRset(org.xbill.DNS.RRset) Name(org.xbill.DNS.Name)

Aggregations

RRset (org.xbill.DNS.RRset)4 SetResponse (org.xbill.DNS.SetResponse)4 CNAMERecord (org.xbill.DNS.CNAMERecord)3 ArrayList (java.util.ArrayList)2 DNAMERecord (org.xbill.DNS.DNAMERecord)2 Message (org.xbill.DNS.Message)2 Name (org.xbill.DNS.Name)2 Record (org.xbill.DNS.Record)2 ExecutionException (java.util.concurrent.ExecutionException)1 ExecutorCompletionService (java.util.concurrent.ExecutorCompletionService)1 ExecutorService (java.util.concurrent.ExecutorService)1 Future (java.util.concurrent.Future)1 ARecord (org.xbill.DNS.ARecord)1 MXRecord (org.xbill.DNS.MXRecord)1 NSRecord (org.xbill.DNS.NSRecord)1 NameTooLongException (org.xbill.DNS.NameTooLongException)1 OPTRecord (org.xbill.DNS.OPTRecord)1 TSIGRecord (org.xbill.DNS.TSIGRecord)1 Zone (org.xbill.DNS.Zone)1