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();