DNS codec for Netty which is based on the work of [#1622].
Motivation: As part of GSOC 2013 we had @mbakkar working on a DNS codec but did not integrate it yet as it needs some cleanup. This commit is based on @mbakkar's work and provide the codec for DNS. Modifications: Add DNS codec Result: Reusable DNS codec will be included in netty. This PR also includes a AsynchronousDnsResolver which allows to resolve DNS entries in a non blocking way by make use of the dns codec and netty transport itself.
This commit is contained in:
parent
89ed1517f5
commit
805ba157e4
51
codec-dns/pom.xml
Normal file
51
codec-dns/pom.xml
Normal file
@ -0,0 +1,51 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ 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.
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>io.netty</groupId>
|
||||
<artifactId>netty-parent</artifactId>
|
||||
<version>5.0.0.Alpha2-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>netty-codec-dns</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>Netty/Codec/DNS</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>netty-codec</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>netty-handler</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.directory.server</groupId>
|
||||
<artifactId>apacheds-protocol-dns</artifactId>
|
||||
<version>1.5.7</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
377
codec-dns/src/main/java/io/netty/handler/codec/dns/DnsEntry.java
Normal file
377
codec-dns/src/main/java/io/netty/handler/codec/dns/DnsEntry.java
Normal file
@ -0,0 +1,377 @@
|
||||
/*
|
||||
* Copyright 2013 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;
|
||||
|
||||
/**
|
||||
* A class representing entries in a DNS packet (questions, and all resource
|
||||
* records). Contains data shared by entries such as name, type, and class.
|
||||
*/
|
||||
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;
|
||||
|
||||
// only allow to extend from same package
|
||||
DnsEntry(String name, int type, int dnsClass) {
|
||||
if (name == null) {
|
||||
throw new NullPointerException("name");
|
||||
}
|
||||
if (name.isEmpty()) {
|
||||
throw new IllegalArgumentException("name must not be left blank.");
|
||||
}
|
||||
if ((type & 0xffff) != type) {
|
||||
throw new IllegalArgumentException("type must be an unsigned short.");
|
||||
}
|
||||
if (dnsClass < 1 || dnsClass > 4 && dnsClass != CLASS_NONE && dnsClass != CLASS_ANY) {
|
||||
throw new IllegalArgumentException("an invalid class has been supplied.");
|
||||
}
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
this.dnsClass = dnsClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of this entry (the domain).
|
||||
*/
|
||||
public String name() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of resource record to be received.
|
||||
*/
|
||||
public int type() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the class for this entry. Default is IN (Internet).
|
||||
*/
|
||||
public int dnsClass() {
|
||||
return dnsClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (name.hashCode() * 31 + type) * 31 + dnsClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder(32).append(getClass().getSimpleName()).append("(domain name: ").append(name)
|
||||
.append(", type: ").append(type).append(", class: ").append(dnsClass).append(')').toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o instanceof DnsEntry) {
|
||||
DnsEntry other = (DnsEntry) o;
|
||||
return other.type() == type && other.dnsClass() == dnsClass && other.name().equals(name);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,194 @@
|
||||
/*
|
||||
* Copyright 2013 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;
|
||||
|
||||
/**
|
||||
* The header super-class which includes information shared by DNS query and
|
||||
* response packet headers such as the ID, opcode, and type. The only flag
|
||||
* shared by both classes is the flag for desiring recursion.
|
||||
*/
|
||||
public class DnsHeader {
|
||||
|
||||
/**
|
||||
* Message type is query.
|
||||
*/
|
||||
public static final int TYPE_QUERY = 0;
|
||||
|
||||
/**
|
||||
* Message type is response.
|
||||
*/
|
||||
public static final int TYPE_RESPONSE = 1;
|
||||
|
||||
/**
|
||||
* Message is for a standard query.
|
||||
*/
|
||||
public static final int OPCODE_QUERY = 0;
|
||||
|
||||
/**
|
||||
* Message is for an inverse query. <strong>Note: inverse queries have been
|
||||
* obsoleted since RFC 3425, and are not necessarily supported.</strong>
|
||||
*/
|
||||
@Deprecated
|
||||
public static final int OPCODE_IQUERY = 1;
|
||||
|
||||
private final DnsMessage parent;
|
||||
|
||||
private boolean recursionDesired;
|
||||
private int opcode;
|
||||
private int id;
|
||||
private int type;
|
||||
private int z;
|
||||
|
||||
// only allow to extend from within the same package
|
||||
DnsHeader(DnsMessage parent) {
|
||||
if (parent == null) {
|
||||
throw new NullPointerException("parent");
|
||||
}
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of questions in the {@link DnsMessage}.
|
||||
*/
|
||||
public int questionCount() {
|
||||
return parent.questions().size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of answer resource records in the {@link DnsMessage}.
|
||||
*/
|
||||
public int answerCount() {
|
||||
return parent.answers().size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of authority resource records in the
|
||||
* {@link DnsMessage}.
|
||||
*/
|
||||
public int authorityResourceCount() {
|
||||
return parent.authorityResources().size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of additional resource records in the
|
||||
* {@link DnsMessage}.
|
||||
*/
|
||||
public int additionalResourceCount() {
|
||||
return parent.additionalResources().size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if a query is to be pursued recursively.
|
||||
*/
|
||||
public boolean isRecursionDesired() {
|
||||
return recursionDesired;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the 4 bit opcode used for the {@link DnsMessage}.
|
||||
*
|
||||
* @see #OPCODE_QUERY
|
||||
* @see #OPCODE_IQUERY
|
||||
*/
|
||||
public int opcode() {
|
||||
return opcode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of {@link DnsMessage}.
|
||||
*
|
||||
* @see #TYPE_QUERY
|
||||
*/
|
||||
public int type() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the 2 byte unsigned identifier number used for the
|
||||
* {@link DnsMessage}.
|
||||
*/
|
||||
public int id() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the opcode for this {@link DnsMessage}.
|
||||
*
|
||||
* @param opcode
|
||||
* opcode to set
|
||||
* @return the header to allow method chaining
|
||||
*/
|
||||
public DnsHeader setOpcode(int opcode) {
|
||||
this.opcode = opcode;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether a name server is directed to pursue a query recursively or
|
||||
* not.
|
||||
*
|
||||
* @param recursionDesired
|
||||
* if set to {@code true}, pursues query recursively
|
||||
* @return the header to allow method chaining
|
||||
*/
|
||||
public DnsHeader setRecursionDesired(boolean recursionDesired) {
|
||||
this.recursionDesired = recursionDesired;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link DnsMessage} type.
|
||||
*
|
||||
* @param type
|
||||
* message type
|
||||
* @return the header to allow method chaining
|
||||
*/
|
||||
public DnsHeader setType(int type) {
|
||||
this.type = type;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the id for this {@link DnsMessage}.
|
||||
*
|
||||
* @param id
|
||||
* a unique 2 byte unsigned identifier
|
||||
* @return the header to allow method chaining
|
||||
*/
|
||||
public DnsHeader setId(int id) {
|
||||
this.id = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the 3 bit reserved field 'Z'.
|
||||
*/
|
||||
public int z() {
|
||||
return z;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the field Z. This field is reserved and should remain as 0 if the
|
||||
* DNS server does not make usage of this field.
|
||||
*
|
||||
* @param z
|
||||
* the value for the reserved field Z
|
||||
*/
|
||||
public DnsHeader setZ(int z) {
|
||||
this.z = z;
|
||||
return this;
|
||||
}
|
||||
}
|
@ -0,0 +1,239 @@
|
||||
/*
|
||||
* Copyright 2013 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.AbstractReferenceCounted;
|
||||
import io.netty.util.ReferenceCountUtil;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* The message super-class which contains core information concerning DNS
|
||||
* packets, both outgoing and incoming.
|
||||
*/
|
||||
public abstract class DnsMessage extends AbstractReferenceCounted {
|
||||
|
||||
private List<DnsQuestion> questions;
|
||||
private List<DnsResource> answers;
|
||||
private List<DnsResource> authority;
|
||||
private List<DnsResource> additional;
|
||||
|
||||
private final DnsHeader header;
|
||||
|
||||
// Only allow to extend from same package
|
||||
DnsMessage(int id) {
|
||||
header = newHeader(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the header belonging to this message.
|
||||
*/
|
||||
public DnsHeader header() {
|
||||
return header;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of all the questions in this message.
|
||||
*/
|
||||
public List<DnsQuestion> questions() {
|
||||
if (questions == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return Collections.unmodifiableList(questions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of all the answer resource records in this message.
|
||||
*/
|
||||
public List<DnsResource> answers() {
|
||||
if (answers == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return Collections.unmodifiableList(answers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of all the authority resource records in this message.
|
||||
*/
|
||||
public List<DnsResource> authorityResources() {
|
||||
if (authority == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return Collections.unmodifiableList(authority);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of all the additional resource records in this message.
|
||||
*/
|
||||
public List<DnsResource> additionalResources() {
|
||||
if (additional == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return Collections.unmodifiableList(additional);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an answer resource record to this message.
|
||||
*
|
||||
* @param answer
|
||||
* the answer resource record to be added
|
||||
* @return the message to allow method chaining
|
||||
*/
|
||||
public DnsMessage addAnswer(DnsResource answer) {
|
||||
if (answers == null) {
|
||||
answers = new LinkedList<DnsResource>();
|
||||
}
|
||||
answers.add(answer);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a question to this message.
|
||||
*
|
||||
* @param question
|
||||
* the question to be added
|
||||
* @return the message to allow method chaining
|
||||
*/
|
||||
public DnsMessage addQuestion(DnsQuestion question) {
|
||||
if (questions == null) {
|
||||
questions = new LinkedList<DnsQuestion>();
|
||||
}
|
||||
questions.add(question);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an authority resource record to this message.
|
||||
*
|
||||
* @param resource
|
||||
* the authority resource record to be added
|
||||
* @return the message to allow method chaining
|
||||
*/
|
||||
public DnsMessage addAuthorityResource(DnsResource resource) {
|
||||
if (authority == null) {
|
||||
authority = new LinkedList<DnsResource>();
|
||||
}
|
||||
authority.add(resource);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an additional resource record to this message.
|
||||
*
|
||||
* @param resource
|
||||
* the additional resource record to be added
|
||||
* @return the message to allow method chaining
|
||||
*/
|
||||
public DnsMessage addAdditionalResource(DnsResource resource) {
|
||||
if (additional == null) {
|
||||
additional = new LinkedList<DnsResource>();
|
||||
}
|
||||
additional.add(resource);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void deallocate() {
|
||||
// NOOP
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean release() {
|
||||
release(questions());
|
||||
release(answers());
|
||||
release(additionalResources());
|
||||
release(authorityResources());
|
||||
return super.release();
|
||||
}
|
||||
|
||||
private static void release(List<?> resources) {
|
||||
for (Object resource: resources) {
|
||||
ReferenceCountUtil.release(resource);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean release(int decrement) {
|
||||
release(questions(), decrement);
|
||||
release(answers(), decrement);
|
||||
release(additionalResources(), decrement);
|
||||
release(authorityResources(), decrement);
|
||||
return super.release(decrement);
|
||||
}
|
||||
|
||||
private static void release(List<?> resources, int decrement) {
|
||||
for (Object resource: resources) {
|
||||
ReferenceCountUtil.release(resource, decrement);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DnsMessage touch(Object hint) {
|
||||
touch(questions(), hint);
|
||||
touch(answers(), hint);
|
||||
touch(additionalResources(), hint);
|
||||
touch(authorityResources(), hint);
|
||||
return this;
|
||||
}
|
||||
|
||||
private static void touch(List<?> resources, Object hint) {
|
||||
for (Object resource: resources) {
|
||||
ReferenceCountUtil.touch(resource, hint);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DnsMessage retain() {
|
||||
retain(questions());
|
||||
retain(answers());
|
||||
retain(additionalResources());
|
||||
retain(authorityResources());
|
||||
super.retain();
|
||||
return this;
|
||||
}
|
||||
|
||||
private static void retain(List<?> resources) {
|
||||
for (Object resource: resources) {
|
||||
ReferenceCountUtil.retain(resource);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DnsMessage retain(int increment) {
|
||||
retain(questions(), increment);
|
||||
retain(answers(), increment);
|
||||
retain(additionalResources(), increment);
|
||||
retain(authorityResources(), increment);
|
||||
super.retain(increment);
|
||||
return this;
|
||||
}
|
||||
|
||||
private static void retain(List<?> resources, int increment) {
|
||||
for (Object resource: resources) {
|
||||
ReferenceCountUtil.retain(resource, increment);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DnsMessage touch() {
|
||||
super.touch();
|
||||
return this;
|
||||
}
|
||||
|
||||
protected abstract DnsHeader newHeader(int id);
|
||||
}
|
103
codec-dns/src/main/java/io/netty/handler/codec/dns/DnsQuery.java
Normal file
103
codec-dns/src/main/java/io/netty/handler/codec/dns/DnsQuery.java
Normal file
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright 2013 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.net.InetSocketAddress;
|
||||
|
||||
/**
|
||||
* A DNS query packet which is sent to a server to receive a DNS response packet
|
||||
* with information answering a DnsQuery's questions.
|
||||
*/
|
||||
public class DnsQuery extends DnsMessage {
|
||||
|
||||
private final InetSocketAddress recipient;
|
||||
|
||||
/**
|
||||
* Constructs a DNS query. By default recursion will be toggled on.
|
||||
*/
|
||||
public DnsQuery(int id, InetSocketAddress recipient) {
|
||||
super(id);
|
||||
if (recipient == null) {
|
||||
throw new NullPointerException("recipient");
|
||||
}
|
||||
this.recipient = recipient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the {@link InetSocketAddress} of the recipient of the {@link DnsQuery}
|
||||
*/
|
||||
public InetSocketAddress recipient() {
|
||||
return recipient;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DnsQuery addAnswer(DnsResource answer) {
|
||||
super.addAnswer(answer);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DnsQuery addQuestion(DnsQuestion question) {
|
||||
super.addQuestion(question);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DnsQuery addAuthorityResource(DnsResource resource) {
|
||||
super.addAuthorityResource(resource);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DnsQuery addAdditionalResource(DnsResource resource) {
|
||||
super.addAdditionalResource(resource);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DnsQuery touch(Object hint) {
|
||||
super.touch(hint);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DnsQuery retain() {
|
||||
super.retain();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DnsQuery retain(int increment) {
|
||||
super.retain(increment);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DnsQuery touch() {
|
||||
super.touch();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DnsQueryHeader header() {
|
||||
return (DnsQueryHeader) super.header();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DnsQueryHeader newHeader(int id) {
|
||||
return new DnsQueryHeader(this, id);
|
||||
}
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright 2013 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.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.socket.DatagramPacket;
|
||||
import io.netty.handler.codec.MessageToMessageEncoder;
|
||||
import io.netty.util.CharsetUtil;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* DnsQueryEncoder accepts {@link DnsQuery} and encodes to {@link ByteBuf}. This
|
||||
* class also contains methods for encoding parts of DnsQuery's such as the
|
||||
* header and questions.
|
||||
*/
|
||||
@ChannelHandler.Sharable
|
||||
public class DnsQueryEncoder extends MessageToMessageEncoder<DnsQuery> {
|
||||
|
||||
@Override
|
||||
protected void encode(ChannelHandlerContext ctx, DnsQuery query, List<Object> out) throws Exception {
|
||||
ByteBuf buf = ctx.alloc().buffer();
|
||||
encodeHeader(query.header(), buf);
|
||||
List<DnsQuestion> questions = query.questions();
|
||||
for (DnsQuestion question : questions) {
|
||||
encodeQuestion(question, CharsetUtil.UTF_8, buf);
|
||||
}
|
||||
out.add(new DatagramPacket(buf, query.recipient(), null));
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the information in a {@link DnsHeader} and writes it to the
|
||||
* specified {@link ByteBuf}. The header is always 12 bytes long.
|
||||
*
|
||||
* @param header
|
||||
* the query header being encoded
|
||||
* @param buf
|
||||
* the buffer the encoded data should be written to
|
||||
*/
|
||||
private static void encodeHeader(DnsHeader header, ByteBuf buf) {
|
||||
buf.writeShort(header.id());
|
||||
int flags = 0;
|
||||
flags |= header.type() << 15;
|
||||
flags |= header.opcode() << 14;
|
||||
flags |= header.isRecursionDesired() ? 1 << 8 : 0;
|
||||
buf.writeShort(flags);
|
||||
buf.writeShort(header.questionCount());
|
||||
buf.writeShort(header.answerCount()); // Must be 0
|
||||
buf.writeShort(header.authorityResourceCount()); // Must be 0
|
||||
buf.writeShort(header.additionalResourceCount()); // Must be 0
|
||||
}
|
||||
|
||||
/**
|
||||
* Encodes the information in a {@link DnsQuestion} and writes it to the
|
||||
* specified {@link ByteBuf}.
|
||||
*
|
||||
* @param question
|
||||
* the question being encoded
|
||||
* @param charset
|
||||
* charset names are encoded in
|
||||
* @param buf
|
||||
* the buffer the encoded data should be written to
|
||||
*/
|
||||
private static void encodeQuestion(DnsQuestion question, Charset charset, ByteBuf buf) {
|
||||
String[] parts = StringUtil.split(question.name(), '.');
|
||||
for (String part: parts) {
|
||||
buf.writeByte(part.length());
|
||||
buf.writeBytes(part.getBytes(charset));
|
||||
}
|
||||
buf.writeByte(0); // marks end of name field
|
||||
buf.writeShort(question.type());
|
||||
buf.writeShort(question.dnsClass());
|
||||
}
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright 2013 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;
|
||||
|
||||
/**
|
||||
* The DNS query header class which is used to represent the 12 byte header in a
|
||||
* {@link DnsQuery}.
|
||||
*/
|
||||
public final class DnsQueryHeader extends DnsHeader {
|
||||
|
||||
/**
|
||||
* Constructor for a DNS packet query header. The id is user generated and
|
||||
* will be replicated in the response packet by the server.
|
||||
*
|
||||
* @param parent the {@link DnsMessage} this header belongs to
|
||||
* @param id a 2 bit unsigned identification number for this query
|
||||
*/
|
||||
public DnsQueryHeader(DnsMessage parent, int id) {
|
||||
super(parent);
|
||||
setId(id);
|
||||
setRecursionDesired(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link DnsMessage} type. This will always return
|
||||
* {@code TYPE_QUERY}.
|
||||
*/
|
||||
@Override
|
||||
public int type() {
|
||||
return TYPE_QUERY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link DnsHeader} type. Must be {@code TYPE_RESPONSE}.
|
||||
*
|
||||
* @param type message type
|
||||
* @return the header to allow method chaining
|
||||
*/
|
||||
@Override
|
||||
public DnsQueryHeader setType(int type) {
|
||||
if (type != TYPE_QUERY) {
|
||||
throw new IllegalArgumentException("type cannot be anything but TYPE_QUERY (0) for a query header.");
|
||||
}
|
||||
super.setType(type);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DnsQueryHeader setId(int id) {
|
||||
super.setId(id);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DnsQueryHeader setRecursionDesired(boolean recursionDesired) {
|
||||
super.setRecursionDesired(recursionDesired);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DnsQueryHeader setOpcode(int opcode) {
|
||||
super.setOpcode(opcode);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DnsQueryHeader setZ(int z) {
|
||||
super.setZ(z);
|
||||
return this;
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 2013 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;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* Usually a message contains a single question, and DNS servers often don't
|
||||
* support multiple questions in a single query.
|
||||
*/
|
||||
public final class DnsQuestion extends DnsEntry {
|
||||
|
||||
/**
|
||||
* Constructs a question with the default class IN (Internet).
|
||||
*
|
||||
* @param name
|
||||
* the domain name being queried i.e. "www.example.com"
|
||||
* @param type
|
||||
* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a question with the given class.
|
||||
*
|
||||
* @param name
|
||||
* the domain name being queried i.e. "www.example.com"
|
||||
* @param type
|
||||
* the question type, which represents the type of
|
||||
* {@link DnsResource} record that should be returned
|
||||
* @param qClass
|
||||
* the class of a DNS record
|
||||
*/
|
||||
public DnsQuestion(String name, int type, int qClass) {
|
||||
super(name, type, qClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (!(other instanceof DnsQuestion)) {
|
||||
return false;
|
||||
}
|
||||
return super.equals(other);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return super.hashCode();
|
||||
}
|
||||
}
|
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright 2013 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.buffer.ByteBuf;
|
||||
import io.netty.buffer.ByteBufHolder;
|
||||
|
||||
/**
|
||||
* Represents any resource record (answer, authority, or additional resource
|
||||
* records).
|
||||
*/
|
||||
public final class DnsResource extends DnsEntry implements ByteBufHolder {
|
||||
|
||||
private final long ttl;
|
||||
private final ByteBuf content;
|
||||
|
||||
/**
|
||||
* Constructs a resource record.
|
||||
*
|
||||
* @param name
|
||||
* the domain name
|
||||
* @param type
|
||||
* the type of record being returned
|
||||
* @param aClass
|
||||
* the class for this resource record
|
||||
* @param ttl
|
||||
* the time to live after reading
|
||||
* @param content
|
||||
* the data contained in this record
|
||||
*/
|
||||
public DnsResource(String name, int type, int aClass, long ttl, ByteBuf content) {
|
||||
super(name, type, aClass);
|
||||
this.ttl = ttl;
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the time to live after reading for this resource record.
|
||||
*/
|
||||
public long timeToLive() {
|
||||
return ttl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the data contained in this resource record.
|
||||
*/
|
||||
@Override
|
||||
public ByteBuf content() {
|
||||
return content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a deep copy of this resource record.
|
||||
*/
|
||||
@Override
|
||||
public DnsResource copy() {
|
||||
return new DnsResource(name(), type(), dnsClass(), ttl, content.copy());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a duplicate of this resource record.
|
||||
*/
|
||||
@Override
|
||||
public ByteBufHolder duplicate() {
|
||||
return new DnsResource(name(), type(), dnsClass(), ttl, content.duplicate());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int refCnt() {
|
||||
return content.refCnt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DnsResource retain() {
|
||||
content.retain();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DnsResource retain(int increment) {
|
||||
content.retain(increment);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean release() {
|
||||
return content.release();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean release(int decrement) {
|
||||
return content.release(decrement);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DnsResource touch() {
|
||||
content.touch();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DnsResource touch(Object hint) {
|
||||
content.touch(hint);
|
||||
return this;
|
||||
}
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright 2013 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.net.InetSocketAddress;
|
||||
|
||||
/**
|
||||
* A DNS response packet which is sent to a client after a server receives a
|
||||
* query.
|
||||
*/
|
||||
public final class DnsResponse extends DnsMessage {
|
||||
|
||||
private final InetSocketAddress sender;
|
||||
|
||||
public DnsResponse(int id, InetSocketAddress sender) {
|
||||
super(id);
|
||||
if (sender == null) {
|
||||
throw new NullPointerException("sender");
|
||||
}
|
||||
this.sender = sender;
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@link InetSocketAddress} of the sender of this {@link DnsResponse}
|
||||
*/
|
||||
public InetSocketAddress sender() {
|
||||
return sender;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DnsResponse addAnswer(DnsResource answer) {
|
||||
super.addAnswer(answer);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DnsResponse addQuestion(DnsQuestion question) {
|
||||
super.addQuestion(question);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DnsResponse addAuthorityResource(DnsResource resource) {
|
||||
super.addAuthorityResource(resource);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DnsResponse addAdditionalResource(DnsResource resource) {
|
||||
super.addAdditionalResource(resource);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DnsResponse touch(Object hint) {
|
||||
super.touch(hint);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DnsResponse retain() {
|
||||
super.retain();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DnsResponse retain(int increment) {
|
||||
super.retain(increment);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DnsResponse touch() {
|
||||
super.touch();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DnsResponseHeader header() {
|
||||
return (DnsResponseHeader) super.header();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DnsResponseHeader newHeader(int id) {
|
||||
return new DnsResponseHeader(this, id);
|
||||
}
|
||||
}
|
@ -0,0 +1,191 @@
|
||||
/*
|
||||
* Copyright 2013 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;
|
||||
|
||||
/**
|
||||
* Represents the possible response codes a server may send after receiving a
|
||||
* query. A response code of 0 indicates no error.
|
||||
*/
|
||||
public final class DnsResponseCode implements Comparable<DnsResponseCode> {
|
||||
|
||||
/**
|
||||
* ID 0, no error
|
||||
*/
|
||||
public static final DnsResponseCode NOERROR = new DnsResponseCode(0, "no error");
|
||||
|
||||
/**
|
||||
* ID 1, format error
|
||||
*/
|
||||
public static final DnsResponseCode FORMERROR = new DnsResponseCode(1, "format error");
|
||||
|
||||
/**
|
||||
* ID 2, server failure
|
||||
*/
|
||||
public static final DnsResponseCode SERVFAIL = new DnsResponseCode(2, "server failure");
|
||||
|
||||
/**
|
||||
* ID 3, name error
|
||||
*/
|
||||
public static final DnsResponseCode NXDOMAIN = new DnsResponseCode(3, "name error");
|
||||
|
||||
/**
|
||||
* ID 4, not implemented
|
||||
*/
|
||||
public static final DnsResponseCode NOTIMPL = new DnsResponseCode(4, "not implemented");
|
||||
|
||||
/**
|
||||
* ID 5, operation refused
|
||||
*/
|
||||
public static final DnsResponseCode REFUSED = new DnsResponseCode(5, "operation refused");
|
||||
|
||||
/**
|
||||
* ID 6, domain name should not exist
|
||||
*/
|
||||
public static final DnsResponseCode YXDOMAIN = new DnsResponseCode(6, "domain name should not exist");
|
||||
|
||||
/**
|
||||
* ID 7, resource record set should not exist
|
||||
*/
|
||||
public static final DnsResponseCode YXRRSET = new DnsResponseCode(7, "resource record set should not exist");
|
||||
|
||||
/**
|
||||
* ID 8, rrset does not exist
|
||||
*/
|
||||
public static final DnsResponseCode NXRRSET = new DnsResponseCode(8, "rrset does not exist");
|
||||
|
||||
/**
|
||||
* ID 9, not authoritative for zone
|
||||
*/
|
||||
public static final DnsResponseCode NOTAUTH = new DnsResponseCode(9, "not authoritative for zone");
|
||||
|
||||
/**
|
||||
* ID 10, name not in zone
|
||||
*/
|
||||
public static final DnsResponseCode NOTZONE = new DnsResponseCode(10, "name not in zone");
|
||||
|
||||
/**
|
||||
* ID 11, bad extension mechanism for version
|
||||
*/
|
||||
public static final DnsResponseCode BADVERS = new DnsResponseCode(11, "bad extension mechanism for version");
|
||||
|
||||
/**
|
||||
* ID 12, bad signature
|
||||
*/
|
||||
public static final DnsResponseCode BADSIG = new DnsResponseCode(12, "bad signature");
|
||||
|
||||
/**
|
||||
* ID 13, bad key
|
||||
*/
|
||||
public static final DnsResponseCode BADKEY = new DnsResponseCode(13, "bad key");
|
||||
|
||||
/**
|
||||
* ID 14, bad timestamp
|
||||
*/
|
||||
public static final DnsResponseCode BADTIME = new DnsResponseCode(14, "bad timestamp");
|
||||
|
||||
private final int errorCode;
|
||||
private final String message;
|
||||
|
||||
/**
|
||||
* Returns the {@link DnsResponseCode} that corresponds with the given
|
||||
* {@code responseCode}.
|
||||
*
|
||||
* @param responseCode
|
||||
* the error code's id
|
||||
* @return corresponding {@link DnsResponseCode} or {@code null} if none can be found.
|
||||
*/
|
||||
public static DnsResponseCode valueOf(int responseCode) {
|
||||
switch (responseCode) {
|
||||
case 0:
|
||||
return NOERROR;
|
||||
case 1:
|
||||
return FORMERROR;
|
||||
case 2:
|
||||
return SERVFAIL;
|
||||
case 3:
|
||||
return NXDOMAIN;
|
||||
case 4:
|
||||
return NOTIMPL;
|
||||
case 5:
|
||||
return REFUSED;
|
||||
case 6:
|
||||
return YXDOMAIN;
|
||||
case 7:
|
||||
return YXRRSET;
|
||||
case 8:
|
||||
return NXRRSET;
|
||||
case 9:
|
||||
return NOTAUTH;
|
||||
case 10:
|
||||
return NOTZONE;
|
||||
case 11:
|
||||
return BADVERS;
|
||||
case 12:
|
||||
return BADSIG;
|
||||
case 13:
|
||||
return BADKEY;
|
||||
case 14:
|
||||
return BADTIME;
|
||||
default:
|
||||
return new DnsResponseCode(responseCode, null);
|
||||
}
|
||||
}
|
||||
|
||||
public DnsResponseCode(int errorCode, String message) {
|
||||
this.errorCode = errorCode;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the error code for this {@link DnsResponseCode}.
|
||||
*/
|
||||
public int code() {
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(DnsResponseCode o) {
|
||||
return code() - o.code();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return code();
|
||||
}
|
||||
|
||||
/**
|
||||
* Equality of {@link DnsResponseCode} only depends on {@link #code()}.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof DnsResponseCode)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return code() == ((DnsResponseCode) o).code();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a formatted error message for this {@link DnsResponseCode}.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
if (message == null) {
|
||||
return "DnsResponseCode(" + errorCode + ')';
|
||||
}
|
||||
return "DnsResponseCode(" + errorCode + ", " + message + ')';
|
||||
}
|
||||
}
|
@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright 2013 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.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.socket.DatagramPacket;
|
||||
import io.netty.handler.codec.MessageToMessageDecoder;
|
||||
import io.netty.util.CharsetUtil;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* DnsResponseDecoder accepts {@link io.netty.channel.socket.DatagramPacket} and encodes to
|
||||
* {@link DnsResponse}. This class also contains methods for decoding parts of
|
||||
* DnsResponses such as questions and resource records.
|
||||
*/
|
||||
@ChannelHandler.Sharable
|
||||
public class DnsResponseDecoder extends MessageToMessageDecoder<DatagramPacket> {
|
||||
|
||||
@Override
|
||||
protected void decode(ChannelHandlerContext ctx, DatagramPacket packet, List<Object> out) throws Exception {
|
||||
ByteBuf buf = packet.content();
|
||||
|
||||
int id = buf.readUnsignedShort();
|
||||
|
||||
DnsResponse response = new DnsResponse(id, packet.sender());
|
||||
DnsResponseHeader header = response.header();
|
||||
int flags = buf.readUnsignedShort();
|
||||
header.setType(flags >> 15);
|
||||
header.setOpcode(flags >> 11 & 0xf);
|
||||
header.setRecursionDesired((flags >> 8 & 1) == 1);
|
||||
header.setAuthoritativeAnswer((flags >> 10 & 1) == 1);
|
||||
header.setTruncated((flags >> 9 & 1) == 1);
|
||||
header.setRecursionAvailable((flags >> 7 & 1) == 1);
|
||||
header.setZ(flags >> 4 & 0x7);
|
||||
header.setResponseCode(DnsResponseCode.valueOf(flags & 0xf));
|
||||
|
||||
int questions = buf.readUnsignedShort();
|
||||
int answers = buf.readUnsignedShort();
|
||||
int authorities = buf.readUnsignedShort();
|
||||
int additionals = buf.readUnsignedShort();
|
||||
|
||||
for (int i = 0; i < questions; i++) {
|
||||
response.addQuestion(decodeQuestion(buf));
|
||||
}
|
||||
if (header.responseCode() != DnsResponseCode.NOERROR) {
|
||||
// response code for error
|
||||
out.add(response);
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < answers; i++) {
|
||||
response.addAnswer(decodeResource(buf));
|
||||
}
|
||||
for (int i = 0; i < authorities; i++) {
|
||||
response.addAuthorityResource(decodeResource(buf));
|
||||
}
|
||||
for (int i = 0; i < additionals; i++) {
|
||||
response.addAdditionalResource(decodeResource(buf));
|
||||
}
|
||||
out.add(response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a domain name given a buffer containing a DNS packet. If the
|
||||
* name contains a pointer, the position of the buffer will be set to
|
||||
* directly after the pointer's index after the name has been read.
|
||||
*
|
||||
* @param buf
|
||||
* the byte buffer containing the DNS packet
|
||||
* @return the domain name for an entry
|
||||
*/
|
||||
private static String readName(ByteBuf buf) {
|
||||
int position = -1;
|
||||
StringBuilder name = new StringBuilder();
|
||||
for (int len = buf.readUnsignedByte(); buf.isReadable() && len != 0; len = buf.readUnsignedByte()) {
|
||||
boolean pointer = (len & 0xc0) == 0xc0;
|
||||
if (pointer) {
|
||||
if (position == -1) {
|
||||
position = buf.readerIndex() + 1;
|
||||
}
|
||||
buf.readerIndex((len & 0x3f) << 8 | buf.readUnsignedByte());
|
||||
} else {
|
||||
name.append(buf.toString(buf.readerIndex(), len, CharsetUtil.UTF_8)).append('.');
|
||||
buf.skipBytes(len);
|
||||
}
|
||||
}
|
||||
if (position != -1) {
|
||||
buf.readerIndex(position);
|
||||
}
|
||||
if (name.length() == 0) {
|
||||
return null;
|
||||
}
|
||||
return name.substring(0, name.length() - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes a question, given a DNS packet in a byte buffer.
|
||||
*
|
||||
* @param buf
|
||||
* the byte buffer containing the DNS packet
|
||||
* @return a decoded {@link DnsQuestion}
|
||||
*/
|
||||
private static DnsQuestion decodeQuestion(ByteBuf buf) {
|
||||
String name = readName(buf);
|
||||
int type = buf.readUnsignedShort();
|
||||
int qClass = buf.readUnsignedShort();
|
||||
return new DnsQuestion(name, type, qClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes a resource record, given a DNS packet in a byte buffer.
|
||||
*
|
||||
* @param buf
|
||||
* the byte buffer containing the DNS packet
|
||||
* @return a {@link DnsResource} record containing response data
|
||||
*/
|
||||
private static DnsResource decodeResource(ByteBuf buf) {
|
||||
String name = readName(buf);
|
||||
int type = buf.readUnsignedShort();
|
||||
int aClass = buf.readUnsignedShort();
|
||||
long ttl = buf.readUnsignedInt();
|
||||
int len = buf.readUnsignedShort();
|
||||
|
||||
int readerIndex = buf.readerIndex();
|
||||
ByteBuf payload = buf.duplicate().setIndex(readerIndex, readerIndex + len).retain();
|
||||
buf.readerIndex(readerIndex + len);
|
||||
return new DnsResource(name, type, aClass, ttl, payload);
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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.handler.codec.DecoderException;
|
||||
|
||||
public final class DnsResponseException extends DecoderException {
|
||||
|
||||
private final DnsResponseCode code;
|
||||
|
||||
public DnsResponseException(DnsResponseCode code) {
|
||||
if (code == null) {
|
||||
throw new NullPointerException("code");
|
||||
}
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@link DnsResponseCode} which caused this {@link DnsResponseException} to be created.
|
||||
*/
|
||||
public DnsResponseCode responseCode() {
|
||||
return code;
|
||||
}
|
||||
}
|
@ -0,0 +1,168 @@
|
||||
/*
|
||||
* Copyright 2013 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;
|
||||
|
||||
/**
|
||||
* The DNS response header class which is used when receiving data from a DNS
|
||||
* server. Contains information contained in a DNS response header, such as
|
||||
* recursion availability, and response codes.
|
||||
*/
|
||||
public final class DnsResponseHeader extends DnsHeader {
|
||||
|
||||
private boolean authoritativeAnswer;
|
||||
private boolean truncated;
|
||||
private boolean recursionAvailable;
|
||||
|
||||
private DnsResponseCode responseCode;
|
||||
|
||||
/**
|
||||
* Constructor for a DNS packet response header. The id is received by
|
||||
* reading a {@link DnsQuery} and is sent back to the client.
|
||||
*
|
||||
* @param parent
|
||||
* the {@link DnsMessage} this header belongs to
|
||||
* @param id
|
||||
* a 2 bit unsigned identification number received from client
|
||||
*/
|
||||
public DnsResponseHeader(DnsMessage parent, int id) {
|
||||
super(parent);
|
||||
setId(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if responding server is authoritative for the domain
|
||||
* name in the query message.
|
||||
*/
|
||||
public boolean isAuthoritativeAnswer() {
|
||||
return authoritativeAnswer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if response has been truncated, usually if it is
|
||||
* over 512 bytes.
|
||||
*/
|
||||
public boolean isTruncated() {
|
||||
return truncated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if DNS server can handle recursive queries.
|
||||
*/
|
||||
public boolean isRecursionAvailable() {
|
||||
return recursionAvailable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the 4 bit return code.
|
||||
*/
|
||||
public DnsResponseCode responseCode() {
|
||||
return responseCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link DnsMessage} type. This will always return
|
||||
* {@code TYPE_RESPONSE}.
|
||||
*/
|
||||
@Override
|
||||
public int type() {
|
||||
return TYPE_RESPONSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to {@code true} if responding server is authoritative for the domain
|
||||
* name in the query message.
|
||||
*
|
||||
* @param authoritativeAnswer
|
||||
* flag for authoritative answer
|
||||
*/
|
||||
public DnsResponseHeader setAuthoritativeAnswer(boolean authoritativeAnswer) {
|
||||
this.authoritativeAnswer = authoritativeAnswer;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to {@code true} if response has been truncated (usually happens for
|
||||
* responses over 512 bytes).
|
||||
*
|
||||
* @param truncated
|
||||
* flag for truncation
|
||||
*/
|
||||
public DnsResponseHeader setTruncated(boolean truncated) {
|
||||
this.truncated = truncated;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to {@code true} if DNS server can handle recursive queries.
|
||||
*
|
||||
* @param recursionAvailable
|
||||
* flag for recursion availability
|
||||
*/
|
||||
public DnsResponseHeader setRecursionAvailable(boolean recursionAvailable) {
|
||||
this.recursionAvailable = recursionAvailable;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the response code for this message.
|
||||
*
|
||||
* @param responseCode
|
||||
* the response code
|
||||
*/
|
||||
public DnsResponseHeader setResponseCode(DnsResponseCode responseCode) {
|
||||
this.responseCode = responseCode;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link DnsHeader} type. Must be {@code TYPE_RESPONSE}.
|
||||
*
|
||||
* @param type
|
||||
* message type
|
||||
* @return the header to allow method chaining
|
||||
*/
|
||||
@Override
|
||||
public DnsResponseHeader setType(int type) {
|
||||
if (type != TYPE_RESPONSE) {
|
||||
throw new IllegalArgumentException("type cannot be anything but TYPE_RESPONSE (1) for a response header.");
|
||||
}
|
||||
super.setType(type);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DnsResponseHeader setId(int id) {
|
||||
super.setId(id);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DnsHeader setRecursionDesired(boolean recursionDesired) {
|
||||
return super.setRecursionDesired(recursionDesired);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DnsResponseHeader setOpcode(int opcode) {
|
||||
super.setOpcode(opcode);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DnsResponseHeader setZ(int z) {
|
||||
super.setZ(z);
|
||||
return this;
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright 2012 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* DNS codec information for writing to and reading from a DNS server.
|
||||
* Includes decoders and classes for representing messages and resources.
|
||||
*/
|
||||
package io.netty.handler.codec.dns;
|
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2013 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.channel.embedded.EmbeddedChannel;
|
||||
|
||||
import io.netty.channel.socket.DatagramPacket;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class DnsQueryTest {
|
||||
|
||||
@Test
|
||||
public void writeQueryTest() throws Exception {
|
||||
InetSocketAddress addr = new InetSocketAddress(0);
|
||||
EmbeddedChannel embedder = new EmbeddedChannel(new DnsQueryEncoder());
|
||||
List<DnsQuery> queries = new ArrayList<DnsQuery>(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)));
|
||||
|
||||
for (DnsQuery query: queries) {
|
||||
Assert.assertEquals("Invalid question count, expected 1.", 1, query.header().questionCount());
|
||||
Assert.assertEquals("Invalid answer count, expected 0.", 0, query.header().answerCount());
|
||||
Assert.assertEquals("Invalid authority resource record count, expected 0.", 0, query.header()
|
||||
.authorityResourceCount());
|
||||
Assert.assertEquals("Invalid additional resource record count, expected 0.", 0, query.header()
|
||||
.additionalResourceCount());
|
||||
Assert.assertEquals("Invalid type, should be TYPE_QUERY (0)", DnsHeader.TYPE_QUERY, query.header()
|
||||
.type());
|
||||
embedder.writeOutbound(query);
|
||||
DatagramPacket packet = embedder.readOutbound();
|
||||
Assert.assertTrue(packet.content().isReadable());
|
||||
packet.release();
|
||||
Assert.assertNull(embedder.readOutbound());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2013 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.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.embedded.EmbeddedChannel;
|
||||
import io.netty.channel.socket.DatagramPacket;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
public class DnsResponseTest {
|
||||
|
||||
private static final byte[][] packets = {
|
||||
{ 0, 1, -127, -128, 0, 1, 0, 1, 0, 0, 0, 0, 3, 119, 119, 119, 7, 101, 120, 97, 109, 112, 108, 101, 3, 99,
|
||||
111, 109, 0, 0, 1, 0, 1, -64, 12, 0, 1, 0, 1, 0, 0, 16, -113, 0, 4, -64, 0, 43, 10 },
|
||||
{ 0, 1, -127, -128, 0, 1, 0, 1, 0, 0, 0, 0, 3, 119, 119, 119, 7, 101, 120, 97, 109, 112, 108, 101, 3, 99,
|
||||
111, 109, 0, 0, 28, 0, 1, -64, 12, 0, 28, 0, 1, 0, 0, 69, -8, 0, 16, 32, 1, 5, 0, 0, -120, 2, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 16 },
|
||||
{ 0, 2, -127, -128, 0, 1, 0, 0, 0, 1, 0, 0, 3, 119, 119, 119, 7, 101, 120, 97, 109, 112, 108, 101, 3, 99,
|
||||
111, 109, 0, 0, 15, 0, 1, -64, 16, 0, 6, 0, 1, 0, 0, 3, -43, 0, 45, 3, 115, 110, 115, 3, 100, 110,
|
||||
115, 5, 105, 99, 97, 110, 110, 3, 111, 114, 103, 0, 3, 110, 111, 99, -64, 49, 119, -4, 39, 112, 0,
|
||||
0, 28, 32, 0, 0, 14, 16, 0, 18, 117, 0, 0, 0, 14, 16 },
|
||||
{ 0, 3, -127, -128, 0, 1, 0, 1, 0, 0, 0, 0, 3, 119, 119, 119, 7, 101, 120, 97, 109, 112, 108, 101, 3, 99,
|
||||
111, 109, 0, 0, 16, 0, 1, -64, 12, 0, 16, 0, 1, 0, 0, 84, 75, 0, 12, 11, 118, 61, 115, 112, 102,
|
||||
49, 32, 45, 97, 108, 108 } };
|
||||
|
||||
@Test
|
||||
public void readResponseTest() throws Exception {
|
||||
EmbeddedChannel embedder = new EmbeddedChannel(new DnsResponseDecoder());
|
||||
for (byte[] p: packets) {
|
||||
ByteBuf packet = embedder.alloc().buffer(512).writeBytes(p);
|
||||
embedder.writeInbound(new DatagramPacket(packet, null, new InetSocketAddress(0)));
|
||||
DnsResponse decoded = embedder.readInbound();
|
||||
packet.retain().readerIndex(0);
|
||||
ByteBuf raw = Unpooled.wrappedBuffer(p);
|
||||
Assert.assertEquals("Invalid id, expected: " + raw.getUnsignedShort(0) + ", actual: "
|
||||
+ decoded.header().id(), raw.getUnsignedShort(0), decoded.header().id());
|
||||
Assert.assertEquals("Invalid resource count, expected: " + raw.getUnsignedShort(4) + ", actual: "
|
||||
+ decoded.questions().size(), raw.getUnsignedShort(4), decoded.questions().size());
|
||||
Assert.assertEquals("Invalid resource count, expected: " + raw.getUnsignedShort(6) + ", actual: "
|
||||
+ decoded.answers().size(), raw.getUnsignedShort(6), decoded.answers().size());
|
||||
Assert.assertEquals("Invalid resource count, expected: " + raw.getUnsignedShort(8) + ", actual: "
|
||||
+ decoded.authorityResources().size(), raw.getUnsignedShort(8), decoded.authorityResources()
|
||||
.size());
|
||||
Assert.assertEquals("Invalid resource count, expected: " + raw.getUnsignedShort(10) + ", actual: "
|
||||
+ decoded.additionalResources().size(), raw.getUnsignedShort(10),
|
||||
decoded.additionalResources().size());
|
||||
decoded.release();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright 2012 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* A DNS client that queries a server and checks if query information and
|
||||
* responses are valid to ensure codec is correct.
|
||||
*/
|
||||
package io.netty.handler.codec.dns;
|
@ -94,7 +94,7 @@ public abstract class AbstractReferenceCounted implements ReferenceCounted {
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean release() {
|
||||
public boolean release() {
|
||||
for (;;) {
|
||||
int refCnt = this.refCnt;
|
||||
if (refCnt == 0) {
|
||||
@ -112,7 +112,7 @@ public abstract class AbstractReferenceCounted implements ReferenceCounted {
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean release(int decrement) {
|
||||
public boolean release(int decrement) {
|
||||
if (decrement <= 0) {
|
||||
throw new IllegalArgumentException("decrement: " + decrement + " (expected: > 0)");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user