Skip to content
This repository has been archived by the owner on Dec 11, 2024. It is now read-only.

Latest commit

 

History

History
97 lines (65 loc) · 4.3 KB

diary.md

File metadata and controls

97 lines (65 loc) · 4.3 KB

开发日志

Part0 选题

其实我选题是排除法选择的(因为什么都不会),以下是心理过程:

  1. MiniNginx?好玩,打开看看;CPP?打扰了,下一位
  2. OrangeDB?有意思,打开看看;使用底层语言?打扰了,下一位
  3. 迷宫?因缺思厅,打开看看;疑似有点思路了(用docker控制容器io+python交互);写不出来迷宫生成,下一位
  4. DNS协议?不选也没得选了;做着做着貌似还挺好玩,遂确定了选题

Part1 DNS协议

由于网上的文章要不过于复杂,充斥着难以理解的名词、要不过于简单,只是拿来糊弄小孩的,所以我选择先实践,后面遇到问题再相应搜索

经过一些抓包,我理解了部分dns请求的组成部分

0. UDP与TCP的区别

TCP请求在头部增添了2字节的总长度标签

1. 1字节的请求id

随机,用来区分多个结果

2. 1字节的标志

解码为二进制后用来标记请求,具体各个标记的意义如下表

具体需要关注的有:
	
	1. Response:0表示查询数据包,1表示回复
	2. Recursion Desired:是否需要服务器代为完成递归查询,若为1则服务器只返回最终结果;为0则只返回下一级ns服务器/结果
	3. Reply code:回复数据包所包含的信息,0000表示成功,0011表示查无此域

3. 4*2字节的数量标记,分别为:

1. Questions:问题数量(通常为1)
2. Answer RRs:标准应答数量
3. Authority RRs:权威应答数量
4. Additional RRs:额外应答数量

4. 问题部分

对于每个问题,包含以下三个参数

1. Name:域名,不定长
2. Type:查询记录的种类,2字节
3. Class:记录类别(在internet上均为1),2字节

其中,对于域名,有如下分割方法:

1. 以.为分界,将域名拆分为不同级别
2. 在每个级别前加上1字节的长度标记
3. 在结束后以长度标记00作为末尾

5. 普通应答

应答组成部分有:域名、查询类型、类别、TTL(有效时间)、数据长度(rdlength)、数据体。

其中前三个部分编码方式与查询类似

需要注意的是,在回复数据包中,可能出现4个字节的指针,具体表现为:
1. 转码为2进制后最高两位为11
2. 其余14为二进制转为10进制后是指向数据的起始位置(距离数据包开头的字节数)
3. 可能出现指针指向指针的情况(如记录1指向查询1,而记录2指向记录1)

此时需要特殊处理

TTL是4字节的数据,代表缓存有效期最长的秒数

数据包

  1. 对于A记录,有4*1字节的数据,分别代表记录IP的ABCD段,以.分割,无需特殊处理
  2. 对于TXT记录,可能出现一个记录中有多个tag的情况,此时需要依据总长度(rdlength)以及每个tag前1字节的长度切割数据
  3. 对于AAAA记录,有8*2字节的数据,分别代表ipv6一个段,以:分割,注意ipv6有化简形式(若整段为0则省略,否则省略一段开头的0)
  4. 对于CNAME,编码方式与查询中域名相同
  5. 对于MX,存在一个2字节的优先级字段,代表该服务器在收信时的优先级,随后跟随服务器域名,编码方式相同
  6. 对于NS,编码方式与查询中域名相同

需要注意,查询A AAAA MX TXT时,有可能返回CNAME记录(代表此域名为CNAME类型)

6. 权威应答

在进行迭代查询时,服务器会将下一级名词服务器的地址包含在权威应答部分中。其数据格式与数据包中ns类型相同

一些dns服务器会在查询无果时在此部分插入SOA记录

7. 额外应答

包含edns等信息,不做处理

Part2 缓存

得益于Python优秀的封装库,我使用最常规的dict存储查询信息。key为一个包含(域名,查询类型)的tuple,value为记录的list

对于持久化保存,我选择使用pickle自动dump整个dict,并且能很方便的load

Part3 命令行参数

使用argparse库处理命令行参数,方便快捷。

Part4 socket通信

值得一提的部分:在服务器收到请求后将数据以yield返回,保证可以连续处理 但间接导致的问题是无法扩展多线程,可能在后续需要将处理部分改写为新建进程