Added DNS packet TC

This commit is contained in:
Ziver Koc 2016-04-18 17:41:55 +02:00
parent fffaa64455
commit 31a47f52cd
5 changed files with 232 additions and 20 deletions

View file

@ -1,17 +1,19 @@
package zutil.net.dns; package zutil.net.dns;
import zutil.parser.binary.BinaryStructInputStream;
import zutil.parser.binary.BinaryStructOutputStream; import zutil.parser.binary.BinaryStructOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/** /**
* This class is a general wrapper for a whole DNS packet. * This class is a general wrapper for a whole DNS packet.
* *
* Created by ezivkoc on 2016-04-11. * Created by Ziver on 2016-04-11.
*/ */
public class DNSPacket { public class DNSPacket {
private DNSPacketHeader header; private DNSPacketHeader header;
@ -30,23 +32,77 @@ public class DNSPacket {
} }
public static DNSPacket read(InputStream in){ public DNSPacketHeader getHeader(){
return null; return header;
}
public List<DNSPacketQuestion> getQuestions(){
return Collections.unmodifiableList(questions);
}
public List<DNSPacketResource> getAnswerRecords(){
return Collections.unmodifiableList(answerRecords);
}
public List<DNSPacketResource> getNameServers(){
return Collections.unmodifiableList(nameServers);
}
public List<DNSPacketResource> getAdditionalRecords(){
return Collections.unmodifiableList(additionalRecords);
}
public void addQuestion(DNSPacketQuestion question){
questions.add(question);
header.countQuestion = questions.size();
}
public void addAnswerRecord(DNSPacketResource resource){
answerRecords.add(resource);
header.countAnswerRecord = answerRecords.size();
}
public void addNameServer(DNSPacketResource resource){
nameServers.add(resource);
header.countNameServer = nameServers.size();
}
public void addAdditionalRecord(DNSPacketResource resource){
additionalRecords.add(resource);
header.countAdditionalRecord = additionalRecords.size();
}
public static DNSPacket read(InputStream in) throws IOException {
BinaryStructInputStream structIn = new BinaryStructInputStream(in);
DNSPacket packet = new DNSPacket();
structIn.read(packet.header);
for (int i=0; i<packet.header.countQuestion; ++i) {
DNSPacketQuestion question = new DNSPacketQuestion();
structIn.read(question);
packet.questions.add(question);
}
readResource(structIn, packet.header.countAnswerRecord, packet.answerRecords);
readResource(structIn, packet.header.countNameServer, packet.nameServers);
readResource(structIn, packet.header.countAdditionalRecord, packet.additionalRecords);
return packet;
}
private static void readResource(BinaryStructInputStream structIn, int count, ArrayList<DNSPacketResource> list) throws IOException {
for (int i=0; i<count; ++i){
DNSPacketResource resource = new DNSPacketResource();
structIn.read(resource);
list.add(resource);
}
} }
public void write(OutputStream out) throws IOException { public void write(OutputStream out) throws IOException {
BinaryStructOutputStream structOut = new BinaryStructOutputStream(out); BinaryStructOutputStream structOut = new BinaryStructOutputStream(out);
structOut.write(header); structOut.write(header);
out.flush();
/*for (DNSPacketQuestion question : questions) for (DNSPacketQuestion question : questions)
question.write(out); structOut.write(question);
for (DNSPacketResource answerRecord : answerRecords) for (DNSPacketResource answerRecord : answerRecords)
answerRecord.write(out); structOut.write(answerRecord);
for (DNSPacketResource nameServer : nameServers) for (DNSPacketResource nameServer : nameServers)
nameServer.write(out); structOut.write(nameServer);
for (DNSPacketResource additionalRecord : additionalRecords) for (DNSPacketResource additionalRecord : additionalRecords)
additionalRecord.write(out);*/ structOut.write(additionalRecord);
} }
} }

View file

@ -37,6 +37,57 @@ import java.io.OutputStream;
* Reference: http://tools.ietf.org/html/rfc1035 * Reference: http://tools.ietf.org/html/rfc1035
*/ */
public class DNSPacketQuestion implements BinaryStruct { public class DNSPacketQuestion implements BinaryStruct {
/** a host address */
public static final int QTYPE_A = 1;
/** an authoritative name server */
public static final int QTYPE_NS = 2;
/** a mail destination (Obsolete - use MX) */
public static final int QTYPE_MD = 3;
/** a mail forwarder (Obsolete - use MX) */
public static final int QTYPE_MF = 4;
/** the canonical name for an alias */
public static final int QTYPE_CNAME = 5;
/** marks the start of a zone of authority */
public static final int QTYPE_SOA = 6;
/** a mailbox domain name (EXPERIMENTAL) */
public static final int QTYPE_MB = 7;
/** a mail group member (EXPERIMENTAL) */
public static final int QTYPE_MG = 8;
/** a mail rename domain name (EXPERIMENTAL) */
public static final int QTYPE_MR = 9;
/** a null RR (EXPERIMENTAL) */
public static final int QTYPE_NULL = 10;
/** a well known service description */
public static final int QTYPE_WKS = 11;
/** a domain name pointer */
public static final int QTYPE_PTR = 12;
/** host information */
public static final int QTYPE_HINFO = 13;
/** mailbox or mail list information */
public static final int QTYPE_MINFO = 14;
/** mail exchange */
public static final int QTYPE_MX = 15;
/** text strings */
public static final int QTYPE_TXT = 16;
/** A request for a transfer of an entire zone */
public static final int QTYPE_AXFR = 252;
/** A request for mailbox-related records (MB, MG or MR) */
public static final int QTYPE_MAILB = 253;
/** A request for mail agent RRs (Obsolete - see MX) */
public static final int QTYPE_MAILA = 254;
/** A request for all records */
public static final int QTYPE_ANY = 255;
/** the Internet */
public static final int QCLASS_IN = 1;
/** the CSNET class (Obsolete - used only for examples in some obsolete RFCs) */
public static final int QCLASS_CS = 2;
/** the CHAOS class */
public static final int QCLASS_CH = 3;
/** Hesiod [Dyer 87] */
public static final int QCLASS_HS = 4;
/** any class */
public static final int QCLASS_ANY = 255;
/* /*
Question section format Question section format
@ -64,7 +115,7 @@ public class DNSPacketQuestion implements BinaryStruct {
* padding is used. * padding is used.
*/ */
@CustomBinaryField(index=10, serializer=DomainStringSerializer.class) @CustomBinaryField(index=10, serializer=DomainStringSerializer.class)
private String name; private String qName;
/** /**
* a two octet code which specifies the type of the query. * a two octet code which specifies the type of the query.
@ -72,15 +123,27 @@ public class DNSPacketQuestion implements BinaryStruct {
* TYPE field, together with some more general codes which * TYPE field, together with some more general codes which
* can match more than one type of RR. * can match more than one type of RR.
*/ */
@BinaryField(index=10, length=1) @BinaryField(index=10, length=16)
private int type; private int qType;
/** /**
* a two octet code that specifies the class of the query. * a two octet code that specifies the class of the query.
* For example, the QCLASS field is IN for the Internet. * For example, the QCLASS field is IN for the Internet.
*/ */
@BinaryField(index=20, length=1) @BinaryField(index=20, length=16)
private int clazz; private int qClass;
public DNSPacketQuestion() {}
public DNSPacketQuestion(String qName, int qType, int qClass) {
this.qName = qName;
this.qType = qType;
this.qClass = qClass;
}
public static class DomainStringSerializer implements BinaryFieldSerializer<String> { public static class DomainStringSerializer implements BinaryFieldSerializer<String> {
@ -101,7 +164,7 @@ public class DNSPacketQuestion implements BinaryStruct {
public void write(OutputStream out, String domain, BinaryFieldData field) throws IOException { public void write(OutputStream out, String domain, BinaryFieldData field) throws IOException {
if (domain != null){ if (domain != null){
String[] labels = domain.split("."); String[] labels = domain.split("\\.");
for (String label : labels) { for (String label : labels) {
out.write(label.length()); out.write(label.length());
out.write(label.getBytes()); out.write(label.getBytes());

View file

@ -33,6 +33,51 @@ import zutil.parser.binary.BinaryStruct;
*/ */
public class DNSPacketResource implements BinaryStruct { public class DNSPacketResource implements BinaryStruct {
/** a host address */
public static final int TYPE_A = 1;
/** an authoritative name server */
public static final int TYPE_NS = 2;
/** a mail destination (Obsolete - use MX) */
public static final int TYPE_MD = 3;
/** a mail forwarder (Obsolete - use MX) */
public static final int TYPE_MF = 4;
/** the canonical name for an alias */
public static final int TYPE_CNAME = 5;
/** marks the start of a zone of authority */
public static final int TYPE_SOA = 6;
/** a mailbox domain name (EXPERIMENTAL) */
public static final int TYPE_MB = 7;
/** a mail group member (EXPERIMENTAL) */
public static final int TYPE_MG = 8;
/** a mail rename domain name (EXPERIMENTAL) */
public static final int TYPE_MR = 9;
/** a null RR (EXPERIMENTAL) */
public static final int TYPE_NULL = 10;
/** a well known service description */
public static final int TYPE_WKS = 11;
/** a domain name pointer */
public static final int TYPE_PTR = 12;
/** host information */
public static final int TYPE_HINFO = 13;
/** mailbox or mail list information */
public static final int TYPE_MINFO = 14;
/** mail exchange */
public static final int TYPE_MX = 15;
/** text strings */
public static final int TYPE_TXT = 16;
/** the Internet */
public static final int CLASS_IN = 1;
/** the CSNET class (Obsolete - used only for examples in some obsolete RFCs) */
public static final int CLASS_CS = 2;
/** the CHAOS class */
public static final int CLASS_CH = 3;
/** Hesiod [Dyer 87] */
public static final int CLASS_HS = 4;
/* /*
The answer, authority, and additional sections all share the same The answer, authority, and additional sections all share the same
format: a variable number of resource records, where the number of format: a variable number of resource records, where the number of

View file

@ -96,6 +96,7 @@ public class BinaryStructOutputStream {
} }
} }
} }
localFlush();
} }

View file

@ -26,9 +26,12 @@ package zutil.net.dns;
import org.junit.Test; import org.junit.Test;
import zutil.parser.binary.BinaryStructOutputStream; import zutil.parser.binary.BinaryStructOutputStream;
import static zutil.net.dns.DNSPacketQuestion.*;
import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
/** /**
@ -37,7 +40,7 @@ import static org.junit.Assert.assertEquals;
public class DNSPacketTest { public class DNSPacketTest {
@Test @Test
public void headerQueryTest() throws IOException { public void writeHeaderTest() throws IOException {
DNSPacketHeader header = new DNSPacketHeader(); DNSPacketHeader header = new DNSPacketHeader();
header.setDefaultQueryData(); header.setDefaultQueryData();
header.countQuestion = 1; header.countQuestion = 1;
@ -51,7 +54,7 @@ public class DNSPacketTest {
} }
@Test @Test
public void headerResponseTest() throws IOException { public void readHheaderTest() throws IOException {
DNSPacketHeader header = new DNSPacketHeader(); DNSPacketHeader header = new DNSPacketHeader();
header.setDefaultResponseData(); header.setDefaultResponseData();
header.countAnswerRecord = 1; header.countAnswerRecord = 1;
@ -63,4 +66,48 @@ public class DNSPacketTest {
assertEquals("Answer count byte1", 0x00, data[6]); assertEquals("Answer count byte1", 0x00, data[6]);
assertEquals("Answer count byte2", 0x01, data[7]); assertEquals("Answer count byte2", 0x01, data[7]);
} }
@Test
public void writeDnsPacketHeaderTest() throws IOException {
DNSPacket packet = new DNSPacket();
packet.getHeader().setDefaultQueryData();
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
packet.write(buffer);
byte[] data = buffer.toByteArray();
byte[] expected = {
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, // QDCOUNT
0x00, 0x00, // ANCOUNT
0x00, 0x00, // NSCOUNT
0x00, 0x00, // ARCOUNT
};
assertArrayEquals(expected, data);
}
@Test
public void writeDnsPacketTest() throws IOException {
DNSPacket packet = new DNSPacket();
packet.getHeader().setDefaultQueryData();
packet.addQuestion(new DNSPacketQuestion("appletv.local", QTYPE_A, QCLASS_IN));
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
packet.write(buffer);
byte[] data = buffer.toByteArray();
byte[] expected = {
0x00, 0x00, 0x00, 0x00,
0x00, 0x01, // QDCOUNT
0x00, 0x00, // ANCOUNT
0x00, 0x00, // NSCOUNT
0x00, 0x00, // ARCOUNT
0x07, 0x61, 0x70, 0x70, 0x6c, 0x65, 0x74, 0x76, // "apple"
0x05, 0x6c, 0x6f, 0x63, 0x61, 0x6c, // "local"
0x00, // NULL
0x00, 0x01, // QTYPE
0x00, 0x01 // QCLASS
};
assertArrayEquals(expected, data);
}
} }