Java库解析DNS响应UDP包?

时间:2018-04-26 03:13:58

标签: java sockets 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);

但是我遇到的问题是我需要解析Hex响应并检索上述信息。我整个上午都在寻找,但我似乎无法找到任何能够解析这些信息的库。

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

干杯 科里

编辑:这是我的完整代码

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

1 个答案:

答案 0 :(得分:1)

你看过ifhttp://dnsjava.org/)了吗?它是一个高级DNS客户端,但您可以根据需要直接重用其内部部分进行数据包解析。

如果您的数据包来自UDP或TCP,则解析时几乎没有什么区别。 如果您查看dnsjava,可能会使用各种Record.java方法。另请参阅fromWire目录和utils/文件。

否则请返回规范:RFC1035第4部分为您提供有关如何格式化邮件的所有详细信息。它在两个方向上都是相同的结构。在您的具体情况下,您需要查看“答案”部分。确保不要忘记名称压缩,如§4.1.4所述。