【问题标题】:What is the correct way to convert my IP Packet data into a String?将我的 IP 数据包数据转换为字符串的正确方法是什么?
【发布时间】:2018-08-14 13:45:57
【问题描述】:

当我收到带有我的 Android VpnService 的 IP 数据包时,我首先读取标头 (as here),然后尝试按如下方式打印接收到的数据:

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")));
}

结果如下:

数据包数据:����5��(��������������������www�google�com������

或者来自未加密网页的另一个例子:

数据包:IP 版本=4,标头长度=20,总长度=60,目标 IP=xx.xx.xxx.xx,主机名=yyyyy.zzz,源 IP=10.1.10.1,协议= 17、Data-Remaining=40

数据包数据:N���5��(@�F������������������m�posttimees�ee������

我尝试了几种不同的字符串编码类型,我认为这不是问题。

我错过了什么步骤?

【问题讨论】:

    标签: java android udp ip android-vpn-service


    【解决方案1】:

    我自己解决了这个问题。我需要的答案是在 this article 关于手写 DNS 数据包和 UDP protocol 以及 UDP 标头 as discussed here

    问题是上面解析的数据仍然包含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);
    

    并产生类似这样的输出:

    标题:
    IP 版本=4
    标头长度=20
    总长度=59
    目的地=88.88.888.88 / dns.mydns.net
    源 IP=10.1.10.1
    协议=17
    源端口=44444
    DestPortUdp=53
    QName=www.google.com
    Remaining-Data: null //为了理智

    【讨论】:

      猜你喜欢
      • 2014-03-18
      • 2011-09-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-24
      • 1970-01-01
      相关资源
      最近更新 更多