add dns resolver code

This commit is contained in:
Jörg Prante 2024-02-03 00:10:02 +01:00
parent ada04aef58
commit fc565512cc
131 changed files with 21681 additions and 0 deletions

View file

@ -0,0 +1,3 @@
dependencies {
api project(':netty-handler')
}

View file

@ -0,0 +1,478 @@
/*
* 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:
*
* https://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 io.netty.util.ReferenceCounted;
import io.netty.util.ResourceLeakDetector;
import io.netty.util.ResourceLeakDetectorFactory;
import io.netty.util.ResourceLeakTracker;
import io.netty.util.internal.StringUtil;
import io.netty.util.internal.UnstableApi;
import java.util.ArrayList;
import java.util.List;
import static io.netty.util.internal.ObjectUtil.checkNotNull;
/**
* A skeletal implementation of {@link DnsMessage}.
*/
@UnstableApi
public abstract class AbstractDnsMessage extends AbstractReferenceCounted implements DnsMessage {
private static final ResourceLeakDetector<DnsMessage> leakDetector =
ResourceLeakDetectorFactory.instance().newResourceLeakDetector(DnsMessage.class);
private static final int SECTION_QUESTION = DnsSection.QUESTION.ordinal();
private static final int SECTION_COUNT = 4;
private final ResourceLeakTracker<DnsMessage> leak = leakDetector.track(this);
private short id;
private DnsOpCode opCode;
private boolean recursionDesired;
private byte z;
// To reduce the memory footprint of a message,
// each of the following fields is a single record or a list of records.
private Object questions;
private Object answers;
private Object authorities;
private Object additionals;
/**
* Creates a new instance with the specified {@code id} and {@link DnsOpCode#QUERY} opCode.
*/
protected AbstractDnsMessage(int id) {
this(id, DnsOpCode.QUERY);
}
/**
* Creates a new instance with the specified {@code id} and {@code opCode}.
*/
protected AbstractDnsMessage(int id, DnsOpCode opCode) {
setId(id);
setOpCode(opCode);
}
@Override
public int id() {
return id & 0xFFFF;
}
@Override
public DnsMessage setId(int id) {
this.id = (short) id;
return this;
}
@Override
public DnsOpCode opCode() {
return opCode;
}
@Override
public DnsMessage setOpCode(DnsOpCode opCode) {
this.opCode = checkNotNull(opCode, "opCode");
return this;
}
@Override
public boolean isRecursionDesired() {
return recursionDesired;
}
@Override
public DnsMessage setRecursionDesired(boolean recursionDesired) {
this.recursionDesired = recursionDesired;
return this;
}
@Override
public int z() {
return z;
}
@Override
public DnsMessage setZ(int z) {
this.z = (byte) (z & 7);
return this;
}
@Override
public int count(DnsSection section) {
return count(sectionOrdinal(section));
}
private int count(int section) {
final Object records = sectionAt(section);
if (records == null) {
return 0;
}
if (records instanceof DnsRecord) {
return 1;
}
@SuppressWarnings("unchecked")
final List<DnsRecord> recordList = (List<DnsRecord>) records;
return recordList.size();
}
@Override
public int count() {
int count = 0;
for (int i = 0; i < SECTION_COUNT; i ++) {
count += count(i);
}
return count;
}
@Override
public <T extends DnsRecord> T recordAt(DnsSection section) {
return recordAt(sectionOrdinal(section));
}
private <T extends DnsRecord> T recordAt(int section) {
final Object records = sectionAt(section);
if (records == null) {
return null;
}
if (records instanceof DnsRecord) {
return castRecord(records);
}
@SuppressWarnings("unchecked")
final List<DnsRecord> recordList = (List<DnsRecord>) records;
if (recordList.isEmpty()) {
return null;
}
return castRecord(recordList.get(0));
}
@Override
public <T extends DnsRecord> T recordAt(DnsSection section, int index) {
return recordAt(sectionOrdinal(section), index);
}
private <T extends DnsRecord> T recordAt(int section, int index) {
final Object records = sectionAt(section);
if (records == null) {
throw new IndexOutOfBoundsException("index: " + index + " (expected: none)");
}
if (records instanceof DnsRecord) {
if (index == 0) {
return castRecord(records);
} else {
throw new IndexOutOfBoundsException("index: " + index + "' (expected: 0)");
}
}
@SuppressWarnings("unchecked")
final List<DnsRecord> recordList = (List<DnsRecord>) records;
return castRecord(recordList.get(index));
}
@Override
public DnsMessage setRecord(DnsSection section, DnsRecord record) {
setRecord(sectionOrdinal(section), record);
return this;
}
private void setRecord(int section, DnsRecord record) {
clear(section);
setSection(section, checkQuestion(section, record));
}
@Override
public <T extends DnsRecord> T setRecord(DnsSection section, int index, DnsRecord record) {
return setRecord(sectionOrdinal(section), index, record);
}
private <T extends DnsRecord> T setRecord(int section, int index, DnsRecord record) {
checkQuestion(section, record);
final Object records = sectionAt(section);
if (records == null) {
throw new IndexOutOfBoundsException("index: " + index + " (expected: none)");
}
if (records instanceof DnsRecord) {
if (index == 0) {
setSection(section, record);
return castRecord(records);
} else {
throw new IndexOutOfBoundsException("index: " + index + " (expected: 0)");
}
}
@SuppressWarnings("unchecked")
final List<DnsRecord> recordList = (List<DnsRecord>) records;
return castRecord(recordList.set(index, record));
}
@Override
public DnsMessage addRecord(DnsSection section, DnsRecord record) {
addRecord(sectionOrdinal(section), record);
return this;
}
private void addRecord(int section, DnsRecord record) {
checkQuestion(section, record);
final Object records = sectionAt(section);
if (records == null) {
setSection(section, record);
return;
}
if (records instanceof DnsRecord) {
final List<DnsRecord> recordList = newRecordList();
recordList.add(castRecord(records));
recordList.add(record);
setSection(section, recordList);
return;
}
@SuppressWarnings("unchecked")
final List<DnsRecord> recordList = (List<DnsRecord>) records;
recordList.add(record);
}
@Override
public DnsMessage addRecord(DnsSection section, int index, DnsRecord record) {
addRecord(sectionOrdinal(section), index, record);
return this;
}
private void addRecord(int section, int index, DnsRecord record) {
checkQuestion(section, record);
final Object records = sectionAt(section);
if (records == null) {
if (index != 0) {
throw new IndexOutOfBoundsException("index: " + index + " (expected: 0)");
}
setSection(section, record);
return;
}
if (records instanceof DnsRecord) {
final List<DnsRecord> recordList;
if (index == 0) {
recordList = newRecordList();
recordList.add(record);
recordList.add(castRecord(records));
} else if (index == 1) {
recordList = newRecordList();
recordList.add(castRecord(records));
recordList.add(record);
} else {
throw new IndexOutOfBoundsException("index: " + index + " (expected: 0 or 1)");
}
setSection(section, recordList);
return;
}
@SuppressWarnings("unchecked")
final List<DnsRecord> recordList = (List<DnsRecord>) records;
recordList.add(index, record);
}
@Override
public <T extends DnsRecord> T removeRecord(DnsSection section, int index) {
return removeRecord(sectionOrdinal(section), index);
}
private <T extends DnsRecord> T removeRecord(int section, int index) {
final Object records = sectionAt(section);
if (records == null) {
throw new IndexOutOfBoundsException("index: " + index + " (expected: none)");
}
if (records instanceof DnsRecord) {
if (index != 0) {
throw new IndexOutOfBoundsException("index: " + index + " (expected: 0)");
}
T record = castRecord(records);
setSection(section, null);
return record;
}
@SuppressWarnings("unchecked")
final List<DnsRecord> recordList = (List<DnsRecord>) records;
return castRecord(recordList.remove(index));
}
@Override
public DnsMessage clear(DnsSection section) {
clear(sectionOrdinal(section));
return this;
}
@Override
public DnsMessage clear() {
for (int i = 0; i < SECTION_COUNT; i ++) {
clear(i);
}
return this;
}
private void clear(int section) {
final Object recordOrList = sectionAt(section);
setSection(section, null);
if (recordOrList instanceof ReferenceCounted) {
((ReferenceCounted) recordOrList).release();
} else if (recordOrList instanceof List) {
@SuppressWarnings("unchecked")
List<DnsRecord> list = (List<DnsRecord>) recordOrList;
if (!list.isEmpty()) {
for (Object r : list) {
ReferenceCountUtil.release(r);
}
}
}
}
@Override
public DnsMessage touch() {
return (DnsMessage) super.touch();
}
@Override
public DnsMessage touch(Object hint) {
if (leak != null) {
leak.record(hint);
}
return this;
}
@Override
public DnsMessage retain() {
return (DnsMessage) super.retain();
}
@Override
public DnsMessage retain(int increment) {
return (DnsMessage) super.retain(increment);
}
@Override
protected void deallocate() {
clear();
final ResourceLeakTracker<DnsMessage> leak = this.leak;
if (leak != null) {
boolean closed = leak.close(this);
assert closed;
}
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof DnsMessage)) {
return false;
}
final DnsMessage that = (DnsMessage) obj;
if (id() != that.id()) {
return false;
}
if (this instanceof DnsQuery) {
if (!(that instanceof DnsQuery)) {
return false;
}
} else if (that instanceof DnsQuery) {
return false;
}
return true;
}
@Override
public int hashCode() {
return id() * 31 + (this instanceof DnsQuery? 0 : 1);
}
private Object sectionAt(int section) {
switch (section) {
case 0:
return questions;
case 1:
return answers;
case 2:
return authorities;
case 3:
return additionals;
default:
break;
}
throw new Error(); // Should never reach here.
}
private void setSection(int section, Object value) {
switch (section) {
case 0:
questions = value;
return;
case 1:
answers = value;
return;
case 2:
authorities = value;
return;
case 3:
additionals = value;
return;
default:
break;
}
throw new Error(); // Should never reach here.
}
private static int sectionOrdinal(DnsSection section) {
return checkNotNull(section, "section").ordinal();
}
private static DnsRecord checkQuestion(int section, DnsRecord record) {
if (section == SECTION_QUESTION && !(checkNotNull(record, "record") instanceof DnsQuestion)) {
throw new IllegalArgumentException(
"record: " + record + " (expected: " + StringUtil.simpleClassName(DnsQuestion.class) + ')');
}
return record;
}
@SuppressWarnings("unchecked")
private static <T extends DnsRecord> T castRecord(Object record) {
return (T) record;
}
private static ArrayList<DnsRecord> newRecordList() {
return new ArrayList<DnsRecord>(2);
}
}

View file

@ -0,0 +1,78 @@
/*
* Copyright 2016 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:
*
* https://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.internal.StringUtil;
import io.netty.util.internal.UnstableApi;
/**
* An <a href="https://tools.ietf.org/html/rfc6891#section-6.1">OPT RR</a> record.
*
* This is used for <a href="https://tools.ietf.org/html/rfc6891#section-6.1.3">
* Extension Mechanisms for DNS (EDNS(0))</a>.
*/
@UnstableApi
public abstract class AbstractDnsOptPseudoRrRecord extends AbstractDnsRecord implements DnsOptPseudoRecord {
protected AbstractDnsOptPseudoRrRecord(int maxPayloadSize, int extendedRcode, int version) {
super(StringUtil.EMPTY_STRING, DnsRecordType.OPT, maxPayloadSize, packIntoLong(extendedRcode, version));
}
protected AbstractDnsOptPseudoRrRecord(int maxPayloadSize) {
super(StringUtil.EMPTY_STRING, DnsRecordType.OPT, maxPayloadSize, 0);
}
// See https://tools.ietf.org/html/rfc6891#section-6.1.3
private static long packIntoLong(int val, int val2) {
// We are currently not support DO and Z fields, just use 0.
return ((val & 0xffL) << 24 | (val2 & 0xff) << 16) & 0xFFFFFFFFL;
}
@Override
public int extendedRcode() {
return (short) (((int) timeToLive() >> 24) & 0xff);
}
@Override
public int version() {
return (short) (((int) timeToLive() >> 16) & 0xff);
}
@Override
public int flags() {
return (short) ((short) timeToLive() & 0xff);
}
@Override
public String toString() {
return toStringBuilder().toString();
}
final StringBuilder toStringBuilder() {
return new StringBuilder(64)
.append(StringUtil.simpleClassName(this))
.append('(')
.append("OPT flags:")
.append(flags())
.append(" version:")
.append(version())
.append(" extendedRecode:")
.append(extendedRcode())
.append(" udp:")
.append(dnsClass())
.append(')');
}
}

View file

@ -0,0 +1,165 @@
/*
* 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:
*
* https://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.internal.PlatformDependent;
import io.netty.util.internal.StringUtil;
import io.netty.util.internal.UnstableApi;
import java.net.IDN;
import static io.netty.util.internal.ObjectUtil.checkNotNull;
import static io.netty.util.internal.ObjectUtil.checkPositiveOrZero;
/**
* A skeletal implementation of {@link DnsRecord}.
*/
@UnstableApi
public abstract class AbstractDnsRecord implements DnsRecord {
private final String name;
private final DnsRecordType type;
private final short dnsClass;
private final long timeToLive;
private int hashCode;
/**
* Creates a new {@link #CLASS_IN IN-class} record.
*
* @param name the domain name
* @param type the type of the record
* @param timeToLive the TTL value of the record
*/
protected AbstractDnsRecord(String name, DnsRecordType type, long timeToLive) {
this(name, type, CLASS_IN, timeToLive);
}
/**
* Creates a new record.
*
* @param name the domain name
* @param type the type of the record
* @param dnsClass the class of the record, usually one of the following:
* <ul>
* <li>{@link #CLASS_IN}</li>
* <li>{@link #CLASS_CSNET}</li>
* <li>{@link #CLASS_CHAOS}</li>
* <li>{@link #CLASS_HESIOD}</li>
* <li>{@link #CLASS_NONE}</li>
* <li>{@link #CLASS_ANY}</li>
* </ul>
* @param timeToLive the TTL value of the record
*/
protected AbstractDnsRecord(String name, DnsRecordType type, int dnsClass, long timeToLive) {
checkPositiveOrZero(timeToLive, "timeToLive");
// 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
this.name = appendTrailingDot(IDNtoASCII(name));
this.type = checkNotNull(type, "type");
this.dnsClass = (short) dnsClass;
this.timeToLive = timeToLive;
}
private static String IDNtoASCII(String name) {
checkNotNull(name, "name");
if (PlatformDependent.isAndroid() && DefaultDnsRecordDecoder.ROOT.equals(name)) {
// Prior Android 10 there was a bug that did not correctly parse ".".
//
// See https://github.com/netty/netty/issues/10034
return name;
}
return IDN.toASCII(name);
}
private static String appendTrailingDot(String name) {
if (name.length() > 0 && name.charAt(name.length() - 1) != '.') {
return name + '.';
}
return name;
}
@Override
public String name() {
return name;
}
@Override
public DnsRecordType type() {
return type;
}
@Override
public int dnsClass() {
return dnsClass & 0xFFFF;
}
@Override
public long timeToLive() {
return timeToLive;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof DnsRecord)) {
return false;
}
final DnsRecord that = (DnsRecord) obj;
final int hashCode = this.hashCode;
if (hashCode != 0 && hashCode != that.hashCode()) {
return false;
}
return type().intValue() == that.type().intValue() &&
dnsClass() == that.dnsClass() &&
name().equals(that.name());
}
@Override
public int hashCode() {
final int hashCode = this.hashCode;
if (hashCode != 0) {
return hashCode;
}
return this.hashCode = name.hashCode() * 31 + type().intValue() * 31 + dnsClass();
}
@Override
public String toString() {
StringBuilder buf = new StringBuilder(64);
buf.append(StringUtil.simpleClassName(this))
.append('(')
.append(name())
.append(' ')
.append(timeToLive())
.append(' ');
DnsMessageUtil.appendRecordClass(buf, dnsClass())
.append(' ')
.append(type().name())
.append(')');
return buf.toString();
}
}

View file

@ -0,0 +1,192 @@
/*
* 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:
*
* https://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.AddressedEnvelope;
import io.netty.util.internal.UnstableApi;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
/**
* A {@link DnsQuery} implementation for UDP/IP.
*/
@UnstableApi
public class DatagramDnsQuery extends DefaultDnsQuery
implements AddressedEnvelope<DatagramDnsQuery, InetSocketAddress> {
private final InetSocketAddress sender;
private final InetSocketAddress recipient;
/**
* Creates a new instance with the {@link DnsOpCode#QUERY} {@code opCode}.
*
* @param sender the address of the sender
* @param recipient the address of the recipient
* @param id the {@code ID} of the DNS query
*/
public DatagramDnsQuery(
InetSocketAddress sender, InetSocketAddress recipient, int id) {
this(sender, recipient, id, DnsOpCode.QUERY);
}
/**
* Creates a new instance.
*
* @param sender the address of the sender
* @param recipient the address of the recipient
* @param id the {@code ID} of the DNS query
* @param opCode the {@code opCode} of the DNS query
*/
public DatagramDnsQuery(
InetSocketAddress sender, InetSocketAddress recipient, int id, DnsOpCode opCode) {
super(id, opCode);
if (recipient == null && sender == null) {
throw new NullPointerException("recipient and sender");
}
this.sender = sender;
this.recipient = recipient;
}
@Override
public DatagramDnsQuery content() {
return this;
}
@Override
public InetSocketAddress sender() {
return sender;
}
@Override
public InetSocketAddress recipient() {
return recipient;
}
@Override
public DatagramDnsQuery setId(int id) {
return (DatagramDnsQuery) super.setId(id);
}
@Override
public DatagramDnsQuery setOpCode(DnsOpCode opCode) {
return (DatagramDnsQuery) super.setOpCode(opCode);
}
@Override
public DatagramDnsQuery setRecursionDesired(boolean recursionDesired) {
return (DatagramDnsQuery) super.setRecursionDesired(recursionDesired);
}
@Override
public DatagramDnsQuery setZ(int z) {
return (DatagramDnsQuery) super.setZ(z);
}
@Override
public DatagramDnsQuery setRecord(DnsSection section, DnsRecord record) {
return (DatagramDnsQuery) super.setRecord(section, record);
}
@Override
public DatagramDnsQuery addRecord(DnsSection section, DnsRecord record) {
return (DatagramDnsQuery) super.addRecord(section, record);
}
@Override
public DatagramDnsQuery addRecord(DnsSection section, int index, DnsRecord record) {
return (DatagramDnsQuery) super.addRecord(section, index, record);
}
@Override
public DatagramDnsQuery clear(DnsSection section) {
return (DatagramDnsQuery) super.clear(section);
}
@Override
public DatagramDnsQuery clear() {
return (DatagramDnsQuery) super.clear();
}
@Override
public DatagramDnsQuery touch() {
return (DatagramDnsQuery) super.touch();
}
@Override
public DatagramDnsQuery touch(Object hint) {
return (DatagramDnsQuery) super.touch(hint);
}
@Override
public DatagramDnsQuery retain() {
return (DatagramDnsQuery) super.retain();
}
@Override
public DatagramDnsQuery retain(int increment) {
return (DatagramDnsQuery) 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,62 @@
/*
* 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:
*
* https://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.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.socket.DatagramPacket;
import io.netty.handler.codec.MessageToMessageDecoder;
import io.netty.util.internal.UnstableApi;
import java.util.List;
import static io.netty.util.internal.ObjectUtil.checkNotNull;
/**
* Decodes a {@link DatagramPacket} into a {@link DatagramDnsQuery}.
*/
@UnstableApi
@ChannelHandler.Sharable
public class DatagramDnsQueryDecoder extends MessageToMessageDecoder<DatagramPacket> {
private final DnsRecordDecoder recordDecoder;
/**
* Creates a new decoder with {@linkplain DnsRecordDecoder#DEFAULT the default record decoder}.
*/
public DatagramDnsQueryDecoder() {
this(DnsRecordDecoder.DEFAULT);
}
/**
* Creates a new decoder with the specified {@code recordDecoder}.
*/
public DatagramDnsQueryDecoder(DnsRecordDecoder recordDecoder) {
this.recordDecoder = checkNotNull(recordDecoder, "recordDecoder");
}
@Override
protected void decode(ChannelHandlerContext ctx, final DatagramPacket packet, List<Object> out) throws Exception {
DnsQuery query = DnsMessageUtil.decodeDnsQuery(recordDecoder, packet.content(),
new DnsMessageUtil.DnsQueryFactory() {
@Override
public DnsQuery newQuery(int id, DnsOpCode dnsOpCode) {
return new DatagramDnsQuery(packet.sender(), packet.recipient(), id, dnsOpCode);
}
});
out.add(query);
}
}

View file

@ -0,0 +1,84 @@
/*
* 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:
*
* https://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.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;
import java.net.InetSocketAddress;
import java.util.List;
/**
* Encodes a {@link DatagramDnsQuery} (or an {@link AddressedEnvelope} of {@link DnsQuery}} into a
* {@link DatagramPacket}.
*/
@UnstableApi
@ChannelHandler.Sharable
public class DatagramDnsQueryEncoder extends MessageToMessageEncoder<AddressedEnvelope<DnsQuery, InetSocketAddress>> {
private final DnsQueryEncoder encoder;
/**
* Creates a new encoder with {@linkplain DnsRecordEncoder#DEFAULT the default record encoder}.
*/
public DatagramDnsQueryEncoder() {
this(DnsRecordEncoder.DEFAULT);
}
/**
* Creates a new encoder with the specified {@code recordEncoder}.
*/
public DatagramDnsQueryEncoder(DnsRecordEncoder recordEncoder) {
this.encoder = new DnsQueryEncoder(recordEncoder);
}
@Override
protected void encode(
ChannelHandlerContext ctx,
AddressedEnvelope<DnsQuery, InetSocketAddress> in, List<Object> out) throws Exception {
final InetSocketAddress recipient = in.recipient();
final DnsQuery query = in.content();
final ByteBuf buf = allocateBuffer(ctx, in);
boolean success = false;
try {
encoder.encode(query, buf);
success = true;
} finally {
if (!success) {
buf.release();
}
}
out.add(new DatagramPacket(buf, recipient, null));
}
/**
* Allocate a {@link ByteBuf} which will be used for constructing a datagram packet.
* Sub-classes may override this method to return a {@link ByteBuf} with a perfect matching initial capacity.
*/
protected ByteBuf allocateBuffer(
ChannelHandlerContext ctx,
@SuppressWarnings("unused") AddressedEnvelope<DnsQuery, InetSocketAddress> msg) throws Exception {
return ctx.alloc().ioBuffer(1024);
}
}

View file

@ -0,0 +1,222 @@
/*
* 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:
*
* https://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.AddressedEnvelope;
import io.netty.util.internal.UnstableApi;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
/**
* A {@link DnsResponse} implementation for UDP/IP.
*/
@UnstableApi
public class DatagramDnsResponse extends DefaultDnsResponse
implements AddressedEnvelope<DatagramDnsResponse, InetSocketAddress> {
private final InetSocketAddress sender;
private final InetSocketAddress recipient;
/**
* Creates a new instance with the {@link DnsOpCode#QUERY} {@code opCode} and
* the {@link DnsResponseCode#NOERROR} {@code RCODE}.
*
* @param sender the address of the sender
* @param recipient the address of the recipient
* @param id the {@code ID} of the DNS response
*/
public DatagramDnsResponse(InetSocketAddress sender, InetSocketAddress recipient, int id) {
this(sender, recipient, id, DnsOpCode.QUERY, DnsResponseCode.NOERROR);
}
/**
* Creates a new instance with the {@link DnsResponseCode#NOERROR} responseCode.
*
* @param sender the address of the sender
* @param recipient the address of the recipient
* @param id the {@code ID} of the DNS response
* @param opCode the {@code opCode} of the DNS response
*/
public DatagramDnsResponse(InetSocketAddress sender, InetSocketAddress recipient, int id, DnsOpCode opCode) {
this(sender, recipient, id, opCode, DnsResponseCode.NOERROR);
}
/**
* Creates a new instance.
*
* @param sender the address of the sender
* @param recipient the address of the recipient
* @param id the {@code ID} of the DNS response
* @param opCode the {@code opCode} of the DNS response
* @param responseCode the {@code RCODE} of the DNS response
*/
public DatagramDnsResponse(
InetSocketAddress sender, InetSocketAddress recipient,
int id, DnsOpCode opCode, DnsResponseCode responseCode) {
super(id, opCode, responseCode);
if (recipient == null && sender == null) {
throw new NullPointerException("recipient and sender");
}
this.sender = sender;
this.recipient = recipient;
}
@Override
public DatagramDnsResponse content() {
return this;
}
@Override
public InetSocketAddress sender() {
return sender;
}
@Override
public InetSocketAddress recipient() {
return recipient;
}
@Override
public DatagramDnsResponse setAuthoritativeAnswer(boolean authoritativeAnswer) {
return (DatagramDnsResponse) super.setAuthoritativeAnswer(authoritativeAnswer);
}
@Override
public DatagramDnsResponse setTruncated(boolean truncated) {
return (DatagramDnsResponse) super.setTruncated(truncated);
}
@Override
public DatagramDnsResponse setRecursionAvailable(boolean recursionAvailable) {
return (DatagramDnsResponse) super.setRecursionAvailable(recursionAvailable);
}
@Override
public DatagramDnsResponse setCode(DnsResponseCode code) {
return (DatagramDnsResponse) super.setCode(code);
}
@Override
public DatagramDnsResponse setId(int id) {
return (DatagramDnsResponse) super.setId(id);
}
@Override
public DatagramDnsResponse setOpCode(DnsOpCode opCode) {
return (DatagramDnsResponse) super.setOpCode(opCode);
}
@Override
public DatagramDnsResponse setRecursionDesired(boolean recursionDesired) {
return (DatagramDnsResponse) super.setRecursionDesired(recursionDesired);
}
@Override
public DatagramDnsResponse setZ(int z) {
return (DatagramDnsResponse) super.setZ(z);
}
@Override
public DatagramDnsResponse setRecord(DnsSection section, DnsRecord record) {
return (DatagramDnsResponse) super.setRecord(section, record);
}
@Override
public DatagramDnsResponse addRecord(DnsSection section, DnsRecord record) {
return (DatagramDnsResponse) super.addRecord(section, record);
}
@Override
public DatagramDnsResponse addRecord(DnsSection section, int index, DnsRecord record) {
return (DatagramDnsResponse) super.addRecord(section, index, record);
}
@Override
public DatagramDnsResponse clear(DnsSection section) {
return (DatagramDnsResponse) super.clear(section);
}
@Override
public DatagramDnsResponse clear() {
return (DatagramDnsResponse) super.clear();
}
@Override
public DatagramDnsResponse touch() {
return (DatagramDnsResponse) super.touch();
}
@Override
public DatagramDnsResponse touch(Object hint) {
return (DatagramDnsResponse) super.touch(hint);
}
@Override
public DatagramDnsResponse retain() {
return (DatagramDnsResponse) super.retain();
}
@Override
public DatagramDnsResponse retain(int increment) {
return (DatagramDnsResponse) 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) {
return that.recipient() == null;
} else {
return recipient().equals(that.recipient());
}
}
@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,69 @@
/*
* 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:
*
* https://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.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.socket.DatagramPacket;
import io.netty.handler.codec.CorruptedFrameException;
import io.netty.handler.codec.MessageToMessageDecoder;
import io.netty.util.internal.UnstableApi;
import java.net.InetSocketAddress;
import java.util.List;
/**
* Decodes a {@link DatagramPacket}