Pythonで複数のIPアドレスの逆引きNS(パッシブDNS)レコードを取得
2005年にFlorian Weimerによって導入されたパッシブDNSは、現在ではIPセキュリティ調査やドメインネームシステム(DNS)運用のセキュリティなどにおいて中心的なリソースとなっている。パッシブDNSデータベースは、DNS通信においてIPがドメイン名に解決されるたびに観測されるイベントを含む。したがって、これは現在の状態やDNS自体の物理的なインフラストラクチャから独立したデータベースである。さらに、このデータベースには時間情報が含まれる。つまり、このような解決が最初に観測された日時と最後に観測された日時である。
そのようなデータを取得する最も簡単な方法のひとつが、WhoisXML APIのサービスを利用することです。本ブログでは、逆引き検索に焦点を当てます。IPv4アドレスを指定し、特定の日にそのアドレスが紐づけられていたドメイン名を明らかにします。
LinuxまたはMac OS XのコマンドラインでPythonを使用するが、Pythonが機能するのであれば、Windowsのコマンドライン環境でも同じことが簡単にできる。Pythonとシェルスクリプトのごく基本的なスキルのみを想定しています。逆IP APIと、APIの使用を非常に簡単にする提供されたPythonパッケージを使用する。このライブラリは、Pythonのパッケージ・マネージャであるpipを使ってインストールすることができる。以下のコマンドをシェルから実行すると、ライブラリがダウンロードされ、インストールされる:
pip3 install reverse-ip
(オプションとして、システム全体でライブラリを利用できるようにするためにrootユーザーで行うか、インストール範囲を限定するためにPythonの仮想環境で行うこともできます。)
reverse-ipパッケージは、技術的には使用可能な状態になっていますが、APIへのサブスクリプションが必要です。無料のサブスクリプションもあります。サブスクリプションを開始すると、APIキー(YOUR_API_KEY)が発行されます。
すべての前提条件が揃いましたので、これでタスクを達成できます。ips_demo.csvというファイルにIPアドレスのリストがあると仮定しましょう。デモのために、以下の例を使用します:
172.67.155.63 104.21.20.75
これらはWhoisXML APIのウェブサービスに属するIPアドレスですが、当社のウェブプロバイダーによって他のサービスとも共有されています。
標準入力からIPアドレスを読み込み、カンマ区切り(csv)形式で標準出力に書き出すスクリプトを実装します。それでは、スクリプトget_reverse_ip_of_a_list.pyを適当なプログラマ用のテキストエディタで編集してみましょう。まず、IPを読み込んで標準出力に繰り返し出力してみましょう。この初期コードはこうなります:
#!/usr/bin/env python3 import sys for line in sys.stdin.readlines(): ip = line.strip() sys.stdout.write('"%s",'%ip) sys.stdout.write("\n")
もっと洗練された方法でIPを読み取ることもできるが、ここではシンプルにいこう。標準入力から来る行を読み、.strip()で改行のような付加的な文字を削除し、IPを標準出力に書き出す。それから改行を書く。スクリプトのメイン部分の2つのsys.stdout.write呼び出しの間はすでに空けてあるからだ。
しかし、拡張する前に、シェルのコマンドラインで次のようにしてみましょう:
chmod +x get_reverse_ip_of_a_list.py get_reverse_ip_of_a_list.py < ips_demo.csv
アウトプットは次のようになります:
"172.67.155.63", "104.21.20.75",
これは予想した通りです。
では、スクリプトを拡張してこれを実行しましょう。スクリプトは次のようになります:
#!/usr/bin/env python3 import datetime from time import sleep from reverseip import Client reverseip = Client('YOUR_API_KEY') for line in sys.stdin.readlines(): ip = line.strip() sys.stdout.write('"%s",'%ip) data = reverseip.data(ip) for record in data['result']: sys.stdout.write('"%s","%s","%s",'%(record['name'], datetime.datetime.fromtimestamp( int(record['first_seen'])).strftime('%c'), datetime.datetime.fromtimestamp( int(record['last_visit'])).strftime('%c'))) sys.stdout.write("\n") sleep(.1)
YOUR_API_KEYを実際のAPIキーに置き換えて動作させることを忘れないでください。モジュールからClientクラスをインポートし、APIキーを渡すインスタンスreverseipを作成するだけです。そして、reverseip.dataを呼び出すと、Python辞書に読み込まれた結果が得られます; 出力データフォーマットの詳細については、APIのドキュメントを参照してください。
現時点では、出力結果フィールド、すなわち、data['result']が、見つかったレコードのイテレータであることを知っていれば十分です。(より厳密に言えば、最大300レコードまでです。一般的に、1つのIPアドレスに対するドメイン名数が50または100を超える場合、そのインフラは共有されており、全てのレコードを取得する意味はあまりありません。しかし、もし全てのレコードが必要な場合は、APIドキュメントにその方法が記載されています。)
そこで、レコードがある場合はそれを繰り返し処理します。各レコードには3つのフィールドがあり、nameは実際のドメイン名、first_seenとlast_visitは、このIPアドレスとドメイン名の組み合わせを最初と最後に確認した日時を示しています。これはAPIを介してタイムスタンプの形式で提供されますが、私たちは一見複雑ですが論理的なPythonライブラリのdatetime標準関数を使用して、ローカルシステムのタイムゾーンで読み取り可能な日付と時刻に変換します。そして、3つの組それぞれを指定された出力行に追加します。
最後に、APIのスロットリング制限にかからないように0.1秒待ちます。(1秒あたりの最大リクエスト数は実際には30ですので、これは省略できます。)どうなったか見てみましょう:
./get_reverse_ip_of_a_list.py < ips_demo.csv
結果は次のようになります:
"172.67.155.63","labbry.com","Fri Jul 26 07:03:05 2019","Fri May 7 11:09:07 2021","livitte.com","Fri Sep 13 07:15:39 2019","Fri May ... "104.21.20.75","taalmedia.com","Fri Jun 21 13:50:38 2019","Fri Apr 23 18:12:27 2021",
少なくとも本稿執筆時点では。(タイポがあったため、2行目は削除しています。)標準出力をファイルに出すこともできます:
./get_reverse_ip_of_a_list.py < ips_demo.csv > ips_pdns.csv
ips_pdns.csvをお使いのスプレッドシートでインポートできるようにします。
以上、初心者でもPythonでパッシブDNSデータを簡単に取得できる方法をご紹介しました。一方、Pythonの上級プログラマーは、Reverse IPのPythonパッケージをインストールし、WhoisXML APIからAPIキーを取得すれば作業完了です。
from reverseip import Client reverseip = Client('YOUR_API_KEY') data = reverseip.data(ip)
IPアドレスのパッシブDNSレコードを含むPythonのdictionaryが作成されます。1回の関数呼び出しでこうしたデータを取得する方法としては、これが最も簡単です。