Fixed a DNS bug and added IPv6 entry

This commit is contained in:
Ziver Koc 2021-08-24 01:24:09 +02:00
parent e42d25fa99
commit 946f5f5133
5 changed files with 157 additions and 19 deletions

View file

@ -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;
}

View file

@ -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 */

View file

@ -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;

View file

@ -38,22 +38,22 @@ public class FQDNStringSerializer implements BinaryFieldSerializer<String> {
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();

View file

@ -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
<Root>: type OPT
Name: <Root>
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);
}
}