You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Java的DatagramSocket实现IP反查主机名的DNS解析器

问题描述

我已实现基于DNS服务器查询的解析器,并将其集成到HostResolutionRequestInterceptor组件中,但无法通过java.net.DatagramSocket根据IP地址获取所有主机名,也未能完成HostResolver接口的getAllHostNamesForHostAddress方法的实现。

以下是我编写的组件代码:

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

import org.burningwave.tools.net.HostResolver;
import org.burningwave.tools.net.IPAddressUtil;

public class IPV4DNSServerHostResolver implements HostResolver {
    private static Random requestIdGenerator;

    static {
        requestIdGenerator = new Random();
    }

    private InetAddress dNSServerIP;
    private int dNSServerPort;

    public IPV4DNSServerHostResolver(String dNSServerIP, int dNSServerPort) throws UnknownHostException {
        this.dNSServerIP = InetAddress.getByName(dNSServerIP);
        this.dNSServerPort = dNSServerPort;
    }

    @Override
    public Collection<InetAddress> getAllAddressesForHostName(Map<String, Object> argumentsMap) {
        return resolveHostForName((String)getMethodArguments(argumentsMap)[0]);
    }

    public Collection<InetAddress> resolveHostForName(String hostName) {
        try {
            Collection<InetAddress> addresses = new ArrayList<>();
            byte[] response = sendRequest(hostName);
            Map<String, String> iPToDomainMap = parseResponse(response);
            for (Map.Entry<String, String> iPToDomain : iPToDomainMap.entrySet()) {
                addresses.add(InetAddress.getByAddress(iPToDomain.getValue(), IPAddressUtil.INSTANCE.textToNumericFormat(iPToDomain.getKey())));
            }
            return addresses;
        } catch (Throwable exc) {
            return sneakyThrow(exc);
        }
    }

    private byte[] sendRequest(String hostName) throws IOException, SocketException {
        short ID = (short)requestIdGenerator.nextInt(32767);
        try (
            ByteArrayOutputStream requestContentStream = new ByteArrayOutputStream();
            DataOutputStream requestWrapper = new DataOutputStream(requestContentStream);
        ) {
            short requestFlags = Short.parseShort("0000000100000000", 2);
            ByteBuffer byteBuffer = ByteBuffer.allocate(2).putShort(requestFlags);
            byte[] flagsByteArray = byteBuffer.array();

            short QDCOUNT = 1;
            short ANCOUNT = 0;
            short NSCOUNT = 0;
            short ARCOUNT = 0;

            requestWrapper.writeShort(ID);
            requestWrapper.write(flagsByteArray);
            requestWrapper.writeShort(QDCOUNT);
            requestWrapper.writeShort(ANCOUNT);
            requestWrapper.writeShort(NSCOUNT);
            requestWrapper.writeShort(ARCOUNT);

            String[] domainParts = hostName.split("\\.");

            for (int i = 0; i < domainParts.length; i++) {
                byte[] domainBytes = domainParts[i].getBytes(StandardCharsets.UTF_8);
                requestWrapper.writeByte(domainBytes.length);
                requestWrapper.write(domainBytes);
            }
            requestWrapper.writeByte(0);
            requestWrapper.writeShort(1);
            requestWrapper.writeShort(1);
            byte[] dnsFrame = requestContentStream.toByteArray();
            DatagramPacket packet;
            byte[] response;
            try (DatagramSocket socket = new DatagramSocket()){
                DatagramPacket dnsReqPacket = new DatagramPacket(dnsFrame, dnsFrame.length, dNSServerIP, dNSServerPort);
                socket.send(dnsReqPacket);
                response = new byte[1024];
                packet = new DatagramPacket(response, response.length);
                socket.receive(packet);
            }
            return response;
        }
    }

    private Map<String, String> parseResponse(byte[] responseContent) throws IOException {
        try (InputStream responseContentStream = new ByteArrayInputStream(responseContent);
            DataInputStream responseWrapper = new DataInputStream(responseContentStream)
        ) {
            responseWrapper.skip(6);
            short ANCOUNT = responseWrapper.readShort();
            responseWrapper.skip(4);
            int recLen;
            while ((recLen = responseWrapper.readByte()) > 0) {
                byte[] record = new byte[recLen];
                for (int i = 0; i < recLen; i++) {
                    record[i] = responseWrapper.readByte();
                }
            }
            responseWrapper.skip(4);
            byte firstBytes = responseWrapper.readByte();
            int firstTwoBits = (firstBytes & 0b11000000) >>> 6;
            Map<String, String> ipToDomainMap = new HashMap<>();
            try (ByteArrayOutputStream label = new ByteArrayOutputStream();) {
                for(int i = 0; i < ANCOUNT; i++) {
                    if(firstTwoBits == 3) {
                        byte currentByte = responseWrapper.readByte();
                        boolean stop = false;
                        byte[] newArray = Arrays.copyOfRange(responseContent, currentByte, responseContent.length);
                        try (InputStream responseSectionContentStream = new ByteArrayInputStream(newArray);
                            DataInputStream responseSectionWrapper = new DataInputStream(responseSectionContentStream);
                        ) {
                            ArrayList<Integer> RDATA = new ArrayList<>();
                            ArrayList<String> DOMAINS = new ArrayList<>();
                            while(!stop) {
                                byte nextByte = responseSectionWrapper.readByte();
                                if(nextByte != 0) {
                                    byte[] currentLabel = new byte[nextByte];
                                    for(int j = 0; j < nextByte; j++) {
                                        currentLabel[j] = responseSectionWrapper.readByte();
                                    }
                                    label.write(currentLabel);
                                } else {
                                    stop = true;
                                    responseWrapper.skip(8);
                                    int RDLENGTH = responseWrapper.readShort();
                                    for(int s = 0; s < RDLENGTH; s++) {
                                        int nx = responseWrapper.readByte() & 255;
                                        RDATA.add(nx);
                                    }
                                }
                                DOMAINS.add(new String( label.toByteArray(), StandardCharsets.UTF_8));
                                label.reset();
                            }

                            StringBuilder ip = new StringBuilder();
                            StringBuilder domainSb = new StringBuilder();
                            for(Integer ipPart:RDATA) {
                                ip.append(ipPart).append(".");
                            }

                            for(String domainPart:DOMAINS) {
                                if(!domainPart.equals("")) {
                                    domainSb.append(domainPart).append(".");
                                }
                            }
                            String domainFinal = domainSb.toString();
                            String ipFinal = ip.toString();
                            ipToDomainMap.put(ipFinal.substring(0, ipFinal.length()-1), domainFinal.substring(0, domainFinal.length()-1));
                        }
                    }

                    firstBytes = responseWrapper.readByte();
                    firstTwoBits = (firstBytes & 0b11000000) >>> 6;
                }
            }
            return ipToDomainMap;
        }
    }

    @Override
    public Collection<String> getAllHostNamesForHostAddress(Map<String, Object> argumentsMap) {
        byte[] addressAsByteArray = (byte[])getMethodArguments(argumentsMap)[0];
        String iPAddress = IPAddressUtil.INSTANCE.numericToTextFormat(addressAsByteArray);
        //To be implemented
        return sneakyThrow(new UnknownHostException(iPAddress));
    }

    private <T> T sneakyThrow(Throwable exc) {
        throwException(exc);
        return null;
    }


    private <E extends Throwable> void throwException(Throwable exc) throws E {
        throw (E)exc;
    }

}

请问有没有人知道如何使用java.net.DatagramSocket通过IP地址获取所有主机名?


内容的提问来源于stack exchange,提问作者Edgar Becker

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 01:10:31