Record.java

  1package de.measite.minidns;
  2
  3import java.io.DataInputStream;
  4import java.io.IOException;
  5import java.util.HashMap;
  6
  7import de.measite.minidns.record.A;
  8import de.measite.minidns.record.AAAA;
  9import de.measite.minidns.record.CNAME;
 10import de.measite.minidns.record.Data;
 11import de.measite.minidns.record.NS;
 12import de.measite.minidns.record.SRV;
 13import de.measite.minidns.util.NameUtil;
 14
 15/**
 16 * A generic DNS record.
 17 */
 18public class Record {
 19
 20    /**
 21     * The record type.
 22     * {@see http://www.iana.org/assignments/dns-parameters}
 23     */
 24    public static enum TYPE {
 25        A(1),
 26        NS(2),
 27        MD(3),
 28        MF(4),
 29        CNAME(5),
 30        SOA(6),
 31        MB(7),
 32        MG(8),
 33        MR(9),
 34        NULL(10),
 35        WKS(11),
 36        PTR(12),
 37        HINFO(13),
 38        MINFO(14),
 39        MX(15),
 40        TXT(16),
 41        RP(17),
 42        AFSDB(18),
 43        X25(19),
 44        ISDN(20),
 45        RT(21),
 46        NSAP(22),
 47        NSAP_PTR(23),
 48        SIG(24),
 49        KEY(25),
 50        PX(26),
 51        GPOS(27),
 52        AAAA(28),
 53        LOC(29),
 54        NXT(30),
 55        EID(31),
 56        NIMLOC(32),
 57        SRV(33),
 58        ATMA(34),
 59        NAPTR(35),
 60        KX(36),
 61        CERT(37),
 62        A6(38),
 63        DNAME(39),
 64        SINK(40),
 65        OPT(41),
 66        APL(42),
 67        DS(43),
 68        SSHFP(44),
 69        IPSECKEY(45),
 70        RRSIG(46),
 71        NSEC(47),
 72        DNSKEY(48),
 73        DHCID(49),
 74        NSEC3(50),
 75        NSEC3PARAM(51),
 76        HIP(55),
 77        NINFO(56),
 78        RKEY(57),
 79        TALINK(58),
 80        SPF(99),
 81        UINFO(100),
 82        UID(101),
 83        GID(102),
 84        TKEY(249),
 85        TSIG(250),
 86        IXFR(251),
 87        AXFR(252),
 88        MAILB(253),
 89        MAILA(254),
 90        ANY(255),
 91        TA(32768),
 92        DLV(32769);
 93
 94        /**
 95         * The value of this DNS record type.
 96         */
 97        private final int value;
 98
 99        /**
100         * Internal lookup table to map values to types.
101         */
102        private final static HashMap<Integer, TYPE> INVERSE_LUT =
103                                        new HashMap<Integer, TYPE>();
104
105        /**
106         * Initialize the reverse lookup table.
107         */
108        static {
109            for(TYPE t: TYPE.values()) {
110                INVERSE_LUT.put(t.getValue(), t);
111            }
112        }
113
114        /**
115         * Create a new record type.
116         * @param value The binary value of this type.
117         */
118        private TYPE(int value) {
119            this.value = value;
120        }
121
122        /**
123         * Retrieve the binary value of this type.
124         * @return The binary value.
125         */
126        public int getValue() {
127            return value;
128        }
129
130        /**
131         * Retrieve the symbolic type of the binary value.
132         * @param value The binary type value.
133         * @return The symbolic tpye.
134         */
135        public static TYPE getType(int value) {
136            return INVERSE_LUT.get(value);
137        }
138    };
139
140    /**
141     * The symbolic class of a DNS record (usually IN for Internet).
142     */
143    public static enum CLASS {
144        IN(1),
145        CH(3),
146        HS(4),
147        NONE(254),
148        ANY(255);
149
150        /**
151         * Internal reverse lookup table to map binary class values to symbolic
152         * names.
153         */
154        private final static HashMap<Integer, CLASS> INVERSE_LUT =
155                                            new HashMap<Integer, CLASS>();
156
157        /**
158         * Initialize the interal reverse lookup table.
159         */
160        static {
161            for(CLASS c: CLASS.values()) {
162                INVERSE_LUT.put(c.getValue(), c);
163            }
164        }
165
166        /**
167         * The binary value of this dns class.
168         */
169        private final int value;
170
171        /**
172         * Create a new DNS class based on a binary value.
173         * @param value The binary value of this DNS class.
174         */
175        private CLASS(int value) {
176            this.value = value;
177        }
178
179        /**
180         * Retrieve the binary value of this DNS class.
181         * @return The binary value of this DNS class.
182         */
183        public int getValue() {
184            return value;
185        }
186
187        /**
188         * Retrieve the symbolic DNS class for a binary class value.
189         * @param value The binary DNS class value.
190         * @return The symbolic class instance.
191         */
192        public static CLASS getClass(int value) {
193            return INVERSE_LUT.get(value);
194        }
195
196    }
197
198    /**
199     * The generic name of this record.
200     */
201    protected String name;
202
203    /**
204     * The type (and payload type) of this record.
205     */
206    protected TYPE type;
207
208    /**
209     * The record class (usually CLASS.IN).
210     */
211    protected CLASS clazz;
212
213    /**
214     * The ttl of this record.
215     */
216    protected long ttl;
217
218    /**
219     * The payload object of this record.
220     */
221    protected Data payloadData;
222
223    /**
224     * Parse a given record based on the full message data and the current
225     * stream position.
226     * @param dis The DataInputStream positioned at the first record byte.
227     * @param data The full message data.
228     * @throws IOException In case of malformed replies.
229     */
230    public void parse(DataInputStream dis, byte[] data) throws IOException {
231        this.name = NameUtil.parse(dis, data);
232        this.type = TYPE.getType(dis.readUnsignedShort());
233        this.clazz = CLASS.getClass(dis.readUnsignedShort());
234        this.ttl = (((long)dis.readUnsignedShort()) << 32) +
235                   dis.readUnsignedShort();
236        int payloadLength = dis.readUnsignedShort();
237        switch (this.type) {
238        case SRV:
239            this.payloadData = new SRV();
240            break;
241        case AAAA:
242            this.payloadData = new AAAA();
243            break;
244        case A:
245            this.payloadData = new A();
246            break;
247        case NS:
248            this.payloadData = new NS();
249            break;
250        case CNAME:
251            this.payloadData = new CNAME();
252            break;
253        default:
254            System.out.println("Unparsed type " + type);
255            this.payloadData = null;
256            for (int i = 0; i < payloadLength; i++) {
257                dis.readByte();
258            }
259            break;
260        }
261        if (this.payloadData != null) {
262            this.payloadData.parse(dis, data, payloadLength);
263        }
264    }
265
266    /**
267     * Retrieve a textual representation of this resource record.
268     * @return String
269     */
270    @Override
271    public String toString() {
272        if (payloadData == null) {
273            return "RR " + type + "/" + clazz;
274        }
275        return "RR " + type + "/" + clazz + ": " + payloadData.toString();
276    };
277
278    /**
279     * Check if this record answers a given query.
280     * @param q The query.
281     * @return True if this record is a valid answer.
282     */
283    public boolean isAnswer(Question q) {
284        return ((q.getType() == type) || (q.getType() == TYPE.ANY)) &&
285               ((q.getClazz() == clazz) || (q.getClazz() == CLASS.ANY)) &&
286               (q.getName().equals(name));
287    }
288
289    public String getName() {
290        return name;
291    }
292
293    public Data getPayload() {
294        return payloadData;
295    }
296
297}