dnspython是python 实现的一个dns场景的工具包。
pip install dnspython
将网站与IP地址相互关联在一起 就叫DNS
一个网站语句其实有自己转悠的格式,这个完整的格式叫FQDN(完全限定域名),从逻辑上准确地表示出互联网上的主机在什么地方。
格式:
主机名.网站名.二级域.顶级域.(根域)
使用:
主机名 - 为了识别公司网站主机,定制的名称 - 一般在内部使用
网站名 - 给大部分人使用的
IPV4的根DNS服务器 全球一共13台(中国没有)
IPV6的根DNS服务器全球一共25台
本地主机、本地DNS服务器、其他DNS服务器
本地主机:
1 用户浏览器输入网站域名
2 查找浏览器缓存,如果找不到的话
3 找本地的hosts文件,如果找不到的话
本地DNS:
4 找本地的DNS服务器,如果没有缓存记录
5 找根域服务器,13台,绝对可以找到顶级域DNS服务器,返回给LDNS
6 LDNS根据信息,找对应顶级域DNS,返回二级域DNS服务器
7 LDNS根据信息,找对应的二级域DNS服务器,找到网站名,返回给LDNS
8 LDNS在本地缓存一份信息,然后返回给客户端主机
其他主机
9 客户端主机根据返回的信息,本地留存记录,然后访问对应的IP地址
10 TCP三次握手,HTTP联通流程,和web服务器建立连接
11 web服务器返回数据给客户端,如果涉及到其他内部主机
12 找本地的hosts文件,找到对应的域名映射的内部ip地址,发起二次请求
13 获取数据后,本地留存一份,原路返回给客户端主机
14 直到HTTP连接断开,tcp连接断开
递归查询 - 班上同学传递小纸条
客户端主机 - LDNS
迭代查询 - 家长去网吧找孩子
LDNS - 其他所有DNS服务器
所谓的记录,其实是满足不同业务场景的dns名称查询方式
-- 一般在DNS服务器上进行配置
SOA 位移的权威服务器记录
A 最常见的,正向解析记录 你给我一个域名,我把ip地址给你
NS nameserver 服务器记录
MX
CNAME 别名记录,公司内部用的比较多
PTR 这个是反解析记录,一般不用
主要应用场景 - 查询解析场景
查询方法- query
qname 指定查询的名称
rdtype 指定查询的类型 默认是A记录
rdclass 指定查询的网络类型 默认是 IN
tcp 是否启用tcp查询模式
source 和source_port 指定 查询用的源地址和端口
raise_on_no_answer 查询无结果的时候,是否需要抛出异常
lifetime 声明周期配置参数,采用默认值
域名解析对象
response对象
answer对象
items对象
address对象
# 导包
import dns.resolver
domain = input("请输入域名地址:") # 输入域名地址
# 2 获取解析对象
query_object = dns.resolver.resolve(qname = domain, rdtype = 'A') # 指定查询记录为A型
print("查询对象:{}".format(query_object))
# 3 查看response 对象
response_object = query_object.response
print("应答对象:{}".format(response_object))
# 4 查看answer对象
answer_object = response_object.answer
print("解析对象:{}".format(answer_object))
# 5 查看解析条目对象
answer_object = response_object.answer
for query_item in answer_object:
print("查询条目:{}".format(query_item))
# 6 查询解析后的记录条目
query_item = response_object.answer[1]
for item in query_item.items:
print("解析记录:{}".format(item))
# 7 查看解析后的记录条目
query_item = response_object.answer[1]
for item in query_item.items:
print("解析地址:{}".format(item.address))
运行结果如下:
请输入域名地址:www.baidu.com
查询对象:<dns.resolver.Answer object at 0x7f8eaf374c70>
应答对象:id 28029
opcode QUERY
rcode NOERROR
flags QR RD RA
edns 0
payload 65494
;QUESTION
www.baidu.com. IN A
;ANSWER
www.baidu.com. 359 IN CNAME www.a.shifen.com.
www.a.shifen.com. 273 IN A 220.181.38.149
www.a.shifen.com. 273 IN A 220.181.38.150
;AUTHORITY
;ADDITIONAL
解析对象:[<DNS www.baidu.com. IN CNAME RRset: [<www.a.shifen.com.>]>, <DNS www.a.shifen.com. IN A RRset: [<220.181.38.149>, <220.181.38.150>]>]
查询条目:www.baidu.com. 359 IN CNAME www.a.shifen.com.
查询条目:www.a.shifen.com. 273 IN A 220.181.38.149
www.a.shifen.com. 273 IN A 220.181.38.150
解析记录:220.181.38.149
解析记录:220.181.38.150
解析地址:220.181.38.149
解析地址:220.181.38.150
或者直接
import dns.resolver
domain = input("请输入域名地址:") # 输入域名地址
query_object = dns.resolver.resolve(qname = domain, rdtype = 'A')
for query_item in query_object.response.answer:
for item in query_item.items:
print("{}的A记录解析地址有:{}".format(domain,item))
这样子我们就将www.baidu.com的域名解析出来了。
除此之外,我们可以在调试窗口中看一下变量i是什么。
实现MX记录查询方法示例,在上面提到了是用于邮箱解析的,所以我们以QQ邮箱为例。
domain = input('Input an domain:')
# 2-1 获取解析对象
query_object = dns.resolver.resolve(domain,'MX')
print('MX记录的结果:{}'.format(query_object))
# 2-2 从应答的response中获取查询记录
resp_object = query_object.response
print('MX记录的结果:{}'.format(resp_object))
# 2-3 从应答的answer中获取查询目录
answer_object = resp_object.answer
print('MX记录的结果:{}'.format(answer_object))
# 2-4 查看解析条目对象
answer_object = resp_object.answer
for query_item in answer_object:
print('查询条目:{}'.format(query_item))
# 2-5 查看解析后的记录条目
query_item = resp_object.answer[0]
for item in query_item.items:
print('查询条目:{}'.format(item))
# 2-6 查看解析后的记录条目-详细
query_item = resp_object.answer[0]
for item in query_item.items:
print('邮件服务器权重:{},邮件服务器地址:{}'.format(item.preference,item.exchange))
结果如下:
Input an domain:126.com
126.com
MX记录的结果:<dns.resolver.Answer object at 0x7f31cf9f0700>
MX记录的结果:id 64572
opcode QUERY
rcode NOERROR
flags QR RD RA
edns 0
payload 65494
;QUESTION
126.com. IN MX
;ANSWER
126.com. 6754 IN MX 10 126mx02.mxmail.netease.com.
126.com. 6754 IN MX 50 126mx00.mxmail.netease.com.
126.com. 6754 IN MX 10 126mx01.mxmail.netease.com.
126.com. 6754 IN MX 10 126mx03.mxmail.netease.com.
;AUTHORITY
;ADDITIONAL
MX记录的结果:[<DNS 126.com. IN MX RRset: [<10 126mx02.mxmail.netease.com.>, <50 126mx00.mxmail.netease.com.>, <10 126mx01.mxmail.netease.com.>, <10 126mx03.mxmail.netease.com.>]>]
查询条目:126.com. 6754 IN MX 10 126mx02.mxmail.netease.com.
126.com. 6754 IN MX 50 126mx00.mxmail.netease.com.
126.com. 6754 IN MX 10 126mx01.mxmail.netease.com.
126.com. 6754 IN MX 10 126mx03.mxmail.netease.com.
查询条目:10 126mx02.mxmail.netease.com.
查询条目:50 126mx00.mxmail.netease.com.
查询条目:10 126mx01.mxmail.netease.com.
查询条目:10 126mx03.mxmail.netease.com.
邮件服务器权重:10,邮件服务器地址:126mx02.mxmail.netease.com.
邮件服务器权重:50,邮件服务器地址:126mx00.mxmail.netease.com.
邮件服务器权重:10,邮件服务器地址:126mx01.mxmail.netease.com.
邮件服务器权重:10,邮件服务器地址:126mx03.mxmail.netease.com.
其中我们可以看到preference值(优先级)和exchange值(交换地址),其中优先级默认为10,MX记录可以通过设置优先级实现主辅服务器设置,”优先级”中的数字越小表示级别越高,“优先级”仅对MX记录有效。
实践:
domain = input('Input an domain:')
query_object = dns.resolver.resolve(domain,'MX')
for query_item in query_object.response.answer:
for item in query_item.items:
print('邮件服务器权重:{},邮件服务器地址:{}'.format(item.preference,item.exchange))
结果如下:
Input an domain:126.com
126.com
邮件服务器权重:10,邮件服务器地址:126mx02.mxmail.netease.com.
邮件服务器权重:50,邮件服务器地址:126mx00.mxmail.netease.com.
邮件服务器权重:10,邮件服务器地址:126mx01.mxmail.netease.com.
邮件服务器权重:10,邮件服务器地址:126mx03.mxmail.netease.com.
NS记录示例代码如下:
import dns.resolver
domain = input('Input an domain:')
NS = dns.resolver.resolve(domain, 'NS')
for i in NS.response.answer:
for j in i.items:
print(j.to_text())
运行结果如下:
>>> Input an domain> baidu.com
dns.baidu.com.
ns3.baidu.com.
ns4.baidu.com.
ns2.baidu.com.
ns7.baidu.com.
NS(Name Server)域名服务器记录。用来表明由哪台服务器对该域名进行解析。在注册域名时,总有默认的DNS服务器,每个注册的域名都是由一个DNS域名服务器来进行解析的。但是需要注意的是只能输入一级域名,如:baidu.com;对于二级以及多级域名,如www.baidu.com、wenku.baidu.com则是错误的。
CNAME记录查询代码示例如下:
import dns.resolver
domain = input('Input an domain:')
CNAME = dns.resolver.resolve(domain,'CNAME')
for i in CNAME.response.answer:
for j in i.items:
print(j.to_text())
运行结果如下:
>>> Input an domain:> www.baidu.com
www.a.shifen.com.
发现又再次出现了上面在A记录中出现的www.a.shifen.com域名,这个域名就是www.baidu.com的别名指向。相当于用子域名来代替ip地址,优点是如果ip地址变化,只需要改动子域名的解析,而不需要逐一改变ip地址解析。
注意事项:
CNAME的目标主机地址只能使用主机名,不能使用IP地址;
主机名前不能有任何其他前缀,如:http://等是不被允许的;
A记录优先于CNAME记录。即如果一个主机地址同时存在A记录和CNAME记录,则CNAME记录不生效。
目标:
域名对应多ip的时候,服务可用性监控
– 一旦后端ip不能用,自动清楚
步骤:
1 实现域名的解析,获取所有的ip列表
2 对ip列表进行 HTTP级别的探测
代码解析:
本示例第一步通过dns.resolver.resolve()方法获取业务域名A记录信息,查询出所有的IP地址列表,再使用httplib模块的request()方法以GET方式请求监控页面,监控业务所有服务的IP是否服务正常。
代码思路:
实践代码:
注意事项:
1 A记录解析的ip地址必须能够被ping正常测试,否则失败
2 代码没有考虑中间的CNAME解析后的A记录,所以百度失败
3 我们正常的126.com 虽然可以正常,但是测试失败?
解决思路:
将二进制格式转换成普通的utf-8字符串
str(b’***********',“utf-8”)