speg03の雑記帳

主に未来の自分のために試したことなどを記録しています

PythonでDNSの正引きと逆引き

諸般の事情からスクリプトでホスト名とIPアドレスの対応を取りたいことがありますのでメモしておきます。

socket

socket --- 低水準ネットワークインターフェイス — Python 3.8.3 ドキュメント

標準ライブラリで実現できるシンプルな方法です。

import socket

# 正引き
socket.gethostbyname("www.google.com")
#=> '172.217.31.164'

# 逆引き
socket.gethostbyaddr("172.217.31.164")
#=> ('nrt12s22-in-f4.1e100.net', ['164.31.217.172.in-addr.arpa'], ['172.217.31.164'])

逆引きの結果はタプルになっていて、最初の値がホスト名です。

dnspython

dnspython home page

高度な機能を使うにはこちらのようなライブラリを使うとよさそうです。本稿執筆時点のバージョンは1.16.0です。

$ pip install dnspython

socketと同じことをやってみます。

from dns import resolver, reversename

# 正引き
answers = resolver.query("www.google.com")
#=> <dns.resolver.Answer object at 0x104829050>
[answer.to_text() for answer in answers]
#=> ['172.217.174.100']

# 逆引き
answers = resolver.query(reversename.from_address("172.217.174.100"), "PTR")
#=> <dns.resolver.Answer object at 0x104eebfd0>
[answer.to_text() for answer in answers]
#=> ['nrt12s28-in-f4.1e100.net.']

クエリの結果は複数の場合があるのでリストとして扱っています。to_text関数を使って値を文字列として取り出すことができます。

逆引きするには、IPアドレスを逆向きにしたようなホスト名をPTRレコードとして問い合わせます。reversename.from_addressが逆向きのホスト名を作る関数です。次のような値になっています。

reversename.from_address("172.217.174.100")
#=> <DNS name 100.174.217.172.in-addr.arpa.>

さらに様々な理由によって、問い合わせ先のネームサーバーの指定が必要だとします。これは(おそらく)socketでは素直にできないです。

新しいresolverを作ってそれにネームサーバーを設定します。あとはそれを使って先ほどと同じようにquery関数を呼ぶだけです。

res = resolver.Resolver()
res.nameservers = ["8.8.8.8"]
answers = res.query("www.google.com")