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;
import zutil.parser.binary.BinaryStructInputStream;
import zutil.parser.binary.BinaryStructOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* 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 {
private DNSPacketHeader header;
@ -30,23 +32,77 @@ public class DNSPacket {
}
public static DNSPacket read(InputStream in){
return null;
public DNSPacketHeader getHeader(){
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 {
BinaryStructOutputStream structOut = new BinaryStructOutputStream(out);
structOut.write(header);
out.flush();
/*for (DNSPacketQuestion question : questions)
question.write(out);
for (DNSPacketQuestion question : questions)
structOut.write(question);
for (DNSPacketResource answerRecord : answerRecords)
answerRecord.write(out);
structOut.write(answerRecord);
for (DNSPacketResource nameServer : nameServers)
nameServer.write(out);
structOut.write(nameServer);
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
*/
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
@ -64,7 +115,7 @@ public class DNSPacketQuestion implements BinaryStruct {
* padding is used.
*/
@CustomBinaryField(index=10, serializer=DomainStringSerializer.class)
private String name;
private String qName;
/**
* 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
* can match more than one type of RR.
*/
@BinaryField(index=10, length=1)
private int type;
@BinaryField(index=10, length=16)
private int qType;
/**
* a two octet code that specifies the class of the query.
* For example, the QCLASS field is IN for the Internet.
*/
@BinaryField(index=20, length=1)
private int clazz;
@BinaryField(index=20, length=16)
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> {
@ -101,7 +164,7 @@ public class DNSPacketQuestion implements BinaryStruct {
public void write(OutputStream out, String domain, BinaryFieldData field) throws IOException {
if (domain != null){
String[] labels = domain.split(".");
String[] labels = domain.split("\\.");
for (String label : labels) {
out.write(label.length());
out.write(label.getBytes());

View file

@ -33,6 +33,51 @@ import zutil.parser.binary.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
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 zutil.parser.binary.BinaryStructOutputStream;
import static zutil.net.dns.DNSPacketQuestion.*;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
/**
@ -37,7 +40,7 @@ import static org.junit.Assert.assertEquals;
public class DNSPacketTest {
@Test
public void headerQueryTest() throws IOException {
public void writeHeaderTest() throws IOException {
DNSPacketHeader header = new DNSPacketHeader();
header.setDefaultQueryData();
header.countQuestion = 1;
@ -51,16 +54,60 @@ public class DNSPacketTest {
}
@Test
public void headerResponseTest() throws IOException {
public void readHheaderTest() throws IOException {
DNSPacketHeader header = new DNSPacketHeader();
header.setDefaultResponseData();
header.countAnswerRecord = 1;
byte[] data = BinaryStructOutputStream.serialize(header);
assertEquals("header length", 12, data.length);
assertEquals("Flag byte1", (byte)0x84, data[2]);
assertEquals("Flag byte2", (byte)0x00, data[3]);
assertEquals("Flag byte1", (byte) 0x84, data[2]);
assertEquals("Flag byte2", (byte) 0x00, data[3]);
assertEquals("Answer count byte1", 0x00, data[6]);
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);
}
}