1 /* |
1 /* |
2 * Copyright (c) 2000, 2002, Oracle and/or its affiliates. All rights reserved. |
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. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * |
4 * |
5 * This code is free software; you can redistribute it and/or modify it |
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 |
6 * under the terms of the GNU General Public License version 2 only, as |
7 * published by the Free Software Foundation. Oracle designates this |
7 * published by the Free Software Foundation. Oracle designates this |
82 */ |
87 */ |
83 static final String rrClassNames[] = { |
88 static final String rrClassNames[] = { |
84 null, "IN", null, null, "HS" |
89 null, "IN", null, null, "HS" |
85 }; |
90 }; |
86 |
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; |
87 |
97 |
88 byte[] msg; // DNS message |
98 byte[] msg; // DNS message |
89 int msgLen; // msg size (in octets) |
99 int msgLen; // msg size (in octets) |
90 boolean qSection; // true if this RR is part of question section |
100 boolean qSection; // true if this RR is part of question section |
91 // and therefore has no ttl or rdata |
101 // and therefore has no ttl or rdata |
108 * not a true resource record in that case, but is treated as if it |
118 * 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 |
119 * were a shortened one (with no ttl or rdata). If decodeRdata is |
110 * false, the rdata is not decoded (and getRdata() will return null) |
120 * false, the rdata is not decoded (and getRdata() will return null) |
111 * unless this is an SOA record. |
121 * unless this is an SOA record. |
112 * |
122 * |
113 * @throws InvalidNameException if a decoded domain name isn't valid. |
123 * @throws CommunicationException if a decoded domain name isn't valid. |
114 * @throws ArrayIndexOutOfBoundsException given certain other corrupt data. |
124 * @throws ArrayIndexOutOfBoundsException given certain other corrupt data. |
115 */ |
125 */ |
116 ResourceRecord(byte[] msg, int msgLen, int offset, |
126 ResourceRecord(byte[] msg, int msgLen, int offset, |
117 boolean qSection, boolean decodeRdata) |
127 boolean qSection, boolean decodeRdata) |
118 throws InvalidNameException { |
128 throws CommunicationException { |
119 |
129 |
120 this.msg = msg; |
130 this.msg = msg; |
121 this.msgLen = msgLen; |
131 this.msgLen = msgLen; |
122 this.offset = offset; |
132 this.offset = offset; |
123 this.qSection = qSection; |
133 this.qSection = qSection; |
233 |
243 |
234 /* |
244 /* |
235 * Decodes the binary format of the RR. |
245 * Decodes the binary format of the RR. |
236 * May throw ArrayIndexOutOfBoundsException given corrupt data. |
246 * May throw ArrayIndexOutOfBoundsException given corrupt data. |
237 */ |
247 */ |
238 private void decode(boolean decodeRdata) throws InvalidNameException { |
248 private void decode(boolean decodeRdata) throws CommunicationException { |
239 int pos = offset; // index of next unread octet |
249 int pos = offset; // index of next unread octet |
240 |
250 |
241 name = new DnsName(); // NAME |
251 name = new DnsName(); // NAME |
242 pos = decodeName(pos, name); |
252 pos = decodeName(pos, name); |
243 |
253 |
314 } |
324 } |
315 |
325 |
316 /* |
326 /* |
317 * Returns the name encoded at msg[pos], including the root label. |
327 * Returns the name encoded at msg[pos], including the root label. |
318 */ |
328 */ |
319 private DnsName decodeName(int pos) throws InvalidNameException { |
329 private DnsName decodeName(int pos) throws CommunicationException { |
320 DnsName n = new DnsName(); |
330 DnsName n = new DnsName(); |
321 decodeName(pos, n); |
331 decodeName(pos, n); |
322 return n; |
332 return n; |
323 } |
333 } |
324 |
334 |
325 /* |
335 /* |
326 * Prepends to "n" the domain name encoded at msg[pos], including the root |
336 * Prepends to "n" the domain name encoded at msg[pos], including the root |
327 * label. Returns the index into "msg" following the name. |
337 * label. Returns the index into "msg" following the name. |
328 */ |
338 */ |
329 private int decodeName(int pos, DnsName n) throws InvalidNameException { |
339 private int decodeName(int pos, DnsName n) throws CommunicationException { |
330 if (msg[pos] == 0) { // end of name |
340 int endPos = -1; |
331 n.add(0, ""); |
341 int level = 0; |
332 return (pos + 1); |
342 try { |
333 } else if ((msg[pos] & 0xC0) != 0) { // name compression |
343 while (true) { |
334 decodeName(getUShort(pos) & 0x3FFF, n); |
344 if (level > MAXIMUM_COMPRESSION_REFERENCES) |
335 return (pos + 2); |
345 throw new IOException("Too many compression references"); |
336 } else { // append a label |
346 int typeAndLen = msg[pos] & 0xFF; |
337 int len = msg[pos++]; |
347 if (typeAndLen == 0) { // end of name |
338 try { |
348 ++pos; |
339 n.add(0, new String(msg, pos, len, "ISO-8859-1")); |
349 n.add(0, ""); |
340 } catch (java.io.UnsupportedEncodingException e) { |
350 break; |
341 // assert false : "ISO-Latin-1 charset unavailable"; |
351 } else if (typeAndLen <= 63) { // regular label |
342 } |
352 ++pos; |
343 return decodeName(pos + len, n); |
353 n.add(0, new String(msg, pos, typeAndLen, |
344 } |
354 StandardCharsets.ISO_8859_1)); |
|
355 pos += typeAndLen; |
|
356 } else if ((typeAndLen & 0xC0) == 0xC0) { // name compression |
|
357 ++level; |
|
358 endPos = pos + 2; |
|
359 pos = getUShort(pos) & 0x3FFF; |
|
360 } else |
|
361 throw new IOException("Invalid label type: " + typeAndLen); |
|
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; |
345 } |
372 } |
346 |
373 |
347 /* |
374 /* |
348 * Returns the rdata encoded at msg[pos]. The format is dependent |
375 * Returns the rdata encoded at msg[pos]. The format is dependent |
349 * on the rrtype and rrclass values, which have already been set. |
376 * on the rrtype and rrclass values, which have already been set. |
350 * The length of the encoded data is rdlen, which has already been |
377 * The length of the encoded data is rdlen, which has already been |
351 * set. |
378 * set. |
352 * The rdata of records with unknown type/class combinations is |
379 * The rdata of records with unknown type/class combinations is |
353 * returned in a newly-allocated byte array. |
380 * returned in a newly-allocated byte array. |
354 */ |
381 */ |
355 private Object decodeRdata(int pos) throws InvalidNameException { |
382 private Object decodeRdata(int pos) throws CommunicationException { |
356 if (rrclass == CLASS_INTERNET) { |
383 if (rrclass == CLASS_INTERNET) { |
357 switch (rrtype) { |
384 switch (rrtype) { |
358 case TYPE_A: |
385 case TYPE_A: |
359 return decodeA(pos); |
386 return decodeA(pos); |
360 case TYPE_AAAA: |
387 case TYPE_AAAA: |
384 } |
411 } |
385 |
412 |
386 /* |
413 /* |
387 * Returns the rdata of an MX record that is encoded at msg[pos]. |
414 * Returns the rdata of an MX record that is encoded at msg[pos]. |
388 */ |
415 */ |
389 private String decodeMx(int pos) throws InvalidNameException { |
416 private String decodeMx(int pos) throws CommunicationException { |
390 int preference = getUShort(pos); |
417 int preference = getUShort(pos); |
391 pos += 2; |
418 pos += 2; |
392 DnsName name = decodeName(pos); |
419 DnsName name = decodeName(pos); |
393 return (preference + " " + name); |
420 return (preference + " " + name); |
394 } |
421 } |
395 |
422 |
396 /* |
423 /* |
397 * Returns the rdata of an SOA record that is encoded at msg[pos]. |
424 * Returns the rdata of an SOA record that is encoded at msg[pos]. |
398 */ |
425 */ |
399 private String decodeSoa(int pos) throws InvalidNameException { |
426 private String decodeSoa(int pos) throws CommunicationException { |
400 DnsName mname = new DnsName(); |
427 DnsName mname = new DnsName(); |
401 pos = decodeName(pos, mname); |
428 pos = decodeName(pos, mname); |
402 DnsName rname = new DnsName(); |
429 DnsName rname = new DnsName(); |
403 pos = decodeName(pos, rname); |
430 pos = decodeName(pos, rname); |
404 |
431 |