From e50027906d85c09f356bc90545f0bc9e3056d600 Mon Sep 17 00:00:00 2001 From: Ziver Koc Date: Fri, 3 Feb 2017 17:01:46 +0100 Subject: [PATCH] Refactored Dns classes and added initial implementation of a MDNS Server --- src/zutil/net/dns/DnsResolutionListener.java | 2 + src/zutil/net/dns/DnsService.java | 16 +++ src/zutil/net/dns/MulticastDnsClient.java | 11 +- src/zutil/net/dns/MulticastDnsServer.java | 119 ++++++++++++++++++ .../net/dns/{ => packet}/DnsConstants.java | 2 +- src/zutil/net/dns/{ => packet}/DnsPacket.java | 2 +- .../net/dns/{ => packet}/DnsPacketHeader.java | 2 +- .../dns/{ => packet}/DnsPacketQuestion.java | 48 +------ .../dns/{ => packet}/DnsPacketResource.java | 4 +- .../net/dns/packet/FQDNStringSerializer.java | 49 ++++++++ test/zutil/net/dns/DnsPacketTest.java | 1 + .../zutil/net/dns/MulticastDnsClientTest.java | 1 + 12 files changed, 201 insertions(+), 56 deletions(-) create mode 100755 src/zutil/net/dns/DnsService.java create mode 100755 src/zutil/net/dns/MulticastDnsServer.java rename src/zutil/net/dns/{ => packet}/DnsConstants.java (99%) rename src/zutil/net/dns/{ => packet}/DnsPacket.java (99%) rename src/zutil/net/dns/{ => packet}/DnsPacketHeader.java (99%) rename src/zutil/net/dns/{ => packet}/DnsPacketQuestion.java (68%) rename src/zutil/net/dns/{ => packet}/DnsPacketResource.java (97%) create mode 100755 src/zutil/net/dns/packet/FQDNStringSerializer.java diff --git a/src/zutil/net/dns/DnsResolutionListener.java b/src/zutil/net/dns/DnsResolutionListener.java index 9b91560..699015b 100755 --- a/src/zutil/net/dns/DnsResolutionListener.java +++ b/src/zutil/net/dns/DnsResolutionListener.java @@ -24,6 +24,8 @@ package zutil.net.dns; +import zutil.net.dns.packet.DnsPacket; + public interface DnsResolutionListener { void receivedResponse(DnsPacket packet); } \ No newline at end of file diff --git a/src/zutil/net/dns/DnsService.java b/src/zutil/net/dns/DnsService.java new file mode 100755 index 0000000..f7b476d --- /dev/null +++ b/src/zutil/net/dns/DnsService.java @@ -0,0 +1,16 @@ +package zutil.net.dns; + +import java.net.InetAddress; +import java.util.HashMap; + +/** + * This class contains data about a service that + * can be looked up through DNS and MDNS. + */ +public class DnsService { + + private String name; + private String dns; + private InetAddress host; + private HashMap properties; +} diff --git a/src/zutil/net/dns/MulticastDnsClient.java b/src/zutil/net/dns/MulticastDnsClient.java index 9442d5b..fa01d96 100755 --- a/src/zutil/net/dns/MulticastDnsClient.java +++ b/src/zutil/net/dns/MulticastDnsClient.java @@ -26,6 +26,9 @@ package zutil.net.dns; import zutil.io.MultiPrintStream; import zutil.log.LogUtil; +import zutil.net.dns.packet.DnsConstants; +import zutil.net.dns.packet.DnsPacket; +import zutil.net.dns.packet.DnsPacketQuestion; import zutil.net.threaded.ThreadedUDPNetwork; import zutil.net.threaded.ThreadedUDPNetworkThread; import zutil.parser.binary.BinaryStructInputStream; @@ -40,9 +43,12 @@ import java.util.HashSet; import java.util.logging.Level; import java.util.logging.Logger; +import static zutil.net.dns.MulticastDnsServer.MDNS_MULTICAST_ADDR; +import static zutil.net.dns.MulticastDnsServer.MDNS_MULTICAST_PORT; + /** * This class implements a MDNS Client. MDNS is a version - * of the DNS protocol but used a Zeroconf application. + * of the DNS protocol but supports Zeroconf. * * @see DNS Spec (rfc1035) * @see DNS-SD Spec (rfc6763) @@ -51,9 +57,6 @@ import java.util.logging.Logger; public class MulticastDnsClient extends ThreadedUDPNetwork implements ThreadedUDPNetworkThread{ private static final Logger logger = LogUtil.getLogger(); - private static final String MDNS_MULTICAST_ADDR = "224.0.0.251"; - private static final int MDNS_MULTICAST_PORT = 5353; - private HashSet activeProbes; private DnsResolutionListener listener; diff --git a/src/zutil/net/dns/MulticastDnsServer.java b/src/zutil/net/dns/MulticastDnsServer.java new file mode 100755 index 0000000..2d80b10 --- /dev/null +++ b/src/zutil/net/dns/MulticastDnsServer.java @@ -0,0 +1,119 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2015 Ziver Koc + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package zutil.net.dns; + +import zutil.log.LogUtil; +import zutil.net.dns.packet.DnsPacket; +import zutil.net.dns.packet.DnsPacketQuestion; +import zutil.net.dns.packet.DnsPacketResource; +import zutil.net.threaded.ThreadedUDPNetwork; +import zutil.net.threaded.ThreadedUDPNetworkThread; +import zutil.parser.binary.BinaryStructInputStream; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.net.DatagramPacket; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * This class implements a MDNS Server. MDNS is a version + * of the DNS protocol but supports Zeroconf. + * + * @see DNS Spec (rfc1035) + * @see DNS-SD Spec (rfc6763) + * @author Ziver + */ +public class MulticastDnsServer extends ThreadedUDPNetwork implements ThreadedUDPNetworkThread{ + private static final Logger logger = LogUtil.getLogger(); + + protected static final String MDNS_MULTICAST_ADDR = "224.0.0.251"; + protected static final int MDNS_MULTICAST_PORT = 5353; + + + private HashMap entries = new HashMap<>(); + + + + public MulticastDnsServer() throws IOException { + super(MDNS_MULTICAST_ADDR, MDNS_MULTICAST_PORT); + setThread( this ); + + } + + + /** + * Add a domain name specific data that will be returned to a requesting client + * + * @param name is the domain name to add the entry under + * @param type {@link zutil.net.dns.packet.DnsConstants.TYPE} + * @param clazz {@link zutil.net.dns.packet.DnsConstants.CLASS} + * @param data + */ + public void addEntry(String name, int type, int clazz, String data){ + DnsPacketResource resource = new DnsPacketResource(); + resource.name = name; + resource.type = type; + resource.clazz = clazz; + //resource.ttl = 10; ??? + resource.length = data.length(); + resource.data = data; + + addEntry(resource); + } + + private void addEntry(DnsPacketResource resource) { + if ( ! entries.containsKey(resource.name)) + entries.put(resource.name, new ArrayList()); + entries.get(resource.name).add(resource); + } + + + + @Override + public void receivedPacket(DatagramPacket packet, ThreadedUDPNetwork network) { + try { + ByteArrayInputStream buffer = new ByteArrayInputStream(packet.getData(), + packet.getOffset(), packet.getLength()); + BinaryStructInputStream in = new BinaryStructInputStream(buffer); + DnsPacket dnsPacket = DnsPacket.read(in); + + // Just handle queries and no responses + if ( ! dnsPacket.getHeader().flagQueryResponse){ + for (DnsPacketQuestion question : dnsPacket.getQuestions()){ + if (entries.containsKey(question.name)){ + // Respond with entries + + } + } + } + } catch (IOException e){ + logger.log(Level.WARNING, null, e); + } + } + +} diff --git a/src/zutil/net/dns/DnsConstants.java b/src/zutil/net/dns/packet/DnsConstants.java similarity index 99% rename from src/zutil/net/dns/DnsConstants.java rename to src/zutil/net/dns/packet/DnsConstants.java index df77066..ca87e32 100755 --- a/src/zutil/net/dns/DnsConstants.java +++ b/src/zutil/net/dns/packet/DnsConstants.java @@ -1,4 +1,4 @@ -package zutil.net.dns; +package zutil.net.dns.packet; /** * diff --git a/src/zutil/net/dns/DnsPacket.java b/src/zutil/net/dns/packet/DnsPacket.java similarity index 99% rename from src/zutil/net/dns/DnsPacket.java rename to src/zutil/net/dns/packet/DnsPacket.java index 3cf02d6..793bb74 100755 --- a/src/zutil/net/dns/DnsPacket.java +++ b/src/zutil/net/dns/packet/DnsPacket.java @@ -1,4 +1,4 @@ -package zutil.net.dns; +package zutil.net.dns.packet; import zutil.parser.binary.BinaryStructInputStream; import zutil.parser.binary.BinaryStructOutputStream; diff --git a/src/zutil/net/dns/DnsPacketHeader.java b/src/zutil/net/dns/packet/DnsPacketHeader.java similarity index 99% rename from src/zutil/net/dns/DnsPacketHeader.java rename to src/zutil/net/dns/packet/DnsPacketHeader.java index a0ef09c..5cfaab7 100755 --- a/src/zutil/net/dns/DnsPacketHeader.java +++ b/src/zutil/net/dns/packet/DnsPacketHeader.java @@ -22,7 +22,7 @@ * THE SOFTWARE. */ -package zutil.net.dns; +package zutil.net.dns.packet; import zutil.parser.binary.BinaryStruct; diff --git a/src/zutil/net/dns/DnsPacketQuestion.java b/src/zutil/net/dns/packet/DnsPacketQuestion.java similarity index 68% rename from src/zutil/net/dns/DnsPacketQuestion.java rename to src/zutil/net/dns/packet/DnsPacketQuestion.java index 9297d7a..ac0ab6c 100755 --- a/src/zutil/net/dns/DnsPacketQuestion.java +++ b/src/zutil/net/dns/packet/DnsPacketQuestion.java @@ -22,16 +22,10 @@ * THE SOFTWARE. */ -package zutil.net.dns; +package zutil.net.dns.packet; -import zutil.parser.binary.BinaryFieldData; -import zutil.parser.binary.BinaryFieldSerializer; import zutil.parser.binary.BinaryStruct; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - /** * @see DNS Spec (rfc1035) * @author Ziver @@ -96,44 +90,4 @@ public class DnsPacketQuestion implements BinaryStruct { } - - - - public static class FQDNStringSerializer implements BinaryFieldSerializer { - - public String read(InputStream in, BinaryFieldData field) throws IOException { - StringBuilder str = new StringBuilder(); - int c = in.read(); - // Is this a pointer - if ((c & 0b1100_0000) == 0b1100_0000 ){ - int offset = (c & 0b0011_1111) << 8; - offset |= in.read() & 0b1111_1111; - str.append(offset); - } - // Normal Domain String - else { - while (c > 0) { - for (int i = 0; i < c; ++i) { - str.append((char) in.read()); - } - c = in.read(); - if (c > 0) - str.append('.'); - } - } - return str.toString(); - } - - public void write(OutputStream out, String domain, BinaryFieldData field) throws IOException { - if (domain != null){ - String[] labels = domain.split("\\."); - for (String label : labels) { - out.write(label.length()); - out.write(label.getBytes()); - } - } - out.write(0); - } - - } } diff --git a/src/zutil/net/dns/DnsPacketResource.java b/src/zutil/net/dns/packet/DnsPacketResource.java similarity index 97% rename from src/zutil/net/dns/DnsPacketResource.java rename to src/zutil/net/dns/packet/DnsPacketResource.java index 028281e..7d1b13b 100755 --- a/src/zutil/net/dns/DnsPacketResource.java +++ b/src/zutil/net/dns/packet/DnsPacketResource.java @@ -22,7 +22,7 @@ * THE SOFTWARE. */ -package zutil.net.dns; +package zutil.net.dns.packet; import zutil.parser.binary.BinaryStruct; @@ -65,7 +65,7 @@ public class DnsPacketResource implements BinaryStruct { /** * a domain name to which this resource record pertains. */ - @CustomBinaryField(index=10, serializer=DnsPacketQuestion.FQDNStringSerializer.class) + @CustomBinaryField(index=10, serializer=FQDNStringSerializer.class) public String name; /** diff --git a/src/zutil/net/dns/packet/FQDNStringSerializer.java b/src/zutil/net/dns/packet/FQDNStringSerializer.java new file mode 100755 index 0000000..9877c68 --- /dev/null +++ b/src/zutil/net/dns/packet/FQDNStringSerializer.java @@ -0,0 +1,49 @@ +package zutil.net.dns.packet; + +import zutil.parser.binary.BinaryFieldData; +import zutil.parser.binary.BinaryFieldSerializer; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +/** + * A serializer class that can read and write a DNS FQDN in binary format. + */ +public class FQDNStringSerializer implements BinaryFieldSerializer { + + public String read(InputStream in, BinaryFieldData field) throws IOException { + StringBuilder str = new StringBuilder(); + int c = in.read(); + // Is this a pointer + if ((c & 0b1100_0000) == 0b1100_0000) { + int offset = (c & 0b0011_1111) << 8; + offset |= in.read() & 0b1111_1111; + str.append(offset); + } + // Normal Domain String + else { + while (c > 0) { + for (int i = 0; i < c; ++i) { + str.append((char) in.read()); + } + c = in.read(); + if (c > 0) + str.append('.'); + } + } + return str.toString(); + } + + public void write(OutputStream out, String domain, BinaryFieldData field) throws IOException { + if (domain != null) { + String[] labels = domain.split("\\."); + for (String label : labels) { + out.write(label.length()); + out.write(label.getBytes()); + } + } + out.write(0); + } + +} diff --git a/test/zutil/net/dns/DnsPacketTest.java b/test/zutil/net/dns/DnsPacketTest.java index 40c8c37..aa8c4aa 100755 --- a/test/zutil/net/dns/DnsPacketTest.java +++ b/test/zutil/net/dns/DnsPacketTest.java @@ -26,6 +26,7 @@ package zutil.net.dns; import org.junit.Test; import zutil.converter.Converter; +import zutil.net.dns.packet.*; import zutil.parser.binary.BinaryStructInputStream; import zutil.parser.binary.BinaryStructOutputStream; diff --git a/test/zutil/net/dns/MulticastDnsClientTest.java b/test/zutil/net/dns/MulticastDnsClientTest.java index 230dd47..d9122f2 100755 --- a/test/zutil/net/dns/MulticastDnsClientTest.java +++ b/test/zutil/net/dns/MulticastDnsClientTest.java @@ -3,6 +3,7 @@ package zutil.net.dns; import zutil.io.MultiPrintStream; import zutil.log.CompactLogFormatter; import zutil.log.LogUtil; +import zutil.net.dns.packet.DnsPacket; import java.io.IOException; import java.util.logging.Level;