Fixed DNS FQDN parsing

This commit is contained in:
Ziver Koc 2021-08-27 01:22:34 +02:00
parent f55473ced0
commit 600a4b648f
9 changed files with 86 additions and 64 deletions

View file

@ -16,7 +16,7 @@ public class PositionalInputStream extends FilterInputStream {
/**
* @param in the underlying input stream.
*/
protected PositionalInputStream(InputStream in) {
public PositionalInputStream(InputStream in) {
super(in);
}
@ -60,8 +60,8 @@ public class PositionalInputStream extends FilterInputStream {
}
@Override
public void mark(int readlimit) {
super.mark(readlimit);
public void mark(int readLimit) {
super.mark(readLimit);
synchronized(this) {
mark = pos;

View file

@ -78,7 +78,6 @@ public class MulticastDnsClient extends ThreadedUDPNetwork implements ThreadedUD
int id = 0; // Needs to be zero when doing multicast
activeProbes.add(id);
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
BinaryStructOutputStream out = new BinaryStructOutputStream(buffer);
DnsPacket dnsPacket = new DnsPacket();
dnsPacket.getHeader().id = id;
@ -87,7 +86,7 @@ public class MulticastDnsClient extends ThreadedUDPNetwork implements ThreadedUD
domain,
DnsConstants.TYPE.SRV,
DnsConstants.CLASS.IN));
dnsPacket.write(out);
dnsPacket.write(buffer);
DatagramPacket udpPacket = new DatagramPacket(
buffer.toByteArray(), buffer.size(),
@ -106,8 +105,7 @@ public class MulticastDnsClient extends ThreadedUDPNetwork implements ThreadedUD
try {
ByteArrayInputStream buffer = new ByteArrayInputStream(packet.getData(),
packet.getOffset(), packet.getLength());
BinaryStructInputStream in = new BinaryStructInputStream(buffer);
DnsPacket dnsPacket = DnsPacket.read(in);
DnsPacket dnsPacket = DnsPacket.read(buffer);
//System.out.println("Received:\n" +ByteUtil.toFormattedString(packet.getData(), packet.getOffset(), packet.getLength()));
MultiPrintStream.out.dump(dnsPacket,3);

View file

@ -112,8 +112,7 @@ public class MulticastDnsServer extends ThreadedUDPNetwork implements ThreadedUD
try {
ByteArrayInputStream buffer = new ByteArrayInputStream(packet.getData(),
packet.getOffset(), packet.getLength());
BinaryStructInputStream in = new BinaryStructInputStream(buffer);
DnsPacket dnsPacket = DnsPacket.read(in);
DnsPacket dnsPacket = DnsPacket.read(buffer);
// Just handle queries and no responses
if (! dnsPacket.getHeader().flagQueryResponse) {
@ -121,9 +120,8 @@ public class MulticastDnsServer extends ThreadedUDPNetwork implements ThreadedUD
if (response != null) {
ByteArrayOutputStream outBuffer = new ByteArrayOutputStream();
BinaryStructOutputStream out = new BinaryStructOutputStream(outBuffer);
response.write(out);
out.close();
response.write(outBuffer);
outBuffer.close();
DatagramPacket outPacket = new DatagramPacket(
outBuffer.toByteArray(), outBuffer.size(),

View file

@ -24,10 +24,13 @@
package zutil.net.dns.packet;
import zutil.io.PositionalInputStream;
import zutil.parser.binary.BinaryStructInputStream;
import zutil.parser.binary.BinaryStructOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@ -94,7 +97,9 @@ public class DnsPacket {
}
public static DnsPacket read(BinaryStructInputStream structIn) throws IOException {
public static DnsPacket read(InputStream in) throws IOException {
BinaryStructInputStream structIn = new BinaryStructInputStream(new PositionalInputStream(in));
DnsPacket packet = new DnsPacket();
structIn.read(packet.header);
@ -116,7 +121,9 @@ public class DnsPacket {
}
}
public void write(BinaryStructOutputStream structOut) throws IOException {
public void write(OutputStream out) throws IOException {
BinaryStructOutputStream structOut = new BinaryStructOutputStream(out);
structOut.write(header);
for (DnsPacketQuestion question : questions)

View file

@ -24,40 +24,64 @@
package zutil.net.dns.packet;
import zutil.io.PositionalInputStream;
import zutil.parser.binary.BinaryFieldData;
import zutil.parser.binary.BinaryFieldSerializer;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
/**
* A serializer class that can read and write a DNS FQDN in binary format.
*/
public class FQDNStringSerializer implements BinaryFieldSerializer<String> {
private HashMap<Integer, String> stringCache = new HashMap<>();
public String read(InputStream in, BinaryFieldData field) throws IOException {
StringBuilder str = new StringBuilder();
StringBuilder buffer = new StringBuilder();
int pos = (int) ((PositionalInputStream) in).getPosition();
int c;
while ((c=in.read()) > 0) {
if (str.length() > 0) // Don't add dot to first loop
str.append('.');
if (buffer.length() > 0) // Don't add dot to first loop
buffer.append('.');
if ((c & 0b1100_0000) == 0b1100_0000) {
// This a offset pointer to the String data
// This is an offset pointer to the String data
int offset = (c & 0b0011_1111) << 8;
offset |= in.read() & 0b1111_1111;
str.append(offset);
if (stringCache.containsKey(offset))
buffer.append(stringCache.get(offset));
else
buffer.append('<').append(offset).append('>');
break; // PTR is always the last part of the FQDN
} else {
// Normal String data
// Read normal String data
for (int i = 0; i < c; ++i) {
str.append((char) in.read());
buffer.append((char) in.read());
}
}
}
return str.toString();
String output = buffer.toString();
// Populate cache
if (in instanceof PositionalInputStream) {
stringCache.put(pos, output);
for (int index = 0; index >= 0;) {
index = buffer.indexOf(".", index);
if (index >= 0) {
++index;
stringCache.put(pos + index, buffer.substring(index));
}
}
}
return output;
}
public void write(OutputStream out, String domain, BinaryFieldData field) throws IOException {
@ -70,5 +94,4 @@ public class FQDNStringSerializer implements BinaryFieldSerializer<String> {
}
out.write(0);
}
}

View file

@ -29,15 +29,13 @@ import java.io.InputStream;
import java.io.OutputStream;
/**
* An Interface where custom field parser and writer can be implemented.
* An Interface defining a custom field parser and writer.
* <p></p>
* One instance of the serializer and will have the scope of the methods
* {@link BinaryStructInputStream#read(BinaryStruct)} and {@link BinaryStructOutputStream#write(BinaryStruct)}
* where as it will be deallocated after the methods have returned.
* One singleton instance of the serializer will be instantiated for the lifetime of the
* {@link BinaryStructInputStream} and {@link BinaryStructOutputStream} objects.
* <p></p>
* NOTE: Partial octet serializing not supported.
*
* Created by Ziver on 2016-04-11.
*/
public interface BinaryFieldSerializer<T> {

View file

@ -35,7 +35,7 @@ import java.util.Map;
/**
* A stream class that parses a byte stream into binary struct objects.
* <p><p/>
* <p></p>
* Limitations:<br>
* - Does not support sub binary objects.<br>
*
@ -47,6 +47,9 @@ public class BinaryStructInputStream {
private byte data;
private int dataBitIndex = -1;
private Map<Class, BinaryFieldSerializer> serializerCache = new HashMap<>();
public BinaryStructInputStream(InputStream in) {
this.in = in;
}
@ -78,7 +81,6 @@ public class BinaryStructInputStream {
*/
public int read(BinaryStruct struct) throws IOException {
List<BinaryFieldData> structDataList = BinaryFieldData.getStructFieldList(struct.getClass());
Map<Class, BinaryFieldSerializer> serializerCache = new HashMap<>();
int totalReadLength = 0;
for (BinaryFieldData field : structDataList) {

View file

@ -36,7 +36,7 @@ import java.util.Map;
/**
* A stream class that generates a byte stream from a binary struct objects.
* <p><p/>
* <p></p>
* Limitations:<br>
* - Does not support sub binary objects.<br>
*
@ -48,6 +48,8 @@ public class BinaryStructOutputStream {
private byte rest;
private int restBitLength; // length from Most Significant Bit
private Map<Class, BinaryFieldSerializer> serializerCache = new HashMap<>();
public BinaryStructOutputStream(OutputStream out) {
this.out = out;
@ -88,7 +90,6 @@ public class BinaryStructOutputStream {
*/
public void write(BinaryStruct struct) throws IOException {
List<BinaryFieldData> structDataList = BinaryFieldData.getStructFieldList(struct.getClass());
Map<Class, BinaryFieldSerializer> serializerCache = new HashMap<>();
for (BinaryFieldData field : structDataList) {
if (field.hasSerializer()) {