src/share/classes/com/sun/jndi/dns/ResourceRecord.java
Print this page
rev 9296 : 8035105: Detect compression loops in the JNDI DNS client
*** 1,7 ****
/*
! * Copyright (c) 2000, 2002, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
--- 1,7 ----
/*
! * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
*** 23,34 ****
--- 23,39 ----
* questions.
*/
package com.sun.jndi.dns;
+ import javax.naming.CommunicationException;
import javax.naming.InvalidNameException;
+ import java.io.IOException;
+
+ import java.nio.charset.StandardCharsets;
+
/**
* The ResourceRecord class represents a DNS resource record.
* The string format is based on the master file representation in
* RFC 1035.
*** 82,91 ****
--- 87,101 ----
*/
static final String rrClassNames[] = {
null, "IN", null, null, "HS"
};
+ /*
+ * Maximum number of compression references in labels.
+ * Used to detect compression loops.
+ */
+ private static final int MAXIMUM_COMPRESSION_REFERENCES = 16;
byte[] msg; // DNS message
int msgLen; // msg size (in octets)
boolean qSection; // true if this RR is part of question section
// and therefore has no ttl or rdata
*** 108,123 ****
* not a true resource record in that case, but is treated as if it
* were a shortened one (with no ttl or rdata). If decodeRdata is
* false, the rdata is not decoded (and getRdata() will return null)
* unless this is an SOA record.
*
! * @throws InvalidNameException if a decoded domain name isn't valid.
* @throws ArrayIndexOutOfBoundsException given certain other corrupt data.
*/
ResourceRecord(byte[] msg, int msgLen, int offset,
boolean qSection, boolean decodeRdata)
! throws InvalidNameException {
this.msg = msg;
this.msgLen = msgLen;
this.offset = offset;
this.qSection = qSection;
--- 118,133 ----
* not a true resource record in that case, but is treated as if it
* were a shortened one (with no ttl or rdata). If decodeRdata is
* false, the rdata is not decoded (and getRdata() will return null)
* unless this is an SOA record.
*
! * @throws CommunicationException if a decoded domain name isn't valid.
* @throws ArrayIndexOutOfBoundsException given certain other corrupt data.
*/
ResourceRecord(byte[] msg, int msgLen, int offset,
boolean qSection, boolean decodeRdata)
! throws CommunicationException {
this.msg = msg;
this.msgLen = msgLen;
this.offset = offset;
this.qSection = qSection;
*** 233,243 ****
/*
* Decodes the binary format of the RR.
* May throw ArrayIndexOutOfBoundsException given corrupt data.
*/
! private void decode(boolean decodeRdata) throws InvalidNameException {
int pos = offset; // index of next unread octet
name = new DnsName(); // NAME
pos = decodeName(pos, name);
--- 243,253 ----
/*
* Decodes the binary format of the RR.
* May throw ArrayIndexOutOfBoundsException given corrupt data.
*/
! private void decode(boolean decodeRdata) throws CommunicationException {
int pos = offset; // index of next unread octet
name = new DnsName(); // NAME
pos = decodeName(pos, name);
*** 314,360 ****
}
/*
* Returns the name encoded at msg[pos], including the root label.
*/
! private DnsName decodeName(int pos) throws InvalidNameException {
DnsName n = new DnsName();
decodeName(pos, n);
return n;
}
/*
* Prepends to "n" the domain name encoded at msg[pos], including the root
* label. Returns the index into "msg" following the name.
*/
! private int decodeName(int pos, DnsName n) throws InvalidNameException {
! if (msg[pos] == 0) { // end of name
! n.add(0, "");
! return (pos + 1);
! } else if ((msg[pos] & 0xC0) != 0) { // name compression
! decodeName(getUShort(pos) & 0x3FFF, n);
! return (pos + 2);
! } else { // append a label
! int len = msg[pos++];
try {
! n.add(0, new String(msg, pos, len, "ISO-8859-1"));
! } catch (java.io.UnsupportedEncodingException e) {
! // assert false : "ISO-Latin-1 charset unavailable";
! }
! return decodeName(pos + len, n);
! }
}
/*
* Returns the rdata encoded at msg[pos]. The format is dependent
* on the rrtype and rrclass values, which have already been set.
* The length of the encoded data is rdlen, which has already been
* set.
* The rdata of records with unknown type/class combinations is
* returned in a newly-allocated byte array.
*/
! private Object decodeRdata(int pos) throws InvalidNameException {
if (rrclass == CLASS_INTERNET) {
switch (rrtype) {
case TYPE_A:
return decodeA(pos);
case TYPE_AAAA:
--- 324,387 ----
}
/*
* Returns the name encoded at msg[pos], including the root label.
*/
! private DnsName decodeName(int pos) throws CommunicationException {
DnsName n = new DnsName();
decodeName(pos, n);
return n;
}
/*
* Prepends to "n" the domain name encoded at msg[pos], including the root
* label. Returns the index into "msg" following the name.
*/
! private int decodeName(int pos, DnsName n) throws CommunicationException {
! int endPos = -1;
! int level = 0;
try {
! while (true) {
! if (level > MAXIMUM_COMPRESSION_REFERENCES)
! throw new IOException("Too many compression references");
! int type = msg[pos] & 0xFF;
! if (type == 0) { // end of name
! ++pos;
! n.add(0, "");
! break;
! } else if (type <= 63) { // regular label
! ++pos;
! n.add(0, new String(msg, pos, type,
! StandardCharsets.ISO_8859_1));
! pos += type;
! } else if ((msg[pos] & 0xC0) == 0xC0) { // name compression
! ++level;
! endPos = pos + 2;
! pos = getUShort(pos) & 0x3FFF;
! } else
! throw new IOException("Invalid label type: " + type);
! }
! } catch (IOException | InvalidNameException e) {
! CommunicationException ce =new CommunicationException(
! "DNS error: malformed packet");
! ce.initCause(e);
! throw ce;
! }
! if (endPos == -1)
! endPos = pos;
! return endPos;
}
/*
* Returns the rdata encoded at msg[pos]. The format is dependent
* on the rrtype and rrclass values, which have already been set.
* The length of the encoded data is rdlen, which has already been
* set.
* The rdata of records with unknown type/class combinations is
* returned in a newly-allocated byte array.
*/
! private Object decodeRdata(int pos) throws CommunicationException {
if (rrclass == CLASS_INTERNET) {
switch (rrtype) {
case TYPE_A:
return decodeA(pos);
case TYPE_AAAA:
*** 384,404 ****
}
/*
* Returns the rdata of an MX record that is encoded at msg[pos].
*/
! private String decodeMx(int pos) throws InvalidNameException {
int preference = getUShort(pos);
pos += 2;
DnsName name = decodeName(pos);
return (preference + " " + name);
}
/*
* Returns the rdata of an SOA record that is encoded at msg[pos].
*/
! private String decodeSoa(int pos) throws InvalidNameException {
DnsName mname = new DnsName();
pos = decodeName(pos, mname);
DnsName rname = new DnsName();
pos = decodeName(pos, rname);
--- 411,431 ----
}
/*
* Returns the rdata of an MX record that is encoded at msg[pos].
*/
! private String decodeMx(int pos) throws CommunicationException {
int preference = getUShort(pos);
pos += 2;
DnsName name = decodeName(pos);
return (preference + " " + name);
}
/*
* Returns the rdata of an SOA record that is encoded at msg[pos].
*/
! private String decodeSoa(int pos) throws CommunicationException {
DnsName mname = new DnsName();
pos = decodeName(pos, mname);
DnsName rname = new DnsName();
pos = decodeName(pos, rname);
*** 419,429 ****
/*
* Returns the rdata of an SRV record that is encoded at msg[pos].
* See RFC 2782.
*/
! private String decodeSrv(int pos) throws InvalidNameException {
int priority = getUShort(pos);
pos += 2;
int weight = getUShort(pos);
pos += 2;
int port = getUShort(pos);
--- 446,456 ----
/*
* Returns the rdata of an SRV record that is encoded at msg[pos].
* See RFC 2782.
*/
! private String decodeSrv(int pos) throws CommunicationException {
int priority = getUShort(pos);
pos += 2;
int weight = getUShort(pos);
pos += 2;
int port = getUShort(pos);
*** 434,444 ****
/*
* Returns the rdata of an NAPTR record that is encoded at msg[pos].
* See RFC 2915.
*/
! private String decodeNaptr(int pos) throws InvalidNameException {
int order = getUShort(pos);
pos += 2;
int preference = getUShort(pos);
pos += 2;
StringBuffer flags = new StringBuffer();
--- 461,471 ----
/*
* Returns the rdata of an NAPTR record that is encoded at msg[pos].
* See RFC 2915.
*/
! private String decodeNaptr(int pos) throws CommunicationException {
int order = getUShort(pos);
pos += 2;
int preference = getUShort(pos);
pos += 2;
StringBuffer flags = new StringBuffer();