Added more DNS required files

This commit is contained in:
nathan 2017-11-08 11:37:46 +01:00
parent 762215304d
commit 873e3e9863
4 changed files with 501 additions and 0 deletions

View File

@ -0,0 +1,76 @@
/*
* Copyright 2015 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 dorkbox.network.dns;
import java.net.InetSocketAddress;
import java.util.List;
import dorkbox.network.dns.records.DnsMessage;
import io.netty.buffer.ByteBuf;
import io.netty.channel.AddressedEnvelope;
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.internal.UnstableApi;
/**
* Encodes an {@link AddressedEnvelope} of {@link DnsQuestion}} into a {@link DatagramPacket}.
*/
@UnstableApi
@ChannelHandler.Sharable
public
class DatagramDnsQueryEncoder extends MessageToMessageEncoder<AddressedEnvelope<DnsQuestion, InetSocketAddress>> {
private final int maxPayloadSize;
/**
* Creates a new encoder
*/
public
DatagramDnsQueryEncoder(int maxPayloadSize) {
this.maxPayloadSize = maxPayloadSize;
}
@Override
protected
void encode(ChannelHandlerContext ctx, AddressedEnvelope<DnsQuestion, InetSocketAddress> in, List<Object> out) throws Exception {
final InetSocketAddress recipient = in.recipient();
final DnsMessage query = in.content();
final ByteBuf buf = ctx.alloc()
.ioBuffer(maxPayloadSize);
boolean success = false;
try {
DnsOutput dnsOutput = new DnsOutput(buf);
query.toWire(dnsOutput);
success = true;
} finally {
if (!success) {
buf.release();
}
}
out.add(new DatagramPacket(buf, recipient, null));
}
@Override
public
void exceptionCaught(final ChannelHandlerContext ctx, final Throwable cause) throws Exception {
cause.printStackTrace();
}
}

View File

@ -0,0 +1,55 @@
/*
* Copyright 2015 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 dorkbox.network.dns;
import java.util.List;
import dorkbox.network.dns.exceptions.WireParseException;
import dorkbox.network.dns.records.Header;
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.internal.UnstableApi;
/**
* Decodes a {@link DatagramPacket} into a {@link DnsResponse}.
*/
@UnstableApi
@ChannelHandler.Sharable
public class DatagramDnsResponseDecoder extends MessageToMessageDecoder<DatagramPacket> {
/**
* Creates a new DNS Response decoder
*/
public DatagramDnsResponseDecoder() {
}
@Override
protected void decode(ChannelHandlerContext ctx, DatagramPacket packet, List<Object> out) throws Exception {
final ByteBuf buf = packet.content();
// Check that the response is long enough.
if (buf.readableBytes() < Header.LENGTH) {
throw new WireParseException("invalid DNS header - " + "too short");
}
DnsInput dnsInput = new DnsInput(buf);
DnsResponse dnsMessage = new DnsResponse(packet.sender(), packet.recipient(), dnsInput);
out.add(dnsMessage);
}
}

View File

@ -0,0 +1,228 @@
package dorkbox.network.dns;
import static io.netty.util.internal.ObjectUtil.checkNotNull;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.Locale;
import dorkbox.network.dns.constants.DnsClass;
import dorkbox.network.dns.constants.DnsOpCode;
import dorkbox.network.dns.constants.DnsRecordType;
import dorkbox.network.dns.constants.DnsSection;
import dorkbox.network.dns.constants.Flags;
import dorkbox.network.dns.records.DnsMessage;
import dorkbox.network.dns.records.DnsRecord;
import io.netty.channel.AddressedEnvelope;
import io.netty.util.internal.StringUtil;
/**
*
*/
public
class DnsQuestion extends DnsMessage implements AddressedEnvelope<DnsQuestion, InetSocketAddress> {
private InetSocketAddress recipient;
private final boolean isResolveQuestion;
/**
* Creates a new instance.
*
* @param isResolveQuestion true if it's a resolve question, which means we ALSO are going to keep resolving names until we get an IP
* address.
*/
private
DnsQuestion(final boolean isResolveQuestion) {
this.isResolveQuestion = isResolveQuestion;
this.recipient = null;
}
public
boolean isResolveQuestion() {
return isResolveQuestion;
}
public static
DnsQuestion newResolveQuestion(final String inetHost, final int type, final boolean isRecursionDesired) {
return newQuestion(inetHost, type, isRecursionDesired, true);
}
public static
DnsQuestion newQuery(final String inetHost, final int type, final boolean isRecursionDesired) {
return newQuestion(inetHost, type, isRecursionDesired, false);
}
private static
DnsQuestion newQuestion(final String inetHost, final int type, final boolean isRecursionDesired, boolean isResolveQuestion) {
// Convert to ASCII which will also check that the length is not too big.
// See:
// - https://github.com/netty/netty/issues/4937
// - https://github.com/netty/netty/issues/4935
String hostname = hostname(checkNotNull(inetHost, "hostname"));
if (hostname == null) {
return null;
}
hostname = hostname.toLowerCase(Locale.US);
if (type == DnsRecordType.A || type == DnsRecordType.AAAA) {
// resolving a hostname -> ip address, the hostname MUST end in a dot
hostname = appendTrailingDot(hostname);
}
try {
DnsRecord questionRecord = DnsRecord.newRecord(Name.fromString(hostname), type, DnsClass.IN);
DnsQuestion question = new DnsQuestion(isResolveQuestion);
question.getHeader()
.setOpcode(DnsOpCode.QUERY);
if (isRecursionDesired) {
question.getHeader()
.setFlag(Flags.RD);
}
question.addRecord(questionRecord, DnsSection.QUESTION);
// keep the question around so we can compare the response to it.
question.retain();
return question;
} catch (Exception e) {
// Name.fromString may throw a TextParseException if it fails to parse
}
return null;
}
public static
String hostname(String inetHost) {
try {
String hostname = java.net.IDN.toASCII(inetHost);
// Check for http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6894622
if (StringUtil.endsWith(inetHost, '.') && !StringUtil.endsWith(hostname, '.')) {
return hostname + '.';
}
return hostname;
} catch (Exception e) {
// java.net.IDN.toASCII(...) may throw an IllegalArgumentException if it fails to parse the hostname
}
return null;
}
private static
String appendTrailingDot(String hostname) {
if (!StringUtil.endsWith(hostname, '.')) {
return hostname + '.';
}
return hostname;
}
public
void init(int id, InetSocketAddress recipient) {
getHeader().setID(id);
this.recipient = recipient;
}
@Override
public
DnsQuestion content() {
return this;
}
@Override
public
InetSocketAddress sender() {
return null;
}
@Override
public
InetSocketAddress recipient() {
return recipient;
}
@Override
public
DnsQuestion touch() {
return (DnsQuestion) super.touch();
}
@Override
public
DnsQuestion touch(Object hint) {
return (DnsQuestion) super.touch(hint);
}
@Override
public
DnsQuestion retain() {
return (DnsQuestion) super.retain();
}
@Override
public
DnsQuestion retain(int increment) {
return (DnsQuestion) super.retain(increment);
}
@Override
public
boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!super.equals(obj)) {
return false;
}
if (!(obj instanceof AddressedEnvelope)) {
return false;
}
@SuppressWarnings("unchecked")
final AddressedEnvelope<?, SocketAddress> that = (AddressedEnvelope<?, SocketAddress>) obj;
if (sender() == null) {
if (that.sender() != null) {
return false;
}
}
else if (!sender().equals(that.sender())) {
return false;
}
if (recipient() == null) {
if (that.recipient() != null) {
return false;
}
}
else if (!recipient().equals(that.recipient())) {
return false;
}
return true;
}
@Override
public
int hashCode() {
int hashCode = super.hashCode();
if (sender() != null) {
hashCode = hashCode * 31 + sender().hashCode();
}
if (recipient() != null) {
hashCode = hashCode * 31 + recipient().hashCode();
}
return hashCode;
}
}

View File

@ -0,0 +1,142 @@
/*
* Copyright 2015 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 dorkbox.network.dns;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import dorkbox.network.dns.records.DnsMessage;
import io.netty.channel.AddressedEnvelope;
import io.netty.util.internal.UnstableApi;
/**
* A {@link DnsResponse} implementation for UDP/IP.
*/
@UnstableApi
public class DnsResponse extends DnsMessage implements AddressedEnvelope<DnsResponse, InetSocketAddress> {
private final InetSocketAddress sender;
private final InetSocketAddress recipient;
/**
* Creates a new instance.
*
* @param sender the address of the sender
* @param recipient the address of the recipient
*/
public
DnsResponse(InetSocketAddress sender, InetSocketAddress recipient, final DnsInput dnsInput) throws IOException {
super(dnsInput);
if (recipient == null && sender == null) {
throw new NullPointerException("recipient and sender");
}
this.sender = sender;
this.recipient = recipient;
}
@Override
public
DnsResponse content() {
return this;
}
@Override
public InetSocketAddress sender() {
return sender;
}
@Override
public InetSocketAddress recipient() {
return recipient;
}
@Override
public
DnsResponse touch() {
return (DnsResponse) super.touch();
}
@Override
public
DnsResponse touch(Object hint) {
return (DnsResponse) super.touch(hint);
}
@Override
public
DnsResponse retain() {
return (DnsResponse) super.retain();
}
@Override
public
DnsResponse retain(int increment) {
return (DnsResponse) super.retain(increment);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!super.equals(obj)) {
return false;
}
if (!(obj instanceof AddressedEnvelope)) {
return false;
}
@SuppressWarnings("unchecked")
final AddressedEnvelope<?, SocketAddress> that = (AddressedEnvelope<?, SocketAddress>) obj;
if (sender() == null) {
if (that.sender() != null) {
return false;
}
} else if (!sender().equals(that.sender())) {
return false;
}
if (recipient() == null) {
if (that.recipient() != null) {
return false;
}
} else if (!recipient().equals(that.recipient())) {
return false;
}
return true;
}
@Override
public int hashCode() {
int hashCode = super.hashCode();
if (sender() != null) {
hashCode = hashCode * 31 + sender().hashCode();
}
if (recipient() != null) {
hashCode = hashCode * 31 + recipient().hashCode();
}
return hashCode;
}
}