Added more DNS required files
This commit is contained in:
parent
762215304d
commit
873e3e9863
76
src/dorkbox/network/dns/DatagramDnsQueryEncoder.java
Normal file
76
src/dorkbox/network/dns/DatagramDnsQueryEncoder.java
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
55
src/dorkbox/network/dns/DatagramDnsResponseDecoder.java
Normal file
55
src/dorkbox/network/dns/DatagramDnsResponseDecoder.java
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
228
src/dorkbox/network/dns/DnsQuestion.java
Normal file
228
src/dorkbox/network/dns/DnsQuestion.java
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
142
src/dorkbox/network/dns/DnsResponse.java
Normal file
142
src/dorkbox/network/dns/DnsResponse.java
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user