From 4a1bae3a69a76cae0341b821e3b880e5b8b8f5a3 Mon Sep 17 00:00:00 2001 From: Sam Whited Date: Tue, 28 Oct 2014 12:14:21 -0400 Subject: Subtree merged in minidns --- .../src/main/java/de/measite/minidns/Record.java | 343 +++++++++++++++++++++ 1 file changed, 343 insertions(+) create mode 100644 libs/minidns/src/main/java/de/measite/minidns/Record.java (limited to 'libs/minidns/src/main/java/de/measite/minidns/Record.java') diff --git a/libs/minidns/src/main/java/de/measite/minidns/Record.java b/libs/minidns/src/main/java/de/measite/minidns/Record.java new file mode 100644 index 00000000..ab081426 --- /dev/null +++ b/libs/minidns/src/main/java/de/measite/minidns/Record.java @@ -0,0 +1,343 @@ +package de.measite.minidns; + +import java.io.DataInputStream; +import java.io.IOException; +import java.util.HashMap; +import java.util.logging.Level; +import java.util.logging.Logger; + +import de.measite.minidns.record.A; +import de.measite.minidns.record.AAAA; +import de.measite.minidns.record.CNAME; +import de.measite.minidns.record.Data; +import de.measite.minidns.record.NS; +import de.measite.minidns.record.PTR; +import de.measite.minidns.record.SRV; +import de.measite.minidns.record.TXT; +import de.measite.minidns.util.NameUtil; + +/** + * A generic DNS record. + */ +public class Record { + + private static final Logger LOGGER = Logger.getLogger(Client.class.getName()); + + /** + * The record type. + * @see IANA DNS Parameters + */ + public static enum TYPE { + A(1), + NS(2), + MD(3), + MF(4), + CNAME(5), + SOA(6), + MB(7), + MG(8), + MR(9), + NULL(10), + WKS(11), + PTR(12), + HINFO(13), + MINFO(14), + MX(15), + TXT(16), + RP(17), + AFSDB(18), + X25(19), + ISDN(20), + RT(21), + NSAP(22), + NSAP_PTR(23), + SIG(24), + KEY(25), + PX(26), + GPOS(27), + AAAA(28), + LOC(29), + NXT(30), + EID(31), + NIMLOC(32), + SRV(33), + ATMA(34), + NAPTR(35), + KX(36), + CERT(37), + A6(38), + DNAME(39), + SINK(40), + OPT(41), + APL(42), + DS(43), + SSHFP(44), + IPSECKEY(45), + RRSIG(46), + NSEC(47), + DNSKEY(48), + DHCID(49), + NSEC3(50), + NSEC3PARAM(51), + HIP(55), + NINFO(56), + RKEY(57), + TALINK(58), + SPF(99), + UINFO(100), + UID(101), + GID(102), + TKEY(249), + TSIG(250), + IXFR(251), + AXFR(252), + MAILB(253), + MAILA(254), + ANY(255), + TA(32768), + DLV(32769); + + /** + * The value of this DNS record type. + */ + private final int value; + + /** + * Internal lookup table to map values to types. + */ + private final static HashMap INVERSE_LUT = + new HashMap(); + + /** + * Initialize the reverse lookup table. + */ + static { + for(TYPE t: TYPE.values()) { + INVERSE_LUT.put(t.getValue(), t); + } + } + + /** + * Create a new record type. + * @param value The binary value of this type. + */ + private TYPE(int value) { + this.value = value; + } + + /** + * Retrieve the binary value of this type. + * @return The binary value. + */ + public int getValue() { + return value; + } + + /** + * Retrieve the symbolic type of the binary value. + * @param value The binary type value. + * @return The symbolic tpye. + */ + public static TYPE getType(int value) { + return INVERSE_LUT.get(value); + } + }; + + /** + * The symbolic class of a DNS record (usually IN for Internet). + */ + public static enum CLASS { + IN(1), + CH(3), + HS(4), + NONE(254), + ANY(255); + + /** + * Internal reverse lookup table to map binary class values to symbolic + * names. + */ + private final static HashMap INVERSE_LUT = + new HashMap(); + + /** + * Initialize the interal reverse lookup table. + */ + static { + for(CLASS c: CLASS.values()) { + INVERSE_LUT.put(c.getValue(), c); + } + } + + /** + * The binary value of this dns class. + */ + private final int value; + + /** + * Create a new DNS class based on a binary value. + * @param value The binary value of this DNS class. + */ + private CLASS(int value) { + this.value = value; + } + + /** + * Retrieve the binary value of this DNS class. + * @return The binary value of this DNS class. + */ + public int getValue() { + return value; + } + + /** + * Retrieve the symbolic DNS class for a binary class value. + * @param value The binary DNS class value. + * @return The symbolic class instance. + */ + public static CLASS getClass(int value) { + return INVERSE_LUT.get(value); + } + + } + + /** + * The generic name of this record. + */ + protected String name; + + /** + * The type (and payload type) of this record. + */ + protected TYPE type; + + /** + * The record class (usually CLASS.IN). + */ + protected CLASS clazz; + + /** + * The ttl of this record. + */ + protected long ttl; + + /** + * The payload object of this record. + */ + protected Data payloadData; + + /** + * MDNS defines the highest bit of the class as the unicast query bit. + */ + protected boolean unicastQuery; + + /** + * Parse a given record based on the full message data and the current + * stream position. + * @param dis The DataInputStream positioned at the first record byte. + * @param data The full message data. + * @throws IOException In case of malformed replies. + */ + public void parse(DataInputStream dis, byte[] data) throws IOException { + this.name = NameUtil.parse(dis, data); + this.type = TYPE.getType(dis.readUnsignedShort()); + int clazzValue = dis.readUnsignedShort(); + this.clazz = CLASS.getClass(clazzValue & 0x7fff); + this.unicastQuery = (clazzValue & 0x8000) > 0; + if (this.clazz == null) { + LOGGER.log(Level.FINE, "Unknown class " + clazzValue); + } + this.ttl = (((long)dis.readUnsignedShort()) << 32) + + dis.readUnsignedShort(); + int payloadLength = dis.readUnsignedShort(); + switch (this.type) { + case SRV: + this.payloadData = new SRV(); + break; + case AAAA: + this.payloadData = new AAAA(); + break; + case A: + this.payloadData = new A(); + break; + case NS: + this.payloadData = new NS(); + break; + case CNAME: + this.payloadData = new CNAME(); + break; + case PTR: + this.payloadData = new PTR(); + break; + case TXT: + this.payloadData = new TXT(); + break; + default: + LOGGER.log(Level.FINE, "Unparsed type " + type); + this.payloadData = null; + for (int i = 0; i < payloadLength; i++) { + dis.readByte(); + } + break; + } + if (this.payloadData != null) { + this.payloadData.parse(dis, data, payloadLength); + } + } + + /** + * Retrieve a textual representation of this resource record. + * @return String + */ + @Override + public String toString() { + if (payloadData == null) { + return "RR " + type + "/" + clazz; + } + return "RR " + type + "/" + clazz + ": " + payloadData.toString(); + }; + + /** + * Check if this record answers a given query. + * @param q The query. + * @return True if this record is a valid answer. + */ + public boolean isAnswer(Question q) { + return ((q.getType() == type) || (q.getType() == TYPE.ANY)) && + ((q.getClazz() == clazz) || (q.getClazz() == CLASS.ANY)) && + (q.getName().equals(name)); + } + + /** + * See if this query/response was a unicast query (highest class bit set). + * @return True if it is a unicast query/response record. + */ + public boolean isUnicastQuery() { + return unicastQuery; + } + + /** + * The generic record name, e.g. "measite.de". + * @return The record name. + */ + public String getName() { + return name; + } + + /** + * The payload data, usually a subclass of data (A, AAAA, CNAME, ...). + * @return The payload data. + */ + public Data getPayload() { + return payloadData; + } + + /** + * Retrieve the record ttl. + * @return The record ttl. + */ + public long getTtl() { + return ttl; + } + +} -- cgit v1.2.3