03 基于 java udp 做一个dns服务器 和 一个dns代理服务器

前言

这个也是 来自于一个朋友的需求 

最终的目的是实现一个 dns 代理服务器, 当然 这本质也是一个 dns 服务器 

并且 dns 代理服务器是依赖于 一个 dns 服务器的, 因此 顺便给一个 dns 服务器的 demo 

这里 主要是 基于 udp 的一个 dns 请求, 响应数据的交互 

 

 

dns 服务器 

一个基础的 dns 服务器 demo 如下 

为了方便测试, 可以将 端口改为 53, 然后使用 System.out.println 之类的进行调试 

package com.hx.test15;

import org.xbill.DNS.*;

import java.io.ByteArrayOutputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.nio.ByteBuffer;

/**
 * @author Jerry.X.He <970655147@qq.com>
 * @version 1.0
 * @date 2024-07-02 22:33
 */
public class Test25SimpleDnsServer {

    public static void main(String[] args) throws Exception {
        DatagramSocket socket = new DatagramSocket(8053);
        System.out.println("DNS Server listening on port 8053...");

        while (true) {
            byte[] receiveData = new byte[512];
            DatagramPacket requestPacket = new DatagramPacket(receiveData, receiveData.length);
            socket.receive(requestPacket);

            byte[] data = requestPacket.getData();
            int offset = requestPacket.getOffset();
            int length = requestPacket.getLength();

            Message request = new Message(ByteBuffer.wrap(data, offset, length));
            Message response = handleRequest(request);

            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            DNSOutput out = new DNSOutput();
            baos.write(out.toByteArray());
            baos.write(response.toWire());
            byte[] responseData = baos.toByteArray();

            DatagramPacket responsePacket = new DatagramPacket(responseData, responseData.length,
                    requestPacket.getAddress(), requestPacket.getPort());
            socket.send(responsePacket);
        }
    }

    private static Message handleRequest(Message request) throws Exception {
        Message response = new Message(request.getHeader().getID());
        response.getHeader().setFlag(Flags.QR);
        response.getHeader().setOpcode(Opcode.QUERY);

        Record question = request.getQuestion();
        if (question.getName().toString().startsWith("www.abc.com") && question.getType() == Type.A) {
            ARecord answer = new ARecord(question.getName(), DClass.IN, 300, InetAddress.getByName("172.0.0.2"));
            response.addRecord(answer, Section.ANSWER);
        } else {
            // apply default
        }

        return response;
    }


}

 

 

最终实现效果如下, dns 服务器中仅仅配置了 "www.abc.com" -> "172.0.0.2" 

因此 www.abc.com 能够拿到查询结果, www.baidu.com 拿不到查询结果 

 

 

dns 代理服务器

主需求是实现一个 dns 的代理服务器  

实现如下, 无非就是 代理发送一次 dns 的请求 到目标 dns 服务器, 拿到响应之后 响应给客户端 

package com.hx.test15;

import org.xbill.DNS.Message;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.nio.ByteBuffer;

/**
 * Test25JavaDnsForwardServer
 *
 * @author Jerry.X.He <970655147@qq.com>
 * @version 1.0
 * @date 2024-07-02 22:10
 */
public class Test25JavaDnsForwardServer {

    public static void main(String[] args) throws IOException {
        DatagramSocket serverSocket = new DatagramSocket(53);
        System.out.println("DNS Proxy Server listening on port 53...");

        while (true) {
            byte[] receiveData = new byte[512];
            DatagramPacket requestPacket = new DatagramPacket(receiveData, receiveData.length);
            serverSocket.receive(requestPacket);

            Message request = readMessage(requestPacket);
            Message response = proxyRequest(request);

            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            baos.write(response.toWire());
            byte[] responseData = baos.toByteArray();

            DatagramPacket responsePacket = new DatagramPacket(responseData, responseData.length,
                    requestPacket.getAddress(), requestPacket.getPort());
            serverSocket.send(responsePacket);
        }
    }

    private static Message readMessage(DatagramPacket packet) throws IOException {
        byte[] data = packet.getData();
        int offset = packet.getOffset();
        int length = packet.getLength();
        return new Message(ByteBuffer.wrap(data, offset, length));
    }

    private static Message proxyRequest(Message request) throws IOException {
        DatagramSocket upstreamSocket = new DatagramSocket();
        InetAddress upstreamAddress = InetAddress.getByName("127.0.0.1");
        int upstreamPort = 8053;

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        baos.write(request.toWire());
        byte[] requestData = baos.toByteArray();
        DatagramPacket upstreamRequest = new DatagramPacket(requestData, requestData.length, upstreamAddress, upstreamPort);
        upstreamSocket.send(upstreamRequest);

        byte[] upstreamResponseData = new byte[512];
        DatagramPacket upstreamResponse = new DatagramPacket(upstreamResponseData, upstreamResponseData.length);
        upstreamSocket.receive(upstreamResponse);

        Message response = new Message(ByteBuffer.wrap(upstreamResponseData, upstreamResponse.getOffset(), upstreamResponse.getLength()));
        upstreamSocket.close();
        return response;
    }


}

 

最终实现效果如下, dns 服务器中仅仅配置了 "www.abc.com" -> "172.0.0.2" 

因此 www.abc.com 能够拿到查询结果, www.baidu.com 拿不到查询结果 

如果 关闭 目标dns服务, 代理服务器会阻塞住 

 

 

完 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值