文章目录
一、DNS域名系统
1.DNS作用
DNS(Domain Name System 的缩写)的作用非常简单。将域名和ip相互映射,一般用于域名解析,就是根据域名查出IP地址。
- DNS使用udp端口53;
 - 域名的层级:域名由“.”进行划分,eg:
主机名.次级域名.顶级域名.根域名,最后一个“.”省略,默认由根管理; - 分级查询:输入一个网址(域名),首先会查找浏览器缓存,然后DNS服务器根据域名的层级,进行分级查询。dig命令的+trace参数可以显示DNS的整个分级查询过程。
 - DNS的记录类型:dns有一些type类型,决定了dns报文的处理,如A记录、AAAA记录、CNAME记录、MX记录、NS记录、TXT记录、SRV记录、URL转发。
 
2.查找过程
虽然只需要返回一个IP地址,但是DNS的查询过程非常复杂,分成多个步骤。
 工具软件dig可以显示整个查询过程。
root@ubuntu:~# dig www.baidu.com
# 第一部分:查询参数和统计
; <<>> DiG 9.10.3-P4-Ubuntu <<>> www.baidu.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 5575
;; flags: qr rd ra; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1
# 第二部分:查询内容
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;www.baidu.com.			IN	A
# 第三部分:DNS服务器的答复
# 显示www.baidu.com.有一个CNAME记录,以及www.a.shifen.com.有两个A记录
# 415、146是TTL值,表示缓存时间,即415s内不用重新查询
;; ANSWER SECTION:
www.baidu.com.		415	IN	CNAME	www.a.shifen.com.
www.a.shifen.com.	146	IN	A	14.215.177.38
www.a.shifen.com.	146	IN	A	14.215.177.39
# 第四部分:DNS服务器的一些传输信息
# 结果显示,本机DNS服务器是192.168.2.1,查询端口是53(DNS服务器默认端口),回应长度为101字节
;; Query time: 2 msec
;; SERVER: 192.168.2.1#53(192.168.2.1)
;; WHEN: Sat Apr 16 01:39:18 PDT 2022
;; MSG SIZE  rcvd: 104
 
若不想看到这么多内容,可使用+short参数
root@ubuntu:~# dig www.baidu.com +short
www.a.shifen.com.
14.215.177.39
14.215.177.38
 
上面命令只返回www.baidu.com对应的2个IP地址(即A记录)。
本机只向自己的DNS服务器查询,dig命令有一个@参数,显示向其他DNS服务器查询的结果。
$ dig @4.2.2.2 www.baidu.com
 
上面命令指定向DNS服务器4.2.2.2查询。
3.其他DNS工具
(1)host 命令
host命令可以看作dig命令的简化版本,返回当前请求域名的各种记录。
$ host github.com
github.com has address 192.30.252.121
github.com mail is handled by 5 ALT2.ASPMX.L.GOOGLE.COM.
github.com mail is handled by 10 ALT4.ASPMX.L.GOOGLE.COM.
github.com mail is handled by 10 ALT3.ASPMX.L.GOOGLE.COM.
github.com mail is handled by 5 ALT1.ASPMX.L.GOOGLE.COM.
github.com mail is handled by 1 ASPMX.L.GOOGLE.COM.
$ host facebook.github.com
facebook.github.com is an alias for github.map.fastly.net.
github.map.fastly.net has address 103.245.222.133
 
host命令也可以用于逆向查询,即从IP地址查询域名,等同于dig -x 。
$ host 192.30.252.153
153.252.30.192.in-addr.arpa domain name pointer pages.github.com.
 
(2)nslookup 命令
nslookup命令用于互动式地查询域名记录。
root@ubuntu:~# nslookup www.baidu.com
Server:		192.168.2.1
Address:	192.168.2.1#53
Non-authoritative answer:
www.baidu.com	canonical name = www.a.shifen.com.
Name:	www.a.shifen.com
Address: 14.215.177.39
Name:	www.a.shifen.com
Address: 14.215.177.38
 
学习一下从根域名解析ip的流程
root@ubuntu:~$ nslookup
> set type=ns    #设置域名解析服务器记录   进行查看
> .				 #查看根域名服务记录
Server:		192.168.0.1
Address:	192.168.0.1#53
Non-authoritative answer:   #中间缓存  不权威的
.	nameserver = m.root-servers.net.
.	nameserver = a.root-servers.net.
.	nameserver = l.root-servers.net.
.	nameserver = c.root-servers.net.
.	nameserver = d.root-servers.net.
.	nameserver = k.root-servers.net.
.	nameserver = j.root-servers.net.
.	nameserver = e.root-servers.net.
.	nameserver = g.root-servers.net.
.	nameserver = f.root-servers.net.
.	nameserver = b.root-servers.net.
.	nameserver = i.root-servers.net.
.	nameserver = h.root-servers.net.
Authoritative answers can be found from:
a.root-servers.net	internet address = 198.41.0.4
b.root-servers.net	internet address = 199.9.14.201
c.root-servers.net	internet address = 192.33.4.12
d.root-servers.net	internet address = 199.7.91.13
e.root-servers.net	internet address = 192.203.230.10
f.root-servers.net	internet address = 192.5.5.241
g.root-servers.net	internet address = 192.112.36.4
h.root-servers.net	internet address = 198.97.190.53
i.root-servers.net	internet address = 192.36.148.17
j.root-servers.net	internet address = 192.58.128.30
k.root-servers.net	internet address = 193.0.14.129
l.root-servers.net	internet address = 199.7.83.42
m.root-servers.net	internet address = 202.12.27.33
a.root-servers.net	has AAAA address 2001:503:ba3e::2:30
b.root-servers.net	has AAAA address 2001:500:200::b
> set type=a		#设置类型为a 查找ip
> a.root-servers.net.	#查看其中一个域名节点的ip
Server:		192.168.0.1
Address:	192.168.0.1#53
Non-authoritative answer:
Name:	a.root-servers.net
Address: 198.41.0.4
> server 198.41.0.4   #设置域名服务器
Default server: 198.41.0.4
Address: 198.41.0.4#53
> set type=ns		#查看根域名服务器
> com.				#在根域名服务器下请求,查看会发现只会去我们设置的server进行
Server:		198.41.0.4
Address:	198.41.0.4#53
Non-authoritative answer:
*** Cant find com.: No answer
Authoritative answers can be found from:
com	nameserver = a.gtld-servers.net.
com	nameserver = b.gtld-servers.net.
com	nameserver = c.gtld-servers.net.
com	nameserver = d.gtld-servers.net.
com	nameserver = e.gtld-servers.net.
com	nameserver = f.gtld-servers.net.
com	nameserver = g.gtld-servers.net.
com	nameserver = h.gtld-servers.net.
com	nameserver = i.gtld-servers.net.
com	nameserver = j.gtld-servers.net.
com	nameserver = k.gtld-servers.net.
com	nameserver = l.gtld-servers.net.
com	nameserver = m.gtld-servers.net.
a.gtld-servers.net	internet address = 192.5.6.30
b.gtld-servers.net	internet address = 192.33.14.30
c.gtld-servers.net	internet address = 192.26.92.30
d.gtld-servers.net	internet address = 192.31.80.30
e.gtld-servers.net	internet address = 192.12.94.30
f.gtld-servers.net	internet address = 192.35.51.30
g.gtld-servers.net	internet address = 192.42.93.30
h.gtld-servers.net	internet address = 192.54.112.30
i.gtld-servers.net	internet address = 192.43.172.30
j.gtld-servers.net	internet address = 192.48.79.30
k.gtld-servers.net	internet address = 192.52.178.30
l.gtld-servers.net	internet address = 192.41.162.30
m.gtld-servers.net	internet address = 192.55.83.30
a.gtld-servers.net	has AAAA address 2001:503:a83e::2:30
b.gtld-servers.net	has AAAA address 2001:503:231d::2:30
> server 192.5.6.30
Default server: 192.5.6.30
Address: 192.5.6.30#53
> set type=ns				#测试一个实际的域名
> bilibili.com
Server:		192.5.6.30
Address:	192.5.6.30#53
Non-authoritative answer:
*** Can't find bilibili.com: No answer
Authoritative answers can be found from:
bilibili.com	nameserver = ns3.dnsv5.com.
bilibili.com	nameserver = ns4.dnsv5.com.
ns3.dnsv5.com	internet address = 129.211.176.212
ns3.dnsv5.com	internet address = 162.14.18.188
ns3.dnsv5.com	internet address = 162.14.24.251
ns3.dnsv5.com	internet address = 162.14.25.251
ns3.dnsv5.com	internet address = 18.194.2.137
ns3.dnsv5.com	internet address = 183.192.201.94
ns3.dnsv5.com	internet address = 223.166.151.16
ns3.dnsv5.com	has AAAA address 2402:4e00:1430:1102:0:9136:2b2b:ba61
ns3.dnsv5.com	internet address = 52.77.238.92
ns3.dnsv5.com	internet address = 61.151.180.51
ns4.dnsv5.com	internet address = 101.226.220.12
ns4.dnsv5.com	internet address = 129.211.176.151
ns4.dnsv5.com	internet address = 162.14.24.248
ns4.dnsv5.com	internet address = 162.14.25.248
ns4.dnsv5.com	internet address = 183.192.164.119
ns4.dnsv5.com	internet address = 223.166.151.126
ns4.dnsv5.com	has AAAA address 2402:4e00:1020:1264:0:9136:29b6:fc32
ns4.dnsv5.com	internet address = 52.198.159.146
ns4.dnsv5.com	internet address = 59.36.120.147
> server 129.211.176.212			#设置com对应的顶级域名服务器
Default server: 129.211.176.212
Address: 129.211.176.212#53
> set type=a					#设置类型为a,查找对应ip
> www.bilibili.com.      		#查看ip,找到对应的内容分发域名
Server:		129.211.176.212
Address:	129.211.176.212#53
www.bilibili.com	canonical name = b.w.bilicdn1.com.
> b.w.bilicdn1.com.				#查看内容分发域名对应的ip,即是我们需要的ip 
Server:		129.211.176.212
Address:	129.211.176.212#53
Name:	b.w.bilicdn1.com
Address: 119.3.211.130
Name:	b.w.bilicdn1.com
Address: 119.3.231.166
Name:	b.w.bilicdn1.com
Address: 119.3.238.64
Name:	b.w.bilicdn1.com
Address: 119.3.229.89
Name:	b.w.bilicdn1.com
Address: 119.3.234.165
Name:	b.w.bilicdn1.com
Address: 119.3.227.169
 
这里获得的ip就会返回给我们本地的dns服务器并且缓存,发送给我们浏览器输入域名时,对应的程序,用ip进行实际请求。
(3)whois 命令
whois命令用来查看域名的注册情况。
$ whois github.com
 
二、DNS实现
dns是基于udp实现的。
1.实现思路
参考udp的协议头以及dns的协议头,构造对应的头结构,对DNS服务器进行数据请求,要能正常获取到返回的ip。
receive(接收udp包)
 ===> decode_msg(解析数据包)
 ===> resolve_query(查表)
 ===> encode_msg(打包)
 ===> send(发回包)
 
2.测试思路
- 直接使用udp socket api进行数据请求,构造符合dns协议的结构数据即可;
 - 解析收到的udp回复报文数据。获取到需要的ip即可。
 
三、两个开源DNS实现
1.dnspod-sr
#编译并运行
root@ubuntu:/root/dnspod-sr-master/src# ./dnspod-sr 
[DBG:] dnspod-sr is successfully running now!!
[DBG:] max_ele_size is 1000000 - 1808
[DBG:] server may contain 332730 useful records
[DBG:] hash_table_size is 65536
[DBG:] we have 10 hash tables
[DBG:] we have 2 fetchers,2 quizzers
 
在另外一个环境上用dig命令进行测试,dns服务器有学习的功能
root@ubuntu:/home/root# dig @192.168.105.143 www.bilibili.com
; <<>> DiG 9.10.3-P4-Ubuntu <<>> @192.168.105.143 www.bilibili.com
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 8662
;; flags: qr ra; QUERY: 1, ANSWER: 8, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;www.bilibili.com.		IN	A
;; ANSWER SECTION:
www.bilibili.com.	214	IN	CNAME	b.w.bilicdn1.com.
b.w.bilicdn1.com.	104	IN	A	120.92.113.99
b.w.bilicdn1.com.	104	IN	A	120.92.108.182
b.w.bilicdn1.com.	104	IN	A	120.92.83.126
b.w.bilicdn1.com.	104	IN	A	120.92.82.179
b.w.bilicdn1.com.	104	IN	A	120.92.211.159
b.w.bilicdn1.com.	104	IN	A	120.131.2.207
b.w.bilicdn1.com.	104	IN	A	120.92.78.97
;; Query time: 2951 msec
;; SERVER: 192.168.105.143#53(192.168.105.143)
;; WHEN: Sat Dec 25 16:50:18 CST 2021
;; MSG SIZE  rcvd: 173
 
使用dnsperf测试性能:
#安装dnsperf https://gitee.com/mirrors_DNS-OARC/dnsperf?_from=gitee_search
#注意按照第一种方式   版本包的安装,我用源码安装时有报错
#安装包下载地址https://www.dns-oarc.net/tools/dnsperf
tar -xvf dnsperf-2.9.0.tar.gz 
cd dnsperf-2.9.0
./configure 
make
make install
#写个配置文件 如下 
root@ubuntu:/root/dnsperf-2.9.0# cat testfile 
www.baidu.com A
www.bilibili.com A
#执行测试,可以分析结果
./src/dnsperf -d testfile -s 192.168.105.143 -c10000 -q10000 -l60
 
2.simpleDNS
下载:https://github.com/mwarning/SimpleDNS.git
启动该代码可执行文件,用dig请求进行查看:
#dig @192.168.105.143 -p 9000 foo.bar.com A
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 8362
;; flags: qr; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;foo.bar.com.			IN	A
;; ANSWER SECTION:
foo.bar.com.		3600	IN	A	192.168.1.1  #这个是测试代码中写死的域名(foo.bar.com)对应的ip
;; Query time: 0 msec
;; SERVER: 192.168.105.143#9000(192.168.105.143)
;; WHEN: Sat Dec 25 22:07:24 CST 2021
;; MSG SIZE  rcvd: 56
 
四、dpdk-dns
1.思路
- 使用dpdk提供的接口,接管udp的数据,对dns相关的请求做协议处理;
 - 参考simpleDNS逻辑,在已有的dpdk处理arp,udp, tcp的逻辑基础上,增加udp报文时,dns相关数据的处理;
 - 参考simpleDNS中的逻辑进行业务处理返回。
 
2.开启KNI回发
kni能够进行tx将数据送回内核处理,但是却不能得到从内核中回环的数据,即kni进行rx时却收不到数据。这时需要进行回环的处理:
 方法一:往“/sys/devices/virtual/net/%s/carrier”中写1,开启回环。
 方法二:插入KNI模块的时候,将carrier设置为on
root@ubuntu:~/share# cd dpdk/
root@ubuntu:~/share/dpdk# cd x86_64-native-linux-gcc/kmod/
root@ubuntu:~/share/dpdk/x86_64-native-linux-gcc/kmod# ls
igb_uio.ko  rte_kni.ko
root@ubuntu:~/share/dpdk/x86_64-native-linux-gcc/kmod# insmod rte_kni.ko carrier=on
 
方法三:代码中调用rte_kni_update_link,动态开启回发数据的功能。
3.dns数据的处理
if (UDP_PORT == ntohs(udp_hdr->dest_port))
{
#if ENABLE_DNS
	g_src_ip = ip_hdr->dst_addr;
	g_dest_ip == ip_hdr->src_addr;
	g_src_port = ntohs(udp_hdr->dst_port);
	g_dest_port = ntohs(udp_hdr->src_port);
	rte_memcpy(g_dest_mac_addr, ehdr->s_addr.addr_bytes, RTE_ETHER_ADDR_LEN);
	// udp userdata
	uint16_t length = ntohs(udp_hdr->dgram_len);
	uint16_t nbytes = length - sizeof(struct rte_udp_hdr);
	uint8_t *data = (uint8_t *)(udp_hdr + 1);
	// decode_msg
	free_questions(msg.questions);
	free_resource_records(msg.answers);
	free_resource_records(msg.authorities);
	free_resource_records(msg.additionals);
	memset(&msg, 0, sizeof(struct Message));
	decode_msg(&msg, data, nbytes);
	// resolve_query
	resolve_query(&msg);
	// encode_msg
	uint8_t *p = data;
	encode_msg(&msg, &p);
	// send_udp_pkt
	int len = p - data;
	do_send_udp(pktmbuf_pool, data, len);









