DNS(域名解析系统),用来把主机名转换成IP地址。DNS是一个分布式的数据库,有许多的服务器。13个根服务器以及许许多多的提供DNS域名解析服务的子服务器。。当程序或系统需要查询某一主机名的IP地址时,会先和其指定的名称服务器同喜,这个服务器是一个递归的名称服务器,若它有DNS缓存,则直接将IP地址返回给程序,若无则将请求向上传递。。。
操作系统上本身带有一些DNS查找功能,像UNIX系统上有一个/etc/hosts文件,其中定义了主机名和IP地址。操作系统通常会先查看这个文件,若没有答案则在去进行DNS查询。。。
在此,我对DNS不再做过多介绍。。本章讨论利用Python来实现这种DNS域名解析功能。。。
通常情况下, 进行正向查询,也就是根据主机名来查找IP地址时,Python的socket库会替我们实现这种查询。不过,也可以自己实现,通过socket.getaddrinfo()函数。
getaddrinfo(host,port[,family[,socktype[,proto[,flags]]]])
host就是主机名,其他参数只有当你想把结果直接传递给socket.socket()或socket.connect()时才用到。它们会在输出中限制显示什么协议,以及为了建立socket而填写根据默认值得到的结果。可以设置port为None,省略其他参数来进行简单查询。这个函数的返回值是一列元组,每一个元组格式如下:
(family,socktype,proto,canonname,sockaddr)
sockaddr是远程机器的地址(IP和端口),返回一个列表是因为对一个查询,可能有多个不同的IP地址。
反向查询
通过IP地址查询主机名。有一个重要的问题:对于一个IP地址,可能不存在反向的映射。需要确保每一个反向查找的行为捕获和处理socket.herror()
#!/usr/bin/env python
from socket import *
import sys
try:
result=gethostbyaddr(sys.argv[1]) #返回一个元组(hostname, aliaslist, ipaddrlist)
print 'Primary hostname:'
print ' '+result[0]
print '\nAddress'
for item in result[2]:
print ' '+ item
except herror,e:
print "Couldn't look up name:",e
需要注意反向查找数据的真实性,也就是这个IP并不是属于查找到的主机名的,可在进行反向查询后,根据主机名在进行一此正向查询来阻止欺骗。
获得环境信息
socket.gethostname(),不带任何参数,返回一个表明操作系统配置中本地机器的主机名。通常是不完整的。socket.getfqdn(),带一 个参数——主机名,并试图获得完整的数据。
使用PyDNS进行高级查询
PyDNS通常不能提供操作系统自带文件的查询,入/etc/hosts,所以不能通过它取得一些本地名称
PyDNS可以从http://pydns.sourceforge.net下载。
DNS.DiscoverNameServers()可以找到系统中的名称服务器,Windows中是注册表,UNIX中是/etc/resolv.conf。若Windows上使用DHCP,则DHCP不会向注册表中发布名称服务器的细腻希,所以DNS.DiscoverNameServer()可能不起作用,这时可以直接设置:DNS.defaults['server']=['192.168.1.1]
初始化名称服务器后,需要建立一个请求对象。通过调用DNS.Request()来实现。请求对象的req()方法用来执行实际的查询。通常有两个参数:name给出了实际查询的名称,qtype指定了某条record类型,具体可查看help(DNS.Type)。请求对象发出查询后,PyDNS会返回一个包含结果的应答对象,它有个属性answers,包含所有返回的应答列表。例子:
#!/usr/bin/env python
import sys,DNS
query=sys.argv[1]
DNS.DiscoverNameServers()
reqobj=DNS.Request()
answerobj=reqobj.req(name=query,qtype=DNS.Type.ANY)
if not len(answerobj.answers):
print 'Not found'
for item in answerobj.answers:
print '%-5s %s'(item['typename'],item['data'])
ANY类型的查询有一个问题,就是它只返回保存在本地名称服务器缓存中的细腻希,可能是不完整的。解决这个问题的办法是跳过本地名称服务器,直接向改域中权威的名称服务器发送查询。代码:
#!/usr/bin/env python
#-*-coding:utf-8-*-
import sys,DNS
def hierquery(qstring,qtype):
reqobj=DNS.Request()
try:
answerobj=reqobj.req(name=qstring,qtype=qtype)
answers=[x['data'] for x in answerobj.answers if x['type']==qtype]
except DNS.Base.DNSError:
answers=[]
if len(answers):
return answers
else:
remainder=qstring.split('.',1)
if len(remainder)==1:
return None
else:
return hierquery(remainder[1],qtype)
def findnameservers(hostname):
return hierquery(hostname,DNS.Type.NS)
def getrecordsfromnameserver(qstring,qtype,nslist):
for ns in nslist:
reqobj=DNS.Request(server=ns)
try:
answers=reqobj.req(name=qstring,qtype=qtype).answers
if len(answers):
return answers
except DNS.Base.DNSError:
pass
return []
def nslookup(qstring,qtype,verbose=1):
nslist=findnameservers(qstring)
if nslist==None:
raise RuntimeError,'Could not find nameserver to use.'
if verbose:
print 'Using nameservers:',','.join(nslist)
return getrecordsfromnameserver(qstring,qtype,nslist)
if __name__=='__main__':
query=sys.argv[1]
DNS.DiscoverNameServers()
answers=nslookup(query,DNS.Type.ANY)
if not len(answers):
print 'Not found'
for item in answers:
print '%-5s %s'%(item['typename'],item['data'])
转载于:https://blog.51cto.com/liandesinian/1554926