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:
Norman Maurer 2014-06-02 15:00:33 +00:00
parent 8074b5c6ee
commit e3c76ec106
20 changed files with 2135 additions and 2 deletions

51
codec-dns/pom.xml Normal file
View 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>4.1.0.Alpha1-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>

View 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;
}
}

View File

@ -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;
}
}

View File

@ -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);
}

View 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);
}
}

View File

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

View File

@ -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;
}
}

View File

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

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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 + ')';
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;

View File

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

View File

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

View File

@ -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;

View File

@ -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)");
}

View File

@ -335,6 +335,7 @@
<module>common</module>
<module>buffer</module>
<module>codec</module>
<module>codec-dns</module>
<module>codec-http</module>
<module>codec-memcache</module>
<module>codec-stomp</module>