DNS Server Lab

Overview

DNS(Domain Name System)是互联网中用于将域名(例如www.example.com)转换为对应IP地址的系统。在互联网上,设备之间通信需要使用IP地址进行定位,但IP地址不便于人们记忆和使用。DNS充当了一个类似电话簿的角色,将易于记忆的域名映射到相应的IP地址,从而使得用户可以通过域名来访问网站或者发送电子邮件,而无需记住复杂的IP地址。当用户在浏览器中输入一个域名时,系统会通过DNS查询将域名解析为对应的IP地址,然后进行通信。DNS起到了极为重要的转换和定位功能,是互联网通信的基础。

在这个实验中,你的任务是实现一个搭建在OpenNetLab上的DNS服务器,该服务器具备拦截特定域名,以及返回域名对应IP的功能。

Getting Started

  1. 下载实验资源 ,解压后进入dns文件夹,其中包含基础的实验代码模板。实验代码包含如下文件:

    • main.py :本地调试运行文件。

    • ipconf.txt : 本地调试配置文件。

    • client.py :客户端文件,无需修改。

    • server.py :服务器文件, TODO 部分待编写。

    • dns_packet.py : DNS数据包解析和编码文件,无需修改。

    • testcases.json :本地评测配置文件。

    • tester :本地评测运行文件,使用说明见相关文档。

  2. 阅读实验任务,完成代码模板中 TODO 部分的代码片段。

  3. 进行本地测试,完成本地测试后将代码提交到OpenNetLab在线平台进行远程评测。

  4. 推荐实验环境:Linux操作系统,Python版本3.6以上。

Tasks

在这个实验中,服务器从配置文件 ipconf.txt 中读取 domain name --- IP address 的映射。你需要按照如下规则处理DNS请求:

  • Intercept:如果请求的DNS域名在配置文件的映射中并且对应的IP为 0.0.0.0 ,对该域名进行拦截,向客户端返回“域名不存在”的报错信息。

  • Local Resolve:如果请求的DNS域名在配置文件的映射中并且对应的IP是合法的,返回对应IP地址给客户端。

  • Relay:如果请求的DNS域名不在配置文件,将对应的DNS请求转发给公网上的DNS服务器,当收到该服务器的应答时,将应答转发给客户端。

该实验 TODO 部分的伪代码如下:

function recv_callback(data){
    # process DNS requests
    resolve data to DNS frame recvdp
    if recvdp is a query message{
        if recvdp.qname is in url_ip table{
            if url_ip[recvdp.qname]="0.0.0.0"{
                generate a reply error data
            }
            else{
                generate response data
            }
        }
        else{
            send query message to public DNS server
            receive data from public server
        }
        send data to client
    }
}

Tips

1.client.py和server.py中一些属性和方法的解释:

self.env

程序运行的环境。

self.debug

控制运行过程中日志信息输出,可以设置为True以方便调试。

self.proc

客户端的进程;

run(self, env)

在给定的环境中运行客户端。

@参数: env - 程序的运行环境

recv_callback(self, data)

接收并保存服务器发送的DNS应答数据包。使用 self.finish_channel.put(True) 来终止客户端的发送进程。

@参数: data - 接收到的数据

2.服务器通过socket与公共DNS服务器建立通信连接,以发送接收DNS数据包。以下代码片段表示服务器向上游DNS服务器(指定为”223.5.5.5”,port 53)发送DNS查询,并监听本地的1088端口得到查询结果。

self.name_server = ("223.5.5.5", 53)
self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.server_socket.bind(("", 1088))
self.server_socket.setblocking(True)

3.DNSClient类和DNSServer类都继承了UDPDevice类,服务器如何向客户端发送数据包可以参考client.py中如何发送DNS请求数据包。


Testing

  1. 进行本地测试

在本机运行 main.py 程序。 main.py 程序会使用本地的一个测试用例对DNS服务器的正确性进行评测并输出运行日志。

python3 main.py

Note

main.py 首先实例化类 Environment ,创建一个基于事件的网络模拟执行环境。然后 main.py 在模拟环境中实例化 DNSClient、DNSServer 类,并直接连接客户端、服务器的实例进行数据包传输。

完成程序基本功能的调试后,可以运行可执行文件 tester 进行多个测试用例评测,更详细的使用说明见 相关文档

  1. 提交代码进行远程评测