概要
- pythonでIPアドレスを扱う方法を記載します
TL;DR
- ipアドレス型は、str型やint型に変換できる
- ipアドレスの計算はint型の方が約2倍程度早かった
pythonのIP-Addressモジュールでできること
- ip addressの形になっているかチェック
- str型やint型に変換
- 2つのip addressの計算
- subnet_of
- supernet_of
- 内包しているipの確認
IP-Address型に変換
-
ipaddress モジュールは簡単に IP アドレス、ネットワーク、インターフェースを生成する
-
例
>>> import ipaddress >>> ipaddress.ip_network('192.168.0.0/24') IPv4Network('192.168.0.0/24') >>> ipaddress.ip_address('192.168.0.1') IPv4Address('192.168.0.1')
-
エラーになる例
-
ip_address
に192.168.0.1/24
を与えると「IPv4またはIPv6アドレスではない」と怒られます- 対策:prefix(
/24
)を削除するもしくは/32
にする
- 対策:prefix(
-
ip_network
に192.168.0.255/24
を与えると「192.168.0.1/24はホストビットが設定されている」と怒られます- 対策:第4オクテットを0にする
>>> ipaddress.ip_address('192.168.0.1/24') Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/ipaddress.py", line 54, in ip_address raise ValueError('%r does not appear to be an IPv4 or IPv6 address' % ValueError: '192.168.0.1/24' does not appear to be an IPv4 or IPv6 address >>> ipaddress.ip_network('192.168.0.255/24') Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/ipaddress.py", line 75, in ip_network return IPv4Network(address, strict) File "/Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/ipaddress.py", line 1510, in __init__ raise ValueError('%s has host bits set' % self) ValueError: 192.168.0.255/24 has host bits set
-
str型やint型に変換
- 変換例
-
str型
>>> str(ipaddress.ip_address('192.168.0.1')) '192.168.0.1' >>> type(str(ipaddress.ip_address('192.168.0.1'))) <class 'str'> >>> type(ipaddress.ip_address('192.168.0.1')) <class 'ipaddress.IPv4Address'>
-
int型
>>> int(ipaddress.ip_address('192.168.0.1')) 3232235521 >>> type(int(ipaddress.ip_address('192.168.0.1'))) <class 'int'> >>> type(ipaddress.ip_address('192.168.0.1')) <class 'ipaddress.IPv4Address'>
-
2つのip addressの計算
IPアドレス型通しの計算
subnet_of
- サブネットを簡単に説明すると
大きなネットワークを分割した際の、それぞれの小さいネットワーク
-
例のip b
が例のip a
のサブネットだった場合にTrueとなる- 構文:
b_ip.subnet_of(a_ip)
- b_ipがa_ipのサブネット(小さいネットワーク)であればTrueを返す
- 構文:
>>> a_ip = ipaddress.ip_network('192.168.0.0/24')
>>> b_ip = ipaddress.ip_network('192.168.0.16/28')
>>> b_ip.subnet_of(a_ip)
True
>>> a_ip.subnet_of(b_ip)
False
supernet_of
- スーパネットを簡単に説明すると
小さなネットワークを合体させて1つの大きなネットワークにすること
- サブネットの逆です
>>> a_ip = ipaddress.ip_network('192.168.0.0/24')
>>> b_ip = ipaddress.ip_network('192.168.0.16/28')
>>> b_ip.subnet_of(a_ip)
True
>>> a_ip.subnet_of(b_ip)
False
IPアドレスをintにして計算
手順
- ipアドレス型に変換し、netowork_addressを取得する
-
1
のipをint型に変換する - ipアドレス型に変換し、broadcast_addressを取得する
-
3
ののipをint型に変換する -
2
と4
でintに変換したipをlistに格納する - 比較したいipにも1-5の動作を行う
- 2つのlistを比較しipのsubnetを確認する
>>> a_int = [int(ipaddress.ip_network('192.168.0.0/24').network_address),int(ipaddress.ip_network('192.168.0.0/24').broadcast_address)]
>>> a_int
[3232235520, 3232235775]
>>> b_int = [int(ipaddress.ip_network('192.168.0.16/28').network_address),int(ipaddress.ip_network('192.168.0.16/28').broadcast_address)]
>>> b_int
[3232235536, 3232235551]
>>> c_int = [int(ipaddress.ip_network('192.168.0.0/16').network_address),int(ipaddress.ip_network('192.168.0.0/16').broadcast_address)]
>>> c_int
[3232235520, 3232301055]
>>> a_int[0] <= b_int[0] and b_int[1] <= a_int[1] # a="192.168.0.0/24" b="192.168.0.16/28"
True
>>> c_int[0] <= a_int[0] and a_int[1] <= c_int[1] # a="192.168.0.0/24" c="192.168.0.0/16"
True
>>> b_int[0] <= a_int[0] and a_int[1] <= b_int[1]
False
>>> a_int[0] <= c_int[0] and c_int[1] <= a_int[1]
False
ポイント
- int型にすると処理が早い
-
約2.26倍で処理している!!
-
int型にすると8.11 µs
>>> %%time >>> a_int[0] <= b_int[0] and b_int[1] <= a_int[1] CPU times: user 5 µs, sys: 1 µs, total: 6 µs Wall time: 8.11 µs
-
ipアドレスで実行すると18.4µs
>>> %%time >>> b_ip.subnet_of(a_ip) CPU times: user 14 µs, sys: 1e+03 ns, total: 15 µs Wall time: 18.4 µs
-
内包しているipの確認
- イテレーション
>>> for addr in ipaddress.IPv4Network('192.0.2.0/28'): print(addr) 192.0.2.0 192.0.2.1 192.0.2.2 192.0.2.3 192.0.2.4 192.0.2.5 192.0.2.6 192.0.2.7 192.0.2.8 192.0.2.9 192.0.2.10 192.0.2.11 192.0.2.12 192.0.2.13 192.0.2.14 192.0.2.15