解析 DNS 响应答案部分未给出预期结果
Parsing DNS response Answer section doesn't give expected results
我正在尝试使用 java 解析 DNS 响应。我正在关注 RFC-1035 有关如何发送请求和接收响应的指南,即格式。
根据所述 RFC,响应的答案部分应如下所示:
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| |
/ /
/ NAME /
| |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| TYPE |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| CLASS |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| TTL |
| |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| RDLENGTH |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
/ RDATA /
/ /
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
我正在尝试解析 NAME
部分。
根据第 4.1.4 节。消息压缩我应该能够获取前 2 位并确定下一个字节是标签还是指针。
到目前为止,这是我的代码,使用 CouldFlare 作为 DNS
,对于 google.com
的 A
记录,请求工作正常
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.nio.charset.StandardCharsets;
import java.util.Random;
public class Stuff {
private static final String DNS_SERVER_ADDRESS = "1.1.1.1";
private static final int DNS_SERVER_PORT = 53;
public static void main(String[] args) throws IOException {
String domain = "google.com";
InetAddress ipAddress = InetAddress.getByName(DNS_SERVER_ADDRESS);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(baos);
//Whenever an octet represents a numeric quantity, the left most bit in
//the diagram is the high order or most significant bit.
//this goes for requests as well as responses
short requestFlags = Short.parseShort("0000000100000000", 2);
ByteBuffer bytes = ByteBuffer.allocate(2).putShort(requestFlags);
byte[] array = bytes.array();
dos.writeShort(1234); // randomly chosen id
dos.write(array);
dos.writeShort(1); // QDCOUNT
dos.writeShort(0); // ANCOUNT
dos.writeShort(0); // NSCOUNT
dos.writeShort(0); // ARCOUNT
String[] domainParts = domain.split("\.");
System.out.println(domain + " has " + domainParts.length + " parts");
for (int i = 0; i < domainParts.length; i++) {
System.out.println("Writing: " + domainParts[i]);
byte[] domainBytes = domainParts[i].getBytes(StandardCharsets.UTF_8);
dos.writeByte(domainBytes.length);
dos.write(domainBytes);
}
// No more parts
dos.writeByte(0);
// Type 0x01 = A (Host Request)
dos.writeShort(1);
// Class 0x01 = IN
dos.writeShort(1);
byte[] dnsFrame = baos.toByteArray();
System.out.println("Sending: " + dnsFrame.length + " bytes");
for (int i = 0; i < dnsFrame.length; i++) {
System.out.print(String.format("%s", dnsFrame[i]) + " ");
}
DatagramSocket socket = new DatagramSocket();
DatagramPacket dnsReqPacket = new DatagramPacket(dnsFrame, dnsFrame.length, ipAddress, DNS_SERVER_PORT);
socket.send(dnsReqPacket);
// Await response from DNS server
byte[] buf = new byte[512];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
socket.receive(packet);
System.out.println("\n\nReceived: " + packet.getLength() + " bytes");
for (int i = 0; i < packet.getLength(); i++) {
System.out.print(String.format("%s", buf[i]) + " ");
}
System.out.println("\n");
//All communications inside of the domain protocol are carried in a single
//format called a message. The top level format of message is divided
//into 5 sections (some of which are empty in certain cases) shown below:
// +---------------------+
// | Header |
// +---------------------+
// | Question | the question for the name server
// +---------------------+
// | Answer | RRs answering the question
// +---------------------+
// | Authority | RRs pointing toward an authority
// +---------------------+
// | Additional | RRs holding additional information
// +---------------------+
// HEADER
// 1 1 1 1 1 1
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | ID |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// |QR| Opcode |AA|TC|RD|RA| Z | RCODE |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | QDCOUNT |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | ANCOUNT |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | NSCOUNT |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | ARCOUNT |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
DataInputStream din = new DataInputStream(new ByteArrayInputStream(buf));
System.out.println("\n\nStart response decode");
System.out.println("Transaction ID: " + din.readShort()); // ID
short flags = din.readByte();
int QR = (flags & 0b10000000) >>> 7; //QR
int opCode = ( flags & 0b01111000) >>> 3; //Opcode
int AA = ( flags & 0b00000100) >>> 2; //AA
int TC = ( flags & 0b00000010) >>> 1; //TC
int RD = flags & 0b00000001;//RD
System.out.println("QR "+QR);
System.out.println("Opcode "+opCode);
System.out.println("AA "+AA);
System.out.println("TC "+TC);
System.out.println("RD "+RD);
flags = din.readByte();
int RA = (flags & 0b10000000) >>> 7;//RA
int Z = ( flags & 0b01110000) >>> 4;//Z
int RCODE = flags & 0b00001111;//RCODE
System.out.println("RA "+RA);
System.out.println("Z "+ Z);
System.out.println("RCODE " +RCODE);
System.out.println("Questions: " + String.format("%s", din.readShort())); //QDCOUNT
System.out.println("Answers RRs: " + String.format("%s", din.readShort())); //ANCOUNT
System.out.println("Authority RRs: " + String.format("%s", din.readShort())); //NSCOUNT
System.out.println("Additional RRs: " + String.format("%s", din.readShort())); //ARCOUNT
// Question
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | |
// / QNAME /
// / /
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | QTYPE |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | QCLASS |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
int recLen;
while ((recLen = din.readByte()) > 0) {
byte[] record = new byte[recLen];
for (int i = 0; i < recLen; i++) {
record[i] = din.readByte();
}
System.out.println("Record: " + new String(record, StandardCharsets.UTF_8)); //QNAME
}
System.out.println("Record Type: " + String.format("%s", din.readShort()));//QTYPE
System.out.println("QCLASS - Class: " + String.format("%s", din.readShort())); // QCLASS
System.out.println("\n\nstart answer, authority, and additional sections\n");
//The answer, authority, and additional
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | |
// / /
// / NAME /
// | |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | TYPE |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | CLASS |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | TTL |
// | |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | RDLENGTH |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
// / RDATA /
// / /
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
byte firstBytes = din.readByte();
int firstTwoBits = (firstBytes & 0b11000000) >>> 6;
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | 1 1| OFFSET |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// 11 for offset
//(The 10 and 01 combinations
//are reserved for future use.)
// 00 for label
//label must begin with two zero bits because
//labels are restricted to 63 octets or less
System.out.println(firstTwoBits);
if(firstTwoBits == 3) {
System.out.println("It's a pointer");
}else if(firstTwoBits == 0){
System.out.println("It's a label");
}
}
}
以及打印的信息
google.com has 2 parts
Writing: google
Writing: com
Sending: 28 bytes
4 -46 1 0 0 1 0 0 0 0 0 0 6 103 111 111 103 108 101 3 99 111 109 0 0 1 0 1
Received: 44 bytes
4 -46 -127 -128 0 1 0 1 0 0 0 0 6 103 111 111 103 108 101 3 99 111 109 0 0 1 0 1 -64 12 0 1 0 1 0 0 1 27 0 4 -114 -5 37 110
Start response decode
Transaction ID: 1234
QR 1
Opcode 0
AA 0
TC 0
RD 1
RA 1
Z 0
RCODE 0
Questions: 1
Answers RRs: 1
Authority RRs: 0
Additional RRs: 0
Record: google
Record: com
Record Type: 1
QCLASS - Class: 1
start answer, authority, and additional sections
3
It's a pointer
Process finished with exit code 0
将其与命令行 DNS 查找工具进行比较
id 1329, opcode QUERY, rcode NOERROR, flags QR RD RA
;QUESTION
google.com. IN A
;ANSWER
google.com. 257 IN A 142.250.81.206
;AUTHORITY
;ADDITIONAL
我得到的结果似乎有效。
我的问题是我似乎无法解析答案部分的 NAME
。它似乎以一个毫无意义的指针开始。
显然我在这里做错了什么,但我不知道是什么。
我知道我问的是含糊不清的问题,但话又说回来,如果我知道问题出在哪里,我就不会来这里了。
我还使用 Wireshark 来拦截我所做的请求以确保响应正确。它似乎确实是正确的(我显然已经将 url 更改为 whosebug.com)
My problem is that I can't seem to parse the NAME in the answer
section. It seems to start with a pointer which makes no sense.
我对这方面的了解可能比你少得多,但我想知道你为什么这么说? firstByte
告诉你有一个指针,下面的值 (0x0c) 显示了用于压缩目的的名称偏移量(如果我没记错的话)。 None 与 firstByte
相同字节中的其他位被设置为从偏移值的角度可以忽略
我正在尝试使用 java 解析 DNS 响应。我正在关注 RFC-1035 有关如何发送请求和接收响应的指南,即格式。
根据所述 RFC,响应的答案部分应如下所示:
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| |
/ /
/ NAME /
| |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| TYPE |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| CLASS |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| TTL |
| |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| RDLENGTH |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
/ RDATA /
/ /
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
我正在尝试解析 NAME
部分。
根据第 4.1.4 节。消息压缩我应该能够获取前 2 位并确定下一个字节是标签还是指针。
到目前为止,这是我的代码,使用 CouldFlare 作为 DNS
,对于google.com
的 A
记录,请求工作正常
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.nio.charset.StandardCharsets;
import java.util.Random;
public class Stuff {
private static final String DNS_SERVER_ADDRESS = "1.1.1.1";
private static final int DNS_SERVER_PORT = 53;
public static void main(String[] args) throws IOException {
String domain = "google.com";
InetAddress ipAddress = InetAddress.getByName(DNS_SERVER_ADDRESS);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(baos);
//Whenever an octet represents a numeric quantity, the left most bit in
//the diagram is the high order or most significant bit.
//this goes for requests as well as responses
short requestFlags = Short.parseShort("0000000100000000", 2);
ByteBuffer bytes = ByteBuffer.allocate(2).putShort(requestFlags);
byte[] array = bytes.array();
dos.writeShort(1234); // randomly chosen id
dos.write(array);
dos.writeShort(1); // QDCOUNT
dos.writeShort(0); // ANCOUNT
dos.writeShort(0); // NSCOUNT
dos.writeShort(0); // ARCOUNT
String[] domainParts = domain.split("\.");
System.out.println(domain + " has " + domainParts.length + " parts");
for (int i = 0; i < domainParts.length; i++) {
System.out.println("Writing: " + domainParts[i]);
byte[] domainBytes = domainParts[i].getBytes(StandardCharsets.UTF_8);
dos.writeByte(domainBytes.length);
dos.write(domainBytes);
}
// No more parts
dos.writeByte(0);
// Type 0x01 = A (Host Request)
dos.writeShort(1);
// Class 0x01 = IN
dos.writeShort(1);
byte[] dnsFrame = baos.toByteArray();
System.out.println("Sending: " + dnsFrame.length + " bytes");
for (int i = 0; i < dnsFrame.length; i++) {
System.out.print(String.format("%s", dnsFrame[i]) + " ");
}
DatagramSocket socket = new DatagramSocket();
DatagramPacket dnsReqPacket = new DatagramPacket(dnsFrame, dnsFrame.length, ipAddress, DNS_SERVER_PORT);
socket.send(dnsReqPacket);
// Await response from DNS server
byte[] buf = new byte[512];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
socket.receive(packet);
System.out.println("\n\nReceived: " + packet.getLength() + " bytes");
for (int i = 0; i < packet.getLength(); i++) {
System.out.print(String.format("%s", buf[i]) + " ");
}
System.out.println("\n");
//All communications inside of the domain protocol are carried in a single
//format called a message. The top level format of message is divided
//into 5 sections (some of which are empty in certain cases) shown below:
// +---------------------+
// | Header |
// +---------------------+
// | Question | the question for the name server
// +---------------------+
// | Answer | RRs answering the question
// +---------------------+
// | Authority | RRs pointing toward an authority
// +---------------------+
// | Additional | RRs holding additional information
// +---------------------+
// HEADER
// 1 1 1 1 1 1
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | ID |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// |QR| Opcode |AA|TC|RD|RA| Z | RCODE |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | QDCOUNT |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | ANCOUNT |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | NSCOUNT |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | ARCOUNT |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
DataInputStream din = new DataInputStream(new ByteArrayInputStream(buf));
System.out.println("\n\nStart response decode");
System.out.println("Transaction ID: " + din.readShort()); // ID
short flags = din.readByte();
int QR = (flags & 0b10000000) >>> 7; //QR
int opCode = ( flags & 0b01111000) >>> 3; //Opcode
int AA = ( flags & 0b00000100) >>> 2; //AA
int TC = ( flags & 0b00000010) >>> 1; //TC
int RD = flags & 0b00000001;//RD
System.out.println("QR "+QR);
System.out.println("Opcode "+opCode);
System.out.println("AA "+AA);
System.out.println("TC "+TC);
System.out.println("RD "+RD);
flags = din.readByte();
int RA = (flags & 0b10000000) >>> 7;//RA
int Z = ( flags & 0b01110000) >>> 4;//Z
int RCODE = flags & 0b00001111;//RCODE
System.out.println("RA "+RA);
System.out.println("Z "+ Z);
System.out.println("RCODE " +RCODE);
System.out.println("Questions: " + String.format("%s", din.readShort())); //QDCOUNT
System.out.println("Answers RRs: " + String.format("%s", din.readShort())); //ANCOUNT
System.out.println("Authority RRs: " + String.format("%s", din.readShort())); //NSCOUNT
System.out.println("Additional RRs: " + String.format("%s", din.readShort())); //ARCOUNT
// Question
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | |
// / QNAME /
// / /
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | QTYPE |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | QCLASS |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
int recLen;
while ((recLen = din.readByte()) > 0) {
byte[] record = new byte[recLen];
for (int i = 0; i < recLen; i++) {
record[i] = din.readByte();
}
System.out.println("Record: " + new String(record, StandardCharsets.UTF_8)); //QNAME
}
System.out.println("Record Type: " + String.format("%s", din.readShort()));//QTYPE
System.out.println("QCLASS - Class: " + String.format("%s", din.readShort())); // QCLASS
System.out.println("\n\nstart answer, authority, and additional sections\n");
//The answer, authority, and additional
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | |
// / /
// / NAME /
// | |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | TYPE |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | CLASS |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | TTL |
// | |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | RDLENGTH |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
// / RDATA /
// / /
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
byte firstBytes = din.readByte();
int firstTwoBits = (firstBytes & 0b11000000) >>> 6;
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// | 1 1| OFFSET |
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// 11 for offset
//(The 10 and 01 combinations
//are reserved for future use.)
// 00 for label
//label must begin with two zero bits because
//labels are restricted to 63 octets or less
System.out.println(firstTwoBits);
if(firstTwoBits == 3) {
System.out.println("It's a pointer");
}else if(firstTwoBits == 0){
System.out.println("It's a label");
}
}
}
以及打印的信息
google.com has 2 parts
Writing: google
Writing: com
Sending: 28 bytes
4 -46 1 0 0 1 0 0 0 0 0 0 6 103 111 111 103 108 101 3 99 111 109 0 0 1 0 1
Received: 44 bytes
4 -46 -127 -128 0 1 0 1 0 0 0 0 6 103 111 111 103 108 101 3 99 111 109 0 0 1 0 1 -64 12 0 1 0 1 0 0 1 27 0 4 -114 -5 37 110
Start response decode
Transaction ID: 1234
QR 1
Opcode 0
AA 0
TC 0
RD 1
RA 1
Z 0
RCODE 0
Questions: 1
Answers RRs: 1
Authority RRs: 0
Additional RRs: 0
Record: google
Record: com
Record Type: 1
QCLASS - Class: 1
start answer, authority, and additional sections
3
It's a pointer
Process finished with exit code 0
将其与命令行 DNS 查找工具进行比较
id 1329, opcode QUERY, rcode NOERROR, flags QR RD RA
;QUESTION
google.com. IN A
;ANSWER
google.com. 257 IN A 142.250.81.206
;AUTHORITY
;ADDITIONAL
我得到的结果似乎有效。
我的问题是我似乎无法解析答案部分的 NAME
。它似乎以一个毫无意义的指针开始。
显然我在这里做错了什么,但我不知道是什么。
我知道我问的是含糊不清的问题,但话又说回来,如果我知道问题出在哪里,我就不会来这里了。
我还使用 Wireshark 来拦截我所做的请求以确保响应正确。它似乎确实是正确的(我显然已经将 url 更改为 whosebug.com)
My problem is that I can't seem to parse the NAME in the answer section. It seems to start with a pointer which makes no sense.
我对这方面的了解可能比你少得多,但我想知道你为什么这么说? firstByte
告诉你有一个指针,下面的值 (0x0c) 显示了用于压缩目的的名称偏移量(如果我没记错的话)。 None 与 firstByte
相同字节中的其他位被设置为从偏移值的角度可以忽略