Java库解析DNS响应UDP数据包



我正在大学编写一门网络课程的作业,我必须在其中手动将DNS查询发送到DNS服务器,然后处理响应以获取邮件服务器,IPv4和IPv6地址以及其他一些内容。在作业规格中,它说我可以使用我想解析DNS响应数据包的任何库,但是我似乎找不到Java的一个。

我正在发送我的DNS请求并得到这样的回复:

int port = 53;
    dnsIP = "8.8.8.8"; // TODO HARDCODED
    DatagramSocket socket;
    // DNS REQUEST
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    DataOutputStream dos = new DataOutputStream(baos);
    dos.writeShort(0x1234);
    // Write Query Flags
    dos.writeShort(0x0100);
    // Question Count: Specifies the number of questions in the Question section of the message.
    dos.writeShort(0x0001);
    // Answer Record Count: Specifies the number of resource records in the Answer section of the message.
    dos.writeShort(0x0000);
    // Authority Record Count: Specifies the number of resource records in the Authority section of 
    // the message. (“NS” stands for “name server”)
    dos.writeShort(0x0000);
    // Additional Record Count: Specifies the number of resource records in the Additional section of the message.
    dos.writeShort(0x0000);        
    String[] domainParts = hostName.split("\.");
    System.out.println(hostName + " has " + domainParts.length + " parts");
    for (int i = 0; i<domainParts.length; i++) {
        System.out.println("Writing: " + domainParts[i]);
        byte[] domainBytes = domainParts[i].getBytes("UTF-8");
        dos.writeByte(domainBytes.length);
        dos.write(domainBytes);
    }
 // No more parts
    dos.writeByte(0x00);
    // Type 0x01 = A (Host Request)
    dos.writeShort(0xFF);
    // Class 0x01 = IN
    dos.writeShort(0x0001);
    byte[] dnsFrame = baos.toByteArray();
    System.out.println("Sending: " + dnsFrame.length + " bytes");
    for (int i =0; i< dnsFrame.length; i++) {
        System.out.print("0x" + String.format("%x", dnsFrame[i]) + " " );
    }
    socket = new DatagramSocket();
    DatagramPacket dnsRequestPacket = new DatagramPacket(dnsFrame, dnsFrame.length, InetAddress.getByName(dnsIP), port);
    socket.send(dnsRequestPacket);
    byte[] buffer = new byte[1024];
    DatagramPacket dnsResponsePacket = new DatagramPacket(buffer, buffer.length);
    socket.receive(dnsResponsePacket);

但是,我的问题是我需要解析十六进制的响应并检索上述信息。我整个早上都在寻找,但我似乎找不到任何能够解析此信息的库。

如果有人知道一个好的图书馆或我可以自己解析的方式,我会非常感谢。

欢呼科里

编辑:这是我的完整代码

package coms3200A2;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import java.awt.BorderLayout;
import java.awt.Color;
import javax.swing.JTextField;
import javax.swing.SpringLayout;
import javax.swing.JLabel;
import javax.swing.JButton;
import java.awt.Font;
public class AppHome {
    private JFrame frame;
    private JTextField DNSServerInput;
    private JTextField hostDomainInput;
    JTabbedPane tabbedPane;
    SpringLayout sl_DNSSearch;
    SpringLayout s2_RDNSSearch;
    JPanel DNSSearch;
    JPanel RDNSSearch;
    JLabel DNSServerLabel;
    JLabel hostDomainLabel;
    JButton submitDNS;
    JLabel DNSErrorsLabel;
    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    AppHome window = new AppHome();
                    window.frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }
    /**
     * Create the application.
     */
    public AppHome() {
        initialize();
    }
    /**
     * Initialize the contents of the frame.
     */
    private void initialize() {
        frame = new JFrame();
        frame.setBounds(0, 0, 1400, 900);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        tabbedPane = new JTabbedPane(JTabbedPane.TOP);
        sl_DNSSearch = new SpringLayout();
        s2_RDNSSearch = new SpringLayout();
        DNSSearch = new JPanel(sl_DNSSearch);
        RDNSSearch = new JPanel(s2_RDNSSearch);
        // TODO TESTING
        DNSSearch.setBackground(Color.LIGHT_GRAY);
        RDNSSearch.setBackground(Color.GRAY);
        // DNS SEARCH
        tabbedPane.addTab("DNS Search", DNSSearch);
        DNSServerLabel = new JLabel("DNS Server: ");
        sl_DNSSearch.putConstraint(SpringLayout.NORTH, DNSServerLabel, 10, SpringLayout.NORTH, DNSSearch);
        sl_DNSSearch.putConstraint(SpringLayout.WEST, DNSServerLabel, 10, SpringLayout.WEST, DNSSearch);
        DNSSearch.add(DNSServerLabel);
        hostDomainLabel = new JLabel("Host/Domain name: ");
        sl_DNSSearch.putConstraint(SpringLayout.NORTH, hostDomainLabel, 21, SpringLayout.SOUTH, DNSServerLabel);
        sl_DNSSearch.putConstraint(SpringLayout.WEST, hostDomainLabel, 0, SpringLayout.WEST, DNSServerLabel);
        DNSSearch.add(hostDomainLabel);
        DNSServerInput = new JTextField();
        sl_DNSSearch.putConstraint(SpringLayout.NORTH, DNSServerInput, -3, SpringLayout.NORTH, DNSServerLabel);
        sl_DNSSearch.putConstraint(SpringLayout.WEST, DNSServerInput, 115, SpringLayout.EAST, DNSServerLabel);
        DNSSearch.add(DNSServerInput);
        DNSServerInput.setColumns(30);
        hostDomainInput = new JTextField();
        sl_DNSSearch.putConstraint(SpringLayout.NORTH, hostDomainInput, -3, SpringLayout.NORTH, hostDomainLabel);
        sl_DNSSearch.putConstraint(SpringLayout.WEST, hostDomainInput, 0, SpringLayout.WEST, DNSServerInput);
        DNSSearch.add(hostDomainInput);
        hostDomainInput.setColumns(30);
        submitDNS = new JButton("Submit");
        sl_DNSSearch.putConstraint(SpringLayout.NORTH, submitDNS, 46, SpringLayout.SOUTH, hostDomainInput);
        sl_DNSSearch.putConstraint(SpringLayout.EAST, submitDNS, 0, SpringLayout.EAST, DNSServerInput);
        DNSSearch.add(submitDNS);
        DNSErrorsLabel = new JLabel(""errors here"");
        sl_DNSSearch.putConstraint(SpringLayout.NORTH, DNSErrorsLabel, 83, SpringLayout.SOUTH, hostDomainLabel);
        sl_DNSSearch.putConstraint(SpringLayout.WEST, DNSErrorsLabel, 0, SpringLayout.WEST, DNSServerLabel);
        DNSErrorsLabel.setFont(new Font("Arial", Font.PLAIN, 20));
        DNSErrorsLabel.setForeground(Color.RED);
        DNSSearch.add(DNSErrorsLabel);
        // REVERSE DNS SEARCH
        tabbedPane.addTab("Reverse DNS Search", RDNSSearch);
        frame.getContentPane().add(tabbedPane, BorderLayout.CENTER);
        submitDNS.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                try {
                    processDNSSearch(DNSServerInput.getText(), hostDomainInput.getText());
                } catch (Exception e2) {
                    e2.printStackTrace();
                    DNSErrorsLabel.setText("Error: " + e2.getMessage());
                }
            }
        });
    }
    private void processDNSSearch(String dnsServer, String hostName) throws IOException {
        String dnsIP = dnsServer;
        int port = 53;
        dnsIP = "8.8.8.8"; // TODO HARDCODED
        DatagramSocket socket;
        // DNS REQUEST
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        DataOutputStream dos = new DataOutputStream(baos);
        dos.writeShort(0x1234);
        // Write Query Flags
        dos.writeShort(0x0100);
        // Question Count: Specifies the number of questions in the Question section of the message.
        dos.writeShort(0x0001);
        // Answer Record Count: Specifies the number of resource records in the Answer section of the message.
        dos.writeShort(0x0000);
        // Authority Record Count: Specifies the number of resource records in the Authority section of 
        // the message. (“NS” stands for “name server”)
        dos.writeShort(0x0000);
        // Additional Record Count: Specifies the number of resource records in the Additional section of the message.
        dos.writeShort(0x0000);        
        String[] domainParts = hostName.split("\.");
        System.out.println(hostName + " has " + domainParts.length + " parts");
        for (int i = 0; i<domainParts.length; i++) {
            System.out.println("Writing: " + domainParts[i]);
            byte[] domainBytes = domainParts[i].getBytes("UTF-8");
            dos.writeByte(domainBytes.length);
            dos.write(domainBytes);
        }
     // No more parts
        dos.writeByte(0x00);
        // Type 0x01 = A (Host Request)
        dos.writeShort(0xFF);
        // Class 0x01 = IN
        dos.writeShort(0x0001);
        byte[] dnsFrame = baos.toByteArray();
        System.out.println("Sending: " + dnsFrame.length + " bytes");
        for (int i =0; i< dnsFrame.length; i++) {
            System.out.print("0x" + String.format("%x", dnsFrame[i]) + " " );
        }
        socket = new DatagramSocket();
        DatagramPacket dnsRequestPacket = new DatagramPacket(dnsFrame, dnsFrame.length, InetAddress.getByName(dnsIP), port);
        socket.send(dnsRequestPacket);
        byte[] buffer = new byte[1024];
        DatagramPacket dnsResponsePacket = new DatagramPacket(buffer, buffer.length);
        socket.receive(dnsResponsePacket);
        System.out.println("nReceived: " + dnsResponsePacket.getLength() + " bytes");
        for (int i = 0; i < dnsResponsePacket.getLength(); i++) {
            //System.out.print(" 0x" + buffer + " " );
            System.out.print(" 0x" + String.format("%x", buffer[i]) + " " );
        }
        System.out.println("n");

        DataInputStream din = new DataInputStream(new ByteArrayInputStream(buffer));
        System.out.println("Transaction ID: 0x" + String.format("%x", din.readShort()));
        System.out.println("Flags: 0x" + String.format("%x", din.readShort()));
        System.out.println("Questions: 0x" + String.format("%x", din.readShort()));
        System.out.println("Answers RRs: 0x" + String.format("%x", din.readShort()));
        System.out.println("Authority RRs: 0x" + String.format("%x", din.readShort()));
        System.out.println("Additional RRs: 0x" + String.format("%x", din.readShort()));
        int recLen = 0;
        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, "UTF-8"));
        }
        System.out.println("Record Type: 0x" + String.format("%x", din.readShort()));
        System.out.println("Class: 0x" + String.format("%x", din.readShort()));
        System.out.println("Field: 0x" + String.format("%x", din.readShort()));
        System.out.println("Type: 0x" + String.format("%x", din.readShort()));
        System.out.println("Class: 0x" + String.format("%x", din.readShort()));
        System.out.println("TTL: 0x" + String.format("%x", din.readInt()));
        short addrLen = din.readShort();
        System.out.println("Len: 0x" + String.format("%x", addrLen));
        System.out.print("Address: ");
        for (int i = 0; i < addrLen; i++ ) {
            System.out.print("" + String.format("%d", (din.readByte() & 0xFF)) + ".");
        }
    }
}
enter code here

您是否查看了dnsjava(http://dnsjava.org/(?这是一个高级DNS客户端,但您可能可以直接重用其内部部分,以根据您的需要进行解析。

如果您的数据包来自UDP或TCP,则在解析方面几乎没有什么不同。如果您查看Record.java,则可能有各种fromWire方法可能有用。另请参见utils/目录和DNSInput.java文件。

否则返回规格:RFC1035第4节为您提供有关如何格式化的所有详细信息。这是两个方向上相同的结构。在您的具体情况下,您需要戳戳"答案"部分。确保不要忘记§4.1.4。

中概述的名称压缩。

最新更新