Search in sources :

Example 11 with Message

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

the class NameResolution method forwardToDnsServer.

/**
   * Sends the query to the DNS server.
   *
   * @param dnsServer
   * @param query
   * @return A message with either a good response or an error.
   */
public static Message forwardToDnsServer(SimpleResolver dnsServer, Message query) {
    try {
        Message dnsResponse = dnsServer.send(query);
        NameResolution.getLogger().log(Level.FINE, "DNS response {0} with {1} answer, {2} authoritative and {3} additional records", new Object[] { Rcode.string(dnsResponse.getHeader().getRcode()), dnsResponse.getSectionArray(Section.ANSWER).length, dnsResponse.getSectionArray(Section.AUTHORITY).length, dnsResponse.getSectionArray(Section.ADDITIONAL).length });
        if (isReasonableResponse(dnsResponse)) {
            NameResolution.getLogger().log(Level.FINE, "Outgoing response from DNS: {0}", dnsResponse.toString());
            return dnsResponse;
        }
    } catch (IOException e) {
        NameResolution.getLogger().log(Level.WARNING, "DNS resolution failed for {0}: {1}", new Object[] { query, e });
    }
    return errorMessage(query, Rcode.NXDOMAIN);
}
Also used : Message(org.xbill.DNS.Message) JSONObject(org.json.JSONObject) IOException(java.io.IOException)

Example 12 with Message

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

the class NameResolution method lookupGnsServer.

/**
   * Lookup the query in the GNS server.
   * @param addr 
   * @param query
   * @param handler
   * @return A message with either a good response or an error.
   */
public static Message lookupGnsServer(InetAddress addr, Message query, ClientRequestHandlerInterface handler) {
    // 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 int fieldName = query.getQuestion().getType();
    final Name requestedName = query.getQuestion().getName();
    final byte[] rawName = requestedName.toWire();
    final String domainName = querytoStringForGNS(rawName);
    // The domain name must be an absolute name, i.e., ended with a dot
    assert (domainName.endsWith(".")) : "The domain name " + domainName + "to resolve is not an absolute name!";
    /**
     *  The query type or domain name can't be null, otherwise return an error message
     */
    if (Type.string(fieldName) == null || domainName == null) {
        return errorMessage(query, Rcode.NXDOMAIN);
    }
    NameResolution.getLogger().log(Level.FINE, "Trying GNS lookup for domain {0}, type {1}", new Object[] { domainName, Type.string(fieldName) });
    /**
     *  Create a response message, build the header first.
     *  The response is constructed later after GNS query.
     */
    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);
    /**
     * Request DNS fields of an alias and prepare a DNS response message 
     */
    ArrayList<String> fields = new ArrayList<>(Arrays.asList("A", "NS", "CNAME", "SOA", "PTR", "MX"));
    /**
     * <p>
     * RFC 1034: the additional section "carries RRs(Resource Records) which may be helpful in
     * 			using the RRs in the other section"
     * RFC 2181: data you put in the additional section can never be promoted into real answers.
     * 
     * <p>When a DNS client needs to look up a name used in a program, it queries DNS servers to resolve the name. 
     * Each query message the client sends contains three pieces of information, specifying a question for the server to answer:
     * 1. A specified DNS domain name, stated as a fully qualified domain name (FQDN).
     * 2. A specified query type, which can either specify a resource record (RR) by type or a specialized type of query operation.
     * 3. A specified class for the DNS domain name. For DNS servers running the Windows operating system, this should always be specified as the Internet (IN) class.
     * 
     * <p>The information is retrieved from GNS based on the queried domain.
     * <p>The response is constructed based on the query type,
     * 1. A: return A records in ANSWER section, NS records in AUTHORITY section, A records of name servers in ADDITIONAL section
     * 2. NS: return NS records in ANSWER section, A records of name servers in ADDITIONAL section
     * 3. MX: return MX records in ANSWER section, NS records in AUTHORITY section, A record of name servers in ADDITIONAL section
     * 4. CNAME: return CNAME records in in ANSWER section, NS records in AUTHORITY section, A record of name servers in ADDITIONAL section
     * 
     * Records in ADDITIONAL section is not required, we do a best-effort resolution for the names in ADDITIONAL section.
     */
    long resolveStart = System.currentTimeMillis();
    JSONObject fieldResponseJson = lookupGuidField(addr.getHostAddress().toString(), query.getHeader().getID(), domainName, null, fields, handler);
    if (fieldResponseJson == null) {
        NameResolution.getLogger().log(Level.FINE, "GNS lookup for domain {0} failed.", domainName);
        return errorMessage(query, Rcode.NXDOMAIN);
    }
    NameResolution.getLogger().log(Level.FINE, "fieldResponse all fields (NS, MX, CNAME, A): {0}", fieldResponseJson.toString());
    switch(fieldName) {
        case Type.NS:
            {
                JSONObject obj = getNSRecordsFromNSField(fieldResponseJson, domainName);
                if (obj != null) {
                    try {
                        JSONArray nsList = obj.getJSONArray("NS");
                        JSONArray aList = obj.getJSONArray("A");
                        for (int i = 0; i < nsList.length(); i++) {
                            response.addRecord((Record) nsList.get(i), Section.ANSWER);
                        }
                        for (int i = 0; i < aList.length(); i++) {
                            response.addRecord((Record) aList.get(i), Section.ADDITIONAL);
                        }
                    } catch (JSONException e) {
                    // do nothing, this happens only because some record is corrupted
                    }
                } else {
                    // I don't have the requested A record, you must ask a wrong guy
                    return errorMessage(query, Rcode.NXDOMAIN);
                }
            }
            break;
        case Type.A:
            {
                // Get A records from retrieved GNS record
                JSONArray aList = getARecordsFromAField(fieldResponseJson, domainName);
                if (aList != null) {
                    for (int i = 0; i < aList.length(); i++) {
                        try {
                            response.addRecord((Record) aList.get(i), Section.ANSWER);
                        } catch (JSONException e) {
                        // trash the record
                        }
                    }
                } else {
                    // I don't have the requested A record, you must ask a wrong guy
                    return errorMessage(query, Rcode.NXDOMAIN);
                }
                //Get NS record if we can
                JSONObject obj = getNSRecordsFromNSField(fieldResponseJson, domainName);
                if (obj != null) {
                    try {
                        JSONArray nsList = obj.getJSONArray("NS");
                        JSONArray aNSList = obj.getJSONArray("A");
                        for (int i = 0; i < nsList.length(); i++) {
                            response.addRecord((Record) nsList.get(i), Section.AUTHORITY);
                        }
                        for (int i = 0; i < aNSList.length(); i++) {
                            response.addRecord((Record) aNSList.get(i), Section.ADDITIONAL);
                        }
                    } catch (JSONException e) {
                    // do nothing, this happens only because some record is corrupted
                    }
                }
            }
            break;
        case Type.MX:
            {
                JSONObject obj = getMXRecordsFromMXField(fieldResponseJson, domainName);
                NameResolution.getLogger().log(Level.FINE, "MX record for domain {0} is {1}", new Object[] { domainName, obj });
                if (obj != null) {
                    try {
                        JSONArray mxList = obj.getJSONArray("MX");
                        JSONArray aList = obj.getJSONArray("A");
                        for (int i = 0; i < mxList.length(); i++) {
                            response.addRecord((Record) mxList.get(i), Section.ANSWER);
                        }
                        for (int i = 0; i < aList.length(); i++) {
                            response.addRecord((Record) aList.get(i), Section.ADDITIONAL);
                        }
                    } catch (JSONException e) {
                    // do nothing, this happens only because some record is corrupted
                    }
                } else {
                    // I don't have the requested MX record, you must ask a wrong guy
                    return errorMessage(query, Rcode.NXDOMAIN);
                }
                //Get NS record if we can
                obj = getNSRecordsFromNSField(fieldResponseJson, domainName);
                if (obj != null) {
                    try {
                        JSONArray nsList = obj.getJSONArray("NS");
                        JSONArray aNSList = obj.getJSONArray("A");
                        for (int i = 0; i < nsList.length(); i++) {
                            response.addRecord((Record) nsList.get(i), Section.AUTHORITY);
                        }
                        for (int i = 0; i < aNSList.length(); i++) {
                            response.addRecord((Record) aNSList.get(i), Section.ADDITIONAL);
                        }
                    } catch (JSONException e) {
                    // do nothing, this happens only because some record is corrupted
                    }
                }
            }
            break;
        case Type.CNAME:
            {
                if (fieldResponseJson.has("CNAME")) {
                    // get CNAME alias, no need to resolve it to an IP address
                    try {
                        String cname = fieldResponseJson.getString("CNAME");
                        // The cname must be an absolute name, i.e., ended with a dot
                        if (!cname.endsWith(".")) {
                            cname = cname + ".";
                        }
                        CNAMERecord cnameRecord = new CNAMERecord(new Name(domainName), DClass.IN, 60, new Name(cname));
                        response.addRecord(cnameRecord, Section.ANSWER);
                    } catch (JSONException | TextParseException e) {
                    }
                } else {
                    // I don't have the requested CNAME record, you must ask a wrong guy
                    return errorMessage(query, Rcode.NXDOMAIN);
                }
            }
            break;
        default:
            // we haven't implemented yet
            return errorMessage(query, Rcode.NOTIMPL);
    }
    DelayProfiler.updateDelay("ResolveName", resolveStart);
    NameResolution.getLogger().log(Level.FINER, "Outgoing response from GNS: {0}", response.toString());
    return response;
}
Also used : Message(org.xbill.DNS.Message) ArrayList(java.util.ArrayList) JSONArray(org.json.JSONArray) JSONException(org.json.JSONException) Name(org.xbill.DNS.Name) CNAMERecord(org.xbill.DNS.CNAMERecord) JSONObject(org.json.JSONObject) 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) JSONObject(org.json.JSONObject)

Example 13 with Message

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

the class NameResolution method buildErrorMessage.

/**
   * Creates an error message from a header, response code and a record.
   *
   * @param header
   * @param rcode
   * @param question
   * @return the error message
   */
private static Message buildErrorMessage(Header header, int rcode, Record question) {
    Message response = new Message();
    response.setHeader(header);
    for (int i = 0; i < 4; i++) {
        response.removeAllRecords(i);
    }
    if (question != null) {
        response.addRecord(question, Section.QUESTION);
    }
    response.getHeader().setRcode(rcode);
    return response;
}
Also used : Message(org.xbill.DNS.Message)

Example 14 with Message

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

the class DNSServer method doAXFR.

byte[] doAXFR(final Name name, final Message query, final TSIG tsig, TSIGRecord qtsig, final Socket s) {
    final Zone zone = m_znames.get(name);
    boolean first = true;
    if (zone == null)
        return errorMessage(query, Rcode.REFUSED);
    @SuppressWarnings("unchecked") final Iterator<RRset> it = zone.AXFR();
    try {
        final DataOutputStream dataOut = new DataOutputStream(s.getOutputStream());
        int id = query.getHeader().getID();
        while (it.hasNext()) {
            final RRset rrset = it.next();
            final Message response = new Message(id);
            final Header header = response.getHeader();
            header.setFlag(Flags.QR);
            header.setFlag(Flags.AA);
            addRRset(rrset.getName(), response, rrset, Section.ANSWER, FLAG_DNSSECOK);
            if (tsig != null) {
                tsig.applyStream(response, qtsig, first);
                qtsig = response.getTSIG();
            }
            first = false;
            final byte[] out = response.toWire();
            dataOut.writeShort(out.length);
            dataOut.write(out);
        }
    } catch (final IOException ex) {
        LOG.warn("AXFR failed", ex);
    }
    try {
        s.close();
    } catch (final IOException ex) {
        LOG.warn("error closing socket", ex);
    }
    return null;
}
Also used : Message(org.xbill.DNS.Message) Header(org.xbill.DNS.Header) Zone(org.xbill.DNS.Zone) DataOutputStream(java.io.DataOutputStream) RRset(org.xbill.DNS.RRset) InterruptedIOException(java.io.InterruptedIOException) IOException(java.io.IOException)

Example 15 with Message

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

the class DNSServer method generateReply.

/*
     * 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.
     */
byte[] generateReply(final Message query, final byte[] in, final int length, final Socket s) throws IOException {
    final Header header = query.getHeader();
    int maxLength;
    int flags = 0;
    if (header.getFlag(Flags.QR))
        return null;
    if (header.getRcode() != Rcode.NOERROR)
        return errorMessage(query, Rcode.FORMERR);
    if (header.getOpcode() != Opcode.QUERY)
        return errorMessage(query, Rcode.NOTIMP);
    final Record queryRecord = query.getQuestion();
    final TSIGRecord queryTSIG = query.getTSIG();
    TSIG tsig = null;
    if (queryTSIG != null) {
        tsig = m_TSIGs.get(queryTSIG.getName());
        if (tsig == null || tsig.verify(query, in, length, null) != Rcode.NOERROR)
            return formerrMessage(in);
    }
    final OPTRecord queryOPT = query.getOPT();
    if (s != null)
        maxLength = 65535;
    else if (queryOPT != null)
        maxLength = Math.max(queryOPT.getPayloadSize(), 512);
    else
        maxLength = 512;
    if (queryOPT != null && (queryOPT.getFlags() & ExtendedFlags.DO) != 0)
        flags = FLAG_DNSSECOK;
    final Message response = new Message(query.getHeader().getID());
    response.getHeader().setFlag(Flags.QR);
    if (query.getHeader().getFlag(Flags.RD)) {
        response.getHeader().setFlag(Flags.RD);
    }
    response.addRecord(queryRecord, Section.QUESTION);
    final Name name = queryRecord.getName();
    final int type = queryRecord.getType();
    final int dclass = queryRecord.getDClass();
    if ((type == Type.AXFR || type == Type.IXFR) && s != null)
        return doAXFR(name, query, tsig, queryTSIG, s);
    if (!Type.isRR(type) && type != Type.ANY)
        return errorMessage(query, Rcode.NOTIMP);
    final byte rcode = addAnswer(response, name, type, dclass, 0, flags);
    if (rcode != Rcode.NOERROR && rcode != Rcode.NXDOMAIN)
        return errorMessage(query, rcode);
    addAdditional(response, flags);
    if (queryOPT != null) {
        final int optflags = (flags == FLAG_DNSSECOK) ? ExtendedFlags.DO : 0;
        final OPTRecord opt = new OPTRecord((short) 4096, rcode, (byte) 0, optflags);
        response.addRecord(opt, Section.ADDITIONAL);
    }
    response.setTSIG(tsig, Rcode.NOERROR, queryTSIG);
    return response.toWire(maxLength);
}
Also used : Header(org.xbill.DNS.Header) Message(org.xbill.DNS.Message) OPTRecord(org.xbill.DNS.OPTRecord) 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) TSIGRecord(org.xbill.DNS.TSIGRecord) TSIG(org.xbill.DNS.TSIG) Name(org.xbill.DNS.Name)

Aggregations

Message (org.xbill.DNS.Message)20 IOException (java.io.IOException)8 Name (org.xbill.DNS.Name)8 Record (org.xbill.DNS.Record)8 Header (org.xbill.DNS.Header)5 ArrayList (java.util.ArrayList)4 RRset (org.xbill.DNS.RRset)4 JSONObject (org.json.JSONObject)3 CERTRecord (org.xbill.DNS.CERTRecord)3 CNAMERecord (org.xbill.DNS.CNAMERecord)3 SimpleResolver (org.xbill.DNS.SimpleResolver)3 InterruptedIOException (java.io.InterruptedIOException)2 Endpoint (org.apache.camel.Endpoint)2 InvocationOnMock (org.mockito.invocation.InvocationOnMock)2 Answer (org.mockito.stubbing.Answer)2 ARecord (org.xbill.DNS.ARecord)2 ExtendedResolver (org.xbill.DNS.ExtendedResolver)2 MXRecord (org.xbill.DNS.MXRecord)2 NSRecord (org.xbill.DNS.NSRecord)2 SetResponse (org.xbill.DNS.SetResponse)2