From 946f5f5133701f0633cfc3f27772f0daafe4026b Mon Sep 17 00:00:00 2001 From: Ziver Koc Date: Tue, 24 Aug 2021 01:24:09 +0200 Subject: [PATCH] Fixed a DNS bug and added IPv6 entry --- src/zutil/net/dns/MulticastDnsServer.java | 9 +- src/zutil/net/dns/packet/DnsConstants.java | 4 +- .../net/dns/packet/DnsPacketQuestion.java | 4 +- .../net/dns/packet/FQDNStringSerializer.java | 26 ++-- test/zutil/net/dns/DnsPacketTest.java | 133 ++++++++++++++++++ 5 files changed, 157 insertions(+), 19 deletions(-) diff --git a/src/zutil/net/dns/MulticastDnsServer.java b/src/zutil/net/dns/MulticastDnsServer.java index 3709143..c980274 100755 --- a/src/zutil/net/dns/MulticastDnsServer.java +++ b/src/zutil/net/dns/MulticastDnsServer.java @@ -92,7 +92,7 @@ public class MulticastDnsServer extends ThreadedUDPNetwork implements ThreadedUD resource.name = name; resource.type = type; resource.clazz = clazz; - //resource.ttl = 10; ??? + resource.ttl = 120; // client can cache the record for 2 min resource.length = data.length; resource.data = new String(data, StandardCharsets.ISO_8859_1); @@ -118,6 +118,7 @@ public class MulticastDnsServer extends ThreadedUDPNetwork implements ThreadedUD // Just handle queries and no responses if (! dnsPacket.getHeader().flagQueryResponse) { DnsPacket response = handleReceivedPacket(packet.getAddress(), dnsPacket); + if (response != null) { ByteArrayOutputStream outBuffer = new ByteArrayOutputStream(); BinaryStructOutputStream out = new BinaryStructOutputStream(outBuffer); @@ -139,6 +140,7 @@ public class MulticastDnsServer extends ThreadedUDPNetwork implements ThreadedUD protected DnsPacket handleReceivedPacket(InetAddress address, DnsPacket request) { DnsPacket response = new DnsPacket(); response.getHeader().setDefaultResponseData(); + for (DnsPacketQuestion question : request.getQuestions()) { if (question.name == null) continue; @@ -148,8 +150,9 @@ public class MulticastDnsServer extends ThreadedUDPNetwork implements ThreadedUD // ------------------------------------------ case DnsConstants.TYPE.A: + case DnsConstants.TYPE.AAAA: if (entries.containsKey(question.name)) { - logger.finer("Received request for domain: '" + question.name + "' from source: " + address); + logger.finer("Received request for IPv4 domain: '" + question.name + "' from source: " + address); response.addAnswerRecord(entries.get(question.name)); } else { logger.finest("Received request for unknown domain: '" + question.name + "' from source: " + address); @@ -175,7 +178,7 @@ public class MulticastDnsServer extends ThreadedUDPNetwork implements ThreadedUD logger.finer("Received request for service: '" + question.name + "' from source: " + address); response.addAnswerRecord(entries.get(question.name)); } else { - logger.finer("Received request for unknown pointer: '" + question.name + "' from source: " + address); + logger.finest("Received request for unknown pointer: '" + question.name + "' from source: " + address); } break; } diff --git a/src/zutil/net/dns/packet/DnsConstants.java b/src/zutil/net/dns/packet/DnsConstants.java index 5535256..97ad36e 100755 --- a/src/zutil/net/dns/packet/DnsConstants.java +++ b/src/zutil/net/dns/packet/DnsConstants.java @@ -79,7 +79,7 @@ public final class DnsConstants { public static final class TYPE { - /** a host address */ + /** a IPv4 host address */ public static final int A = 1; /** an authoritative name server */ public static final int NS = 2; @@ -111,6 +111,8 @@ public final class DnsConstants { public static final int MX = 15; /** text strings */ public static final int TXT = 16; + /** a IPv6 host address */ + public static final int AAAA = 28; /** service location record in format {Instance}.{Service}.{Domain}*/ public static final int SRV = 33; /** A request for a transfer of an entire zone */ diff --git a/src/zutil/net/dns/packet/DnsPacketQuestion.java b/src/zutil/net/dns/packet/DnsPacketQuestion.java index 82943e7..c9eda02 100755 --- a/src/zutil/net/dns/packet/DnsPacketQuestion.java +++ b/src/zutil/net/dns/packet/DnsPacketQuestion.java @@ -68,7 +68,7 @@ public class DnsPacketQuestion implements BinaryStruct { * * @see DnsConstants.TYPE */ - @BinaryField(index=10, length=16) + @BinaryField(index=20, length=16) public int type; /** @@ -77,7 +77,7 @@ public class DnsPacketQuestion implements BinaryStruct { * * @see DnsConstants.CLASS */ - @BinaryField(index=20, length=16) + @BinaryField(index=30, length=16) public int clazz; diff --git a/src/zutil/net/dns/packet/FQDNStringSerializer.java b/src/zutil/net/dns/packet/FQDNStringSerializer.java index a201eca..10cad8e 100755 --- a/src/zutil/net/dns/packet/FQDNStringSerializer.java +++ b/src/zutil/net/dns/packet/FQDNStringSerializer.java @@ -38,22 +38,22 @@ 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) { + int c; + + while ((c=in.read()) > 0) { + if (str.length() > 0) // Don't add dot to first loop + str.append('.'); + + if ((c & 0b1100_0000) == 0b1100_0000) { + // This a pointer + int offset = (c & 0b0011_1111) << 8; + offset |= in.read() & 0b1111_1111; + str.append(offset); + } else { + // Normal String for (int i = 0; i < c; ++i) { str.append((char) in.read()); } - c = in.read(); - if (c > 0) - str.append('.'); } } return str.toString(); diff --git a/test/zutil/net/dns/DnsPacketTest.java b/test/zutil/net/dns/DnsPacketTest.java index 0d0369e..13d15da 100755 --- a/test/zutil/net/dns/DnsPacketTest.java +++ b/test/zutil/net/dns/DnsPacketTest.java @@ -332,4 +332,137 @@ Domain Name System (response) assertEquals("CLASS", DnsConstants.CLASS.IN, answer.clazz); assertEquals("TTL", 227, answer.ttl); } + + @Test + public void rawIphoneQuery() throws IOException { +/* +0000 00 00 00 00 00 06 00 00 00 00 00 01 0f 5f 63 6f ............._co +0010 6d 70 61 6e 69 6f 6e 2d 6c 69 6e 6b 04 5f 74 63 mpanion-link._tc +0020 70 05 6c 6f 63 61 6c 00 00 0c 00 01 08 5f 68 6f p.local......_ho +0030 6d 65 6b 69 74 c0 1c 00 0c 00 01 03 68 61 6c c0 mekit.......hal. +0040 21 00 41 00 01 c0 3b 00 1c 00 01 c0 3b 00 01 00 !.A...;.....;... +0050 01 0c 5f 73 6c 65 65 70 2d 70 72 6f 78 79 04 5f .._sleep-proxy._ +0060 75 64 70 c0 21 00 0c 00 01 00 00 29 05 a0 00 00 udp.!......).... +0070 11 94 00 12 00 04 00 0e 00 65 7a e6 ba 29 34 00 .........ez..)4. +0080 d6 07 3a f2 2e e7 ..:... + + + +Multicast Domain Name System (query) + Transaction ID: 0x0000 + Flags: 0x0000 Standard query + Questions: 6 + Answer RRs: 0 + Authority RRs: 0 + Additional RRs: 1 + Queries + _companion-link._tcp.local: type PTR, class IN, "QM" question + Name: _companion-link._tcp.local + [Name Length: 26] + [Label Count: 3] + Type: PTR (domain name PoinTeR) (12) + .000 0000 0000 0001 = Class: IN (0x0001) + 0... .... .... .... = "QU" question: False + _homekit._tcp.local: type PTR, class IN, "QM" question + Name: _homekit._tcp.local + [Name Length: 19] + [Label Count: 3] + Type: PTR (domain name PoinTeR) (12) + .000 0000 0000 0001 = Class: IN (0x0001) + 0... .... .... .... = "QU" question: False + hal.local: type Unknown (65), class IN, "QM" question + Name: hal.local + [Name Length: 9] + [Label Count: 2] + Type: Unknown (65) + .000 0000 0000 0001 = Class: IN (0x0001) + 0... .... .... .... = "QU" question: False + hal.local: type AAAA, class IN, "QM" question + Name: hal.local + [Name Length: 9] + [Label Count: 2] + Type: AAAA (IPv6 Address) (28) + .000 0000 0000 0001 = Class: IN (0x0001) + 0... .... .... .... = "QU" question: False + hal.local: type A, class IN, "QM" question + Name: hal.local + [Name Length: 9] + [Label Count: 2] + Type: A (Host Address) (1) + .000 0000 0000 0001 = Class: IN (0x0001) + 0... .... .... .... = "QU" question: False + _sleep-proxy._udp.local: type PTR, class IN, "QM" question + Name: _sleep-proxy._udp.local + [Name Length: 23] + [Label Count: 3] + Type: PTR (domain name PoinTeR) (12) + .000 0000 0000 0001 = Class: IN (0x0001) + 0... .... .... .... = "QU" question: False + Additional records + : type OPT + Name: + Type: OPT (41) + .000 0101 1010 0000 = UDP payload size: 0x05a0 + 0... .... .... .... = Cache flush: False + Higher bits in extended RCODE: 0x00 + EDNS0 version: 0 + Z: 0x1194 + 0... .... .... .... = DO bit: Cannot handle DNSSEC security RRs + .001 0001 1001 0100 = Reserved: 0x1194 + Data length: 18 + Option: Owner (reserved) + */ + + byte[] input = Converter.hexToByte(( + "00 00 00 00 00 06 00 00 00 00 00 01" + // Header + "0f 5f 63 6f 6d 70 61 6e 69 6f 6e 2d 6c 69 6e 6b 04 5f 74 63 70 05 6c 6f 63 61 6c 00 00 0c 00 01" + // Query PTR: _companion-link._tcp.local + "08 5f 68 6f 6d 65 6b 69 74 c0 1c 00 0c 00 01" + // Query PTR: _homekit._tcp.local + "03 68 61 6c c0 21 00 41 00 01" + // Query Unknown: hal.local + "c0 3b 00 1c 00 01" + // Query IPv6: hal.local + "c0 3b 00 01 00 01" + // Query IPv4: hal.local + "0c 5f 73 6c 65 65 70 2d 70 72 6f 78 79 04 5f 75 64 70 c0 21 00 0c 00 01" + // Query PTR: _sleep-proxy._udp.local + "00 00 29 05 a0 00 00 11 94 00 12 00 04 00 0e 00 65 7a e6 ba 29 34 00 d6 07 3a f2 2e e7" // Additional records + ).replace(" ", "")); + ByteArrayInputStream buffer = new ByteArrayInputStream(input); + BinaryStructInputStream in = new BinaryStructInputStream(buffer); + DnsPacket packet = DnsPacket.read(in); + + assertEquals("id", 0x00, packet.getHeader().id); + assertFalse("flagQueryResponse", packet.getHeader().flagQueryResponse); + assertEquals("No Of Question records", 6, packet.getHeader().countQuestion); + assertEquals("No Of Answer records", 0, packet.getHeader().countAnswerRecord); + assertEquals("No Of NameServer records", 0, packet.getHeader().countNameServer); + assertEquals("No Of Additional records", 1, packet.getHeader().countAdditionalRecord); + + // Query + DnsPacketQuestion question1 = packet.getQuestions().get(0); + assertEquals("qNAME", "_companion-link._tcp.local", question1.name); + assertEquals("type", DnsConstants.TYPE.PTR, question1.type); + assertEquals("clazz", DnsConstants.CLASS.IN, question1.clazz); + + DnsPacketQuestion question2 = packet.getQuestions().get(1); + //assertEquals("qNAME", "_homekit._tcp.local", question2.name); + assertEquals("qNAME", "_homekit.28", question2.name); // TODO: Fix support for string pointers + assertEquals("type", DnsConstants.TYPE.PTR, question2.type); + assertEquals("clazz", DnsConstants.CLASS.IN, question2.clazz); + + DnsPacketQuestion question3 = packet.getQuestions().get(2); + assertEquals("qNAME", "hal.local", question3.name); + assertEquals("clazz", DnsConstants.CLASS.IN, question3.clazz); + + DnsPacketQuestion question4 = packet.getQuestions().get(3); + assertEquals("qNAME", "hal.local", question4.name); + assertEquals("type", DnsConstants.TYPE.AAAA, question4.type); + assertEquals("clazz", DnsConstants.CLASS.IN, question4.clazz); + + DnsPacketQuestion question5 = packet.getQuestions().get(4); + assertEquals("qNAME", "hal.local", question5.name); + assertEquals("type", DnsConstants.TYPE.A, question5.type); + assertEquals("clazz", DnsConstants.CLASS.IN, question5.clazz); + + DnsPacketQuestion question6 = packet.getQuestions().get(5); + assertEquals("qNAME", "_sleep-proxy._udp.local", question6.name); + assertEquals("type", DnsConstants.TYPE.PTR, question6.type); + assertEquals("clazz", DnsConstants.CLASS.IN, question6.clazz); + } }