1 /*
2 * Copyright (c) 2000, 2002, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package com.sun.jndi.dns;
27
28 import javax.naming.InvalidNameException;
29
30
31 /**
32 * The ResourceRecord class represents a DNS resource record.
33 * The string format is based on the master file representation in
34 * RFC 1035.
35 *
36 * @author Scott Seligman
37 */
38
39
40 public class ResourceRecord {
41
42 /*
43 * Resource record type codes
44 */
45 static final int TYPE_A = 1;
46 static final int TYPE_NS = 2;
47 static final int TYPE_CNAME = 5;
48 static final int TYPE_SOA = 6;
49 static final int TYPE_PTR = 12;
67 null, null, null, null, null,
68 null, null, null, "AAAA", null,
69 null, null, null, "SRV", null,
70 "NAPTR"
71 };
72
73 /*
74 * Resource record class codes
75 */
76 static final int CLASS_INTERNET = 1;
77 static final int CLASS_HESIOD = 2;
78 static final int QCLASS_STAR = 255; // query class "*"
79
80 /*
81 * Mapping from resource record type codes to class name strings.
82 */
83 static final String rrClassNames[] = {
84 null, "IN", null, null, "HS"
85 };
86
87
88 byte[] msg; // DNS message
89 int msgLen; // msg size (in octets)
90 boolean qSection; // true if this RR is part of question section
91 // and therefore has no ttl or rdata
92 int offset; // offset of RR w/in msg
93 int rrlen; // number of octets in encoded RR
94 DnsName name; // name field of RR, including root label
95 int rrtype; // type field of RR
96 String rrtypeName; // name of of rrtype
97 int rrclass; // class field of RR
98 String rrclassName; // name of rrclass
99 int ttl = 0; // ttl field of RR
100 int rdlen = 0; // number of octets of rdata
101 Object rdata = null; // rdata -- most are String, unknown are byte[]
102
103
104 /*
105 * Constructs a new ResourceRecord. The encoded data of the DNS
106 * message is contained in msg; data for this RR begins at msg[offset].
107 * If qSection is true this RR is part of a question section. It's
108 * not a true resource record in that case, but is treated as if it
109 * were a shortened one (with no ttl or rdata). If decodeRdata is
110 * false, the rdata is not decoded (and getRdata() will return null)
111 * unless this is an SOA record.
112 *
113 * @throws InvalidNameException if a decoded domain name isn't valid.
114 * @throws ArrayIndexOutOfBoundsException given certain other corrupt data.
115 */
116 ResourceRecord(byte[] msg, int msgLen, int offset,
117 boolean qSection, boolean decodeRdata)
118 throws InvalidNameException {
119
120 this.msg = msg;
121 this.msgLen = msgLen;
122 this.offset = offset;
123 this.qSection = qSection;
124 decode(decodeRdata);
125 }
126
127 public String toString() {
128 String text = name + " " + rrclassName + " " + rrtypeName;
129 if (!qSection) {
130 text += " " + ttl + " " +
131 ((rdata != null) ? rdata : "[n/a]");
132 }
133 return text;
134 }
135
136 /*
137 * Returns the name field of this RR, including the root label.
138 */
218 * than the second. If the serial numbers are not comparable the
219 * result is undefined. Note that the relation is not transitive.
220 */
221 public static int compareSerialNumbers(long s1, long s2) {
222 long diff = s2 - s1;
223 if (diff == 0) {
224 return 0;
225 } else if ((diff > 0 && diff <= 0x7FFFFFFF) ||
226 (diff < 0 && -diff > 0x7FFFFFFF)) {
227 return -1;
228 } else {
229 return 1;
230 }
231 }
232
233
234 /*
235 * Decodes the binary format of the RR.
236 * May throw ArrayIndexOutOfBoundsException given corrupt data.
237 */
238 private void decode(boolean decodeRdata) throws InvalidNameException {
239 int pos = offset; // index of next unread octet
240
241 name = new DnsName(); // NAME
242 pos = decodeName(pos, name);
243
244 rrtype = getUShort(pos); // TYPE
245 rrtypeName = (rrtype < rrTypeNames.length)
246 ? rrTypeNames[rrtype]
247 : null;
248 if (rrtypeName == null) {
249 rrtypeName = Integer.toString(rrtype);
250 }
251 pos += 2;
252
253 rrclass = getUShort(pos); // CLASS
254 rrclassName = (rrclass < rrClassNames.length)
255 ? rrClassNames[rrclass]
256 : null;
257 if (rrclassName == null) {
258 rrclassName = Integer.toString(rrclass);
299
300 /*
301 * Returns the 4-byte signed value at msg[pos]. The high
302 * order byte comes first.
303 */
304 private int getInt(int pos) {
305 return ((getUShort(pos) << 16) | getUShort(pos + 2));
306 }
307
308 /*
309 * Returns the 4-byte unsigned value at msg[pos]. The high
310 * order byte comes first.
311 */
312 private long getUInt(int pos) {
313 return (getInt(pos) & 0xffffffffL);
314 }
315
316 /*
317 * Returns the name encoded at msg[pos], including the root label.
318 */
319 private DnsName decodeName(int pos) throws InvalidNameException {
320 DnsName n = new DnsName();
321 decodeName(pos, n);
322 return n;
323 }
324
325 /*
326 * Prepends to "n" the domain name encoded at msg[pos], including the root
327 * label. Returns the index into "msg" following the name.
328 */
329 private int decodeName(int pos, DnsName n) throws InvalidNameException {
330 if (msg[pos] == 0) { // end of name
331 n.add(0, "");
332 return (pos + 1);
333 } else if ((msg[pos] & 0xC0) != 0) { // name compression
334 decodeName(getUShort(pos) & 0x3FFF, n);
335 return (pos + 2);
336 } else { // append a label
337 int len = msg[pos++];
338 try {
339 n.add(0, new String(msg, pos, len, "ISO-8859-1"));
340 } catch (java.io.UnsupportedEncodingException e) {
341 // assert false : "ISO-Latin-1 charset unavailable";
342 }
343 return decodeName(pos + len, n);
344 }
345 }
346
347 /*
348 * Returns the rdata encoded at msg[pos]. The format is dependent
349 * on the rrtype and rrclass values, which have already been set.
350 * The length of the encoded data is rdlen, which has already been
351 * set.
352 * The rdata of records with unknown type/class combinations is
353 * returned in a newly-allocated byte array.
354 */
355 private Object decodeRdata(int pos) throws InvalidNameException {
356 if (rrclass == CLASS_INTERNET) {
357 switch (rrtype) {
358 case TYPE_A:
359 return decodeA(pos);
360 case TYPE_AAAA:
361 return decodeAAAA(pos);
362 case TYPE_CNAME:
363 case TYPE_NS:
364 case TYPE_PTR:
365 return decodeName(pos);
366 case TYPE_MX:
367 return decodeMx(pos);
368 case TYPE_SOA:
369 return decodeSoa(pos);
370 case TYPE_SRV:
371 return decodeSrv(pos);
372 case TYPE_NAPTR:
373 return decodeNaptr(pos);
374 case TYPE_TXT:
375 return decodeTxt(pos);
376 case TYPE_HINFO:
377 return decodeHinfo(pos);
378 }
379 }
380 // Unknown RR type/class
381 byte[] rd = new byte[rdlen];
382 System.arraycopy(msg, pos, rd, 0, rdlen);
383 return rd;
384 }
385
386 /*
387 * Returns the rdata of an MX record that is encoded at msg[pos].
388 */
389 private String decodeMx(int pos) throws InvalidNameException {
390 int preference = getUShort(pos);
391 pos += 2;
392 DnsName name = decodeName(pos);
393 return (preference + " " + name);
394 }
395
396 /*
397 * Returns the rdata of an SOA record that is encoded at msg[pos].
398 */
399 private String decodeSoa(int pos) throws InvalidNameException {
400 DnsName mname = new DnsName();
401 pos = decodeName(pos, mname);
402 DnsName rname = new DnsName();
403 pos = decodeName(pos, rname);
404
405 long serial = getUInt(pos);
406 pos += 4;
407 long refresh = getUInt(pos);
408 pos += 4;
409 long retry = getUInt(pos);
410 pos += 4;
411 long expire = getUInt(pos);
412 pos += 4;
413 long minimum = getUInt(pos); // now used as negative TTL
414 pos += 4;
415
416 return (mname + " " + rname + " " + serial + " " +
417 refresh + " " + retry + " " + expire + " " + minimum);
418 }
419
420 /*
421 * Returns the rdata of an SRV record that is encoded at msg[pos].
422 * See RFC 2782.
423 */
424 private String decodeSrv(int pos) throws InvalidNameException {
425 int priority = getUShort(pos);
426 pos += 2;
427 int weight = getUShort(pos);
428 pos += 2;
429 int port = getUShort(pos);
430 pos += 2;
431 DnsName target = decodeName(pos);
432 return (priority + " " + weight + " " + port + " " + target);
433 }
434
435 /*
436 * Returns the rdata of an NAPTR record that is encoded at msg[pos].
437 * See RFC 2915.
438 */
439 private String decodeNaptr(int pos) throws InvalidNameException {
440 int order = getUShort(pos);
441 pos += 2;
442 int preference = getUShort(pos);
443 pos += 2;
444 StringBuffer flags = new StringBuffer();
445 pos += decodeCharString(pos, flags);
446 StringBuffer services = new StringBuffer();
447 pos += decodeCharString(pos, services);
448 StringBuffer regexp = new StringBuffer(rdlen);
449 pos += decodeCharString(pos, regexp);
450 DnsName replacement = decodeName(pos);
451
452 return (order + " " + preference + " " + flags + " " +
453 services + " " + regexp + " " + replacement);
454 }
455
456 /*
457 * Returns the rdata of a TXT record that is encoded at msg[pos].
458 * The rdata consists of one or more <character-string>s.
459 */
|
1 /*
2 * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package com.sun.jndi.dns;
27
28 import javax.naming.CommunicationException;
29 import javax.naming.InvalidNameException;
30
31 import java.io.IOException;
32
33 import java.nio.charset.StandardCharsets;
34
35
36 /**
37 * The ResourceRecord class represents a DNS resource record.
38 * The string format is based on the master file representation in
39 * RFC 1035.
40 *
41 * @author Scott Seligman
42 */
43
44
45 public class ResourceRecord {
46
47 /*
48 * Resource record type codes
49 */
50 static final int TYPE_A = 1;
51 static final int TYPE_NS = 2;
52 static final int TYPE_CNAME = 5;
53 static final int TYPE_SOA = 6;
54 static final int TYPE_PTR = 12;
72 null, null, null, null, null,
73 null, null, null, "AAAA", null,
74 null, null, null, "SRV", null,
75 "NAPTR"
76 };
77
78 /*
79 * Resource record class codes
80 */
81 static final int CLASS_INTERNET = 1;
82 static final int CLASS_HESIOD = 2;
83 static final int QCLASS_STAR = 255; // query class "*"
84
85 /*
86 * Mapping from resource record type codes to class name strings.
87 */
88 static final String rrClassNames[] = {
89 null, "IN", null, null, "HS"
90 };
91
92 /*
93 * Maximum number of compression references in labels.
94 * Used to detect compression loops.
95 */
96 private static final int MAXIMUM_COMPRESSION_REFERENCES = 16;
97
98 byte[] msg; // DNS message
99 int msgLen; // msg size (in octets)
100 boolean qSection; // true if this RR is part of question section
101 // and therefore has no ttl or rdata
102 int offset; // offset of RR w/in msg
103 int rrlen; // number of octets in encoded RR
104 DnsName name; // name field of RR, including root label
105 int rrtype; // type field of RR
106 String rrtypeName; // name of of rrtype
107 int rrclass; // class field of RR
108 String rrclassName; // name of rrclass
109 int ttl = 0; // ttl field of RR
110 int rdlen = 0; // number of octets of rdata
111 Object rdata = null; // rdata -- most are String, unknown are byte[]
112
113
114 /*
115 * Constructs a new ResourceRecord. The encoded data of the DNS
116 * message is contained in msg; data for this RR begins at msg[offset].
117 * If qSection is true this RR is part of a question section. It's
118 * not a true resource record in that case, but is treated as if it
119 * were a shortened one (with no ttl or rdata). If decodeRdata is
120 * false, the rdata is not decoded (and getRdata() will return null)
121 * unless this is an SOA record.
122 *
123 * @throws CommunicationException if a decoded domain name isn't valid.
124 * @throws ArrayIndexOutOfBoundsException given certain other corrupt data.
125 */
126 ResourceRecord(byte[] msg, int msgLen, int offset,
127 boolean qSection, boolean decodeRdata)
128 throws CommunicationException {
129
130 this.msg = msg;
131 this.msgLen = msgLen;
132 this.offset = offset;
133 this.qSection = qSection;
134 decode(decodeRdata);
135 }
136
137 public String toString() {
138 String text = name + " " + rrclassName + " " + rrtypeName;
139 if (!qSection) {
140 text += " " + ttl + " " +
141 ((rdata != null) ? rdata : "[n/a]");
142 }
143 return text;
144 }
145
146 /*
147 * Returns the name field of this RR, including the root label.
148 */
228 * than the second. If the serial numbers are not comparable the
229 * result is undefined. Note that the relation is not transitive.
230 */
231 public static int compareSerialNumbers(long s1, long s2) {
232 long diff = s2 - s1;
233 if (diff == 0) {
234 return 0;
235 } else if ((diff > 0 && diff <= 0x7FFFFFFF) ||
236 (diff < 0 && -diff > 0x7FFFFFFF)) {
237 return -1;
238 } else {
239 return 1;
240 }
241 }
242
243
244 /*
245 * Decodes the binary format of the RR.
246 * May throw ArrayIndexOutOfBoundsException given corrupt data.
247 */
248 private void decode(boolean decodeRdata) throws CommunicationException {
249 int pos = offset; // index of next unread octet
250
251 name = new DnsName(); // NAME
252 pos = decodeName(pos, name);
253
254 rrtype = getUShort(pos); // TYPE
255 rrtypeName = (rrtype < rrTypeNames.length)
256 ? rrTypeNames[rrtype]
257 : null;
258 if (rrtypeName == null) {
259 rrtypeName = Integer.toString(rrtype);
260 }
261 pos += 2;
262
263 rrclass = getUShort(pos); // CLASS
264 rrclassName = (rrclass < rrClassNames.length)
265 ? rrClassNames[rrclass]
266 : null;
267 if (rrclassName == null) {
268 rrclassName = Integer.toString(rrclass);
309
310 /*
311 * Returns the 4-byte signed value at msg[pos]. The high
312 * order byte comes first.
313 */
314 private int getInt(int pos) {
315 return ((getUShort(pos) << 16) | getUShort(pos + 2));
316 }
317
318 /*
319 * Returns the 4-byte unsigned value at msg[pos]. The high
320 * order byte comes first.
321 */
322 private long getUInt(int pos) {
323 return (getInt(pos) & 0xffffffffL);
324 }
325
326 /*
327 * Returns the name encoded at msg[pos], including the root label.
328 */
329 private DnsName decodeName(int pos) throws CommunicationException {
330 DnsName n = new DnsName();
331 decodeName(pos, n);
332 return n;
333 }
334
335 /*
336 * Prepends to "n" the domain name encoded at msg[pos], including the root
337 * label. Returns the index into "msg" following the name.
338 */
339 private int decodeName(int pos, DnsName n) throws CommunicationException {
340 int endPos = -1;
341 int level = 0;
342 try {
343 while (true) {
344 if (level > MAXIMUM_COMPRESSION_REFERENCES)
345 throw new IOException("Too many compression references");
346 int type = msg[pos] & 0xFF;
347 if (type == 0) { // end of name
348 ++pos;
349 n.add(0, "");
350 break;
351 } else if (type <= 63) { // regular label
352 ++pos;
353 n.add(0, new String(msg, pos, type,
354 StandardCharsets.ISO_8859_1));
355 pos += type;
356 } else if ((msg[pos] & 0xC0) == 0xC0) { // name compression
357 ++level;
358 endPos = pos + 2;
359 pos = getUShort(pos) & 0x3FFF;
360 } else
361 throw new IOException("Invalid label type: " + type);
362 }
363 } catch (IOException | InvalidNameException e) {
364 CommunicationException ce =new CommunicationException(
365 "DNS error: malformed packet");
366 ce.initCause(e);
367 throw ce;
368 }
369 if (endPos == -1)
370 endPos = pos;
371 return endPos;
372 }
373
374 /*
375 * Returns the rdata encoded at msg[pos]. The format is dependent
376 * on the rrtype and rrclass values, which have already been set.
377 * The length of the encoded data is rdlen, which has already been
378 * set.
379 * The rdata of records with unknown type/class combinations is
380 * returned in a newly-allocated byte array.
381 */
382 private Object decodeRdata(int pos) throws CommunicationException {
383 if (rrclass == CLASS_INTERNET) {
384 switch (rrtype) {
385 case TYPE_A:
386 return decodeA(pos);
387 case TYPE_AAAA:
388 return decodeAAAA(pos);
389 case TYPE_CNAME:
390 case TYPE_NS:
391 case TYPE_PTR:
392 return decodeName(pos);
393 case TYPE_MX:
394 return decodeMx(pos);
395 case TYPE_SOA:
396 return decodeSoa(pos);
397 case TYPE_SRV:
398 return decodeSrv(pos);
399 case TYPE_NAPTR:
400 return decodeNaptr(pos);
401 case TYPE_TXT:
402 return decodeTxt(pos);
403 case TYPE_HINFO:
404 return decodeHinfo(pos);
405 }
406 }
407 // Unknown RR type/class
408 byte[] rd = new byte[rdlen];
409 System.arraycopy(msg, pos, rd, 0, rdlen);
410 return rd;
411 }
412
413 /*
414 * Returns the rdata of an MX record that is encoded at msg[pos].
415 */
416 private String decodeMx(int pos) throws CommunicationException {
417 int preference = getUShort(pos);
418 pos += 2;
419 DnsName name = decodeName(pos);
420 return (preference + " " + name);
421 }
422
423 /*
424 * Returns the rdata of an SOA record that is encoded at msg[pos].
425 */
426 private String decodeSoa(int pos) throws CommunicationException {
427 DnsName mname = new DnsName();
428 pos = decodeName(pos, mname);
429 DnsName rname = new DnsName();
430 pos = decodeName(pos, rname);
431
432 long serial = getUInt(pos);
433 pos += 4;
434 long refresh = getUInt(pos);
435 pos += 4;
436 long retry = getUInt(pos);
437 pos += 4;
438 long expire = getUInt(pos);
439 pos += 4;
440 long minimum = getUInt(pos); // now used as negative TTL
441 pos += 4;
442
443 return (mname + " " + rname + " " + serial + " " +
444 refresh + " " + retry + " " + expire + " " + minimum);
445 }
446
447 /*
448 * Returns the rdata of an SRV record that is encoded at msg[pos].
449 * See RFC 2782.
450 */
451 private String decodeSrv(int pos) throws CommunicationException {
452 int priority = getUShort(pos);
453 pos += 2;
454 int weight = getUShort(pos);
455 pos += 2;
456 int port = getUShort(pos);
457 pos += 2;
458 DnsName target = decodeName(pos);
459 return (priority + " " + weight + " " + port + " " + target);
460 }
461
462 /*
463 * Returns the rdata of an NAPTR record that is encoded at msg[pos].
464 * See RFC 2915.
465 */
466 private String decodeNaptr(int pos) throws CommunicationException {
467 int order = getUShort(pos);
468 pos += 2;
469 int preference = getUShort(pos);
470 pos += 2;
471 StringBuffer flags = new StringBuffer();
472 pos += decodeCharString(pos, flags);
473 StringBuffer services = new StringBuffer();
474 pos += decodeCharString(pos, services);
475 StringBuffer regexp = new StringBuffer(rdlen);
476 pos += decodeCharString(pos, regexp);
477 DnsName replacement = decodeName(pos);
478
479 return (order + " " + preference + " " + flags + " " +
480 services + " " + regexp + " " + replacement);
481 }
482
483 /*
484 * Returns the rdata of a TXT record that is encoded at msg[pos].
485 * The rdata consists of one or more <character-string>s.
486 */
|