WIP DnsServer

This commit is contained in:
nathan 2018-01-30 16:24:24 +01:00
parent 5e729abb81
commit 4eae019189
10 changed files with 565 additions and 152 deletions

View File

@ -1,3 +1,18 @@
/*
* Copyright 2018 dorkbox, llc.
*
* Licensed 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;
import org.slf4j.Logger;
@ -19,12 +34,16 @@ import io.netty.channel.epoll.EpollChannelOption;
import io.netty.channel.epoll.EpollDatagramChannel;
import io.netty.channel.epoll.EpollEventLoopGroup;
import io.netty.channel.epoll.EpollServerSocketChannel;
import io.netty.channel.kqueue.KQueueDatagramChannel;
import io.netty.channel.kqueue.KQueueEventLoopGroup;
import io.netty.channel.kqueue.KQueueServerSocketChannel;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.oio.OioEventLoopGroup;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.oio.OioDatagramChannel;
import io.netty.channel.socket.oio.OioServerSocketChannel;
import io.netty.channel.unix.UnixChannelOption;
/**
* from: https://blog.cloudflare.com/how-the-consumer-product-safety-commission-is-inadvertently-behind-the-internets-largest-ddos-attacks/
@ -56,6 +75,25 @@ class DnsServer extends Shutdownable {
private final int udpPort;
private final String hostName;
public static
void main(String[] args) {
DnsServer server = new DnsServer("localhost", 2053);
// server.bind(false);
server.bind();
// DnsClient client = new DnsClient("localhost", 2053);
// List<InetAddress> resolve = null;
// try {
// resolve = client.resolve("google.com");
// } catch (UnknownHostException e) {
// e.printStackTrace();
// }
// System.err.println("RESOLVED: " + resolve);
// client.stop();
// server.stop();
}
public
DnsServer(String host, int port) {
@ -87,6 +125,11 @@ class DnsServer extends Shutdownable {
boss = new EpollEventLoopGroup(EndPoint.DEFAULT_THREAD_POOL_SIZE, new NamedThreadFactory(threadName + "-boss", threadGroup));
worker = new EpollEventLoopGroup(EndPoint.DEFAULT_THREAD_POOL_SIZE, new NamedThreadFactory(threadName, threadGroup));
}
else if (OS.isMacOsX()) {
// KQueue network stack is MUCH faster (but only on macosx)
boss = new KQueueEventLoopGroup(EndPoint.DEFAULT_THREAD_POOL_SIZE, new NamedThreadFactory(threadName + "-boss", threadGroup));
worker = new KQueueEventLoopGroup(EndPoint.DEFAULT_THREAD_POOL_SIZE, new NamedThreadFactory(threadName, threadGroup));
}
else {
boss = new NioEventLoopGroup(EndPoint.DEFAULT_THREAD_POOL_SIZE, new NamedThreadFactory(threadName + "-boss", threadGroup));
worker = new NioEventLoopGroup(EndPoint.DEFAULT_THREAD_POOL_SIZE, new NamedThreadFactory(threadName, threadGroup));
@ -101,63 +144,72 @@ class DnsServer extends Shutdownable {
udpBootstrap = new Bootstrap();
if (OS.isAndroid()) {
// android ONLY supports OIO (not NIO)
tcpBootstrap.channel(OioServerSocketChannel.class);
}
else if (OS.isLinux()) {
// JNI network stack is MUCH faster (but only on linux)
tcpBootstrap.channel(EpollServerSocketChannel.class);
}
else {
tcpBootstrap.channel(NioServerSocketChannel.class);
}
if (OS.isAndroid()) {
// android ONLY supports OIO (not NIO)
tcpBootstrap.channel(OioServerSocketChannel.class);
}
else if (OS.isLinux()) {
// JNI network stack is MUCH faster (but only on linux)
tcpBootstrap.channel(EpollServerSocketChannel.class);
}
else if (OS.isMacOsX()) {
// KQueue network stack is MUCH faster (but only on macosx)
tcpBootstrap.channel(KQueueServerSocketChannel.class);
}
else {
tcpBootstrap.channel(NioServerSocketChannel.class);
}
// TODO: If we use netty for an HTTP server,
// Beside the usual ChannelOptions the Native Transport allows to enable TCP_CORK which may come in handy if you implement a HTTP Server.
// TODO: If we use netty for an HTTP server,
// Beside the usual ChannelOptions the Native Transport allows to enable TCP_CORK which may come in handy if you implement a HTTP Server.
tcpBootstrap.group(boss, worker)
.option(ChannelOption.SO_BACKLOG, backlogConnectionCount)
.option(ChannelOption.SO_REUSEADDR, true)
.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
.childOption(ChannelOption.SO_KEEPALIVE, true)
.option(ChannelOption.WRITE_BUFFER_WATER_MARK, new WriteBufferWaterMark(EndPoint.WRITE_BUFF_LOW, EndPoint.WRITE_BUFF_HIGH))
.childHandler(new DnsServerHandler());
tcpBootstrap.group(boss, worker)
.option(ChannelOption.SO_BACKLOG, backlogConnectionCount)
.option(ChannelOption.SO_REUSEADDR, true)
.childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
.childOption(ChannelOption.SO_KEEPALIVE, true)
.option(ChannelOption.WRITE_BUFFER_WATER_MARK, new WriteBufferWaterMark(EndPoint.WRITE_BUFF_LOW, EndPoint.WRITE_BUFF_HIGH))
.childHandler(new DnsServerHandler(logger));
// have to check options.host for null. we don't bind to 0.0.0.0, we bind to "null" to get the "any" address!
if (hostName != null) {
tcpBootstrap.localAddress(hostName, tcpPort);
}
else {
tcpBootstrap.localAddress(tcpPort);
}
// have to check options.host for null. we don't bind to 0.0.0.0, we bind to "null" to get the "any" address!
if (hostName != null) {
tcpBootstrap.localAddress(hostName, tcpPort);
}
else {
tcpBootstrap.localAddress(tcpPort);
}
// android screws up on this!!
tcpBootstrap.option(ChannelOption.TCP_NODELAY, !OS.isAndroid())
.childOption(ChannelOption.TCP_NODELAY, !OS.isAndroid());
// android screws up on this!!
tcpBootstrap.option(ChannelOption.TCP_NODELAY, !OS.isAndroid())
.childOption(ChannelOption.TCP_NODELAY, !OS.isAndroid());
if (OS.isAndroid()) {
// android ONLY supports OIO (not NIO)
udpBootstrap.channel(OioDatagramChannel.class);
}
else if (OS.isLinux()) {
// JNI network stack is MUCH faster (but only on linux)
udpBootstrap.channel(EpollDatagramChannel.class)
.option(EpollChannelOption.SO_REUSEPORT, true);
}
else {
udpBootstrap.channel(NioDatagramChannel.class);
}
if (OS.isAndroid()) {
// android ONLY supports OIO (not NIO)
udpBootstrap.channel(OioDatagramChannel.class);
}
else if (OS.isLinux()) {
// JNI network stack is MUCH faster (but only on linux)
udpBootstrap.channel(EpollDatagramChannel.class)
.option(EpollChannelOption.SO_REUSEPORT, true);
}
else if (OS.isMacOsX()) {
// JNI network stack is MUCH faster (but only on macosx)
udpBootstrap.channel(KQueueDatagramChannel.class)
.option(UnixChannelOption.SO_REUSEPORT, true);
}
else {
udpBootstrap.channel(NioDatagramChannel.class);
}
udpBootstrap.group(worker)
.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
.option(ChannelOption.WRITE_BUFFER_WATER_MARK, new WriteBufferWaterMark(EndPoint.WRITE_BUFF_LOW, EndPoint.WRITE_BUFF_HIGH))
udpBootstrap.group(worker)
.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
.option(ChannelOption.WRITE_BUFFER_WATER_MARK, new WriteBufferWaterMark(EndPoint.WRITE_BUFF_LOW, EndPoint.WRITE_BUFF_HIGH))
// not binding to specific address, since it's driven by TCP, and that can be bound to a specific address
.localAddress(udpPort) // if you bind to a specific interface, Linux will be unable to receive broadcast packets!
.handler(new DnsServerHandler());
// not binding to specific address, since it's driven by TCP, and that can be bound to a specific address
.localAddress(udpPort) // if you bind to a specific interface, Linux will be unable to receive broadcast packets!
.handler(new DnsServerHandler(logger));
}
/**

View File

@ -36,6 +36,15 @@ class DnsEnvelope extends DnsMessage implements AddressedEnvelope<DnsEnvelope, I
super();
}
public
DnsEnvelope(final int id, final InetSocketAddress localAddress, final InetSocketAddress remoteAddress) {
super(id);
this.localAddress = localAddress;
this.remoteAddress = remoteAddress;
}
public
DnsEnvelope(final ByteBuf buffer, final InetSocketAddress localAddress, final InetSocketAddress remoteAddress) throws IOException {
super(buffer);

View File

@ -12,19 +12,11 @@ import dorkbox.network.dns.Compression;
import dorkbox.network.dns.DnsInput;
import dorkbox.network.dns.DnsOutput;
import dorkbox.network.dns.Name;
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.constants.*;
import dorkbox.network.dns.exceptions.WireParseException;
import dorkbox.util.OS;
import io.netty.buffer.ByteBuf;
import io.netty.util.AbstractReferenceCounted;
import io.netty.util.ReferenceCounted;
import io.netty.util.ResourceLeakDetector;
import io.netty.util.ResourceLeakDetectorFactory;
import io.netty.util.ResourceLeakTracker;
import io.netty.util.*;
/**
* A DNS DnsMessage. A message is the basic unit of communication between
@ -658,7 +650,7 @@ class DnsMessage extends AbstractReferenceCounted implements Cloneable, Referenc
return out.toByteArray();
}
/* Returns true if the message could be rendered. */
/** Returns true if the message could be rendered. */
private
boolean toWire(DnsOutput out, int maxLength) {
if (maxLength < Header.LENGTH) {
@ -749,7 +741,7 @@ class DnsMessage extends AbstractReferenceCounted implements Cloneable, Referenc
return null;
}
/* Returns the number of records not successfully rendered. */
/** Returns the number of records not successfully rendered. */
private
int sectionToWire(DnsOutput out, int section, Compression c, int maxLength) {
final Object records = sectionAt(section);
@ -839,7 +831,6 @@ class DnsMessage extends AbstractReferenceCounted implements Cloneable, Referenc
Object clone() {
DnsMessage m = new DnsMessage();
for (int i = 0; i < DnsSection.TOTAL_SECTION_COUNT; i++) {
final Object records = sectionAt(i);
if (records == null) {
@ -864,6 +855,7 @@ class DnsMessage extends AbstractReferenceCounted implements Cloneable, Referenc
/**
* Converts the DnsMessage to a String.
*/
@Override
public
String toString() {
String NL = OS.LINE_SEPARATOR;
@ -949,8 +941,7 @@ class DnsMessage extends AbstractReferenceCounted implements Cloneable, Referenc
}
/**
* Returns the size of the message. Only valid if the message has been
* converted to or from wire format.
* Returns the size of the message. Only valid if the message has been converted to or from wire format.
*/
public
int numBytes() {

View File

@ -43,5 +43,4 @@ class EmptyRecord extends DnsRecord {
@Override
void rdataFromString(Tokenizer st, Name origin) throws IOException {
}
}

View File

@ -30,7 +30,7 @@ class RRset implements Serializable {
* rrs contains both normal and RRSIG records, with the RRSIG records
* at the end.
*/
private List rrs;
private List resourceRecords;
private short nsigs;
private short position;
@ -48,7 +48,7 @@ class RRset implements Serializable {
*/
public
RRset() {
rrs = new ArrayList(1);
resourceRecords = new ArrayList(1);
nsigs = 0;
position = 0;
}
@ -57,14 +57,14 @@ class RRset implements Serializable {
void safeAddRR(DnsRecord r) {
if (!(r instanceof RRSIGRecord)) {
if (nsigs == 0) {
rrs.add(r);
resourceRecords.add(r);
}
else {
rrs.add(rrs.size() - nsigs, r);
resourceRecords.add(resourceRecords.size() - nsigs, r);
}
}
else {
rrs.add(r);
resourceRecords.add(r);
nsigs++;
}
}
@ -75,7 +75,7 @@ class RRset implements Serializable {
public
RRset(RRset rrset) {
synchronized (rrset) {
rrs = (List) ((ArrayList) rrset.rrs).clone();
resourceRecords = (List) ((ArrayList) rrset.resourceRecords).clone();
nsigs = rrset.nsigs;
position = rrset.position;
}
@ -86,7 +86,7 @@ class RRset implements Serializable {
*/
public synchronized
void addRR(DnsRecord r) {
if (rrs.size() == 0) {
if (resourceRecords.size() == 0) {
safeAddRR(r);
return;
}
@ -101,16 +101,16 @@ class RRset implements Serializable {
r.setTTL(first.getTTL());
}
else {
for (int i = 0; i < rrs.size(); i++) {
DnsRecord tmp = (DnsRecord) rrs.get(i);
for (int i = 0; i < resourceRecords.size(); i++) {
DnsRecord tmp = (DnsRecord) resourceRecords.get(i);
tmp = tmp.cloneRecord();
tmp.setTTL(r.getTTL());
rrs.set(i, tmp);
resourceRecords.set(i, tmp);
}
}
}
if (!rrs.contains(r)) {
if (!resourceRecords.contains(r)) {
safeAddRR(r);
}
}
@ -122,10 +122,10 @@ class RRset implements Serializable {
*/
public synchronized
DnsRecord first() {
if (rrs.size() == 0) {
if (resourceRecords.size() == 0) {
throw new IllegalStateException("rrset is empty");
}
return (DnsRecord) rrs.get(0);
return (DnsRecord) resourceRecords.get(0);
}
/**
@ -133,7 +133,7 @@ class RRset implements Serializable {
*/
public synchronized
void deleteRR(DnsRecord r) {
if (rrs.remove(r) && (r instanceof RRSIGRecord)) {
if (resourceRecords.remove(r) && (r instanceof RRSIGRecord)) {
nsigs--;
}
}
@ -143,7 +143,7 @@ class RRset implements Serializable {
*/
public synchronized
void clear() {
rrs.clear();
resourceRecords.clear();
position = 0;
nsigs = 0;
}
@ -163,7 +163,7 @@ class RRset implements Serializable {
Iterator iterator(boolean data, boolean cycle) {
int size, start, total;
total = rrs.size();
total = resourceRecords.size();
if (data) {
size = total - nsigs;
@ -192,13 +192,13 @@ class RRset implements Serializable {
List list = new ArrayList(size);
if (data) {
list.addAll(rrs.subList(start, size));
list.addAll(resourceRecords.subList(start, size));
if (start != 0) {
list.addAll(rrs.subList(0, start));
list.addAll(resourceRecords.subList(0, start));
}
}
else {
list.addAll(rrs.subList(start, total));
list.addAll(resourceRecords.subList(start, total));
}
return list.iterator();
@ -226,15 +226,16 @@ class RRset implements Serializable {
*/
public synchronized
int size() {
return rrs.size() - nsigs;
return resourceRecords.size() - nsigs;
}
/**
* Converts the RRset to a String
*/
@Override
public
String toString() {
if (rrs.size() == 0) {
if (resourceRecords.size() == 0) {
return ("{empty}");
}
StringBuilder sb = new StringBuilder();

View File

@ -0,0 +1,344 @@
/*
* Copyright 2018 dorkbox, llc.
*
* Licensed 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.serverHandlers;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
import org.slf4j.Logger;
import dorkbox.network.dns.DnsEnvelope;
import dorkbox.network.dns.Name;
import dorkbox.network.dns.constants.DnsOpCode;
import dorkbox.network.dns.constants.DnsRecordType;
import dorkbox.network.dns.constants.DnsResponseCode;
import dorkbox.network.dns.constants.DnsSection;
import dorkbox.network.dns.records.*;
import dorkbox.util.collections.IntMap;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.ReferenceCountUtil;
public class DnsDecisionHandler extends ChannelInboundHandlerAdapter {
private final Logger logger;
private IntMap responses = new IntMap();
// private final DnsClient dnsClient;
private final InetAddress localHost;
public
DnsDecisionHandler(final Logger logger) {
this.logger = logger;
// dnsClient = new DnsClient();
InetAddress local;
try {
local = InetAddress.getLocalHost();
} catch (UnknownHostException e) {
e.printStackTrace();
local = null;
}
localHost = local;
}
@Override
public
void channelRead(ChannelHandlerContext context, Object message) throws Exception {
onChannelRead(context, (DnsEnvelope) message);
ReferenceCountUtil.release(message);
}
public
void onChannelRead(final ChannelHandlerContext context, final DnsEnvelope dnsMessage) {
int opcode = dnsMessage.getHeader()
.getOpcode();
switch (opcode) {
case DnsOpCode.QUERY:
onQuery(context, dnsMessage, dnsMessage.recipient());
dnsMessage.release();
return;
case DnsOpCode.IQUERY:
onIQuery(context, dnsMessage, dnsMessage.recipient());
dnsMessage.release();
return;
case DnsOpCode.NOTIFY:
onNotify(context, dnsMessage, dnsMessage.recipient());
dnsMessage.release();
return;
case DnsOpCode.STATUS:
onStatus(context, dnsMessage, dnsMessage.recipient());
dnsMessage.release();
return;
case DnsOpCode.UPDATE:
onUpdate(context, (Update) (DnsMessage) dnsMessage, dnsMessage.recipient());
dnsMessage.release();
return;
default:
logger.error("Unknown DNS opcode {} from {}", opcode, context.channel().remoteAddress());
dnsMessage.release();
}
}
private
void onQuery(final ChannelHandlerContext context, final DnsMessage dnsQuestion, final InetSocketAddress recipient) {
// either I have an answer, or I don't (and have to forward to another DNS server
// it might be more that 1 question...
Header header = dnsQuestion.getHeader();
int count = header.getCount(DnsSection.QUESTION);
// we don't support more than 1 question at a time.
if (count == 1) {
DnsEnvelope dnsEnvelope = new DnsEnvelope(dnsQuestion.getHeader()
.getID(),
(InetSocketAddress) context.channel().localAddress(),
recipient);
// dnsEnvelope.getHeader().setRcode(DnsResponseCode.NXDOMAIN);
DnsRecord[] sectionArray = dnsQuestion.getSectionArray(DnsSection.QUESTION);
DnsRecord dnsRecord = sectionArray[0];
Name name = dnsRecord.getName();
long ttl = dnsRecord.getTTL();
int type = dnsRecord.getType();
// // what type of record? A, AAAA, MX, PTR, etc?
if (DnsRecordType.A == type) {
ARecord answerRecord = new ARecord(name, dnsRecord.getDClass(), 10, localHost);
dnsEnvelope.addRecord(dnsRecord, DnsSection.QUESTION);
dnsEnvelope.addRecord(answerRecord, DnsSection.ANSWER);
dnsEnvelope.getHeader().setRcode(DnsResponseCode.NOERROR);
System.err.println("write");
}
// dnsEnvelope.retain();
// NOTE: I suspect this must be a "client" that writes back. there are errors if not.
context.channel()
.writeAndFlush(dnsEnvelope);
// out.add(new DatagramPacket(buf, recipient, null));
// ChannelBuffer buffer = (ChannelBuffer) e.getMessage();
// DNSMessage msg = new DNSMessage(buffer);
// msg.header().id(this.original.header().id());
// ChannelBuffer newone = ChannelBuffers.buffer(buffer.capacity());
// msg.write(newone);
// newone.resetReaderIndex();
// this.originalChannel.write(newone, this.originalAddress)
// .addListener(new ChannelFutureListener() {
// @Override
// public void operationComplete(ChannelFuture future)
// throws Exception {
// e.getChannel().close();
// }
// });
// }
return;
}
// boolean success = false;
// try {
// DnsMessage dnsMessage = new DnsMessage(dnsQuestion.getHeader()
// .getID());
//
// dnsMessage.getHeader()
// .setRcode(DnsResponseCode.NOERROR);
//
// // what type of record? A, AAAA, MX, PTR, etc?
//
// DnsRecord[] sectionArray = dnsMessage.getSectionArray(DnsSection.ANSWER);
//
// // if (code == DnsResponseCode.NOERROR) {
// // return response.getSectionArray(DnsSection.ANSWER);
// // }
// //
// // DnsOutput dnsOutput = new DnsOutput(buf);
// // query.toWire(dnsOutput);
// success = true;
// } finally {
// if (!success) {
// // buf.release();
// }
// }
DnsRecord[] sectionArray = dnsQuestion.getSectionArray(DnsSection.QUESTION);
DnsRecord dnsRecord = sectionArray[0];
System.err.println(dnsRecord);
}
private
void onIQuery(final ChannelHandlerContext context, final DnsMessage dnsQuestion, final InetSocketAddress recipient) {
System.err.println("DECISION HANDLER READ");
System.err.println(dnsQuestion);
}
private
void onNotify(final ChannelHandlerContext context, final DnsMessage dnsQuestion, final InetSocketAddress recipient) {
System.err.println("DECISION HANDLER READ");
System.err.println(dnsQuestion);
}
private
void onStatus(final ChannelHandlerContext context, final DnsMessage dnsQuestion, final InetSocketAddress recipient) {
System.err.println("DECISION HANDLER READ");
System.err.println(dnsQuestion);
}
private
void onUpdate(final ChannelHandlerContext context, final Update dnsUpdate, final InetSocketAddress recipient) {
System.err.println("DECISION HANDLER READ");
System.err.println(dnsUpdate);
}
// @Override
// public void messageReceived(ChannelHandlerContext ctx, final MessageEvent e) throws Exception {
// final DNSMessage original = DNSMessage.class.cast(e.getMessage());
//
// ClientBootstrap cb = new ClientBootstrap(this.clientChannelFactory);
// cb.setOption("broadcast", "false");
// cb.setPipelineFactory(new ChannelPipelineFactory() {
// @Override
// public ChannelPipeline getPipeline() throws Exception {
// return Channels.pipeline(new ClientHanler(original, e
// .getChannel(), e.getRemoteAddress()));
// }
// });
//
// List<SocketAddress> newlist = new ArrayList<SocketAddress>(this.config.getForwarders());
// sendRequest(e, original, cb, newlist);
// }
//
// protected void sendRequest(final MessageEvent e, final DNSMessage original, final ClientBootstrap bootstrap, final List<SocketAddress> forwarders) {
// if (0 < forwarders.size()) {
// SocketAddress sa = forwarders.remove(0);
// LOG.debug("send to {}", sa);
//
// ChannelFuture f = bootstrap.connect(sa);
// ChannelBuffer newone = ChannelBuffers.buffer(512);
// DNSMessage msg = new DNSMessage(original);
// msg.write(newone);
// newone.resetReaderIndex();
// final Channel c = f.getChannel();
//
// if (LOG.isDebugEnabled()) {
// LOG.debug(
// "STATUS : [isOpen/isConnected/isWritable {}] {} {}",
// new Object[] {
// new boolean[] { c.isOpen(), c.isConnected(),
// c.isWritable() }, c.getRemoteAddress(),
// c.getClass() });
// }
//
// c.write(newone, sa).addListener(new ChannelFutureListener() {
// @Override
// public void operationComplete(ChannelFuture future)
// throws Exception {
// LOG.debug("request complete isSuccess : {}",
// future.isSuccess());
// if (future.isSuccess() == false) {
// if (0 < forwarders.size()) {
// sendRequest(e, original, bootstrap, forwarders);
// } else {
// original.header().rcode(RCode.ServFail);
// ChannelBuffer buffer = ChannelBuffers.buffer(512);
// original.write(buffer);
// // close inbound channel
// e.getChannel().write(buffer)
// .addListener(ChannelFutureListener.CLOSE);
// }
// }
// }
// });
//
// // f.awaitUninterruptibly(30, TimeUnit.SECONDS);
// }
// }
@Override
public
void exceptionCaught(final ChannelHandlerContext context, final Throwable cause) throws Exception {
logger.error("ForwardingHandler#exceptionCaught", cause);
super.exceptionCaught(context, cause);
}
protected class ClientHandler extends ChannelInboundHandlerAdapter {
// protected DNSMessage original;
//
// protected Channel originalChannel;
//
// protected SocketAddress originalAddress;
//
// public ClientHanler(DNSMessage msg, Channel c, SocketAddress sa) {
// this.original = msg;
// this.originalChannel = c;
// this.originalAddress = sa;
// }
//
// @Override
// public void messageReceived(ChannelHandlerContext ctx, final MessageEvent e) throws Exception {
// LOG.debug("ClientHanler#messageReceived");
// ChannelBuffer buffer = (ChannelBuffer) e.getMessage();
// DNSMessage msg = new DNSMessage(buffer);
// msg.header().id(this.original.header().id());
// ChannelBuffer newone = ChannelBuffers.buffer(buffer.capacity());
// msg.write(newone);
// newone.resetReaderIndex();
// this.originalChannel.write(newone, this.originalAddress)
// .addListener(new ChannelFutureListener() {
// @Override
// public void operationComplete(ChannelFuture future)
// throws Exception {
// e.getChannel().close();
// }
// });
// }
//
@Override
public
void exceptionCaught(final ChannelHandlerContext ctx, final Throwable cause) throws Exception {
logger.error("ClientHanler#exceptionCaught");
logger.error(cause.getMessage(), cause);
// e.getFuture()
// .setFailure(t);
ctx.channel().close();
}
}
}

View File

@ -1,46 +1,58 @@
package dorkbox.network.dns.serverHandlers;
import java.net.InetSocketAddress;
import java.util.List;
import dorkbox.network.dns.records.DnsMessage;
import org.slf4j.Logger;
import dorkbox.network.dns.DnsEnvelope;
import dorkbox.network.dns.exceptions.WireParseException;
import dorkbox.network.dns.records.Header;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.socket.DatagramPacket;
import io.netty.handler.codec.MessageToMessageDecoder;
public
class DnsMessageDecoder extends MessageToMessageDecoder<DatagramPacket> {
private final Logger logger;
DnsMessageDecoder(final Logger logger) {
this.logger = logger;
}
@Override
public
void exceptionCaught(ChannelHandlerContext context, Throwable cause) throws Exception {
// Channel channel = context.channel();
System.err.println("POW! ");
cause.printStackTrace();
// this.logger.error("Unexpected exception while trying to send/receive data on Client remote (network) channel. ({})" +
// System.getProperty("line.separator"), channel.remoteAddress(), cause);
// if (channel.isOpen()) {
// channel.close();
// }
void exceptionCaught(final ChannelHandlerContext context, final Throwable cause) throws Exception {
logger.error("DnsMessageDecoder#exceptionCaught", cause);
super.exceptionCaught(context, cause);
}
@Override
protected
void decode(ChannelHandlerContext ctx, DatagramPacket packet, List<Object> out) throws Exception {
System.err.println("READING MESSAGE");
void decode(ChannelHandlerContext context, 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");
}
boolean success = false;
try {
DnsMessage dnsMessage = new DnsMessage(buf);
dnsMessage.retain();
out.add(dnsMessage);
InetSocketAddress localAddress = packet.recipient();
InetSocketAddress remoteAddress = packet.sender();
DnsEnvelope dnsEnvelope = new DnsEnvelope(buf, localAddress, remoteAddress);
dnsEnvelope.retain();
// send down the pipeline
out.add(dnsEnvelope);
success = true;
} finally {
if (!success) {
buf.release();
}
}
}
}
}

View File

@ -13,12 +13,13 @@ import io.netty.channel.ChannelPipeline;
*/
public
class DnsServerHandler extends ChannelInboundHandlerAdapter {
private static final Logger LOG = org.slf4j.LoggerFactory.getLogger(DnsServerHandler.class);
protected final DnsMessageDecoder decoder = new DnsMessageDecoder();
protected final DnsMessageDecoder decoder;
private final Logger logger;
public
DnsServerHandler() {
DnsServerHandler(final Logger logger) {
this.logger = logger;
decoder = new DnsMessageDecoder(logger);
}
@Override
@ -30,7 +31,7 @@ class DnsServerHandler extends ChannelInboundHandlerAdapter {
context.fireChannelRegistered();
success = true;
} catch (Throwable t) {
LOG.error("Failed to initialize a channel. Closing: {}", context.channel(), t);
logger.error("Failed to initialize a channel. Closing: {}", context.channel(), t);
} finally {
if (!success) {
context.close();
@ -52,7 +53,8 @@ class DnsServerHandler extends ChannelInboundHandlerAdapter {
// ENCODE (or downstream)
/////////////////////////
pipeline.addLast("fowarder", new ForwardingHandler());
pipeline.addLast("dnsDecision", new DnsDecisionHandler(logger));
pipeline.addLast("fowarder", new ForwardingHandler(logger));
// pipeline.addLast("fowarder", new ForwardingHandler(this.config, this.clientChannelFactory));
}
}

View File

@ -1,17 +1,29 @@
package dorkbox.network.dns.serverHandlers;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import org.slf4j.Logger;
import dorkbox.network.dns.DnsEnvelope;
import dorkbox.network.dns.DnsOutput;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelOutboundHandlerAdapter;
import io.netty.channel.socket.DatagramPacket;
import io.netty.handler.codec.MessageToByteEncoder;
public class ForwardingHandler extends ChannelOutboundHandlerAdapter {
public class ForwardingHandler extends MessageToByteEncoder<DnsEnvelope> {
static final Logger LOG = LoggerFactory.getLogger(ForwardingHandler.class);
// protected ServerConfiguration config;
private final int maxPayloadSize = 512;
private final Logger logger;
public
ForwardingHandler(final Logger logger) {
this.logger = logger;
}
// protected ServerConfiguration config;
// protected ChannelFactory clientChannelFactory;
// public
@ -21,18 +33,27 @@ public class ForwardingHandler extends ChannelOutboundHandlerAdapter {
// this.clientChannelFactory = clientChannelFactory;
// }
@Override
public
void read(final ChannelHandlerContext ctx) throws Exception {
System.err.println("FORWARD HANDLER READ");
super.read(ctx);
protected
void encode(final ChannelHandlerContext context, final DnsEnvelope message, final ByteBuf out) throws Exception {
System.err.println("FORWARD HANDLER ENCODE");
try {
DnsOutput dnsOutput = new DnsOutput(out);
message.toWire(dnsOutput);
context.channel()
.writeAndFlush(new DatagramPacket(out, message.recipient(), null));
// .write(new DatagramPacket(out, message.recipient(), message.sender()));
} catch (Exception e) {
context.fireExceptionCaught(new IOException("Unable to write dns message: " + message, e));
}
}
// @Override
// public void messageReceived(ChannelHandlerContext ctx, final MessageEvent e)
// throws Exception {
// public void messageReceived(ChannelHandlerContext ctx, final MessageEvent e) throws Exception {
// final DNSMessage original = DNSMessage.class.cast(e.getMessage());
//
// ClientBootstrap cb = new ClientBootstrap(this.clientChannelFactory);
@ -40,13 +61,11 @@ public class ForwardingHandler extends ChannelOutboundHandlerAdapter {
// cb.setPipelineFactory(new ChannelPipelineFactory() {
// @Override
// public ChannelPipeline getPipeline() throws Exception {
// return Channels.pipeline(new ClientHanler(original, e
// .getChannel(), e.getRemoteAddress()));
// return Channels.pipeline(new ClientHandler(original, e.getChannel(), e.getRemoteAddress()));
// }
// });
//
// List<SocketAddress> newlist = new ArrayList<SocketAddress>(
// this.config.getForwarders());
// List<SocketAddress> newlist = new ArrayList<SocketAddress>(this.config.getForwarders());
// sendRequest(e, original, cb, newlist);
// }
//
@ -73,10 +92,8 @@ public class ForwardingHandler extends ChannelOutboundHandlerAdapter {
//
// c.write(newone, sa).addListener(new ChannelFutureListener() {
// @Override
// public void operationComplete(ChannelFuture future)
// throws Exception {
// LOG.debug("request complete isSuccess : {}",
// future.isSuccess());
// public void operationComplete(ChannelFuture future) throws Exception {
// LOG.debug("request complete isSuccess : {}", future.isSuccess());
// if (future.isSuccess() == false) {
// if (0 < forwarders.size()) {
// sendRequest(e, original, bootstrap, forwarders);
@ -98,9 +115,9 @@ public class ForwardingHandler extends ChannelOutboundHandlerAdapter {
@Override
public
void exceptionCaught(final ChannelHandlerContext ctx, final Throwable cause) throws Exception {
LOG.error("ForwardingHandler#exceptionCaught");
LOG.error(cause.getMessage(), cause);
void exceptionCaught(final ChannelHandlerContext context, final Throwable cause) throws Exception {
logger.error("ForwardingHandler#exceptionCaught", cause);
super.exceptionCaught(context, cause);
}
@ -117,13 +134,6 @@ public class ForwardingHandler extends ChannelOutboundHandlerAdapter {
// this.originalChannel = c;
// this.originalAddress = sa;
// }
//
// @Override
// public void messageReceived(ChannelHandlerContext ctx, final MessageEvent e) throws Exception {
// LOG.debug("ClientHanler#messageReceived");
@ -147,8 +157,8 @@ public class ForwardingHandler extends ChannelOutboundHandlerAdapter {
@Override
public
void exceptionCaught(final ChannelHandlerContext ctx, final Throwable cause) throws Exception {
LOG.error("ClientHanler#exceptionCaught");
LOG.error(cause.getMessage(), cause);
logger.error("ClientHandler#exceptionCaught");
logger.error(cause.getMessage(), cause);
// e.getFuture()
// .setFailure(t);
ctx.channel().close();

View File

@ -7,14 +7,7 @@ import dorkbox.util.NamedThreadFactory;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandler;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.oio.OioEventLoopGroup;
import io.netty.channel.socket.DatagramPacket;
@ -24,7 +17,7 @@ import io.netty.util.internal.PlatformDependent;
@ChannelHandler.Sharable
public
class DNSMessageDecoder extends ChannelInboundHandlerAdapter {
class aaaDNSMessageDecoderandForwarder extends ChannelInboundHandlerAdapter {
/**
* This is what is called whenever a DNS packet is received. Currently only support UDP packets.