本地DNS服务器

本文介绍了一位初学者使用Python编写的本地DNS服务器,该服务器基于UDP并使用迭代方法工作。代码中未添加注释,仅对特定网址生效。服务器从13个根DNS服务器列表中随机选取一个开始迭代解析过程,最终将响应发送回客户端,并存入缓存。作者还提到使用第三方库dns.resolver可能更为简便。
摘要由CSDN通过智能技术生成

小菜鸡第一次拿python做作业
实现了一个简易的local dns server
使用迭代的方法
毫无注释,只对本部分网址有效
基于UDP
需要使用dig测试

  • 迭代原理图:
    在这里插入图片描述
    在这里插入图片描述
  • DNS 信息结构:
    在这里插入图片描述
    在这里插入图片描述

localDNS.py

# -*- coding: UTF-8 -*-

import socket
import dnslib


def local_DNS_Server():
    # List of records about the domain name and IPv4 address of Root DNS servers.
    root_DNS_servers=[
        ["A.root-servers.net",'198.41.0.4'],
        ["B.root-servers.net",'192.228.79.201'],
        ["C.root-servers.net",'192.33.4.12'],
        ["D.root-servers.net",'128.8.10.90'],
        ["E.root-servers.net",'192.203.230.10'],
        ["F.root-servers.net",'192.5.5.241'],
        ["G.root-servers.net",'192.112.36.4'],
        ["H.root-servers.net",'128.63.2.53'],
        ["I.root-servers.net",'192.36.148.17'],
        ["J.root-servers.net",'192.58.128.30'],
        ["K.root-servers.net",'193.0.14.129'],
        ["L.root-servers.net",'198.32.64.12'],
        ["M.root-servers.net",'202.12.27.33'],
    ]
    print("========================================================================\nList of root dns servers:")
    for root in root_DNS_servers:
        print(root[0] + "  " + root[1])
    print("===========================================")


    # Maintain a cache here.
    # cache[qname]=responseMessage
    cache = {}
    while True:  # Keep the local dns server working.
        serverSocket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        serverSocket.bind(('127.0.0.1', 12000))
        message, clientAddress = serverSocket.recvfrom(2048)
        # Parse DNS packet data and return DNSRecord instance.
        message_parse = dnslib.DNSRecord.parse(message)
        message_parse.header.set_rd(0)
        message = dnslib.DNSRecord.pack(message_parse)

        # Judge whether the query is already in the cache.
        if message_parse.q.qname in cache:
            responseMessage = cache[message_parse.q.qname]
            serverSocket.sendto(responseMessage, clientAddress)
        else:
            # Split the qname into ['com.', 'baidu.', 'www.']
            qname = str(message_parse.q.qname);
            qnamelist = qname.split(".")
            qnamelist.pop(len(qnamelist) - 1)  # ['www', 'baidu.', 'com']
            for i in range(0, len(qnamelist)):
                qnamelist[i] = qnamelist[i] + "."
            qnamelist.reverse()  # ['com.', 'baidu.', 'www.']
            # Select a root server from 13 root_DNS_servers randomly to begin the iteration.
            # I select ["A.root-servers.net",'198.41.0.4'] here.
            a = "A.root-servers.net"
            domain = ""
            # Do iterations, take www.baidu.com as an example:
            # 1. domain='com.' 2. domain='baidu.com' 3.domain='www.baidu.com'
            for i in qnamelist:
                domain = i + domain
                r = dnslib.DNSRecord.question(domain, qtype="NS")
                rr = r.send(a)
                res = dnslib.DNSRecord.parse(rr)
                # print(res)
                # print("==============================================")
                a = res.auth[0].rdata.__str__()
            domain = str(res.rr[0].rdata)
            r = dnslib.DNSRecord.question(domain, qtype="A")
            rr = r.send(a)
            res1 = dnslib.DNSRecord.parse(rr)
            # print(res1)

            # Get Answer list, for example and then add these answers to response packet:
            # ;; ANSWER SECTION:
            # www.a.shifen.com.       300     IN      A       14.215.177.38
            # www.a.shifen.com.       300     IN      A       14.215.177.39
            rrlist = res1.rr
            for i in rrlist:
                res.rr.append(i)
            # Modify some parameters of response packets
            res.header.id = message_parse.header.id  # Set the id of response packet same with query packet. (dig)
            res.header.ra = 1
            res.q.qtype = 1 # Type"A"
            # Clear the AUTHORITY SECTION and ADDITIONAL SECTION to make the response packet simpler.
            res.auth = []
            res.ar = []
            print("===========================================\n response packet:")
            print(res)
            # Send the response packet back to the terminal.
            serverSocket.sendto(res.pack(), clientAddress)
            # Add the response packet into the cache.
            cache[message_parse.q.qname] = res.pack()


if __name__ == '__main__':
    # dig @127.0.0.1 -p 12000 www.baidu.com
    # dig @127.0.0.1 -p 12000 www.sohu.com
    try:
        local_DNS_Server()
    except KeyboardInterrupt:
        pass

  • 测试:
    在这里插入图片描述
    在这里插入图片描述

  • pychram 结果:

  • 在这里插入图片描述
    在这里插入图片描述

  • 写在最后:
    花这么大力气来写,dns.resolver 他不香吗?

要使用 Python 编写一个 DNS 服务器,你可以使用 `dnspython` 库来处理 DNS 请求和响应。以下是一个简单的示例: 首先,确保你已经安装了 `dnspython` 库,可以使用以下命令进行安装: ``` pip install dnspython ``` 然后,创建一个 Python 脚本(例如 `dns_server.py`),并使用以下代码编写 DNS 服务器: ```python import dns.message import dns.resolver import dns.query from dnslib import DNSRecord, QTYPE def handle_dns_request(data): request = DNSRecord.parse(data) qname = str(request.q.qname) qtype = request.q.qtype # 查询真实的 DNS 服务器 resolver = dns.resolver.Resolver() response = resolver.query(qname, qtype) # 构建 DNS 响应 dns_response = DNSRecord(DNSHeader(id=request.header.id, qr=1, aa=1, ra=1), q=request.q) for answer in response: rrtype = QTYPE[answer.rdtype] dns_response.add_answer(RR(qname, getattr(QTYPE, rrtype), rdata=RDMAP[rrtype](answer.to_text()))) return dns_response.pack() # DNS 服务器地址和端口 server_address = '127.0.0.1' server_port = 53 # 创建 UDP socket 并监听指定地址和端口 sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.bind((server_address, server_port)) print(f"DNS server is running on {server_address}:{server_port}...") while True: data, addr = sock.recvfrom(1024) # 处理 DNS 请求 response_data = handle_dns_request(data) # 发送 DNS 响应 sock.sendto(response_data, addr) ``` 这个示例使用了 `dnspython` 和 `dnslib` 库来处理 DNS 请求和响应。它接收来自客户端的 DNS 请求,并将其转发到真实的 DNS 服务器上进行查询,然后将查询结果返回给客户端。 请注意,上述示例仅提供了一个基本的框架,你可能需要根据实际情况做出适当的修改和扩展。例如,添加错误处理、缓存功能等。 运行上述脚本后,你可以将你的计算机的 DNS 设置为 `127.0.0.1`,以便使用你编写的 DNS 服务器进行域名解析。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值