将我的 IP 数据包数据转换为字符串的正确方法是什么?
What is the correct way to convert my IP Packet data into a String?
当我收到带有 Android VpnService I read the headers first () 的 IP 数据包时,我尝试按如下方式打印接收到的数据:
int lengthRemaining = packet.remaining();
if (lengthRemaining > 0) {
byte[] data = new byte[lengthRemaining];
packet.get(data, packet.arrayOffset(), lengthRemaining);
Log.d(TAG, "Packet-Data: " + new String(data, Charset.forName("UTF-8")));
}
结果如下:
Packet-Data: ����5��(��������������������www�google�com������
或者来自未加密网页的另一个示例:
Packet: IP Version=4, Header-Length=20, Total-Length=60, Destination-IP=xx.xx.xxx.xx, Hostname=yyyyy.zzz, Source-IP=10.1.10.1, Protocol=17, Data-Remaining=40
Packet-Data: N���5��(@�F�����������������m�postimees�ee������
我试过几种不同的字符串编码类型,我认为这不是问题所在。
我错过了哪一步?
我自己解决了这个问题。我需要的答案在 this article about handwriting DNS packets and the UDP protocol in addition to the UDP headers .
问题是上面解析出来的数据还包含UDP和DNS头,我们只解析了应用层头
以下代码将从 DNS 数据包中读取 DNS 域
int buffer = packet.get();
int ipVersion = buffer >> 4;
int headerLength = buffer & 0x0F; //the number of 32 bit words in the header
headerLength *= 4;
packet.get(); //DSCP + EN
int totalLength = packet.getChar(); //Total Length
packet.getChar(); //Identification
packet.getChar(); //Flags + Fragment Offset
packet.get(); //Time to Live
int protocol = packet.get(); //Protocol
packet.getChar(); //Header checksum
String sourceIP = "";
sourceIP += packet.get() & 0xFF; //Source IP 1st Octet
sourceIP += ".";
sourceIP += packet.get() & 0xFF; //Source IP 2nd Octet
sourceIP += ".";
sourceIP += packet.get() & 0xFF; //Source IP 3rd Octet
sourceIP += ".";
sourceIP += packet.get() & 0xFF; //Source IP 4th Octet
String destIP = "";
destIP += packet.get() & 0xFF; //Destination IP 1st Octet
destIP += ".";
destIP += packet.get() & 0xFF; //Destination IP 2nd Octet
destIP += ".";
destIP += packet.get() & 0xFF; //Destination IP 3rd Octet
destIP += ".";
destIP += packet.get() & 0xFF; //Destination IP 4th Octet
//NOTE: RFC diagram showed a byte of zeroes here, but it doesn't appear to match the implementation
//int supposedZeroes = packet.get();
//Log.d(TAG, "Supposed Zeroes: " + supposedZeroes);
int sourcePortUdp = packet.getChar();
int destPortUdp = packet.getChar();
packet.getChar(); //UDP Data Length
packet.getChar(); //UDP Checksum
//NOTE: DNS HEADERS INSIDE UDP DATA - https://routley.io/tech/2017/12/28/hand-writing-dns-messages.html
packet.getChar(); //DNS ID
packet.get(); //OPTIONS: QR + OPCODE + AA + TC + RD
packet.get(); //OPTIONS: Z + RCODE
packet.getChar(); //DNS QDCOUNT //number of entities/questions
packet.getChar(); //DNS ANCOUNT //num answers
packet.getChar(); //DNS NSCOUNT //num auth records
packet.getChar(); //DNS ARCOUNT //num additional records
//NOTE: QNAME is url encoded, in several separated sections, each preceded by an int saying the number of bytes
//NOTE: The QNAME section is terminated with a zero byte (00).
int qnameSectionByteCount = packet.get();
byte[] qnameBytes = new byte[0];
byte[] qnameSectionBytes;
int oldLength;
while (qnameSectionByteCount > 0 && qnameSectionByteCount <= packet.remaining()) {
qnameSectionBytes = new byte[qnameSectionByteCount];
packet.get(qnameSectionBytes);
//insert the bytes from the new section
oldLength = qnameBytes.length;
qnameBytes = Arrays.copyOf(qnameBytes, oldLength + qnameSectionBytes.length);
System.arraycopy(qnameSectionBytes, 0, qnameBytes, oldLength, qnameSectionBytes.length);
//get the byte that determines if there is another loop iteration
qnameSectionByteCount = packet.get();
//add a connecting dot if there will be another loop iteration
if (qnameSectionByteCount > 0) {
//add a dot
byte[] dot = ".".getBytes();
oldLength = qnameBytes.length;
qnameBytes = Arrays.copyOf(qnameBytes, oldLength + dot.length);
System.arraycopy(dot, 0, qnameBytes, oldLength, dot.length);
}
}
packet.getChar(); //QCLASS
packet.getChar(); //QCLASS
String destHostName;
try {
InetAddress addr = InetAddress.getByName(destIP);
destHostName = addr.getHostName();
} catch (UnknownHostException e) {
destHostName = "Unresolved";
}
int orphanDataLength = packet.remaining();
String dataStr = null;
if (orphanDataLength > 0) {
byte[] data = new byte[orphanDataLength];
packet.get(data, packet.arrayOffset(), orphanDataLength);
dataStr = new String(data, Charset.forName("UTF-8"));
}
Log.v(TAG, "---\nHeaders:\nIP Version=" + ipVersion + "\nHeader-Length=" + headerLength
+ "\nTotal-Length=" + totalLength + "\nDestination=" + destIP + " / "
+ destHostName + "\nSource-IP=" + sourceIP + "\nProtocol=" + protocol
+ "\nSource-Port=" + sourcePortUdp + "\nDestPortUdp=" + destPortUdp + "\nQname="
+ new String(qnameBytes, Charset.forName("UTF-8")) + "\nRemaining-Data: " + dataStr);
并产生类似这样的输出:
Headers:
IP Version=4
Header-Length=20
Total-Length=59
Destination=88.88.888.88 / dns.mydns.net
Source-IP=10.1.10.1
Protocol=17
Source-Port=44444
DestPortUdp=53
QName=www.google.com
Remaining-Data: null //for sanity
当我收到带有 Android VpnService I read the headers first (
int lengthRemaining = packet.remaining();
if (lengthRemaining > 0) {
byte[] data = new byte[lengthRemaining];
packet.get(data, packet.arrayOffset(), lengthRemaining);
Log.d(TAG, "Packet-Data: " + new String(data, Charset.forName("UTF-8")));
}
结果如下:
Packet-Data: ����5��(��������������������www�google�com������
或者来自未加密网页的另一个示例:
Packet: IP Version=4, Header-Length=20, Total-Length=60, Destination-IP=xx.xx.xxx.xx, Hostname=yyyyy.zzz, Source-IP=10.1.10.1, Protocol=17, Data-Remaining=40
Packet-Data: N���5��(@�F�����������������m�postimees�ee������
我试过几种不同的字符串编码类型,我认为这不是问题所在。
我错过了哪一步?
我自己解决了这个问题。我需要的答案在 this article about handwriting DNS packets and the UDP protocol in addition to the UDP headers
问题是上面解析出来的数据还包含UDP和DNS头,我们只解析了应用层头
以下代码将从 DNS 数据包中读取 DNS 域
int buffer = packet.get();
int ipVersion = buffer >> 4;
int headerLength = buffer & 0x0F; //the number of 32 bit words in the header
headerLength *= 4;
packet.get(); //DSCP + EN
int totalLength = packet.getChar(); //Total Length
packet.getChar(); //Identification
packet.getChar(); //Flags + Fragment Offset
packet.get(); //Time to Live
int protocol = packet.get(); //Protocol
packet.getChar(); //Header checksum
String sourceIP = "";
sourceIP += packet.get() & 0xFF; //Source IP 1st Octet
sourceIP += ".";
sourceIP += packet.get() & 0xFF; //Source IP 2nd Octet
sourceIP += ".";
sourceIP += packet.get() & 0xFF; //Source IP 3rd Octet
sourceIP += ".";
sourceIP += packet.get() & 0xFF; //Source IP 4th Octet
String destIP = "";
destIP += packet.get() & 0xFF; //Destination IP 1st Octet
destIP += ".";
destIP += packet.get() & 0xFF; //Destination IP 2nd Octet
destIP += ".";
destIP += packet.get() & 0xFF; //Destination IP 3rd Octet
destIP += ".";
destIP += packet.get() & 0xFF; //Destination IP 4th Octet
//NOTE: RFC diagram showed a byte of zeroes here, but it doesn't appear to match the implementation
//int supposedZeroes = packet.get();
//Log.d(TAG, "Supposed Zeroes: " + supposedZeroes);
int sourcePortUdp = packet.getChar();
int destPortUdp = packet.getChar();
packet.getChar(); //UDP Data Length
packet.getChar(); //UDP Checksum
//NOTE: DNS HEADERS INSIDE UDP DATA - https://routley.io/tech/2017/12/28/hand-writing-dns-messages.html
packet.getChar(); //DNS ID
packet.get(); //OPTIONS: QR + OPCODE + AA + TC + RD
packet.get(); //OPTIONS: Z + RCODE
packet.getChar(); //DNS QDCOUNT //number of entities/questions
packet.getChar(); //DNS ANCOUNT //num answers
packet.getChar(); //DNS NSCOUNT //num auth records
packet.getChar(); //DNS ARCOUNT //num additional records
//NOTE: QNAME is url encoded, in several separated sections, each preceded by an int saying the number of bytes
//NOTE: The QNAME section is terminated with a zero byte (00).
int qnameSectionByteCount = packet.get();
byte[] qnameBytes = new byte[0];
byte[] qnameSectionBytes;
int oldLength;
while (qnameSectionByteCount > 0 && qnameSectionByteCount <= packet.remaining()) {
qnameSectionBytes = new byte[qnameSectionByteCount];
packet.get(qnameSectionBytes);
//insert the bytes from the new section
oldLength = qnameBytes.length;
qnameBytes = Arrays.copyOf(qnameBytes, oldLength + qnameSectionBytes.length);
System.arraycopy(qnameSectionBytes, 0, qnameBytes, oldLength, qnameSectionBytes.length);
//get the byte that determines if there is another loop iteration
qnameSectionByteCount = packet.get();
//add a connecting dot if there will be another loop iteration
if (qnameSectionByteCount > 0) {
//add a dot
byte[] dot = ".".getBytes();
oldLength = qnameBytes.length;
qnameBytes = Arrays.copyOf(qnameBytes, oldLength + dot.length);
System.arraycopy(dot, 0, qnameBytes, oldLength, dot.length);
}
}
packet.getChar(); //QCLASS
packet.getChar(); //QCLASS
String destHostName;
try {
InetAddress addr = InetAddress.getByName(destIP);
destHostName = addr.getHostName();
} catch (UnknownHostException e) {
destHostName = "Unresolved";
}
int orphanDataLength = packet.remaining();
String dataStr = null;
if (orphanDataLength > 0) {
byte[] data = new byte[orphanDataLength];
packet.get(data, packet.arrayOffset(), orphanDataLength);
dataStr = new String(data, Charset.forName("UTF-8"));
}
Log.v(TAG, "---\nHeaders:\nIP Version=" + ipVersion + "\nHeader-Length=" + headerLength
+ "\nTotal-Length=" + totalLength + "\nDestination=" + destIP + " / "
+ destHostName + "\nSource-IP=" + sourceIP + "\nProtocol=" + protocol
+ "\nSource-Port=" + sourcePortUdp + "\nDestPortUdp=" + destPortUdp + "\nQname="
+ new String(qnameBytes, Charset.forName("UTF-8")) + "\nRemaining-Data: " + dataStr);
并产生类似这样的输出:
Headers:
IP Version=4
Header-Length=20
Total-Length=59
Destination=88.88.888.88 / dns.mydns.net
Source-IP=10.1.10.1
Protocol=17
Source-Port=44444
DestPortUdp=53
QName=www.google.com
Remaining-Data: null //for sanity