@SuppressWarnings("unchecked") private static void addRRset( Name name, final Message response, Record[] records, final int section) { Multimap<RequestType, Record> rrsets = ArrayListMultimap.create(); for (Record r : records) { RequestType type = RequestType.typeOf(r.getType()); rrsets.get(type).addAll(Collections2.filter(Arrays.asList(records), type)); } Predicate<Record> checkNewRecord = new Predicate<Record>() { @Override public boolean apply(Record input) { for (int s = 1; s <= section; s++) { if (response.findRecord(input, s)) { return false; } } return true; } }; if (rrsets.containsKey(RequestType.CNAME)) { for (Record cnames : Iterables.filter(rrsets.removeAll(RequestType.CNAME), checkNewRecord)) { response.addRecord(cnames, section); } } for (Record sectionRecord : Iterables.filter(rrsets.values(), checkNewRecord)) { response.addRecord(sectionRecord, section); } }
/** Test of getRecord method, of class DNSJavaDecoder. */ @Test public void testGetRecord() { System.out.println("getRecord"); String recstr = ". A IN"; DNSJavaDecoder instance = new DNSJavaDecoder(); Record result = instance.getRecord(recstr); assertTrue(result.toString().endsWith("A")); }
protected static long getMaximumTTL(final List<Record> records) { long maximumTTL = 0; for (Record record : records) { if (record.getTTL() > maximumTTL) { maximumTTL = record.getTTL(); } } return maximumTTL; }
/** * This resolver works when it is: 1. Enabled 2. The query is absolute 3. The name/address is not * in a Eucalyptus controlled subdomain * * @see com.eucalyptus.util.dns.DnsResolvers.DnsResolver#checkAccepts(Record, org.xbill.DNS.Name, * InetAddress) */ @Override public boolean checkAccepts(Record query, InetAddress source) { if (!Bootstrap.isOperational() || !enabled) { return false; } else if ((RequestType.A.apply(query) || RequestType.AAAA.apply(query)) && query.getName().isAbsolute() && !DomainNames.isSystemSubdomain(query.getName())) { return true; } else if (RequestType.PTR.apply(query) && !Subnets.isSystemManagedAddress( DomainNameRecords.inAddrArpaToInetAddress(query.getName()))) { return true; } return false; }
/* * Look for SOA records corresponding to the request * TODO: Add cache coherency to SOA records? */ protected synchronized Record checkForSoaRecord(String questionName) { if (!questionName.endsWith(".")) questionName += "."; if (soaRecords == null) { DnsRecord[] getRecs = null; // load all SOA records... try { getRecs = proxy.getDNSByType(Type.SOA); if (getRecs == null || getRecs.length == 0) soaRecords = Collections.emptyMap(); else { soaRecords = new HashMap<String, Record>(); for (DnsRecord rec : getRecs) { Record newRec = Record.newRecord( Name.fromString(rec.getName()), Type.SOA, rec.getDclass(), rec.getTtl(), rec.getData()); soaRecords.put(newRec.getName().toString(), newRec); } } } catch (Exception e) { LOGGER.error("Failed to load SOA records from config service."); } } Record retVal = null; if (soaRecords.size() > 0) { // look for the record by question name retVal = soaRecords.get(questionName); if (retVal == null) { // start taking apart the question name . by . int index = -1; while ((index = questionName.indexOf(".")) > 0 && index < (questionName.length() - 1)) { questionName = questionName.substring(index + 1); retVal = soaRecords.get(questionName); if (retVal != null) break; } } } return retVal; }
@Test public void itLogsServerErrors() throws Exception { header.setRcode(Rcode.REFUSED); Name name = Name.fromString("John Wayne."); Record question = Record.newRecord(name, 65530, 43210); Message query = Message.newQuery(question); Message response = mock(Message.class); when(response.getHeader()).thenReturn(header); when(response.getSectionArray(Section.ANSWER)).thenReturn(null); when(response.getQuestion()).thenReturn(question); when(nameServer.query( any(Message.class), any(InetAddress.class), any(DNSAccessRecord.Builder.class))) .thenThrow(new RuntimeException("Aw snap!")); FakeAbstractProtocol abstractProtocol = new FakeAbstractProtocol(client, query.toWire()); abstractProtocol.setNameServer(nameServer); abstractProtocol.run(); verify(accessLogger) .info( "144140678.000 qtype=DNS chi=192.168.23.45 ttms=345.123 xn=65535 fqdn=John\\032Wayne. type=TYPE65530 class=CLASS43210 rcode=SERVFAIL rtype=- rloc=\"-\" rdtl=- rerr=\"Server Error:RuntimeException:Aw snap!\" ttl=\"-\" ans=\"-\""); }
private Message makeQuery(DNSRequest request, int id) throws TextParseException { Name name = Name.fromString(request.getHostname(), Name.root); int type; switch (request.getRecordType()) { case DNSRequest.A: type = Type.A; break; case DNSRequest.AAAA: type = Type.AAAA; break; case DNSRequest.MX: type = Type.MX; break; case DNSRequest.PTR: type = Type.PTR; break; case DNSRequest.SPF: type = Type.SPF; break; case DNSRequest.TXT: type = Type.TXT; break; default: throw new UnsupportedOperationException("Unknown query type: " + request.getRecordType()); } Record question = Record.newRecord(name, type, DClass.ANY); Message query = Message.newQuery(question); query.getHeader().setID(id); return query; }
private static String createQuery(final Record query) { if (query != null && query.getName() != null) { final String qname = query.getName().toString(); final String qtype = Type.string(query.getType()); final String qclass = DClass.string(query.getDClass()); return new StringBuilder() .append("fqdn=") .append(qname) .append(" type=") .append(qtype) .append(" class=") .append(qclass) .toString(); } return ""; }
private void parseRecord(Message message, InetAddress address) { // We really only care about the ADDITIONAL section (specifically the text records) Record[] responses = message.getSectionArray(Section.ADDITIONAL); // We only want to process records that actually have a length, have an ANSWER // section that has stuff in it and that the ANSWER to our query is what we sent if (responses.length != 0 && message.getSectionArray(Section.ANSWER).length != 0 && message .getSectionArray(Section.ANSWER)[0] .getName() .toString() .equals(NvmDNS.MDNS_QUERY)) { Log.v("NvmDNS Response", "Got a packet from " + address.getCanonicalHostName()); Log.v( "NvmDNS Response", "Question: " + message.getSectionArray(Section.ANSWER)[0].getName().toString()); Log.v("NvmDNS Response", "Response: " + responses[0].getName().toString()); // TODO: The DNS entry we get is "XENITH._nvstream._tcp.local." // And the .'s in there are not actually periods. Or something. String hostname = responses[0].getName().toString(); // The records can be returned in any order, so we need to figure out which one is the // TXTRecord // We get three records back: A TXTRecord, a SRVRecord and an ARecord TXTRecord txtRecord = null; for (Record record : responses) { Log.v( "NvmDNS Response", "We recieved a DNS repsonse with a " + record.getClass().getName() + " record."); if (record instanceof TXTRecord) { txtRecord = (TXTRecord) record; } } if (txtRecord == null) { Log.e("NvmDNS Response", "We recieved a malformed DNS repsonse with no TXTRecord"); return; } this.parseTXTRecord(txtRecord, address, hostname); } }
private static String createTTLandAnswer(final Message dnsMessage) { if (dnsMessage.getSectionArray(Section.ANSWER) == null || dnsMessage.getSectionArray(Section.ANSWER).length == 0) { return "ttl=\"-\" ans=\"-\""; } final StringBuilder answerStringBuilder = new StringBuilder(); final StringBuilder ttlStringBuilder = new StringBuilder(); for (final Record record : dnsMessage.getSectionArray(Section.ANSWER)) { final String s = record.rdataToString() + " "; final String ttl = record.getTTL() + " "; answerStringBuilder.append(s); ttlStringBuilder.append(ttl); } return "ttl=\"" + ttlStringBuilder.toString().trim() + "\" ans=\"" + answerStringBuilder.toString().trim() + "\""; }
public static SetResponse findRecords( final Message response, final Record queryRecord, final InetAddress source) { final Name name = queryRecord.getName(); final int type = queryRecord.getType(); try { if (!enabled || !Bootstrap.isOperational()) { return SetResponse.ofType(SetResponse.UNKNOWN); } else { final Iterable<DnsResolver> resolverList = DnsResolvers.resolversFor(queryRecord, source); LOG.debug("DnsResolvers.findRecords(): resolvers for " + name + " are: " + resolverList); if (Iterables.isEmpty(resolverList)) { return SetResponse.ofType(SetResponse.UNKNOWN); } else { return DnsResolvers.lookupRecords(response, queryRecord, source); } } } catch (final Exception ex) { LOG.error(ex); LOG.trace(ex, ex); } return SetResponse.ofType(SetResponse.UNKNOWN); }
private static SetResponse lookupRecords( final Message response, final Record query, final InetAddress source) { final Name name = query.getName(); final int type = query.getType(); response.getHeader().setFlag(Flags.RA); // always mark the response w/ the recursion available // bit LOG.debug("DnsResolver: " + RequestType.typeOf(type) + " " + name); for (final DnsResolver r : DnsResolvers.resolversFor(query, source)) { try { final DnsResponse reply = r.lookupRecords(query); if (reply == null) { LOG.debug("DnsResolver: returned null " + name + " using " + r); continue; } if (reply.isAuthoritative()) { // mark response.getHeader().setFlag(Flags.AA); } if (reply.isNxdomain()) { addRRset(name, response, new Record[] {DomainNameRecords.sourceOfAuthority(name)}, type); response.getHeader().setRcode(Rcode.NXDOMAIN); return SetResponse.ofType(SetResponse.NXDOMAIN); } else if (reply.hasAnswer()) { for (ResponseSection s : ResponseSection.values()) { Record[] records = reply.section(s); if (records != null) { addRRset(name, response, records, s.section()); } } return SetResponse.ofType(SetResponse.SUCCESSFUL); } } catch (final Exception ex) { LOG.debug( "DnsResolver: failed for " + name + " using " + r + " because of: " + ex.getMessage(), ex); } } return SetResponse.ofType(SetResponse.UNKNOWN); // no dice, return unknown }
private void sendQuery() { Header queryHeader = new Header(); // If we set the RA (Recursion Available) flag and our message ID to 0 // then the packet matches the real mDNS query packet as displayed in Wireshark queryHeader.setFlag(org.xbill.DNS.Flags.RA); queryHeader.setID(0); Record question = null; try { // We need to create our "Question" DNS query that is a pointer record to // the mDNS Query "Name" question = Record.newRecord(new Name(NvmDNS.MDNS_QUERY), Type.PTR, DClass.IN); } catch (TextParseException e) { Log.e("NvmDNS Query", e.getMessage()); return; } // We combine our header and our question into a single message Message query = new Message(); query.setHeader(queryHeader); query.addRecord(question, Section.QUESTION); // Convert the message into Network Byte Order byte[] wireQuery = query.toWire(); Log.i("NvmDNS Query", query.toString()); // Convert our byte array into a Packet DatagramPacket transmitPacket = new DatagramPacket(wireQuery, wireQuery.length); transmitPacket.setAddress(NvmDNS.MDNS_MULTICAST_ADDRESS); transmitPacket.setPort(NvmDNS.MDNS_PORT); // And (attempt) to send the packet try { Log.d("NvmDNS Query", "Blocking on this.nvstream_socket.send(transmitPacket)"); this.socket.send(transmitPacket); Log.d("NvmDNS Query", "Passed this.nvstream_socket.send(transmitPacket)"); } catch (IOException e) { Log.e("NvmDNS Query", "There was an error sending the DNS query."); Log.e("NvmDNS Query", e.getMessage()); } }
@Test public void itLogsARecordQueries() throws Exception { header.setRcode(Rcode.NOERROR); Name name = Name.fromString("www.example.com."); Record question = Record.newRecord(name, Type.A, DClass.IN, 0L); Message query = Message.newQuery(question); query.getHeader().getRcode(); byte[] queryBytes = query.toWire(); whenNew(Message.class).withArguments(queryBytes).thenReturn(query); InetAddress resolvedAddress = Inet4Address.getByName("192.168.8.9"); Record answer = new ARecord(name, DClass.IN, 3600L, resolvedAddress); Record[] answers = new Record[] {answer}; Message response = mock(Message.class); when(response.getHeader()).thenReturn(header); when(response.getSectionArray(Section.ANSWER)).thenReturn(answers); when(response.getQuestion()).thenReturn(question); InetAddress client = Inet4Address.getByName("192.168.23.45"); when(nameServer.query( any(Message.class), any(InetAddress.class), any(DNSAccessRecord.Builder.class))) .thenReturn(response); FakeAbstractProtocol abstractProtocol = new FakeAbstractProtocol(client, queryBytes); abstractProtocol.setNameServer(nameServer); abstractProtocol.run(); verify(accessLogger) .info( "144140678.000 qtype=DNS chi=192.168.23.45 ttms=345.123 xn=65535 fqdn=www.example.com. type=A class=IN rcode=NOERROR rtype=- rloc=\"-\" rdtl=- rerr=\"-\" ttl=\"3600\" ans=\"192.168.8.9\""); }
protected Collection<Record> processGenericANYRecordRequest(String name) throws DNSException { DnsRecord records[]; try { records = proxy.getDNSByNameAndType(name, Type.ANY); } catch (Exception e) { throw new DNSException( DNSError.newError(Rcode.SERVFAIL), "DNS service proxy call for DNS records failed: " + e.getMessage(), e); } if (records == null || records.length == 0) return null; Collection<Record> retVal = new ArrayList<Record>(); try { for (DnsRecord record : records) { Record rec = Record.newRecord( Name.fromString(record.getName()), record.getType(), record.getDclass(), record.getTtl(), record.getData()); retVal.add(rec); } } catch (Exception e) { throw new DNSException( DNSError.newError(Rcode.SERVFAIL), "Failure while parsing generic record data: " + e.getMessage(), e); } return retVal; }
@SuppressWarnings("unchecked") public void execute() throws Exception { // Read in the zone List<Record> records = ZoneUtils.readZoneFile(state.inputfile, null); if (records == null || records.size() == 0) { System.err.println("error: empty RRset file"); state.usage(); } // Construct the RRset. Complain if the records in the input file // consist of more than one RRset. RRset rrset = null; for (Record r : records) { // skip RRSIGs if (r.getType() == Type.RRSIG || r.getType() == Type.SIG) { continue; } // Handle the first record. if (rrset == null) { rrset = new RRset(); rrset.addRR(r); continue; } // Ensure that the remaining records all belong to the same rrset. if (rrset.getName().equals(r.getName()) && rrset.getType() == r.getType() && rrset.getDClass() == r.getDClass()) { rrset.addRR(r); } else { System.err.println("Records do not all belong to the same RRset."); state.usage(); } } if (rrset.size() == 0) { System.err.println("No records found in inputfile."); state.usage(); } // Load the key pairs. if (state.keyFiles.length == 0) { System.err.println("error: at least one keyfile must be specified"); state.usage(); } List<DnsKeyPair> keypairs = getKeys(state.keyFiles, 0, state.keyDirectory); // Make sure that all the keypairs have the same name. // This will be used as the zone name, too. Name keysetName = null; for (DnsKeyPair pair : keypairs) { if (keysetName == null) { keysetName = pair.getDNSKEYName(); continue; } if (!pair.getDNSKEYName().equals(keysetName)) { System.err.println("Keys do not all have the same name."); state.usage(); } } // default the output file, if not set. if (state.outputfile == null && !state.inputfile.equals("-")) { state.outputfile = state.inputfile + ".signed"; } JCEDnsSecSigner signer = new JCEDnsSecSigner(); List<RRSIGRecord> sigs = signer.signRRset(rrset, keypairs, state.start, state.expire); for (RRSIGRecord s : sigs) { rrset.addRR(s); } // write out the signed RRset List<Record> signed_records = new ArrayList<Record>(); for (Iterator<Record> i = rrset.rrs(); i.hasNext(); ) { signed_records.add(i.next()); } for (Iterator<Record> i = rrset.sigs(); i.hasNext(); ) { signed_records.add(i.next()); } // write out the signed zone ZoneUtils.writeZoneFile(signed_records, state.outputfile); if (state.verifySigs) { log.fine("verifying generated signatures"); boolean res = verifySigs(keysetName, signed_records, keypairs); if (res) { System.out.println("Generated signatures verified"); // log.info("Generated signatures verified"); } else { System.out.println("Generated signatures did not verify."); // log.warn("Generated signatures did not verify."); } } }
@Override public DnsResponse lookupRecords(final Record query) { final Name name = query.getName(); final int type = query.getType(); final Cache cache = new Cache(); Lookup aLookup = new Lookup(name, type); aLookup.setCache(cache); Record[] found = aLookup.run(); List<Record> queriedrrs = Arrays.asList(found != null ? found : new Record[] {}); List<Name> cnames = (List<Name>) (aLookup.getAliases().length > 0 ? Arrays.asList(aLookup.getAliases()) : Lists.newArrayList()); List<Record> answer = Lists.newArrayList(); List<Record> authority = Lists.newArrayList(); List<Record> additional = Lists.newArrayList(); for (Name cnameRec : cnames) { SetResponse sr = cache.lookupRecords(cnameRec, Type.CNAME, Credibility.ANY); if (sr != null && sr.isSuccessful() && sr.answers() != null) { for (RRset result : sr.answers()) { Iterator rrs = result.rrs(false); if (rrs != null) { for (Object record : ImmutableSet.copyOf(rrs)) { answer.add((Record) record); } } } } } for (Record queriedRec : queriedrrs) { SetResponse sr = cache.lookupRecords(queriedRec.getName(), queriedRec.getType(), Credibility.ANY); if (sr != null && sr.isSuccessful() && sr.answers() != null) { for (RRset result : sr.answers()) { Iterator rrs = result.rrs(false); if (rrs != null) { for (Object record : ImmutableSet.copyOf(rrs)) { answer.add((Record) record); } } } } } for (Record aRec : queriedrrs) { List<Record> nsRecs = lookupNSRecords(aRec.getName(), cache); for (Record nsRec : nsRecs) { authority.add(nsRec); Lookup nsLookup = new Lookup(((NSRecord) nsRec).getTarget(), Type.A); nsLookup.setCache(cache); Record[] nsAnswers = nsLookup.run(); if (nsAnswers != null) { additional.addAll(Arrays.asList(nsAnswers)); } } } return DnsResponse.forName(query.getName()) .recursive() .withAuthority(authority) .withAdditional(additional) .answer(answer); }
/** {@inheritDoc} */ @SuppressWarnings("unchecked") @Override public Message get(Message request) throws DNSException { LOGGER.trace("get(Message) Entered"); /* for testing time out cases try { Thread.sleep(1000000); } catch (Exception e) { } */ if (request == null) throw new DNSException(DNSError.newError(Rcode.FORMERR)); Header header = request.getHeader(); if (header.getFlag(Flags.QR) || header.getRcode() != Rcode.NOERROR) throw new DNSException(DNSError.newError(Rcode.FORMERR)); if (header.getOpcode() != Opcode.QUERY) throw new DNSException(DNSError.newError(Rcode.NOTIMP)); Record question = request.getQuestion(); if (question == null || question.getDClass() != DClass.IN) { throw new DNSException(DNSError.newError(Rcode.NOTIMP)); } Record queryRecord = request.getQuestion(); Name name = queryRecord.getName(); int type = queryRecord.getType(); if (LOGGER.isDebugEnabled()) { StringBuilder builder = new StringBuilder("Recieved Query Request:"); builder.append("\r\n\tName: " + name.toString()); builder.append("\r\n\tType: " + type); builder.append("\r\n\tDClass: " + queryRecord.getDClass()); LOGGER.debug(builder.toString()); } Collection<Record> lookupRecords = null; switch (question.getType()) { case Type.A: case Type.MX: case Type.SOA: case Type.SRV: case Type.NS: case Type.CNAME: { try { final RRset set = processGenericRecordRequest(name.toString(), type); if (set != null) { lookupRecords = new ArrayList<Record>(); Iterator<Record> iter = set.rrs(); while (iter.hasNext()) lookupRecords.add(iter.next()); } } catch (Exception e) { throw new DNSException( DNSError.newError(Rcode.SERVFAIL), "DNS service proxy call failed: " + e.getMessage(), e); } break; } case Type.CERT: { final RRset set = processCERTRecordRequest(name.toString()); if (set != null) { lookupRecords = new ArrayList<Record>(); Iterator<Record> iter = set.rrs(); while (iter.hasNext()) lookupRecords.add(iter.next()); } break; } case Type.ANY: { Collection<Record> genRecs = processGenericANYRecordRequest(name.toString()); RRset certRecs = processCERTRecordRequest(name.toString()); if (genRecs != null || certRecs != null) { lookupRecords = new ArrayList<Record>(); if (genRecs != null) lookupRecords.addAll(genRecs); if (certRecs != null) { Iterator<Record> iter = certRecs.rrs(); while (iter.hasNext()) lookupRecords.add(iter.next()); } } break; } default: { LOGGER.debug("Query Type " + type + " not implemented"); throw new DNSException( DNSError.newError(Rcode.NOTIMP), "Query Type " + type + " not implemented"); } } if (lookupRecords == null || lookupRecords.size() == 0) { LOGGER.debug("No records found."); return null; } final Message response = new Message(request.getHeader().getID()); response.getHeader().setFlag(Flags.QR); if (request.getHeader().getFlag(Flags.RD)) response.getHeader().setFlag(Flags.RD); response.addRecord(queryRecord, Section.QUESTION); final Iterator<Record> iter = lookupRecords.iterator(); while (iter.hasNext()) response.addRecord(iter.next(), Section.ANSWER); // we are authoritative only response.getHeader().setFlag(Flags.AA); // look for an SOA record final Record soaRecord = checkForSoaRecord(name.toString()); if (soaRecord != null) response.addRecord(soaRecord, Section.AUTHORITY); LOGGER.trace("get(Message) Exit"); return response; }
/* * converts a configuration service DnsRecord to a dnsjava Record */ private Record toRecord(DnsRecord rec) { return Record.newRecord( nameFromString(rec.getName()), rec.getType(), rec.getDclass(), rec.getTtl(), rec.getData()); }
@Override public boolean apply(Record input) { return input.getType() == this.type; }