From 9734170b7dcc0ca0f5f48bd250819c2fca17c564 Mon Sep 17 00:00:00 2001 From: Tim Boudreau Date: Tue, 22 Jul 2014 03:02:58 -0400 Subject: [PATCH] Use value types for class and type in DNS entries to make them immune to parameter order bugs Motivation: DNS class and type were represented as integers rather than an enum or a similar dedicated value type. This can be a potential source of a parameter order bug which might be difficult to track down. Modifications: Add DnsClass and DnsType to replace integer parameters Result: Type safety and less error-proneness --- .../io/netty/handler/codec/dns/DnsClass.java | 136 ++++++ .../io/netty/handler/codec/dns/DnsEntry.java | 304 +------------ .../handler/codec/dns/DnsQueryEncoder.java | 4 +- .../netty/handler/codec/dns/DnsQuestion.java | 8 +- .../netty/handler/codec/dns/DnsResource.java | 2 +- .../handler/codec/dns/DnsResponseDecoder.java | 8 +- .../io/netty/handler/codec/dns/DnsType.java | 400 ++++++++++++++++++ .../netty/handler/codec/dns/DnsClassTest.java | 84 ++++ .../netty/handler/codec/dns/DnsQueryTest.java | 10 +- .../netty/handler/codec/dns/DnsTypeTest.java | 81 ++++ 10 files changed, 725 insertions(+), 312 deletions(-) create mode 100644 codec-dns/src/main/java/io/netty/handler/codec/dns/DnsClass.java create mode 100644 codec-dns/src/main/java/io/netty/handler/codec/dns/DnsType.java create mode 100644 codec-dns/src/test/java/io/netty/handler/codec/dns/DnsClassTest.java create mode 100644 codec-dns/src/test/java/io/netty/handler/codec/dns/DnsTypeTest.java diff --git a/codec-dns/src/main/java/io/netty/handler/codec/dns/DnsClass.java b/codec-dns/src/main/java/io/netty/handler/codec/dns/DnsClass.java new file mode 100644 index 0000000000..2059762a3a --- /dev/null +++ b/codec-dns/src/main/java/io/netty/handler/codec/dns/DnsClass.java @@ -0,0 +1,136 @@ +/* + * Copyright 2014 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.netty.handler.codec.dns; + +import java.util.Arrays; + +/** + * Represents a class field in DNS protocol + */ +public class DnsClass { + + /** + * Default class for DNS entries. + */ + public static final DnsClass IN = new DnsClass(0x0001, "IN"); + public static final DnsClass CSNET = new DnsClass(0x0002, "CSNET"); + public static final DnsClass CHAOS = new DnsClass(0x0003, "CHAOS"); + public static final DnsClass HESIOD = new DnsClass(0x0004, "HESIOD"); + public static final DnsClass NONE = new DnsClass(0x00fe, "NONE"); + public static final DnsClass ANY = new DnsClass(0x00ff, "ANY"); + + /** + * The protocol value of this DNS class + */ + private final int clazz; + /** + * The name of this DNS class + */ + private final String name; + + DnsClass(int clazz, String name) { + this.clazz = clazz; + this.name = name; + } + + /** + * Returns the name of this class as used in bind config files + */ + public final String name() { + return name; + } + + /** + * Returns the protocol value represented by this class + */ + public final int clazz() { + return clazz; + } + + /** + * Returns an instance of DnsClass for a custom type. + * + * @param clazz The class + * @param name The name + */ + public static DnsClass create(int clazz, String name) { + return new DnsClass(clazz, name); + } + + /** + * Returns true if this class is valid with respect to DNS protocol + */ + public boolean isValid() { + if (clazz < 1 || clazz > 4 && clazz != NONE.clazz && clazz != ANY.clazz) { + return false; + } + return true; + } + + public static DnsClass forName(String name) { + if (IN.name.equals(name)) { + return IN; + } else if (NONE.name().equals(name)) { + return NONE; + } else if (ANY.name().equals(name)) { + return ANY; + } else if (CSNET.name().equals(name)) { + return CSNET; + } else if (CHAOS.name().equals(name)) { + return CHAOS; + } else if (HESIOD.name().equals(name)) { + return HESIOD; + } + throw new IllegalArgumentException("name: " + name + " (expected: " + + "IN, ANY, CSNET, CHAOS, HESIOD)"); + } + + public static DnsClass valueOf(int clazz) { + switch (clazz) { + case 0x0001: + return IN; + case 0x0002: + return CSNET; + case 0x0003: + return CHAOS; + case 0x0004: + return HESIOD; + case 0x00fe: + return NONE; + case 0x00ff: + return ANY; + default: + throw new IllegalArgumentException("clazz: " + clazz + " (expected: " + + Arrays.asList(new Integer[] {IN.clazz, CSNET.clazz, + CHAOS.clazz, HESIOD.clazz, NONE.clazz, ANY.clazz}) + ")"); + } + } + + @Override + public final int hashCode() { + return clazz; + } + + @Override + public final boolean equals(Object o) { + return o instanceof DnsClass && ((DnsClass) o).clazz == clazz; + } + + @Override + public final String toString() { + return name; + } +} diff --git a/codec-dns/src/main/java/io/netty/handler/codec/dns/DnsEntry.java b/codec-dns/src/main/java/io/netty/handler/codec/dns/DnsEntry.java index 94d77501d5..1308e37ff5 100644 --- a/codec-dns/src/main/java/io/netty/handler/codec/dns/DnsEntry.java +++ b/codec-dns/src/main/java/io/netty/handler/codec/dns/DnsEntry.java @@ -21,306 +21,16 @@ package io.netty.handler.codec.dns; */ public class DnsEntry { - /** - * Address record RFC 1035 Returns a 32-bit IPv4 address, most commonly used - * to map hostnames to an IP address of the host, but also used for DNSBLs, - * storing subnet masks in RFC 1101, etc. - */ - public static final int TYPE_A = 0x0001; - - /** - * Name server record RFC 1035 Delegates a DNS zone to use the given - * authoritative name servers - */ - public static final int TYPE_NS = 0x0002; - - /** - * Canonical name record RFC 1035 Alias of one name to another: the DNS - * lookup will continue by retrying the lookup with the new name. - */ - public static final int TYPE_CNAME = 0x0005; - - /** - * Start of [a zone of] authority record RFC 1035 and RFC 2308 Specifies - * authoritative information about a DNS zone, including the primary name - * server, the email of the domain administrator, the domain serial number, - * and several timers relating to refreshing the zone. - */ - public static final int TYPE_SOA = 0x0006; - - /** - * Pointer record RFC 1035 Pointer to a canonical name. Unlike a CNAME, DNS - * processing does NOT proceed, just the name is returned. The most common - * use is for implementing reverse DNS lookups, but other uses include such - * things as DNS-SD. - */ - public static final int TYPE_PTR = 0x000c; - - /** - * Mail exchange record RFC 1035 Maps a domain name to a list of message - * transfer agents for that domain. - */ - public static final int TYPE_MX = 0x000f; - - /** - * Text record RFC 1035 Originally for arbitrary human-readable text in a - * DNS record. Since the early 1990s, however, this record more often - * carries machine-readable data, such as specified by RFC 1464, - * opportunistic encryption, Sender Policy Framework, DKIM, DMARC DNS-SD, - * etc. - */ - public static final int TYPE_TXT = 0x0010; - - /** - * Responsible person record RFC 1183 Information about the responsible - * person(s) for the domain. Usually an email address with the @ replaced by - * a . - */ - public static final int TYPE_RP = 0x0011; - - /** - * AFS database record RFC 1183 Location of database servers of an AFS cell. - * This record is commonly used by AFS clients to contact AFS cells outside - * their local domain. A subtype of this record is used by the obsolete - * DCE/DFS file system. - */ - public static final int TYPE_AFSDB = 0x0012; - - /** - * Signature record RFC 2535 Signature record used in SIG(0) (RFC 2931) and - * TKEY (RFC 2930). RFC 3755 designated RRSIG as the replacement for SIG for - * use within DNSSEC. - */ - public static final int TYPE_SIG = 0x0018; - - /** - * key record RFC 2535 and RFC 2930 Used only for SIG(0) (RFC 2931) and TKEY - * (RFC 2930). RFC 3445 eliminated their use for application keys and - * limited their use to DNSSEC. RFC 3755 designates DNSKEY as the - * replacement within DNSSEC. RFC 4025 designates IPSECKEY as the - * replacement for use with IPsec. - */ - public static final int TYPE_KEY = 0x0019; - - /** - * IPv6 address record RFC 3596 Returns a 128-bit IPv6 address, most - * commonly used to map hostnames to an IP address of the host. - */ - public static final int TYPE_AAAA = 0x001c; - - /** - * Location record RFC 1876 Specifies a geographical location associated - * with a domain name. - */ - public static final int TYPE_LOC = 0x001d; - - /** - * Service locator RFC 2782 Generalized service location record, used for - * newer protocols instead of creating protocol-specific records such as MX. - */ - public static final int TYPE_SRV = 0x0021; - - /** - * Naming Authority Pointer record RFC 3403 Allows regular expression based - * rewriting of domain names which can then be used as URIs, further domain - * names to lookups, etc. - */ - public static final int TYPE_NAPTR = 0x0023; - - /** - * Key eXchanger record RFC 2230 Used with some cryptographic systems (not - * including DNSSEC) to identify a key management agent for the associated - * domain-name. Note that this has nothing to do with DNS Security. It is - * Informational status, rather than being on the IETF standards-track. It - * has always had limited deployment, but is still in use. - */ - public static final int TYPE_KX = 0x0024; - - /** - * Certificate record RFC 4398 Stores PKIX, SPKI, PGP, etc. - */ - public static final int TYPE_CERT = 0x0025; - - /** - * Delegation name record RFC 2672 DNAME creates an alias for a name and all - * its subnames, unlike CNAME, which aliases only the exact name in its - * label. Like the CNAME record, the DNS lookup will continue by retrying - * the lookup with the new name. - */ - public static final int TYPE_DNAME = 0x0027; - - /** - * Option record RFC 2671 This is a pseudo DNS record type needed to support - * EDNS. - */ - public static final int TYPE_OPT = 0x0029; - - /** - * Address Prefix List record RFC 3123 Specify lists of address ranges, e.g. - * in CIDR format, for various address families. Experimental. - */ - public static final int TYPE_APL = 0x002a; - - /** - * Delegation signer record RFC 4034 The record used to identify the DNSSEC - * signing key of a delegated zone. - */ - public static final int TYPE_DS = 0x002b; - - /** - * SSH Public Key Fingerprint record RFC 4255 Resource record for publishing - * SSH public host key fingerprints in the DNS System, in order to aid in - * verifying the authenticity of the host. RFC 6594 defines ECC SSH keys and - * SHA-256 hashes. See the IANA SSHFP RR parameters registry for details. - */ - public static final int TYPE_SSHFP = 0x002c; - - /** - * IPsec Key record RFC 4025 Key record that can be used with IPsec. - */ - public static final int TYPE_IPSECKEY = 0x002d; - - /** - * DNSSEC signature record RFC 4034 Signature for a DNSSEC-secured record - * set. Uses the same format as the SIG record. - */ - public static final int TYPE_RRSIG = 0x002e; - - /** - * Next-Secure record RFC 4034 Part of DNSSEC, used to prove a name does not - * exist. Uses the same format as the (obsolete) NXT record. - */ - public static final int TYPE_NSEC = 0x002f; - - /** - * DNS Key record RFC 4034 The key record used in DNSSEC. Uses the same - * format as the KEY record. - */ - public static final int TYPE_DNSKEY = 0x0030; - - /** - * DHCP identifier record RFC 4701 Used in conjunction with the FQDN option - * to DHCP. - */ - public static final int TYPE_DHCID = 0x0031; - - /** - * NSEC record version 3 RFC 5155 An extension to DNSSEC that allows proof - * of nonexistence for a name without permitting zonewalking. - */ - public static final int TYPE_NSEC3 = 0x0032; - - /** - * NSEC3 parameters record RFC 5155 Parameter record for use with NSEC3. - */ - public static final int TYPE_NSEC3PARAM = 0x0033; - - /** - * TLSA certificate association record RFC 6698 A record for DNS-based - * Authentication of Named Entities (DANE). RFC 6698 defines The TLSA DNS - * resource record is used to associate a TLS server certificate or public - * key with the domain name where the record is found, thus forming a 'TLSA - * certificate association'. - */ - public static final int TYPE_TLSA = 0x0034; - - /** - * Host Identity Protocol record RFC 5205 Method of separating the end-point - * identifier and locator roles of IP addresses. - */ - public static final int TYPE_HIP = 0x0037; - - /** - * Sender Policy Framework record RFC 4408 Specified as part of the SPF - * protocol as an alternative to of storing SPF data in TXT records. Uses - * the same format as the earlier TXT record. - */ - public static final int TYPE_SPF = 0x0063; - - /** - * Secret key record RFC 2930 A method of providing keying material to be - * used with TSIG that is encrypted under the public key in an accompanying - * KEY RR.. - */ - public static final int TYPE_TKEY = 0x00f9; - - /** - * Transaction Signature record RFC 2845 Can be used to authenticate dynamic - * updates as coming from an approved client, or to authenticate responses - * as coming from an approved recursive name server similar to DNSSEC. - */ - public static final int TYPE_TSIG = 0x00fa; - - /** - * Incremental Zone Transfer record RFC 1996 Requests a zone transfer of the - * given zone but only differences from a previous serial number. This - * request may be ignored and a full (AXFR) sent in response if the - * authoritative server is unable to fulfill the request due to - * configuration or lack of required deltas. - */ - public static final int TYPE_IXFR = 0x00fb; - - /** - * Authoritative Zone Transfer record RFC 1035 Transfer entire zone file - * from the master name server to secondary name servers. - */ - public static final int TYPE_AXFR = 0x00fc; - - /** - * All cached records RFC 1035 Returns all records of all types known to the - * name server. If the name server does not have any information on the - * name, the request will be forwarded on. The records returned may not be - * complete. For example, if there is both an A and an MX for a name, but - * the name server has only the A record cached, only the A record will be - * returned. Sometimes referred to as ANY, for example in Windows nslookup - * and Wireshark. - */ - public static final int TYPE_ANY = 0x00ff; - - /** - * Certification Authority Authorization record RFC 6844 CA pinning, - * constraining acceptable CAs for a host/domain. - */ - public static final int TYPE_CAA = 0x0101; - - /** - * DNSSEC Trust Authorities record N/A Part of a deployment proposal for - * DNSSEC without a signed DNS root. See the IANA database and Weiler Spec - * for details. Uses the same format as the DS record. - */ - public static final int TYPE_TA = 0x8000; - - /** - * DNSSEC Lookaside Validation record RFC 4431 For publishing DNSSEC trust - * anchors outside of the DNS delegation chain. Uses the same format as the - * DS record. RFC 5074 describes a way of using these records. - */ - public static final int TYPE_DLV = 0x8001; - - /** - * Default class for DNS entries. - */ - public static final int CLASS_IN = 0x0001; - - public static final int CLASS_CSNET = 0x0002; - public static final int CLASS_CHAOS = 0x0003; - public static final int CLASS_HESIOD = 0x0004; - public static final int CLASS_NONE = 0x00fe; - public static final int CLASS_ANY = 0x00ff; - private final String name; - private final int type; - private final int dnsClass; + private final DnsType type; + private final DnsClass dnsClass; // only allow to extend from same package - DnsEntry(String name, int type, int dnsClass) { + DnsEntry(String name, DnsType type, DnsClass dnsClass) { if (name == null) { throw new NullPointerException("name"); } - if ((type & 0xffff) != type) { - throw new IllegalArgumentException("type must be an unsigned short."); - } - if (dnsClass < 1 || dnsClass > 4 && dnsClass != CLASS_NONE && dnsClass != CLASS_ANY) { + if (!dnsClass.isValid()) { throw new IllegalArgumentException("an invalid class has been supplied."); } this.name = name; @@ -338,20 +48,20 @@ public class DnsEntry { /** * Returns the type of resource record to be received. */ - public int type() { + public DnsType type() { return type; } /** * Returns the class for this entry. Default is IN (Internet). */ - public int dnsClass() { + public DnsClass dnsClass() { return dnsClass; } @Override public int hashCode() { - return (name.hashCode() * 31 + type) * 31 + dnsClass; + return (name.hashCode() * 31 + type.hashCode()) * 31 + dnsClass.hashCode(); } @Override diff --git a/codec-dns/src/main/java/io/netty/handler/codec/dns/DnsQueryEncoder.java b/codec-dns/src/main/java/io/netty/handler/codec/dns/DnsQueryEncoder.java index fed619dd9b..638ab85f2c 100644 --- a/codec-dns/src/main/java/io/netty/handler/codec/dns/DnsQueryEncoder.java +++ b/codec-dns/src/main/java/io/netty/handler/codec/dns/DnsQueryEncoder.java @@ -85,7 +85,7 @@ public class DnsQueryEncoder extends MessageToMessageEncoder { buf.writeBytes(part.getBytes(charset)); } buf.writeByte(0); // marks end of name field - buf.writeShort(question.type()); - buf.writeShort(question.dnsClass()); + buf.writeShort(question.type().type()); + buf.writeShort(question.dnsClass().clazz()); } } diff --git a/codec-dns/src/main/java/io/netty/handler/codec/dns/DnsQuestion.java b/codec-dns/src/main/java/io/netty/handler/codec/dns/DnsQuestion.java index 05ea266227..4b7df6be6b 100644 --- a/codec-dns/src/main/java/io/netty/handler/codec/dns/DnsQuestion.java +++ b/codec-dns/src/main/java/io/netty/handler/codec/dns/DnsQuestion.java @@ -15,6 +15,8 @@ */ package io.netty.handler.codec.dns; +import static io.netty.handler.codec.dns.DnsClass.IN; + /** * The DNS question class which represents a question being sent to a server via * a query, or the question being duplicated and sent back in a response. @@ -32,8 +34,8 @@ public final class DnsQuestion extends DnsEntry { * the question type, which represents the type of * {@link DnsResource} record that should be returned */ - public DnsQuestion(String name, int type) { - this(name, type, CLASS_IN); + public DnsQuestion(String name, DnsType type) { + this(name, type, IN); } /** @@ -47,7 +49,7 @@ public final class DnsQuestion extends DnsEntry { * @param qClass * the class of a DNS record */ - public DnsQuestion(String name, int type, int qClass) { + public DnsQuestion(String name, DnsType type, DnsClass qClass) { super(name, type, qClass); if (name.isEmpty()) { diff --git a/codec-dns/src/main/java/io/netty/handler/codec/dns/DnsResource.java b/codec-dns/src/main/java/io/netty/handler/codec/dns/DnsResource.java index 30064269e2..a6aa3106c9 100644 --- a/codec-dns/src/main/java/io/netty/handler/codec/dns/DnsResource.java +++ b/codec-dns/src/main/java/io/netty/handler/codec/dns/DnsResource.java @@ -41,7 +41,7 @@ public final class DnsResource extends DnsEntry implements ByteBufHolder { * @param content * the data contained in this record */ - public DnsResource(String name, int type, int aClass, long ttl, ByteBuf content) { + public DnsResource(String name, DnsType type, DnsClass aClass, long ttl, ByteBuf content) { super(name, type, aClass); this.ttl = ttl; this.content = content; diff --git a/codec-dns/src/main/java/io/netty/handler/codec/dns/DnsResponseDecoder.java b/codec-dns/src/main/java/io/netty/handler/codec/dns/DnsResponseDecoder.java index 7a3706b824..28d438a79c 100644 --- a/codec-dns/src/main/java/io/netty/handler/codec/dns/DnsResponseDecoder.java +++ b/codec-dns/src/main/java/io/netty/handler/codec/dns/DnsResponseDecoder.java @@ -126,8 +126,8 @@ public class DnsResponseDecoder extends MessageToMessageDecoder */ private static DnsQuestion decodeQuestion(ByteBuf buf) { String name = readName(buf); - int type = buf.readUnsignedShort(); - int qClass = buf.readUnsignedShort(); + DnsType type = DnsType.valueOf(buf.readUnsignedShort()); + DnsClass qClass = DnsClass.valueOf(buf.readUnsignedShort()); return new DnsQuestion(name, type, qClass); } @@ -140,8 +140,8 @@ public class DnsResponseDecoder extends MessageToMessageDecoder */ private static DnsResource decodeResource(ByteBuf buf) { String name = readName(buf); - int type = buf.readUnsignedShort(); - int aClass = buf.readUnsignedShort(); + DnsType type = DnsType.valueOf(buf.readUnsignedShort()); + DnsClass aClass = DnsClass.valueOf(buf.readUnsignedShort()); long ttl = buf.readUnsignedInt(); int len = buf.readUnsignedShort(); diff --git a/codec-dns/src/main/java/io/netty/handler/codec/dns/DnsType.java b/codec-dns/src/main/java/io/netty/handler/codec/dns/DnsType.java new file mode 100644 index 0000000000..eb2d166cbc --- /dev/null +++ b/codec-dns/src/main/java/io/netty/handler/codec/dns/DnsType.java @@ -0,0 +1,400 @@ +/* + * Copyright 2014 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.netty.handler.codec.dns; + +import io.netty.util.collection.IntObjectHashMap; +import java.util.HashMap; +import java.util.Map; + +/** + * Represents a DNS record type. + */ +public class DnsType { + + /** + * Address record RFC 1035 Returns a 32-bit IPv4 address, most commonly used + * to map hostnames to an IP address of the host, but also used for DNSBLs, + * storing subnet masks in RFC 1101, etc. + */ + public static final DnsType A = new DnsType(0x0001, "A"); + + /** + * Name server record RFC 1035 Delegates a DNS zone to use the given + * authoritative name servers + */ + public static final DnsType NS = new DnsType(0x0002, "NS"); + + /** + * Canonical name record RFC 1035 Alias of one name to another: the DNS + * lookup will continue by retrying the lookup with the new name. + */ + public static final DnsType CNAME = new DnsType(0x0005, "CNAME"); + + /** + * Start of [a zone of] authority record RFC 1035 and RFC 2308 Specifies + * authoritative information about a DNS zone, including the primary name + * server, the email of the domain administrator, the domain serial number, + * and several timers relating to refreshing the zone. + */ + public static final DnsType SOA = new DnsType(0x0006, "SOA"); + + /** + * Pointer record RFC 1035 Pointer to a canonical name. Unlike a CNAME, DNS + * processing does NOT proceed, just the name is returned. The most common + * use is for implementing reverse DNS lookups, but other uses include such + * things as DNS-SD. + */ + public static final DnsType PTR = new DnsType(0x000c, "PTR"); + + /** + * Mail exchange record RFC 1035 Maps a domain name to a list of message + * transfer agents for that domain. + */ + public static final DnsType MX = new DnsType(0x000f, "MX"); + + /** + * Text record RFC 1035 Originally for arbitrary human-readable text in a + * DNS record. Since the early 1990s, however, this record more often + * carries machine-readable data, such as specified by RFC 1464, + * opportunistic encryption, Sender Policy Framework, DKIM, DMARC DNS-SD, + * etc. + */ + public static final DnsType TXT = new DnsType(0x0010, "TXT"); + + /** + * Responsible person record RFC 1183 Information about the responsible + * person(s) for the domain. Usually an email address with the @ replaced by + * a . + */ + public static final DnsType RP = new DnsType(0x0011, "RP"); + + /** + * AFS database record RFC 1183 Location of database servers of an AFS cell. + * This record is commonly used by AFS clients to contact AFS cells outside + * their local domain. A subtype of this record is used by the obsolete + * DCE/DFS file system. + */ + public static final DnsType AFSDB = new DnsType(0x0012, "AFSDB"); + + /** + * Signature record RFC 2535 Signature record used in SIG(0) (RFC 2931) and + * TKEY (RFC 2930). RFC 3755 designated RRSIG as the replacement for SIG for + * use within DNSSEC. + */ + public static final DnsType SIG = new DnsType(0x0018, "SIG"); + + /** + * key record RFC 2535 and RFC 2930 Used only for SIG(0) (RFC 2931) and TKEY + * (RFC 2930). RFC 3445 eliminated their use for application keys and + * limited their use to DNSSEC. RFC 3755 designates DNSKEY as the + * replacement within DNSSEC. RFC 4025 designates IPSECKEY as the + * replacement for use with IPsec. + */ + public static final DnsType KEY = new DnsType(0x0019, "KEY"); + + /** + * IPv6 address record RFC 3596 Returns a 128-bit IPv6 address, most + * commonly used to map hostnames to an IP address of the host. + */ + public static final DnsType AAAA = new DnsType(0x001c, "AAAA"); + + /** + * Location record RFC 1876 Specifies a geographical location associated + * with a domain name. + */ + public static final DnsType LOC = new DnsType(0x001d, "LOC"); + + /** + * Service locator RFC 2782 Generalized service location record, used for + * newer protocols instead of creating protocol-specific records such as MX. + */ + public static final DnsType SRV = new DnsType(0x0021, "SRV"); + + /** + * Naming Authority Pointer record RFC 3403 Allows regular expression based + * rewriting of domain names which can then be used as URIs, further domain + * names to lookups, etc. + */ + public static final DnsType NAPTR = new DnsType(0x0023, "NAPTR"); + + /** + * Key eXchanger record RFC 2230 Used with some cryptographic systems (not + * including DNSSEC) to identify a key management agent for the associated + * domain-name. Note that this has nothing to do with DNS Security. It is + * Informational status, rather than being on the IETF standards-track. It + * has always had limited deployment, but is still in use. + */ + public static final DnsType KX = new DnsType(0x0024, "KX"); + + /** + * Certificate record RFC 4398 Stores PKIX, SPKI, PGP, etc. + */ + public static final DnsType CERT = new DnsType(0x0025, "CERT"); + + /** + * Delegation name record RFC 2672 DNAME creates an alias for a name and all + * its subnames, unlike CNAME, which aliases only the exact name in its + * label. Like the CNAME record, the DNS lookup will continue by retrying + * the lookup with the new name. + */ + public static final DnsType DNAME = new DnsType(0x0027, "DNAME"); + + /** + * Option record RFC 2671 This is a pseudo DNS record type needed to support + * EDNS. + */ + public static final DnsType OPT = new DnsType(0x0029, "OPT"); + + /** + * Address Prefix List record RFC 3123 Specify lists of address ranges, e.g. + * in CIDR format, for various address families. Experimental. + */ + public static final DnsType APL = new DnsType(0x002a, "APL"); + + /** + * Delegation signer record RFC 4034 The record used to identify the DNSSEC + * signing key of a delegated zone. + */ + public static final DnsType DS = new DnsType(0x002b, "DS"); + + /** + * SSH Public Key Fingerprint record RFC 4255 Resource record for publishing + * SSH public host key fingerprints in the DNS System, in order to aid in + * verifying the authenticity of the host. RFC 6594 defines ECC SSH keys and + * SHA-256 hashes. See the IANA SSHFP RR parameters registry for details. + */ + public static final DnsType SSHFP = new DnsType(0x002c, "SSHFP"); + + /** + * IPsec Key record RFC 4025 Key record that can be used with IPsec. + */ + public static final DnsType IPSECKEY = new DnsType(0x002d, "IPSECKEY"); + + /** + * DNSSEC signature record RFC 4034 Signature for a DNSSEC-secured record + * set. Uses the same format as the SIG record. + */ + public static final DnsType RRSIG = new DnsType(0x002e, "RRSIG"); + + /** + * Next-Secure record RFC 4034 Part of DNSSEC, used to prove a name does not + * exist. Uses the same format as the (obsolete) NXT record. + */ + public static final DnsType NSEC = new DnsType(0x002f, "NSEC"); + + /** + * DNS Key record RFC 4034 The key record used in DNSSEC. Uses the same + * format as the KEY record. + */ + public static final DnsType DNSKEY = new DnsType(0x0030, "DNSKEY"); + + /** + * DHCP identifier record RFC 4701 Used in conjunction with the FQDN option + * to DHCP. + */ + public static final DnsType DHCID = new DnsType(0x0031, "DHCID"); + + /** + * NSEC record version 3 RFC 5155 An extension to DNSSEC that allows proof + * of nonexistence for a name without permitting zonewalking. + */ + public static final DnsType NSEC3 = new DnsType(0x0032, "NSEC3"); + + /** + * NSEC3 parameters record RFC 5155 Parameter record for use with NSEC3. + */ + public static final DnsType NSEC3PARAM = new DnsType(0x0033, "NSEC3PARAM"); + + /** + * TLSA certificate association record RFC 6698 A record for DNS-based + * Authentication of Named Entities (DANE). RFC 6698 defines The TLSA DNS + * resource record is used to associate a TLS server certificate or public + * key with the domain name where the record is found, thus forming a 'TLSA + * certificate association'. + */ + public static final DnsType TLSA = new DnsType(0x0034, "TLSA"); + + /** + * Host Identity Protocol record RFC 5205 Method of separating the end-point + * identifier and locator roles of IP addresses. + */ + public static final DnsType HIP = new DnsType(0x0037, "HIP"); + + /** + * Sender Policy Framework record RFC 4408 Specified as part of the SPF + * protocol as an alternative to of storing SPF data in TXT records. Uses + * the same format as the earlier TXT record. + */ + public static final DnsType SPF = new DnsType(0x0063, "SPF"); + + /** + * Secret key record RFC 2930 A method of providing keying material to be + * used with TSIG that is encrypted under the public key in an accompanying + * KEY RR.. + */ + public static final DnsType TKEY = new DnsType(0x00f9, "TKEY"); + + /** + * Transaction Signature record RFC 2845 Can be used to authenticate dynamic + * updates as coming from an approved client, or to authenticate responses + * as coming from an approved recursive name server similar to DNSSEC. + */ + public static final DnsType TSIG = new DnsType(0x00fa, "TSIG"); + + /** + * Incremental Zone Transfer record RFC 1996 Requests a zone transfer of the + * given zone but only differences from a previous serial number. This + * request may be ignored and a full (AXFR) sent in response if the + * authoritative server is unable to fulfill the request due to + * configuration or lack of required deltas. + */ + public static final DnsType IXFR = new DnsType(0x00fb, "IXFR"); + + /** + * Authoritative Zone Transfer record RFC 1035 Transfer entire zone file + * from the master name server to secondary name servers. + */ + public static final DnsType AXFR = new DnsType(0x00fc, "AXFR"); + + /** + * All cached records RFC 1035 Returns all records of all types known to the + * name server. If the name server does not have any information on the + * name, the request will be forwarded on. The records returned may not be + * complete. For example, if there is both an A and an MX for a name, but + * the name server has only the A record cached, only the A record will be + * returned. Sometimes referred to as ANY, for example in Windows nslookup + * and Wireshark. + */ + public static final DnsType ANY = new DnsType(0x00ff, "ANY"); + + /** + * Certification Authority Authorization record RFC 6844 CA pinning, + * constraining acceptable CAs for a host/domain. + */ + public static final DnsType CAA = new DnsType(0x0101, "CAA"); + + /** + * DNSSEC Trust Authorities record N/A Part of a deployment proposal for + * DNSSEC without a signed DNS root. See the IANA database and Weiler Spec + * for details. Uses the same format as the DS record. + */ + public static final DnsType TA = new DnsType(0x8000, "TA"); + + /** + * DNSSEC Lookaside Validation record RFC 4431 For publishing DNSSEC trust + * anchors outside of the DNS delegation chain. Uses the same format as the + * DS record. RFC 5074 describes a way of using these records. + */ + public static final DnsType DLV = new DnsType(0x8001, "DLV"); + + private static final Map BY_NAME + = new HashMap(); + + private static final IntObjectHashMap BY_TYPE + = new IntObjectHashMap(); + + static { + DnsType[] all = {A, NS, CNAME, SOA, PTR, MX, + TXT, RP, AFSDB, SIG, KEY, AAAA, LOC, + SRV, NAPTR, KX, CERT, DNAME, OPT, + APL, DS, SSHFP, IPSECKEY, RRSIG, NSEC, + DNSKEY, DHCID, NSEC3, NSEC3PARAM, TLSA, + HIP, SPF, TKEY, TSIG, IXFR, AXFR, + ANY, CAA, TA, DLV}; + for (DnsType type : all) { + BY_NAME.put(type.name(), type); + BY_TYPE.put(type.type(), type); + } + } + + private final int type; + private final String name; + + DnsType(int type, String name) { + if ((type & 0xffff) != type) { + throw new IllegalArgumentException("type: " + type + + " (expected: 0 ~ 65535)"); + } + this.type = type; + this.name = name; + } + + /** + * Returns the name of this type, as seen in bind config files + */ + public final String name() { + return name; + } + + /** + * Returns the value of this DnsType as it appears in DNS protocol + */ + public final int type() { + return type; + } + + /** + * Returns a new DnsType instance + */ + public static DnsType create(int type, String name) { + return new DnsType(type, name); + } + + @Override + public final int hashCode() { + return type; + } + + @Override + public final boolean equals(Object o) { + return o instanceof DnsType && ((DnsType) o).type == type; + } + + @Override + public final String toString() { + return name; + } + + public static DnsType valueOf(int type) { + DnsType result = BY_TYPE.get(type); + if (result == null) { + throw new IllegalArgumentException("type: " + type + + "(expected: " + keysString() + ")"); + } + return result; + } + + private static CharSequence keysString() { + // Replace with Objects.toString(BY_TYPE.keys()) when JDK 7 supported + StringBuilder sb = new StringBuilder(); + for (int key : BY_TYPE.keys()) { + if (sb.length() > 0) { + sb.append(", "); + } + sb.append(key); + } + return sb; + } + + public static DnsType forName(String name) { + DnsType result = BY_NAME.get(name); + if (result == null) { + throw new IllegalArgumentException("name: " + name + + " (expected: " + BY_NAME.keySet() + ")"); + } + return result; + } +} diff --git a/codec-dns/src/test/java/io/netty/handler/codec/dns/DnsClassTest.java b/codec-dns/src/test/java/io/netty/handler/codec/dns/DnsClassTest.java new file mode 100644 index 0000000000..2fa8344b0b --- /dev/null +++ b/codec-dns/src/test/java/io/netty/handler/codec/dns/DnsClassTest.java @@ -0,0 +1,84 @@ +/* + * Copyright 2014 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.netty.handler.codec.dns; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertSame; +import org.junit.Test; + +public class DnsClassTest { + + private List allTypes() throws Exception { + List result = new ArrayList(); + for (Field field : DnsClass.class.getDeclaredFields()) { + if ((field.getModifiers() & Modifier.STATIC) != 0) { + result.add((DnsClass) field.get(null)); + } + } + assertFalse(result.isEmpty()); + return result; + } + + @Test + public void testSanity() throws Exception { + assertEquals("More than one type has the same int value", + allTypes().size(), new HashSet(allTypes()).size()); + } + + /** + * Test of hashCode method, of class DnsClass. + */ + @Test + public void testHashCode() throws Exception { + for (DnsClass t : allTypes()) { + assertEquals(t.clazz(), t.hashCode()); + } + } + + /** + * Test of equals method, of class DnsClass. + */ + @Test + public void testEquals() throws Exception { + for (DnsClass t1 : allTypes()) { + for (DnsClass t2 : allTypes()) { + if (t1 != t2) { + assertNotEquals(t1, t2); + } + } + } + } + + /** + * Test of find method, of class DnsClass. + */ + @Test + public void testFind() throws Exception { + for (DnsClass t : allTypes()) { + DnsClass found = DnsClass.valueOf(t.clazz()); + assertSame(t, found); + found = DnsClass.forName(t.toString()); + assertSame(t.toString(), t, found); + } + } +} diff --git a/codec-dns/src/test/java/io/netty/handler/codec/dns/DnsQueryTest.java b/codec-dns/src/test/java/io/netty/handler/codec/dns/DnsQueryTest.java index 18e999b58d..fd9be0dfd8 100644 --- a/codec-dns/src/test/java/io/netty/handler/codec/dns/DnsQueryTest.java +++ b/codec-dns/src/test/java/io/netty/handler/codec/dns/DnsQueryTest.java @@ -32,11 +32,11 @@ public class DnsQueryTest { InetSocketAddress addr = new InetSocketAddress(0); EmbeddedChannel embedder = new EmbeddedChannel(new DnsQueryEncoder()); List queries = new ArrayList(5); - queries.add(new DnsQuery(1, addr).addQuestion(new DnsQuestion("1.0.0.127.in-addr.arpa", DnsEntry.TYPE_PTR))); - queries.add(new DnsQuery(1, addr).addQuestion(new DnsQuestion("www.example.com", DnsEntry.TYPE_A))); - queries.add(new DnsQuery(1, addr).addQuestion(new DnsQuestion("example.com", DnsEntry.TYPE_AAAA))); - queries.add(new DnsQuery(1, addr).addQuestion(new DnsQuestion("example.com", DnsEntry.TYPE_MX))); - queries.add(new DnsQuery(1, addr).addQuestion(new DnsQuestion("example.com", DnsEntry.TYPE_CNAME))); + queries.add(new DnsQuery(1, addr).addQuestion(new DnsQuestion("1.0.0.127.in-addr.arpa", DnsType.PTR))); + queries.add(new DnsQuery(1, addr).addQuestion(new DnsQuestion("www.example.com", DnsType.A))); + queries.add(new DnsQuery(1, addr).addQuestion(new DnsQuestion("example.com", DnsType.AAAA))); + queries.add(new DnsQuery(1, addr).addQuestion(new DnsQuestion("example.com", DnsType.MX))); + queries.add(new DnsQuery(1, addr).addQuestion(new DnsQuestion("example.com", DnsType.CNAME))); for (DnsQuery query: queries) { Assert.assertEquals("Invalid question count, expected 1.", 1, query.header().questionCount()); diff --git a/codec-dns/src/test/java/io/netty/handler/codec/dns/DnsTypeTest.java b/codec-dns/src/test/java/io/netty/handler/codec/dns/DnsTypeTest.java new file mode 100644 index 0000000000..aac8035cde --- /dev/null +++ b/codec-dns/src/test/java/io/netty/handler/codec/dns/DnsTypeTest.java @@ -0,0 +1,81 @@ +/* + * Copyright 2014 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.netty.handler.codec.dns; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import org.junit.Test; +import static org.junit.Assert.*; + +public class DnsTypeTest { + + private List allTypes() throws Exception { + List result = new ArrayList(); + for (Field field : DnsType.class.getFields()) { + if ((field.getModifiers() & Modifier.STATIC) != 0 && DnsType.class == field.getType()) { + result.add((DnsType) field.get(null)); + } + } + assertFalse(result.isEmpty()); + return result; + } + + @Test + public void testSanity() throws Exception { + assertEquals("More than one type has the same int value", + allTypes().size(), new HashSet(allTypes()).size()); + } + + /** + * Test of hashCode method, of class DnsType. + */ + @Test + public void testHashCode() throws Exception { + for (DnsType t : allTypes()) { + assertEquals(t.type(), t.hashCode()); + } + } + + /** + * Test of equals method, of class DnsType. + */ + @Test + public void testEquals() throws Exception { + for (DnsType t1 : allTypes()) { + for (DnsType t2 : allTypes()) { + if (t1 != t2) { + assertNotEquals(t1, t2); + } + } + } + } + + /** + * Test of find method, of class DnsType. + */ + @Test + public void testFind() throws Exception { + for (DnsType t : allTypes()) { + DnsType found = DnsType.valueOf(t.type()); + assertSame(t, found); + found = DnsType.forName(t.toString()); + assertSame(t.toString(), t, found); + } + } +}