/** * Builds a new Record from its textual representation * * @param name The owner name of the record. * @param type The record's type. * @param dclass The record's class. * @param ttl The record's time to live. * @param st A tokenizer containing the textual representation of the rdata. * @param origin The default origin to be appended to relative domain names. * @return The new record * @throws IOException The text format was invalid. */ public static Record fromString( Name name, int type, int dclass, long ttl, Tokenizer st, Name origin) throws IOException { Record rec; if (!name.isAbsolute()) throw new RelativeNameException(name); Type.check(type); DClass.check(dclass); TTL.check(ttl); Tokenizer.Token t = st.get(); if (t.type == Tokenizer.IDENTIFIER && t.value.equals("\\#")) { int length = st.getUInt16(); byte[] data = st.getHex(); if (data == null) { data = new byte[0]; } if (length != data.length) throw st.exception("invalid unknown RR encoding: " + "length mismatch"); DNSInput in = new DNSInput(data); return newRecord(name, type, dclass, ttl, length, in); } st.unget(); rec = getEmptyRecord(name, type, dclass, ttl, true); rec.rdataFromString(st, origin); t = st.get(); if (t.type != Tokenizer.EOL && t.type != Tokenizer.EOF) { throw st.exception("unexpected tokens at end of record"); } return rec; }
/** Converts the RRSIG/SIG Record to a String */ public String rdataToString() { StringBuffer sb = new StringBuffer(); if (signature != null) { sb.append(Type.string(covered)); sb.append(" "); sb.append(alg); sb.append(" "); sb.append(labels); sb.append(" "); sb.append(origttl); sb.append(" "); if (Options.check("multiline")) sb.append("(\n\t"); sb.append(FormattedTime.format(expire)); sb.append(" "); sb.append(FormattedTime.format(timeSigned)); sb.append(" "); sb.append(footprint); sb.append(" "); sb.append(signer); if (Options.check("multiline")) { sb.append("\n"); sb.append(base64.formatString(signature, 64, "\t", true)); } else { sb.append(" "); sb.append(base64.toString(signature)); } } return sb.toString(); }
private Record parseRR(MyStringTokenizer st, boolean useLast, Record last, Name origin) throws IOException { Name name; int ttl; short type, dclass; if (!useLast) name = new Name(st.nextToken(), origin); else name = last.getName(); String s = st.nextToken(); try { ttl = TTL.parseTTL(s); s = st.nextToken(); } catch (NumberFormatException e) { if (!useLast || last == null) ttl = defaultTTL; else ttl = last.getTTL(); } if ((dclass = DClass.value(s)) > 0) s = st.nextToken(); else dclass = DClass.IN; if ((type = Type.value(s)) < 0) throw new IOException("Parse error"); return Record.fromString(name, type, dclass, ttl, st, origin); }
public SIGBase( Name name, int type, int dclass, long ttl, int covered, int alg, long origttl, Date expire, Date timeSigned, int footprint, Name signer, byte[] signature) { super(name, type, dclass, ttl); Type.check(covered); checkU8("alg", alg); checkU8("labels", labels); TTL.check(origttl); checkU16("footprint", footprint); this.covered = covered; this.alg = alg; this.labels = name.labels(); this.origttl = origttl; this.expire = expire; this.timeSigned = timeSigned; this.footprint = footprint; if (!signer.isAbsolute()) throw new RelativeNameException(signer); this.signer = signer; this.signature = signature; }
/** * Creates a new empty record, with the given parameters. * * @param name The owner name of the record. * @param type The record's type. * @param dclass The record's class. * @param ttl The record's time to live. * @return An object of a subclass of Record */ public static Record newRecord(Name name, int type, int dclass, long ttl) { if (!name.isAbsolute()) throw new RelativeNameException(name); Type.check(type); DClass.check(dclass); TTL.check(ttl); return getEmptyRecord(name, type, dclass, ttl, false); }
public String toString() { StringBuffer sb = new StringBuffer(); if (type == 0) sb.append("NXDOMAIN " + name); else sb.append("NXRRSET " + name + " " + Type.string(type)); sb.append(" cl = "); sb.append(credibility); return sb.toString(); }
/** * Indicates whether generation is supported for this type. * * @throws InvalidTypeException The type is out of range. */ public static boolean supportedType(int type) { Type.check(type); return (type == Type.PTR || type == Type.CNAME || type == Type.DNAME || type == Type.A || type == Type.AAAA || type == Type.NS); }
Record(Name name, int type, int dclass, long ttl) { if (!name.isAbsolute()) throw new RelativeNameException(name); Type.check(type); DClass.check(dclass); TTL.check(ttl); this.name = name; this.type = type; this.dclass = dclass; this.ttl = ttl; }
/** * Converts the generate specification to a string containing the corresponding $GENERATE * statement. */ public String toString() { StringBuffer sb = new StringBuffer(); sb.append("$GENERATE "); sb.append(start + "-" + end); if (step > 1) sb.append("/" + step); sb.append(" "); sb.append(namePattern + " "); sb.append(ttl + " "); if (dclass != DClass.IN || !Options.check("noPrintIN")) sb.append(DClass.string(dclass) + " "); sb.append(Type.string(type) + " "); sb.append(rdataPattern + " "); return sb.toString(); }
Record rdataFromString(Name name, short dclass, int ttl, MyStringTokenizer st, Name origin) throws TextParseException { SIGRecord rec = new SIGRecord(name, dclass, ttl); rec.covered = Type.value(st.nextToken()); rec.alg = Byte.parseByte(st.nextToken()); rec.labels = Byte.parseByte(st.nextToken()); rec.origttl = TTL.parseTTL(st.nextToken()); rec.expire = parseDate(st.nextToken()); rec.timeSigned = parseDate(st.nextToken()); rec.footprint = (short) Integer.parseInt(st.nextToken()); rec.signer = Name.fromString(st.nextToken(), origin); if (st.hasMoreTokens()) rec.signature = base64.fromString(st.remainingTokens()); return rec; }
/** * Creates a new record, with the given parameters. * * @param name The owner name of the record. * @param type The record's type. * @param dclass The record's class. * @param ttl The record's time to live. * @param length The length of the record's data. * @param data The rdata of the record, in uncompressed DNS wire format. Only the first length * bytes are used. */ public static Record newRecord( Name name, int type, int dclass, long ttl, int length, byte[] data) { if (!name.isAbsolute()) throw new RelativeNameException(name); Type.check(type); DClass.check(dclass); TTL.check(ttl); DNSInput in; if (data != null) in = new DNSInput(data); else in = null; try { return newRecord(name, type, dclass, ttl, length, in); } catch (IOException e) { return null; } }
/** * Converts the given section of the Message to a String. * * @see Section */ public String sectionToString(int i) { if (i > 3) return null; StringBuffer sb = new StringBuffer(); Record[] records = getSectionArray(i); for (int j = 0; j < records.length; j++) { Record rec = records[j]; if (i == Section.QUESTION) { sb.append(";;\t" + rec.name); sb.append(", type = " + Type.string(rec.type)); sb.append(", class = " + DClass.string(rec.dclass)); } else sb.append(rec); sb.append("\n"); } return sb.toString(); }
/** * 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); } } }
protected static Record rdataFromString(SIGBase rec, Tokenizer st, Name origin) throws IOException { String typeString = st.getString(); int covered = Type.value(typeString); if (covered < 0) throw st.exception("Invalid type: " + typeString); rec.covered = covered; String algString = st.getString(); int alg = DNSSEC.Algorithm.value(algString); if (alg < 0) throw st.exception("Invalid algorithm: " + algString); rec.alg = alg; rec.labels = st.getUInt8(); rec.origttl = st.getTTL(); rec.expire = FormattedTime.parse(st.getString()); rec.timeSigned = FormattedTime.parse(st.getString()); rec.footprint = st.getUInt16(); rec.signer = st.getName(origin); rec.signature = st.getBase64(); return rec; }
private static final Record getTypedObject(int type) { if (type < 0 || type > knownRecords.length) return unknownRecord.getObject(); if (knownRecords[type] != null) return knownRecords[type]; /* Construct the class name by putting the type before "Record". */ String s = Record.class.getPackage().getName() + "." + Type.string(type).replace('-', '_') + "Record"; try { Class c = Class.forName(s); Constructor m = c.getDeclaredConstructor(emptyClassArray); knownRecords[type] = (Record) m.newInstance(emptyObjectArray); } catch (ClassNotFoundException e) { /* This is normal; do nothing */ } catch (Exception e) { if (Options.check("verbose")) System.err.println(e); } if (knownRecords[type] == null) knownRecords[type] = unknownRecord.getObject(); return knownRecords[type]; }
/** Converts a Record into a String representation */ public String toString() { StringBuffer sb = new StringBuffer(); sb.append(name); if (sb.length() < 8) sb.append("\t"); if (sb.length() < 16) sb.append("\t"); sb.append("\t"); if (Options.check("BINDTTL")) sb.append(TTL.format(ttl)); else sb.append(ttl); sb.append("\t"); if (dclass != DClass.IN || !Options.check("noPrintIN")) { sb.append(DClass.string(dclass)); sb.append("\t"); } sb.append(Type.string(type)); String rdata = rrToString(); if (!rdata.equals("")) { sb.append("\t"); sb.append(rdata); } return sb.toString(); }
/** Converts rdata to a String */ public String rdataToString() { StringBuffer sb = new StringBuffer(); if (signature != null) { sb.append(Type.string(covered)); sb.append(" "); sb.append(alg); sb.append(" "); sb.append(labels); sb.append(" "); sb.append(origttl); sb.append(" (\n\t"); sb.append(formatDate(expire)); sb.append(" "); sb.append(formatDate(timeSigned)); sb.append(" "); sb.append((int) footprint & 0xFFFF); sb.append(" "); sb.append(signer); sb.append("\n"); sb.append(base64.formatString(signature, 64, "\t", true)); } return sb.toString(); }
public void check(int val) { Type.check(val); }
private void logLookup(Name name, short type, String msg) { System.err.println("lookupRecords(" + name + " " + Type.string(type) + "): " + msg); }
/** * 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; }