private static List<Name> subdomainsForName(Name name) { final List<Name> names = Lists.newArrayList(name); final String sub = parentDomainForName(name); if (sub.equals("") || sub.equals(".")) { names.add(Name.fromConstantString(".")); } else { names.addAll(subdomainsForName(Name.fromConstantString(sub))); } return names; }
public static DnsRecord createNSRecord(String name, String target) throws Exception { if (!name.endsWith(".")) name = name + "."; if (!target.endsWith(".")) target = target + "."; NSRecord rec = new NSRecord(Name.fromString(name), DClass.IN, 86400L, Name.fromString(target)); return toDnsRecord(DNSRecord.fromWire(rec.toWireCanonical())); }
public static Zone getPtrZone(Name queryName) { try { String nameString = queryName.toString(); Name name; int index = nameString.indexOf(".in-addr.arpa."); if (index > 0) { String ipString = nameString.substring(0, index); String[] parts = ipString.split("\\."); // fix this for v6 if (parts.length == 4) { nameString = nameString.substring(parts[0].length() + 1); name = new Name(nameString); } else { return null; } } else { return null; } long serial = 1; long refresh = 86400; long retry = ttl; long expires = 2419200; // This is the negative cache TTL long minimum = 600; Record soarec = new SOARecord( name, DClass.IN, ttl, name, Name.fromString("root." + name.toString()), serial, refresh, retry, expires, minimum); long nsTTL = 604800; Record nsrec = new NSRecord( name, DClass.IN, nsTTL, Name.fromString(Internets.localHostInetAddress().getCanonicalHostName() + ".")); return new TransientZone(name, new Record[] {soarec, nsrec}); } catch (Exception e) { LOG.error(e, e); return null; } }
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; }
@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=\"-\""); }
public static Name getInternalName() throws TextParseException { String internalNameString = VmInstances.INSTANCE_SUBDOMAIN + ".internal."; internalNameString = internalNameString.startsWith(".") ? internalNameString.replaceFirst("\\.", "") : internalNameString; Name internalName = Name.fromString(internalNameString); return internalName; }
/* * converts a String to a DNS name */ private Name nameFromString(String str) { if (!str.endsWith(".")) str += "."; try { return Name.fromString(str); } catch (Exception e) { throw new IllegalArgumentException("Invalid DNS name"); } }
public static Zone getInstanceExternalZone() { try { Name name = getExternalName(); Name host = Name.fromString("root." + name.toString()); Name admin = Name.fromString( Internets.localHostInetAddress().getCanonicalHostName() + "." + name.toString()); Name target = Name.fromString(Internets.localHostInetAddress().getCanonicalHostName() + "."); long serial = 1; long refresh = 86400; long retry = ttl; long expires = 2419200; // This is the negative cache TTL long minimum = 600; Record soarec = new SOARecord( name, DClass.IN, ttl, host, admin, serial, refresh, retry, expires, minimum); long nsTTL = 604800; Record nsrec = new NSRecord(name, DClass.IN, nsTTL, target); return new TransientZone(name, new Record[] {soarec, nsrec}); } catch (Exception e) { LOG.error(e, e); return null; } }
public static Name getExternalName() throws TextParseException { String externalNameString = VmInstances.INSTANCE_SUBDOMAIN + "." + SystemConfiguration.getSystemConfiguration().getDnsDomain() + "."; externalNameString = externalNameString.startsWith(".") ? externalNameString.replaceFirst("\\.", "") : externalNameString; Name externalName = Name.fromString(externalNameString); return externalName; }
/* * 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 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; }
/** * Processes all DNS CERT requests. * * @param name The record name. In many cases this a email address. * @return Returns a set of record responses to the request. * @throws DNSException */ @SuppressWarnings("unused") protected RRset processCERTRecordRequest(String name) throws DNSException { if (name.endsWith(".")) name = name.substring(0, name.length() - 1); Certificate[] certs; // use the certificate configuration service try { certs = proxy.getCertificatesForOwner(name, null); } catch (Exception e) { throw new DNSException( DNSError.newError(Rcode.SERVFAIL), "DNS service proxy call for certificates failed: " + e.getMessage(), e); } if (certs == null || certs.length == 0) { // unless the call above was for an org level cert, it will probably always fail because the // "name" parameter has had all instances of "@" replaced with ".". The certificate service // stores owners using "@". // This is horrible, but try hitting the cert service replacing each "." with "@" one by one. // Start at the beginning of the address because this is more than likely where the "@" // character // will be. int previousIndex = 0; int replaceIndex = 0; while ((replaceIndex = name.indexOf(".", previousIndex)) > -1) { char[] chars = name.toCharArray(); chars[replaceIndex] = '@'; try { certs = proxy.getCertificatesForOwner(String.copyValueOf(chars), null); } catch (Exception e) { throw new DNSException( DNSError.newError(Rcode.SERVFAIL), "DNS service proxy call for certificates failed: " + e.getMessage(), e); } if (certs != null && certs.length > 0) break; if (replaceIndex >= (name.length() - 1)) break; previousIndex = replaceIndex + 1; } } if (certs == null || certs.length == 0) return null; if (!name.endsWith(".")) name += "."; RRset retVal = new RRset(); try { for (Certificate cert : certs) { int certRecordType = CERTRecord.PKIX; byte[] retData = null; X509Certificate xCert = null; try { // need to convert to cert container because this might be // a certificate with wrapped private key data final CertUtils.CertContainer cont = CertUtils.toCertContainer(cert.getData()); xCert = cont.getCert(); // check if this is a compliant certificate with the configured policy... if not, move on if (!isCertCompliantWithPolicy(xCert)) continue; retData = xCert.getEncoded(); } catch (CertificateConversionException e) { // probably not a Certificate... might be a URL } if (xCert == null) { // see if it's a URL try { retData = cert.getData(); URL url = new URL(new String(retData)); certRecordType = CERTRecord.URI; } catch (Exception e) { throw new DNSException( DNSError.newError(Rcode.SERVFAIL), "Failure while parsing CERT record data: " + e.getMessage(), e); } } int keyTag = 0; int alg = 0; if (xCert != null && xCert.getPublicKey() instanceof RSAKey) { RSAKey key = (RSAKey) xCert.getPublicKey(); byte[] modulus = key.getModulus().toByteArray(); keyTag = (modulus[modulus.length - 2] << 8) & 0xFF00; keyTag |= modulus[modulus.length - 1] & 0xFF; alg = 5; } CERTRecord rec = new CERTRecord( Name.fromString(name), DClass.IN, 86400L, certRecordType, keyTag, alg /*public key alg, RFC 4034*/, retData); retVal.addRR(rec); } } catch (Exception e) { throw new DNSException( DNSError.newError(Rcode.SERVFAIL), "Failure while parsing CERT record data: " + e.getMessage(), e); } // because of policy filtering, it's possible that we could have filtered out every cert // resulting in an empty RR set return (retVal.size() == 0) ? null : retVal; }
private static String parentDomainForName(Name name) { return name.toString().replaceAll("\\A[^\\.]+\\.", ""); }
/* (non-Javadoc) * @see com.eucalyptus.dns.Zone#findRecords(org.xbill.DNS.Name, int) */ @Override public SetResponse findRecords(Name name, int type) { if (type == Type.AAAA) return (SetResponse.ofType(SetResponse.SUCCESSFUL)); if (StackConfiguration.USE_INSTANCE_DNS && name.toString().matches("euca-.+{3}-.+{3}-.+{3}-.+{3}\\..*")) { try { String[] tryIp = name.toString() .replaceAll("euca-", "") .replaceAll(VmInstances.INSTANCE_SUBDOMAIN + ".*", "") .split("-"); if (tryIp.length < 4) return super.findRecords(name, type); String ipCandidate = new StringBuffer() .append(tryIp[0]) .append(".") .append(tryIp[1]) .append(".") .append(tryIp[2]) .append(".") .append(tryIp[3]) .toString(); try { VmInstances.lookupByPublicIp(ipCandidate); } catch (Exception e) { try { VmInstances.lookupByPrivateIp(ipCandidate); } catch (Exception e1) { return super.findRecords(name, type); } } InetAddress ip = InetAddress.getByName(ipCandidate); SetResponse resp = new SetResponse(SetResponse.SUCCESSFUL); resp.addRRset(new RRset(new ARecord(name, 1, ttl, ip))); return resp; } catch (Exception e) { return super.findRecords(name, type); } } else if (StackConfiguration.USE_INSTANCE_DNS && name.toString().endsWith(".in-addr.arpa.")) { int index = name.toString().indexOf(".in-addr.arpa."); Name target; if (index > 0) { String ipString = name.toString().substring(0, index); String[] parts = ipString.split("\\."); String ipCandidate; if (parts.length == 4) { ipCandidate = new StringBuffer() .append(parts[3]) .append(".") .append(parts[2]) .append(".") .append(parts[1]) .append(".") .append(parts[0]) .toString(); } else { return super.findRecords(name, type); } try { VmInstance instance = VmInstances.lookupByPublicIp(ipCandidate); target = new Name(instance.getPublicDnsName() + "."); } catch (Exception e) { try { VmInstance instance = VmInstances.lookupByPrivateIp(ipCandidate); target = new Name(instance.getPrivateDnsName() + "."); } catch (Exception e1) { return super.findRecords(name, type); } } SetResponse resp = new SetResponse(SetResponse.SUCCESSFUL); resp.addRRset(new RRset(new PTRRecord(name, DClass.IN, ttl, target))); return resp; } else { return super.findRecords(name, type); } } else { return super.findRecords(name, type); } }
/** {@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; }
public static void main(String[] args) throws Exception { ZoneTransferIn xfrin; TSIG key = null; int ixfr_serial = -1; String server = null; int port = SimpleResolver.DEFAULT_PORT; boolean fallback = false; Name zname; int arg = 0; while (arg < args.length) { if (args[arg].equals("-i")) { ixfr_serial = Integer.parseInt(args[++arg]); if (ixfr_serial < 0) usage("invalid serial number"); } else if (args[arg].equals("-k")) { String s = args[++arg]; int index = s.indexOf('/'); if (index < 0) usage("invalid key"); key = new TSIG(s.substring(0, index), s.substring(index + 1)); } else if (args[arg].equals("-s")) { server = args[++arg]; } else if (args[arg].equals("-p")) { port = Integer.parseInt(args[++arg]); if (port < 0 || port > 0xFFFF) usage("invalid port"); } else if (args[arg].equals("-f")) { fallback = true; } else if (args[arg].startsWith("-")) { usage("invalid option"); } else { break; } arg++; } if (arg >= args.length) usage("no zone name specified"); zname = Name.fromString(args[arg]); if (server == null) { Lookup l = new Lookup(zname, Type.NS); Record[] ns = l.run(); if (ns == null) { System.out.println("failed to look up NS record: " + l.getErrorString()); System.exit(1); } server = ns[0].rdataToString(); System.out.println("sending to server '" + server + "'"); } if (ixfr_serial >= 0) xfrin = ZoneTransferIn.newIXFR(zname, ixfr_serial, fallback, server, port, key); else xfrin = ZoneTransferIn.newAXFR(zname, server, port, key); List response = xfrin.run(); if (xfrin.isAXFR()) { if (ixfr_serial >= 0) System.out.println("AXFR-like IXFR response"); else System.out.println("AXFR response"); Iterator it = response.iterator(); while (it.hasNext()) System.out.println(it.next()); } else if (xfrin.isIXFR()) { System.out.println("IXFR response"); Iterator it = response.iterator(); while (it.hasNext()) { ZoneTransferIn.Delta delta; delta = (ZoneTransferIn.Delta) it.next(); System.out.println("delta from " + delta.start + " to " + delta.end); System.out.println("deletes"); Iterator it2 = delta.deletes.iterator(); while (it2.hasNext()) System.out.println(it2.next()); System.out.println("adds"); it2 = delta.adds.iterator(); while (it2.hasNext()) System.out.println(it2.next()); } } else if (xfrin.isCurrent()) { System.out.println("up to date"); } }