alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (ResourceRecord.java)

This example Java source code file (ResourceRecord.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

dnsname, invalidnameexception, naming, object, qclass_star, qtype_star, resourcerecord, string, stringbuffer, type_aaaa, type_cname, type_ns, type_soa, type_txt

The ResourceRecord.java Java example source code

/*
 * 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
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package com.sun.jndi.dns;

import javax.naming.InvalidNameException;


/**
 * The ResourceRecord class represents a DNS resource record.
 * The string format is based on the master file representation in
 * RFC 1035.
 *
 * @author Scott Seligman
 */


public class ResourceRecord {

    /*
     * Resource record type codes
     */
    static final int TYPE_A     =  1;
    static final int TYPE_NS    =  2;
    static final int TYPE_CNAME =  5;
    static final int TYPE_SOA   =  6;
    static final int TYPE_PTR   = 12;
    static final int TYPE_HINFO = 13;
    static final int TYPE_MX    = 15;
    static final int TYPE_TXT   = 16;
    static final int TYPE_AAAA  = 28;
    static final int TYPE_SRV   = 33;
    static final int TYPE_NAPTR = 35;
    static final int QTYPE_AXFR = 252;          // zone transfer
    static final int QTYPE_STAR = 255;          // query type "*"

    /*
     * Mapping from resource record type codes to type name strings.
     */
    static final String rrTypeNames[] = {
        null, "A", "NS", null, null,
        "CNAME", "SOA", null, null, null,
        null, null, "PTR", "HINFO", null,
        "MX", "TXT", null, null, null,
        null, null, null, null, null,
        null, null, null, "AAAA", null,
        null, null, null, "SRV", null,
        "NAPTR"
    };

    /*
     * Resource record class codes
     */
    static final int CLASS_INTERNET = 1;
    static final int CLASS_HESIOD   = 2;
    static final int QCLASS_STAR    = 255;      // query class "*"

    /*
     * Mapping from resource record type codes to class name strings.
     */
    static final String rrClassNames[] = {
        null, "IN", null, null, "HS"
    };


    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
    int offset;                 // offset of RR w/in msg
    int rrlen;                  // number of octets in encoded RR
    DnsName name;               // name field of RR, including root label
    int rrtype;                 // type field of RR
    String rrtypeName;          // name of of rrtype
    int rrclass;                // class field of RR
    String rrclassName;         // name of rrclass
    int ttl = 0;                // ttl field of RR
    int rdlen = 0;              // number of octets of rdata
    Object rdata = null;        // rdata -- most are String, unknown are byte[]


    /*
     * Constructs a new ResourceRecord.  The encoded data of the DNS
     * message is contained in msg; data for this RR begins at msg[offset].
     * If qSection is true this RR is part of a question section.  It's
     * 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;
        decode(decodeRdata);
    }

    public String toString() {
        String text = name + " " + rrclassName + " " + rrtypeName;
        if (!qSection) {
            text += " " + ttl + " " +
                ((rdata != null) ? rdata : "[n/a]");
        }
        return text;
    }

    /*
     * Returns the name field of this RR, including the root label.
     */
    public DnsName getName() {
        return name;
    }

    /*
     * Returns the number of octets in the encoded RR.
     */
    public int size() {
        return rrlen;
    }

    public int getType() {
        return rrtype;
    }

    public int getRrclass() {
        return rrclass;
    }

    public Object getRdata() {
        return rdata;
    }


    public static String getTypeName(int rrtype) {
        return valueToName(rrtype, rrTypeNames);
    }

    public static int getType(String typeName) {
        return nameToValue(typeName, rrTypeNames);
    }

    public static String getRrclassName(int rrclass) {
        return valueToName(rrclass, rrClassNames);
    }

    public static int getRrclass(String className) {
        return nameToValue(className, rrClassNames);
    }

    private static String valueToName(int val, String[] names) {
        String name = null;
        if ((val > 0) && (val < names.length)) {
            name = names[val];
        } else if (val == QTYPE_STAR) {         // QTYPE_STAR == QCLASS_STAR
            name = "*";
        }
        if (name == null) {
            name = Integer.toString(val);
        }
        return name;
    }

    private static int nameToValue(String name, String[] names) {
        if (name.equals("")) {
            return -1;                          // invalid name
        } else if (name.equals("*")) {
            return QTYPE_STAR;                  // QTYPE_STAR == QCLASS_STAR
        }
        if (Character.isDigit(name.charAt(0))) {
            try {
                return Integer.parseInt(name);
            } catch (NumberFormatException e) {
            }
        }
        for (int i = 1; i < names.length; i++) {
            if ((names[i] != null) &&
                    name.equalsIgnoreCase(names[i])) {
                return i;
            }
        }
        return -1;                              // unknown name
    }

    /*
     * Compares two SOA record serial numbers using 32-bit serial number
     * arithmetic as defined in RFC 1982.  Serial numbers are unsigned
     * 32-bit quantities.  Returns a negative, zero, or positive value
     * as the first serial number is less than, equal to, or greater
     * than the second.  If the serial numbers are not comparable the
     * result is undefined.  Note that the relation is not transitive.
     */
    public static int compareSerialNumbers(long s1, long s2) {
        long diff = s2 - s1;
        if (diff == 0) {
            return 0;
        } else if ((diff > 0 &&  diff <= 0x7FFFFFFF) ||
                   (diff < 0 && -diff >  0x7FFFFFFF)) {
            return -1;
        } else {
            return 1;
        }
    }


    /*
     * 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);

        rrtype = getUShort(pos);                        // TYPE
        rrtypeName = (rrtype < rrTypeNames.length)
            ? rrTypeNames[rrtype]
            : null;
        if (rrtypeName == null) {
            rrtypeName = Integer.toString(rrtype);
        }
        pos += 2;

        rrclass = getUShort(pos);                       // CLASS
        rrclassName = (rrclass < rrClassNames.length)
            ? rrClassNames[rrclass]
            : null;
        if (rrclassName == null) {
            rrclassName = Integer.toString(rrclass);
        }
        pos += 2;

        if (!qSection) {
            ttl = getInt(pos);                          // TTL
            pos += 4;

            rdlen = getUShort(pos);                     // RDLENGTH
            pos += 2;

            rdata = (decodeRdata ||                     // RDATA
                     (rrtype == TYPE_SOA))
                ? decodeRdata(pos)
                : null;
            if (rdata instanceof DnsName) {
                rdata = rdata.toString();
            }
            pos += rdlen;
        }

        rrlen = pos - offset;

        msg = null;     // free up for GC
    }

    /*
     * Returns the 1-byte unsigned value at msg[pos].
     */
    private int getUByte(int pos) {
        return (msg[pos] & 0xFF);
    }

    /*
     * Returns the 2-byte unsigned value at msg[pos].  The high
     * order byte comes first.
     */
    private int getUShort(int pos) {
        return (((msg[pos] & 0xFF) << 8) |
                (msg[pos + 1] & 0xFF));
    }

    /*
     * Returns the 4-byte signed value at msg[pos].  The high
     * order byte comes first.
     */
    private int getInt(int pos) {
        return ((getUShort(pos) << 16) | getUShort(pos + 2));
    }

    /*
     * Returns the 4-byte unsigned value at msg[pos].  The high
     * order byte comes first.
     */
    private long getUInt(int pos) {
        return (getInt(pos) & 0xffffffffL);
    }

    /*
     * 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:
                return decodeAAAA(pos);
            case TYPE_CNAME:
            case TYPE_NS:
            case TYPE_PTR:
                return decodeName(pos);
            case TYPE_MX:
                return decodeMx(pos);
            case TYPE_SOA:
                return decodeSoa(pos);
            case TYPE_SRV:
                return decodeSrv(pos);
            case TYPE_NAPTR:
                return decodeNaptr(pos);
            case TYPE_TXT:
                return decodeTxt(pos);
            case TYPE_HINFO:
                return decodeHinfo(pos);
            }
        }
        // Unknown RR type/class
        byte[] rd = new byte[rdlen];
        System.arraycopy(msg, pos, rd, 0, rdlen);
        return rd;
    }

    /*
     * 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);

        long serial = getUInt(pos);
        pos += 4;
        long refresh = getUInt(pos);
        pos += 4;
        long retry = getUInt(pos);
        pos += 4;
        long expire = getUInt(pos);
        pos += 4;
        long minimum = getUInt(pos);    // now used as negative TTL
        pos += 4;

        return (mname + " " + rname + " " + serial + " " +
                refresh + " " + retry + " " + expire + " " + minimum);
    }

    /*
     * 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);
        pos += 2;
        DnsName target = decodeName(pos);
        return (priority + " " + weight + " " + port + " " + target);
    }

    /*
     * 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();
        pos += decodeCharString(pos, flags);
        StringBuffer services = new StringBuffer();
        pos += decodeCharString(pos, services);
        StringBuffer regexp = new StringBuffer(rdlen);
        pos += decodeCharString(pos, regexp);
        DnsName replacement = decodeName(pos);

        return (order + " " + preference + " " + flags + " " +
                services + " " + regexp + " " + replacement);
    }

    /*
     * Returns the rdata of a TXT record that is encoded at msg[pos].
     * The rdata consists of one or more <character-string>s.
     */
    private String decodeTxt(int pos) {
        StringBuffer buf = new StringBuffer(rdlen);
        int end = pos + rdlen;
        while (pos < end) {
            pos += decodeCharString(pos, buf);
            if (pos < end) {
                buf.append(' ');
            }
        }
        return buf.toString();
    }

    /*
     * Returns the rdata of an HINFO record that is encoded at msg[pos].
     * The rdata consists of two <character-string>s.
     */
    private String decodeHinfo(int pos) {
        StringBuffer buf = new StringBuffer(rdlen);
        pos += decodeCharString(pos, buf);
        buf.append(' ');
        pos += decodeCharString(pos, buf);
        return buf.toString();
    }

    /*
     * Decodes the <character-string> at msg[pos] and adds it to buf.
     * If the string contains one of the meta-characters ' ', '\\', or
     * '"', then the result is quoted and any embedded '\\' or '"'
     * chars are escaped with '\\'.  Empty strings are also quoted.
     * Returns the size of the encoded string, including the initial
     * length octet.
     */
    private int decodeCharString(int pos, StringBuffer buf) {
        int start = buf.length();       // starting index of this string
        int len = getUByte(pos++);      // encoded string length
        boolean quoted = (len == 0);    // quote string if empty
        for (int i = 0; i < len; i++) {
            int c = getUByte(pos++);
            quoted |= (c == ' ');
            if ((c == '\\') || (c == '"')) {
                quoted = true;
                buf.append('\\');
            }
            buf.append((char) c);
        }
        if (quoted) {
            buf.insert(start, '"');
            buf.append('"');
        }
        return (len + 1);       // size includes initial octet
    }

    /*
     * Returns the rdata of an A record, in dotted-decimal format,
     * that is encoded at msg[pos].
     */
    private String decodeA(int pos) {
        return ((msg[pos] & 0xff) + "." +
                (msg[pos + 1] & 0xff) + "." +
                (msg[pos + 2] & 0xff) + "." +
                (msg[pos + 3] & 0xff));
    }

    /*
     * Returns the rdata of an AAAA record, in colon-separated format,
     * that is encoded at msg[pos].  For example:  4321:0:1:2:3:4:567:89ab.
     * See RFCs 1886 and 2373.
     */
    private String decodeAAAA(int pos) {
        int[] addr6 = new int[8];  // the unsigned 16-bit words of the address
        for (int i = 0; i < 8; i++) {
            addr6[i] = getUShort(pos);
            pos += 2;
        }

        // Find longest sequence of two or more zeros, to compress them.
        int curBase = -1;
        int curLen = 0;
        int bestBase = -1;
        int bestLen = 0;
        for (int i = 0; i < 8; i++) {
            if (addr6[i] == 0) {
                if (curBase == -1) {    // new sequence
                    curBase = i;
                    curLen = 1;
                } else {                // extend sequence
                    ++curLen;
                    if ((curLen >= 2) && (curLen > bestLen)) {
                        bestBase = curBase;
                        bestLen = curLen;
                    }
                }
            } else {                    // not in sequence
                curBase = -1;
            }
        }

        // If addr begins with at least 6 zeros and is not :: or ::1,
        // or with 5 zeros followed by 0xffff, use the text format for
        // IPv4-compatible or IPv4-mapped addresses.
        if (bestBase == 0) {
            if ((bestLen == 6) ||
                    ((bestLen == 7) && (addr6[7] > 1))) {
                return ("::" + decodeA(pos - 4));
            } else if ((bestLen == 5) && (addr6[5] == 0xffff)) {
                return ("::ffff:" + decodeA(pos - 4));
            }
        }

        // If bestBase != -1, compress zeros in [bestBase, bestBase+bestLen)
        boolean compress = (bestBase != -1);

        StringBuffer buf = new StringBuffer(40);
        if (bestBase == 0) {
            buf.append(':');
        }
        for (int i = 0; i < 8; i++) {
            if (!compress || (i < bestBase) || (i >= bestBase + bestLen)) {
                buf.append(Integer.toHexString(addr6[i]));
                if (i < 7) {
                    buf.append(':');
                }
            } else if (compress && (i == bestBase)) {  // first compressed zero
                buf.append(':');
            }
        }

        return buf.toString();
    }
}

Other Java examples (source code examples)

Here is a short list of links related to this Java ResourceRecord.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.