private final void maybeAddRecord(Record record) throws IOException { int rtype = record.getType(); Name name = record.getName(); if (rtype == Type.SOA && !name.equals(origin)) { throw new IOException("SOA owner " + name + " does not match zone origin " + origin); } if (name.subdomain(origin)) addRecord(record); }
private final void maybeAddRecord(Record record, Cache cache, Object source) throws IOException { int type = record.getType(); Name name = record.getName(); if (type == Type.SOA) { if (!name.equals(origin)) throw new IOException("SOA owner " + name + " does not match zone origin " + origin); else { setOrigin(origin); dclass = record.getDClass(); } } if (origin == null && type != Type.SOA) throw new IOException("non-SOA record seen at " + name + " with no origin set"); if (name.subdomain(origin)) addRecord(record); else if (cache != null) cache.addRecord(record, Credibility.GLUE, source); }
/** * Adds all data from a Message into the Cache. Each record is added with the appropriate * credibility, and negative answers are cached as such. * * @param in The Message to be added * @see Message */ public void addMessage(Message in) { boolean isAuth = in.getHeader().getFlag(Flags.AA); Name qname = in.getQuestion().getName(); Name curname = qname; short qtype = in.getQuestion().getType(); short qclass = in.getQuestion().getDClass(); byte cred; short rcode = in.getHeader().getRcode(); boolean haveAnswer = false; boolean completed = false; boolean restart = false; RRset[] answers, auth, addl; if (rcode != Rcode.NOERROR && rcode != Rcode.NXDOMAIN) return; if (secure) { Cache c = new Cache(dclass); c.addMessage(in); verifyRecords(c); return; } answers = in.getSectionRRsets(Section.ANSWER); for (int i = 0; i < answers.length; i++) { if (answers[i].getDClass() != qclass) continue; short type = answers[i].getType(); Name name = answers[i].getName(); cred = getCred(Section.ANSWER, isAuth); if (type == Type.CNAME && name.equals(curname)) { CNAMERecord cname; addRRset(answers[i], cred); cname = (CNAMERecord) answers[i].first(); curname = cname.getTarget(); restart = true; haveAnswer = true; } else if (type == Type.DNAME && curname.subdomain(name)) { DNAMERecord dname; addRRset(answers[i], cred); dname = (DNAMERecord) answers[i].first(); try { curname = curname.fromDNAME(dname); } catch (NameTooLongException e) { break; } restart = true; haveAnswer = true; } else if ((type == qtype || qtype == Type.ANY) && name.equals(curname)) { addRRset(answers[i], cred); completed = true; haveAnswer = true; } if (restart) { restart = false; i = 0; } } auth = in.getSectionRRsets(Section.AUTHORITY); if (!completed) { /* This is a negative response or a referral. */ RRset soa = null, ns = null; for (int i = 0; i < auth.length; i++) { if (auth[i].getType() == Type.SOA && curname.subdomain(auth[i].getName())) soa = auth[i]; else if (auth[i].getType() == Type.NS && curname.subdomain(auth[i].getName())) ns = auth[i]; } short cachetype = (rcode == Rcode.NXDOMAIN) ? (short) 0 : qtype; if (soa != null || ns == null) { /* Negative response */ cred = getCred(Section.AUTHORITY, isAuth); SOARecord soarec = null; if (soa != null) soarec = (SOARecord) soa.first(); addNegative(curname, cachetype, soarec, cred); /* NXT records are not cached yet. */ } else { /* Referral response */ cred = getCred(Section.AUTHORITY, isAuth); addRRset(ns, cred); } } addl = in.getSectionRRsets(Section.ADDITIONAL); for (int i = 0; i < addl.length; i++) { short type = addl[i].getType(); if (type != Type.A && type != Type.AAAA && type != Type.A6) continue; /* XXX check the name */ Name name = addl[i].getName(); cred = getCred(Section.ADDITIONAL, isAuth); addRRset(addl[i], cred); } }
/** * Looks up Records in the Cache. This follows CNAMEs and handles negatively cached data. * * @param name The name to look up * @param type The type to look up * @param minCred The minimum acceptable credibility * @return A SetResponse object * @see SetResponse * @see Credibility */ public SetResponse lookupRecords(Name name, short type, byte minCred) { SetResponse cr = null; boolean verbose = Options.check("verbosecache"); Object o = lookup(name, type); if (verbose) logLookup(name, type, "Starting"); if (o == null || o == NXRRSET) { /* * The name exists, but the type was not found. Or, the * name does not exist and no parent does either. Punt. */ if (verbose) logLookup(name, type, "no information found"); return SetResponse.ofType(SetResponse.UNKNOWN); } Object[] objects; if (o instanceof Element) objects = new Object[] {o}; else objects = (Object[]) o; int nelements = 0; for (int i = 0; i < objects.length; i++) { Element element = (Element) objects[i]; if (element.expired()) { if (verbose) { logLookup(name, type, element.toString()); logLookup(name, type, "expired: ignoring"); } removeSet(name, type, element); objects[i] = null; } else if (element.credibility < minCred) { if (verbose) { logLookup(name, type, element.toString()); logLookup(name, type, "not credible: ignoring"); } objects[i] = null; } else { nelements++; } } if (nelements == 0) { /* We have data, but can't use it. Punt. */ if (verbose) logLookup(name, type, "no useful data found"); return SetResponse.ofType(SetResponse.UNKNOWN); } /* * We have something at the name. It could be the answer, * a CNAME, DNAME, or NS, or a negative cache entry. * * Ignore wildcards, since it's pretty unlikely that any will be * cached. The occasional extra query is easily balanced by the * reduced number of lookups. */ for (int i = 0; i < objects.length; i++) { if (objects[i] == null) continue; Element element = (Element) objects[i]; if (verbose) logLookup(name, type, element.toString()); RRset rrset = null; if (element instanceof PositiveElement) rrset = ((PositiveElement) element).rrset; /* Is this a negatively cached entry? */ if (rrset == null) { /* * If this is an NXDOMAIN entry, return NXDOMAIN. */ if (element.getType() == 0) { if (verbose) logLookup(name, type, "NXDOMAIN"); return SetResponse.ofType(SetResponse.NXDOMAIN); } /* * If we're not looking for type ANY, return NXRRSET. * Otherwise ignore this. */ if (type != Type.ANY) { if (verbose) logLookup(name, type, "NXRRSET"); return SetResponse.ofType(SetResponse.NXRRSET); } else { if (verbose) logLookup(name, type, "ANY query; " + "ignoring NXRRSET"); continue; } } short rtype = rrset.getType(); Name rname = rrset.getName(); if (name.equals(rname)) { if (type != Type.CNAME && type != Type.ANY && rtype == Type.CNAME) { if (verbose) logLookup(name, type, "cname"); return new SetResponse(SetResponse.CNAME, rrset); } else if (type != Type.NS && type != Type.ANY && rtype == Type.NS) { if (verbose) logLookup(name, type, "exact delegation"); return new SetResponse(SetResponse.DELEGATION, rrset); } else { if (verbose) logLookup(name, type, "exact match"); if (cr == null) cr = new SetResponse(SetResponse.SUCCESSFUL); cr.addRRset(rrset); } } else if (name.subdomain(rname)) { if (rtype == Type.DNAME) { if (verbose) logLookup(name, type, "dname"); return new SetResponse(SetResponse.DNAME, rrset); } else if (rtype == Type.NS) { if (verbose) logLookup(name, type, "parent delegation"); return new SetResponse(SetResponse.DELEGATION, rrset); } else { if (verbose) logLookup(name, type, "ignoring rrset (" + rname + " " + Type.string(rtype) + ")"); } } else { if (verbose) logLookup(name, type, "ignoring rrset (" + rname + " " + Type.string(rtype) + ")"); } } /* * As far as I can tell, the only legitimate time cr will be null is * if we queried for ANY and only saw negative responses, but not an * NXDOMAIN. Return UNKNOWN. */ if (cr == null && type == Type.ANY) return SetResponse.ofType(SetResponse.UNKNOWN); else if (cr == null) throw new IllegalStateException( "looking up (" + name + " " + Type.string(type) + "): " + "cr == null."); return cr; }
private synchronized SetResponse lookup(Name name, int type) { int labels; int olabels; int tlabels; RRset rrset; Name tname; Object types; SetResponse sr; if (!name.subdomain(origin)) return SetResponse.ofType(SetResponse.NXDOMAIN); labels = name.labels(); olabels = origin.labels(); for (tlabels = olabels; tlabels <= labels; tlabels++) { boolean isOrigin = (tlabels == olabels); boolean isExact = (tlabels == labels); if (isOrigin) tname = origin; else if (isExact) tname = name; else tname = new Name(name, labels - tlabels); types = exactName(tname); if (types == null) continue; /* If this is a delegation, return that. */ if (!isOrigin) { RRset ns = oneRRset(types, Type.NS); if (ns != null) return new SetResponse(SetResponse.DELEGATION, ns); } /* If this is an ANY lookup, return everything. */ if (isExact && type == Type.ANY) { sr = new SetResponse(SetResponse.SUCCESSFUL); RRset[] sets = allRRsets(types); for (int i = 0; i < sets.length; i++) sr.addRRset(sets[i]); return sr; } /* * If this is the name, look for the actual type or a CNAME. * Otherwise, look for a DNAME. */ if (isExact) { rrset = oneRRset(types, type); if (rrset != null) { sr = new SetResponse(SetResponse.SUCCESSFUL); sr.addRRset(rrset); return sr; } rrset = oneRRset(types, Type.CNAME); if (rrset != null) return new SetResponse(SetResponse.CNAME, rrset); } else { rrset = oneRRset(types, Type.DNAME); if (rrset != null) return new SetResponse(SetResponse.DNAME, rrset); } /* We found the name, but not the type. */ if (isExact) return SetResponse.ofType(SetResponse.NXRRSET); } if (hasWild) { for (int i = 0; i < labels - olabels; i++) { tname = name.wild(i + 1); types = exactName(tname); if (types == null) continue; rrset = oneRRset(types, type); if (rrset != null) { sr = new SetResponse(SetResponse.SUCCESSFUL); sr.addRRset(rrset); return sr; } } } return SetResponse.ofType(SetResponse.NXDOMAIN); }