There was a task to check that multiple records in multiple zones matched for each name server, and there were so many, so I scripted it with python.
At that time, I wondered if there was something good about a library that digs with NS specification in python, but as of early 202006, I could not find a page with useful information, so I will write it down here. thought.
I think python was faster to write in a shell script if I wanted to do it easily because I'm just studying python.
To check the operation when writing this article, Installed on Windows10 / WSL / Ubuntu-18.04
# pyenv --version
pyenv 1.2.17-2-ga8ca63fc
# pipenv --version
pipenv, version 2018.11.26
# python --version
Python 3.8.2
I have confirmed it at.
Apart from the above, it is also implemented in the same version pyenv / pipenv / python on CentOS8.
A sample of what I wanted to try.
# dig blog.watarinohibi.tokyo @8.8.8.8
;; ANSWER SECTION:
blog.watarinohibi.tokyo. 19 IN A 157.230.43.191
# dig blog.watarinohibi.tokyo @dns1.p06.nsone.net
;; ANSWER SECTION:
blog.watarinohibi.tokyo. 20 IN A 157.230.45.115
dns1.p06.nsone.net is Netlify's NS server The URL you are searching for is your blog site deployed on Netlify The above is an example, and it was actually performed for A record, SOA record, TXT record, MX record, etc. that return one specific record.
socket
https://docs.python.org/ja/3/library/socket.html#socket.gethostbyname
socket.gethostbyname_ex(hostname) Obtains various IPv4 format address information from the host name. The return value is a tuple of (hostname, aliaslist, ipaddrlist), hostname is the official name of the host specified by ip_address, aliaslist is a list of aliases for the same address (which can be empty), and ipaddrlist is for the same interface on the same host. Shows a list of IPv4 addresses (mostly just a single address).
test1.py
#!/usr/bin/env python3
import socket
domain = 'blog.watarinohibi.tokyo'
ns1 = '8.8.8.8' # google DNS
ns2 = 'dns1.p06.nsone.net' # Netlify DNS
# socket
print ("=== socket.getaddinfo")
addrs = socket.getaddrinfo(domain, 80)
for addr in addrs:
print(addr)
print ("=== socket.gethostbyname")
addrs = socket.gethostbyname(domain)
print (addrs)
# ./test.py
=== socket.getaddinfo
(<AddressFamily.AF_INET: 2>, <SocketKind.SOCK_STREAM: 1>, 6, '', ('157.230.45.115', 80))
(<AddressFamily.AF_INET: 2>, <SocketKind.SOCK_DGRAM: 2>, 17, '', ('157.230.45.115', 80))
(<AddressFamily.AF_INET: 2>, <SocketKind.SOCK_RAW: 3>, 0, '', ('157.230.45.115', 80))
(<AddressFamily.AF_INET6: 10>, <SocketKind.SOCK_STREAM: 1>, 6, '', ('2400:6180:0:d1::575:a001', 80, 0, 0))
(<AddressFamily.AF_INET6: 10>, <SocketKind.SOCK_DGRAM: 2>, 17, '', ('2400:6180:0:d1::575:a001', 80, 0, 0))
(<AddressFamily.AF_INET6: 10>, <SocketKind.SOCK_RAW: 3>, 0, '', ('2400:6180:0:d1::575:a001', 80, 0, 0))
=== socket.gethostbyname
157.230.45.115
There is no option to specify NS (probably not overlooked). Not suitable for this use, but if you want to try name resolution with the standard library, this is fine.
dnspython
http://www.dnspython.org/ https://github.com/rthalley/dnspython https://pypi.org/project/dnspython/
http://www.dnspython.org/examples.html  Please refer to the area. This time, I want to try lookup of A record by specifying NS.
test.py
import dns.resolver
print ("=== dns.resolver @", ns1)
resolver = dns.resolver.Resolver()
resolver.nameservers = [ns1]
answers = resolver.query(domain, 'A')
for rdata in answers:
print (rdata)
print ("=== dns.resolver @", ns2)
resolver = dns.resolver.Resolver()
resolver.nameservers = [ns2]
answers = resolver.query(domain, 'A')
for rdata in answers:
print (rdata)
# ./test.py
=== dns.resolver @ 8.8.8.8
134.209.106.40
=== dns.resolver @ dns1.p06.nsone.net
Traceback (most recent call last):
~~~ stack trace
With that feeling, it worked with NS specification with IPv4 address, but an error occurred with NS specification with CNAME record such as Netlify DNS. https://github.com/rthalley/dnspython/issues/235 There is an exchange that seems to be this error, but it seems that it is not supported because it is not in RFC. However, I don't really understand here because there is an image that NS records are used in CNAME at all. ..
pynslookup
https://github.com/wesinator/pynslookup https://pypi.org/project/nslookup/
test.py
from nslookup import Nslookup
print ("=== nslookup @", ns1)
dns_query = Nslookup(dns_servers=[ns1])
ips_record = dns_query.dns_lookup(domain)
print(ips_record.response_full, ips_record.answer)
print ("=== nslookup @", ns2)
dns_query = Nslookup(dns_servers=[ns2])
ips_record = dns_query.dns_lookup(domain)
print(ips_record.response_full, ips_record.answer)
# ./test.py
=== nslookup @ 8.8.8.8
['blog.watarinohibi.tokyo. 19 IN A 178.128.17.49'] ['178.128.17.49']
=== nslookup @ dns1.p06.nsone.net
Traceback (most recent call last):
~~~ stack trace
That's why this is also an error. When I checked the code, https://github.com/wesinator/pynslookup/blob/master/nslookup/nslookup.py
nslookup.py
import dns.resolver, dns.exception
It seems that dnspython is used as it is internally.
pydig
https://github.com/leonsmith/pydig https://pypi.org/project/pydig/
test.py
import pydig
print ("=== nslookup @", ns1)
resolver = pydig.Resolver(
nameservers = [ns1]
)
answer = resolver.query(domain, 'A')
print (answer)
print ("=== nslookup @", ns2)
resolver = pydig.Resolver(
nameservers = [ns2]
)
answer = resolver.query(domain, 'A')
print (answer)
# ./test.py
=== nslookup @ 8.8.8.8
['157.230.35.153']
=== nslookup @ dns1.p06.nsone.net
['206.189.89.118']
Oh, it worked. This guy seems to work even with the NS designation of CNAME. If you check the code, https://github.com/leonsmith/pydig/blob/master/pydig/resolver.py
import subprocess
--
Builds up the final arguments to pass into subprocess
Was written, and the local dig was just running in subprocess. I see. If the dig path is different or you want to specify it, you can specify it as an option.
>>> resolver = pydig.Resolver(
... executable='/usr/bin/dig',
... nameservers=[
... '1.1.1.1',
... '1.0.0.1',
... ],
... additional_args=[
... '+time=10',
... ]
... )
If you want to use dig with NS specified in Python, you can use pydig which is a wrapper of the dig command, but it seems that it is just a wrapper, so you may write it by yourself in subprocess. unknown.
DNS is messy.
Recommended Posts