初めに #
Linuxサーバの運用において、「どのIPアドレスからアクセスを許可するか、あるいは拒否するか」といったネットワーク制御の設定は、セキュリティ対策の中でも非常に重要な要素です。
たとえば、海外からのアクセスを遮断したい場合や、自社・社内ネットワークからのみアクセスを許可したい場合など、IPベースの制限を設けるケースは少なくありません。
このような設定を行う際には、国ごとのIPアドレス一覧を活用するのが一般的で、多くの場合それらはCIDR形式で提供されています。
しかし、CIDRの記法に不慣れな方にとっては、「このCIDRには、実際にどのIPアドレスが含まれているのか?」と疑問に感じる場面も多いはずです。
CIDRを手作業で展開するのは手間がかかるうえ、設定ミスはセキュリティリスクにも直結します。
そこで本記事では、Pythonを利用し、CIDR形式の表記からIPアドレス一覧を取得する方法を、初心者の方にもわかりやすく解説していきます。
CIDRとは? #
CIDR(サイダー)とは、IPアドレスの後ろに「/24」のような数字を付けて、そのアドレスがどんな範囲のネットワークに属しているかを表す方法です。
たとえば、次のような表記があります。
192.168.0.0/24
この例では「/24」は、「このネットワークには何個のIPアドレスが含まれているか」を表しています。
実際には、「192.168.0.0 ~ 192.168.0.255」のように合計 256個のIPアドレス がこのネットワークに含まれています。
CIDR形式を利用することで、クラスA・B・Cといった古い分類に縛られず、柔軟にネットワークを設計・管理できるようになります。
その他の特徴は以下の通りです。
- 視覚的にもわかりやすく整理しやすい
- プログラムにて扱いやすい形式
Pythonのipaddressモジュール #
Pythonには標準ライブラリとしてipaddressモジュールが用意されており、IPアドレスやネットワークの操作を簡単に行うことができます。
このモジュールは Pythonに最初から含まれているため、追加でインストールする必要はありません。
python3 -c "help('modules')" |grep "ipaddress"
HTMLParser bsddb ipaddress shelve
このモジュールを利用することで、あるIPアドレスがどのネットワークに含まれているかを調べたり、 指定したCIDR(サブネット)の中に含まれるすべてのIPアドレスを一覧表示したりすることが可能です。
CIDRからIPアドレス一覧を取得する方法 #
ワンライナーで確認 #
特定のCIDRブロックに含まれるIPアドレスを素早く確認したい場合、Pythonのワンライナーを活用することで、コマンドライン上で即座に確認できます。
以下は基本的な実行方法となります。
python3 -c 'import ipaddress; [print(ip) for ip in ipaddress.ip_network("xxx.xxx.xxx.xxx/xx", strict=False)]'
例えば 192.168.0.0/24 を指定する場合は以下のようになります。
python3 -c 'import ipaddress; [print(ip) for ip in ipaddress.ip_network("192.168.0.0/24", strict=False)]'
上記を実行すると以下のようにネットワークに含まれるすべてのIPアドレス(256個)が順番に表示されます。
python3 -c 'import ipaddress; [print(ip) for ip in ipaddress.ip_network("192.168.0.0/24", strict=False)]'
192.168.0.0
192.168.0.1
192.168.0.2
192.168.0.3
192.168.0.4
192.168.0.5
192.168.0.6
192.168.0.7
192.168.0.8
192.168.0.9
192.168.0.10
※一部抜粋
スクリプトとして実行する方法 #
確認作業が繰り返し発生する場合や、複数のCIDRを処理したい場合には、Pythonスクリプトとして記述しておくのが効率的です。
以下は、CIDRを指定してその範囲に含まれるIPアドレスをすべて出力する基本的なスクリプトの例となります。
import sys
import ipaddress
for cidr in sys.argv[1:]:
network = ipaddress.ip_network(cidr, strict=False)
for ip in network:
print(ip)
今回は例として cidr_to_iplist.py を作成し 192.168.0.0/30 を引数に実行してみます。
python3 cidr_to_iplist.py "192.168.0.0/30"
上記を実行すると先ほどと同様に指定したCIDRに含まれるすべてのIPアドレスが1行ずつ表示されます。
python3 cidr_to_iplist.py "192.168.0.0/30"
192.168.0.0
192.168.0.1
192.168.0.2
192.168.0.3
また、以下のように引数を指定し複数のCIDRブロックを同時に指定して実行することも可能です。
python3 cidr_to_iplist.py "192.168.0.0/30" "10.0.0.0/31"
192.168.0.0
192.168.0.1
192.168.0.2
192.168.0.3
10.0.0.0
10.0.0.1
なお本スクリプトでは機能の説明を重視しており、入力値のチェックやエラーハンドリングは実装されていません。
国別のIP情報の取得方法 #
インフラ技術部では、国別のIPアドレス情報をCIDR形式で整理したデータセットを、以下のGitHubリポジトリにて公開しています。
このプロジェクトでは、各国コードごとにIPv4アドレスのブロックを分割・整理しており、ファイアウォールの設定やアクセス制御のベースデータとして利用することが可能となっています。
本データセットは CC0 ライセンスで公開されており、商用・非商用を問わず、誰でも自由に利用することが可能です。
IPv4アドレスの割当情報を国別に分類したデータを公開するリポジトリです