Beispiel #1
0
 private synchronized void addRRset(Name name, RRset rrset) {
   if (!hasWild && name.isWild()) hasWild = true;
   Object types = data.get(name);
   if (types == null) {
     data.put(name, rrset);
     return;
   }
   int rtype = rrset.getType();
   if (types instanceof List) {
     List list = (List) types;
     for (int i = 0; i < list.size(); i++) {
       RRset set = (RRset) list.get(i);
       if (set.getType() == rtype) {
         list.set(i, rrset);
         return;
       }
     }
     list.add(rrset);
   } else {
     RRset set = (RRset) types;
     if (set.getType() == rtype) data.put(name, rrset);
     else {
       LinkedList list = new LinkedList();
       list.add(set);
       list.add(rrset);
       data.put(name, list);
     }
   }
 }
Beispiel #2
0
 /**
  * Returns an array containing all records in the given section grouped into RRsets.
  *
  * @see RRset
  * @see Section
  */
 public RRset[] getSectionRRsets(int section) {
   if (sections[section] == null) return emptyRRsetArray;
   List sets = new LinkedList();
   Record[] recs = getSectionArray(section);
   Set hash = new HashSet();
   for (int i = 0; i < recs.length; i++) {
     Name name = recs[i].getName();
     boolean newset = true;
     if (hash.contains(name)) {
       for (int j = sets.size() - 1; j >= 0; j--) {
         RRset set = (RRset) sets.get(j);
         if (set.getType() == recs[i].getRRsetType()
             && set.getDClass() == recs[i].getDClass()
             && set.getName().equals(name)) {
           set.addRR(recs[i]);
           newset = false;
           break;
         }
       }
     }
     if (newset) {
       RRset set = new RRset(recs[i]);
       sets.add(set);
       hash.add(name);
     }
   }
   return (RRset[]) sets.toArray(new RRset[sets.size()]);
 }
Beispiel #3
0
 /**
  * Adds a record to the Zone
  *
  * @param r The record to be added
  * @see Record
  */
 public void addRecord(Record r) {
   Name name = r.getName();
   short type = r.getRRsetType();
   RRset rrset = (RRset) findExactSet(name, type);
   if (rrset == null) addSet(name, type, rrset = new RRset());
   rrset.addRR(r);
 }
Beispiel #4
0
 /**
  * Removes a record from the Zone
  *
  * @param r The record to be removed
  * @see Record
  */
 public void removeRecord(Record r) {
   Name name = r.getName();
   short type = r.getRRsetType();
   RRset rrset = (RRset) findExactSet(name, type);
   if (rrset != null) {
     rrset.deleteRR(r);
     if (rrset.size() == 0) removeSet(name, type, rrset);
   }
 }
Beispiel #5
0
 private void validate() throws IOException {
   RRset rrset = (RRset) findExactSet(origin, Type.SOA);
   if (rrset == null || rrset.size() != 1)
     throw new IOException(origin + ": exactly 1 SOA must be specified");
   Iterator it = rrset.rrs();
   SOA = (SOARecord) it.next();
   NS = (RRset) findExactSet(origin, Type.NS);
   if (NS == null) throw new IOException(origin + ": no NS set specified");
 }
Beispiel #6
0
 /**
  * Adds an RRset to the Cache.
  *
  * @param r The RRset to be added
  * @param cred The credibility of these records
  * @param o The source of this RRset (this could be a Message, for example)
  * @see RRset
  */
 public void addRRset(RRset rrset, byte cred) {
   Name name = rrset.getName();
   short type = rrset.getType();
   if (verifier != null) rrset.setSecurity(verifier.verify(rrset, this));
   if (secure && rrset.getSecurity() < DNSSEC.Secure) return;
   Element element = (Element) findExactSet(name, type);
   if (element == null || cred > element.credibility)
     addSet(name, type, new PositiveElement(rrset, cred));
 }
Beispiel #7
0
 private void nodeToString(StringBuffer sb, Object node) {
   RRset[] sets = allRRsets(node);
   for (int i = 0; i < sets.length; i++) {
     RRset rrset = sets[i];
     Iterator it = rrset.rrs();
     while (it.hasNext()) sb.append(it.next() + "\n");
     it = rrset.sigs();
     while (it.hasNext()) sb.append(it.next() + "\n");
   }
 }
Beispiel #8
0
 /**
  * Removes a record from the Zone
  *
  * @param r The record to be removed
  * @see Record
  */
 public void removeRecord(Record r) {
   Name name = r.getName();
   int rtype = r.getRRsetType();
   synchronized (this) {
     RRset rrset = findRRset(name, rtype);
     if (rrset == null) return;
     rrset.deleteRR(r);
     if (rrset.size() == 0) removeRRset(name, rtype);
   }
 }
Beispiel #9
0
  private void validate() throws IOException {
    originNode = exactName(origin);
    if (originNode == null) throw new IOException(origin + ": no data specified");

    RRset rrset = oneRRset(originNode, Type.SOA);
    if (rrset == null || rrset.size() != 1)
      throw new IOException(origin + ": exactly 1 SOA must be specified");
    Iterator it = rrset.rrs();
    SOA = (SOARecord) it.next();

    NS = oneRRset(originNode, Type.NS);
    if (NS == null) throw new IOException(origin + ": no NS set specified");
  }
Beispiel #10
0
 /**
  * Adds a Record to the Zone
  *
  * @param r The record to be added
  * @see Record
  */
 public void addRecord(Record r) {
   Name name = r.getName();
   int rtype = r.getRRsetType();
   synchronized (this) {
     RRset rrset = findRRset(name, rtype);
     if (rrset == null) {
       rrset = new RRset(r);
       addRRset(name, rrset);
     } else {
       rrset.addRR(r);
     }
   }
 }
Beispiel #11
0
 private synchronized RRset oneRRset(Object types, int type) {
   if (type == Type.ANY) throw new IllegalArgumentException("oneRRset(ANY)");
   if (types instanceof List) {
     List list = (List) types;
     for (int i = 0; i < list.size(); i++) {
       RRset set = (RRset) list.get(i);
       if (set.getType() == type) return set;
     }
   } else {
     RRset set = (RRset) types;
     if (set.getType() == type) return set;
   }
   return null;
 }
Beispiel #12
0
 /** Returns the contents of a Zone in master file format. */
 public String toMasterFile() {
   Iterator znames = names();
   StringBuffer sb = new StringBuffer();
   while (znames.hasNext()) {
     Name name = (Name) znames.next();
     TypeMap tm = findName(name);
     Object[] sets = tm.getAll();
     for (int i = 0; i < sets.length; i++) {
       RRset rrset = (RRset) sets[i];
       Iterator it = rrset.rrs();
       while (it.hasNext()) sb.append(it.next() + "\n");
       it = rrset.sigs();
       while (it.hasNext()) sb.append(it.next() + "\n");
     }
   }
   return sb.toString();
 }
Beispiel #13
0
 /**
  * Adds a record to the Cache.
  *
  * @param r The record to be added
  * @param cred The credibility of the record
  * @param o The source of the record (this could be a Message, for example)
  * @see Record
  */
 public void addRecord(Record r, byte cred, Object o) {
   Name name = r.getName();
   short type = r.getRRsetType();
   if (!Type.isRR(type)) return;
   boolean addrrset = false;
   Element element = (Element) findExactSet(name, type);
   if (element == null || cred > element.credibility) {
     RRset rrset = new RRset();
     rrset.addRR(r);
     addRRset(rrset, cred);
   } else if (cred == element.credibility) {
     if (element instanceof PositiveElement) {
       PositiveElement pe = (PositiveElement) element;
       pe.rrset.addRR(r);
     }
   }
 }
Beispiel #14
0
  /**
   * Looks up Records in the Zone. This follows CNAMEs and wildcards.
   *
   * @param name The name to look up
   * @param type The type to look up
   * @return A SetResponse object
   * @see SetResponse
   */
  public SetResponse findRecords(Name name, short type) {
    SetResponse zr = null;

    Object o = findSets(name, type);
    if (o == null) {
      /* The name does not exist */
      if (name.isWild()) return SetResponse.ofType(SetResponse.NXDOMAIN);

      int labels = name.labels() - origin.labels();
      if (labels == 0) return SetResponse.ofType(SetResponse.NXDOMAIN);
      if (hasWild) {
        SetResponse sr;
        Name tname = name;
        do {
          sr = findRecords(tname.wild(1), type);
          if (!sr.isNXDOMAIN()) return sr;
          tname = new Name(tname, 1);
        } while (labels-- >= 1);
        return sr;
      } else return SetResponse.ofType(SetResponse.NXDOMAIN);
    }

    if (o instanceof TypeMap) {
      /* The name exists but the type does not. */
      return SetResponse.ofType(SetResponse.NXRRSET);
    }

    Object[] objects;
    RRset rrset;

    if (o instanceof RRset) {
      objects = null;
      rrset = (RRset) o;
    } else {
      objects = (Object[]) o;
      rrset = (RRset) objects[0];
    }

    if (name.equals(rrset.getName())) {
      if (type != Type.CNAME && type != Type.ANY && rrset.getType() == Type.CNAME)
        zr = new SetResponse(SetResponse.CNAME, rrset);
      else if (rrset.getType() == Type.NS && !name.equals(origin))
        zr = new SetResponse(SetResponse.DELEGATION, rrset);
      else {
        zr = new SetResponse(SetResponse.SUCCESSFUL);
        zr.addRRset(rrset);
        if (objects != null) {
          for (int i = 1; i < objects.length; i++) zr.addRRset((RRset) objects[i]);
        }
      }
    } else {
      if (rrset.getType() == Type.CNAME) return SetResponse.ofType(SetResponse.NXDOMAIN);
      else if (rrset.getType() == Type.DNAME) {
        zr = new SetResponse(SetResponse.DNAME, rrset);
      } else if (rrset.getType() == Type.NS) {
        zr = new SetResponse(SetResponse.DELEGATION, rrset);
      }
    }
    return zr;
  }
Beispiel #15
0
  private void verifyRecords(Cache tcache) {
    Iterator it;

    it = tcache.names();
    while (it.hasNext()) {
      Name name = (Name) it.next();
      Object[] elements = findExactSets(name);
      for (int i = 0; i < elements.length; i++) {
        Element element = (Element) elements[i];
        if (element instanceof PositiveElement) continue;
        RRset rrset = ((PositiveElement) element).rrset;

        /* for now, ignore negative cache entries */
        if (rrset == null) continue;
        if (verifier != null) rrset.setSecurity(verifier.verify(rrset, this));
        if (rrset.getSecurity() < DNSSEC.Secure) continue;
        addSet(name, rrset.getType(), element);
      }
    }
  }
Beispiel #16
0
  /**
   * Creates an array containing fields of the SIG record and the RRsets to be signed/verified.
   *
   * @param sig The SIG record used to sign/verify the rrset.
   * @param rrset The data to be signed/verified.
   * @return The data to be cryptographically signed or verified.
   */
  public static byte[] digestRRset(SIGRecord sig, RRset rrset) {
    DataByteOutputStream out = new DataByteOutputStream();
    digestSIG(out, sig);

    int size = rrset.size();
    byte[][] records = new byte[size][];

    Iterator it = rrset.rrs();
    Name name = rrset.getName();
    Name wild = null;
    if (name.labels() > sig.getLabels()) wild = name.wild(name.labels() - sig.getLabels());
    while (it.hasNext()) {
      Record rec = (Record) it.next();
      if (wild != null) rec = rec.withName(wild);
      records[--size] = rec.toWireCanonical();
    }
    Arrays.sort(records);
    for (int i = 0; i < records.length; i++) out.writeArray(records[i]);
    return out.toByteArray();
  }
Beispiel #17
0
 private synchronized void removeRRset(Name name, int type) {
   Object types = data.get(name);
   if (types == null) {
     return;
   }
   if (types instanceof List) {
     List list = (List) types;
     for (int i = 0; i < list.size(); i++) {
       RRset set = (RRset) list.get(i);
       if (set.getType() == type) {
         list.remove(i);
         if (list.size() == 0) data.remove(name);
         return;
       }
     }
   } else {
     RRset set = (RRset) types;
     if (set.getType() != type) return;
     data.remove(name);
   }
 }
Beispiel #18
0
 public Object next() {
   if (sentLastSOA) return null;
   if (!sentFirstSOA) {
     sentFirstSOA = true;
     return (RRset) findExactSet(origin, Type.SOA);
   }
   if (!sentNS) {
     sentNS = true;
     return getNS();
   }
   if (!sentOrigin) {
     if (currentName == null) {
       currentName = getOrigin();
       TypeMap tm = findName(currentName);
       current = (Object[]) tm.getAll();
       count = 0;
     }
     while (count < current.length) {
       RRset rrset = (RRset) current[count];
       if (rrset.getType() != Type.SOA && rrset.getType() != Type.NS) return current[count++];
       count++;
     }
     current = null;
     sentOrigin = true;
   }
   if (current != null && count < current.length) return current[count++];
   while (znames.hasNext()) {
     Name currentName = (Name) znames.next();
     if (currentName.equals(getOrigin())) continue;
     TypeMap tm = findName(currentName);
     current = (Object[]) tm.getAll();
     count = 0;
     if (count < current.length) return current[count++];
   }
   sentLastSOA = true;
   RRset rrset = new RRset();
   rrset.addRR(getSOA());
   return rrset;
 }
Beispiel #19
0
 /**
  * Adds an RRset to the Zone
  *
  * @param rrset The RRset to be added
  * @see RRset
  */
 public void addRRset(RRset rrset) {
   Name name = rrset.getName();
   addRRset(name, rrset);
 }
Beispiel #20
0
  public static Record[] getRecords(String namestr, short type, short dclass, byte cred) {
    Message query;
    Message response;
    Record question;
    Record[] answers;
    int answerCount = 0, i = 0;
    Enumeration e;
    Name name = new Name(namestr);

    /*System.out.println("lookup of " + name + " " + Type.string(type));*/
    if (!Type.isRR(type) && type != Type.ANY) return null;

    if (res == null) {
      try {
        eres = new ExtendedResolver();
      } catch (UnknownHostException uhe) {
        System.out.println("Failed to initialize resolver");
        System.exit(-1);
      }
    }
    if (cache == null) cache = new Cache();

    CacheResponse cached = cache.lookupRecords(name, type, dclass, cred);
    /*System.out.println(cached);*/
    if (cached.isSuccessful()) {
      RRset rrset = cached.answer();
      answerCount = rrset.size();
      e = rrset.rrs();
    } else if (cached.isNegative()) {
      answerCount = 0;
      e = null;
    } else {
      question = Record.newRecord(name, type, dclass);
      query = Message.newQuery(question);

      if (res != null) response = res.send(query);
      else response = eres.send(query);

      short rcode = response.getHeader().getRcode();
      if (rcode == Rcode.NOERROR || rcode == Rcode.NXDOMAIN) cache.addMessage(response);

      if (rcode != Rcode.NOERROR) return null;

      e = response.getSection(Section.ANSWER);
      while (e.hasMoreElements()) {
        Record r = (Record) e.nextElement();
        if (matchType(r.getType(), type)) answerCount++;
      }

      e = response.getSection(Section.ANSWER);
    }

    if (answerCount == 0) return null;

    answers = new Record[answerCount];

    while (e.hasMoreElements()) {
      Record r = (Record) e.nextElement();
      if (matchType(r.getType(), type)) answers[i++] = r;
    }

    return answers;
  }
Beispiel #21
0
 public short getType() {
   return rrset.getType();
 }
Beispiel #22
0
  /**
   * 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);
    }
  }
Beispiel #23
0
 public PositiveElement(RRset r, byte cred) {
   rrset = r;
   setValues(cred, r.getTTL());
 }
Beispiel #24
0
  /**
   * 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;
  }