ipaddressモジュールは、IPアドレスやIPアドレスのネットワークを表すクラスを提供しています。

これらのオブジェクトを使うと、IPアドレスがネットワークに含まれるかを確認したり、ネットワークに含まれるIPアドレスを一覧するなど、IPアドレスに関する様々な処理を簡単に行うことができます。

このモジュールには、IPv4用とIPv6用の次のクラスが定義されています。

  • ipaddress.IPv4Address
  • ipaddress.IPv6Address
  • ipaddress.IPv4Network
  • ipaddress.IPv6Network
  • ipaddress.IPv4Interface
  • ipaddress.IPv6Interface

これらのオブジェクトは次の3つのに分類できます。

アドレスオブジェクト

IPアドレスを表すオブジェクト(IPv4Address、IPv6Addressオブジェクト)。

「192.168.10.5」のような単一のIPアドレスを表します。

ネットワークオブジェクト

ネットワークアドレスを表すオブジェクト(IPv4Network、IPv6Networkのオブジェクト)。

「192.168.10.0/24」のようにネットワークを表します。

インターフェイスオブジェクト

インターフェイスを表すオブジェクト(IPv4Interface、IPv6Interfaceのオブジェクト)

「192.168.10.5/24」のようなネットワーク内のIPアドレスを表します。

ipaddressモジュールは、これらのオブジェクトを生成するファクトリー関数も提供しています。ファクトリー関数はオブジェクトの生成には便利ですが詳細を隠してしまうため、先ほど分類したオブジェクトから順に説明していきます。

ファクトリー関数については最後に説明します。

なお、この記事ではIPv4用のクラスについてのみ説明します。IPv6用のクラスについては機会があれば書きたいと思います。

アドレスオブジェクト

アドレスオブジェクトはIPアドレスを表すオブジェクトです。IPv4用のIPv4AddressオブジェクトとIPv6用のIP64Addressオブジェクトがあります。

ここではIPv4用のIPv4Addressクラスのみに絞って説明します。

ipaddress.IPv4Addressクラス

IPv4AddressクラスはIPv4のIPアドレスを表すクラスです。

IPv4Addressオブジェクトの生成

まずはIPv4Addressオブジェクトの作り方から説明します。このクラスのオブジェクトを生成するには次の関数を使います。

ipaddress.IPv4Address(address)

addressには次のいずれかを渡します。

  • 10進数のドット区切り形式。つまり0~255の範囲の4つの10進数をドッド(.)で区切ったもの (例:192.168.0.1)
  • 32ビットに収まる整数
  • 長さ4のbytesオブジェクト(最上位オクテットが先頭)

次の例は、どれも同じIPアドレスを表すIPv4Addressオブジェクトを生成します。

>>> ipaddress.IPv4Address('192.168.100.1')
IPv4Address('192.168.100.1')
>>> ipaddress.IPv4Address(3232261121)
IPv4Address('192.168.100.1')
>>> ipaddress.IPv4Address(bytes([192, 168, 100, 1]))
IPv4Address('192.168.100.1')

bytesオブジェクトの4つの要素は、IPアドレスのそれぞれのオクテットに対応します。

addressがIPv4アドレスとして不正ならAddressValueErrorが発生します。

>>> ipaddress.IPv4Address('192.168.100.256')
Traceback (most recent call last):
...
    raise AddressValueError("%s in %r" % (exc, ip_str)) from None
ipaddress.AddressValueError: Octet 256 (> 255) not permitted in '192.168.100.256'

アドレスオブジェクトを文字列へ変換する

アドレスオブジェクトは簡単にドット区切り形式の文字列へ変換することができます。それには組み込みのstr()関数を使います。

>>> str(ipaddress.IPv4Address('192.168.100.1'))
'192.168.100.1'

アドレスオブジェクトを数値へ変換する

IPアドレスは32ビットの単なる数値です。人間にわかりやすドット区切り形式から、本来の数値へ変換するには組み込みのint()関数を使います。

>>> int(ipaddress.IPv4Address('192.168.100.1'))
3232261121

アドレスオブジェクトの演算

アドレスオブジェクトはいくつかの演算をサポートしています。

比較演算

アドレスオブジェクト同士は比較演算子で比較することができます。これらの使い方は直感的でわかりやすいでしょう。

>>> ip1 = ipaddress.IPv4Address('192.168.0.1')
>>> ip2 = ipaddress.IPv4Address('192.168.0.2')
>>> ip1 < ip2
True
>>> ip1 == ip2
False
>>> ip1 != ip2
True

算術演算

アドレスオブジェクトへ整数を加算したり、減算したりできます。

>>> ip1 + 1
IPv4Address('192.168.0.2')
>>> ip1 - 2
IPv4Address('192.167.255.255')

ネットワークオブジェクト

ネットワークオブジェクトは「IPアドレス」と「サブネットマスク(あるいは単にマスク)」の組み合わせによりネットワークを表すオブジェクトです。

ネットワークオブジェクトを扱うには、ネットワークを表す一般的な表記についての理解が必要です。ここで少しおさらいをしましょう。

ネットワークを表すには「ネットワークアドレス/マスク」という表記を使います。マスクの表記には2種類の形式があり、10進数のドット区切りで表す形式とプレフィックスを示す整数で表すCIDR形式(プレフィックス形式)があります。それぞれ次のような形式です。

192.168.1.0/255.255.255.0
192.168.1.0/24

IPアドレスはマスクによって、ネットワークアドレス部とホストアドレス部に分けられます。

ホストアドレス部のビットがすべて0のIPアドレスは、ネットワークアドレスと呼ばれます。これはネットワークアドレス部が示すネットワークを表します。

ipaddress.IPv4Networkクラス

IPv4NetworkクラスはIPv4のネットワークを表すクラスです。

IPv4Networkオブジェクトの生成

このクラスのオブジェクトを生成するには次の関数を使います。

ipaddress.IPv4Network(address, strict=True)

ddressに渡すのは次のいずれかです。

  • IPアドレスとオプションでスラッシュ(/)で区切られたマスクを持つ文字列

    マスクはCIDR形式(プレフィックスを表す整数)かドット区切り形式(例えば255.255.255.0)です

  • 32ビットに収まる整数
  • 長さ4のbytesオブジェクト(最上位オクテットが先頭)
  • アドレスとマスクを要素に持つタプル

    アドレスはドット区切り形式の文字列、32ビットの整数、長さ4のbytesオブジェクト、IPv4Addressオブジェクトのいずれかです。

    マスクはCIDR形式かドット区切り形式です。

マスクが省略された場合、あるいは指定できない形式を使うとマスクは「/32」が指定されたものとみなされます。

32ビットのマスクは、1つのIPアドレスのみ含むネットワークアドレスを表すとして許容されます。

strict=Trueの場合、与えられたIPアドレスのホストアドレス部のビットがすべて0でなければ、ValueError を発生させます。strict=Falseの場合、ホストビットをマスクして正しいネットワークアドレスが計算されます。

addressがIPv4アドレスとして不正なら、AddressValueError例外が発生します。マスクがIPv4アドレスに対して有効ではない場合、NetmaskValueError例外が発生します。

「ネットワークアドレス/マスク」形式からオブジェクトの生成する

「ネットワークアドレス/マスク」形式を渡してネットワークオブジェクトを生成できます。マスクは「CIDR形式」か「10進数のドット区切り形式」です。

>>> ipaddress.IPv4Network('192.168.10.0/24')
Ipv4network('192.168.10.0/24')
>>> ipaddress.IPv4Network('192.168.10.0/255.255.255.0')
IPv4Network('192.168.10.0/24')

与えたIPアドレスがネットワークアドレスではない場合、ValueErrorが発生します。これはstrict=Trueの場合の動作です。

>>> ipaddress.IPv4Network('192.168.0.1/24')
Traceback (most recent call last):
...
    raise ValueError('%s has host bits set' % self)
ValueError: 192.168.0.1/24 has host bits set

この例はホストアドレス部のビットがすべて0ではないのでネットワークアドレスではありません。

「192.168.0.1/24」のような表記は、「192.168.0.0」のネットワーク上の「192.168.0.1」を持つインターファエイスを表すために使われ、ipaddressモジュールではこのような用途のためにインターフェイスオブジェクトが定義されています。

strict=Falseの場合は、マスクから計算されたネットワークアドレスを持つネットワークオブジェクトが作成されます。

>>> ipaddress.IPv4Network('192.168.0.1/24', strict=False)
IPv4Network('192.168.0.0/24')
32ビット整数やbytesオブジェクトからオブジェクトを生成する

32ビットに収まる整数や長さ4のbytesオブジェクトからもネットワークオブジェクトを作成できます。

>>> ipaddress.IPv4Network(3232238081)
IPv4Network('192.168.10.1/32')
>>> ipaddress.IPv4Network(bytes([192, 168, 10, 1]))
IPv4Network('192.168.10.1/32')

これらの場合はマスクが「/32」になります。32ビットのマスクは、1つのIPアドレスのみを持つネットワークを表すとして、不正なネットワークアドレスとはみなされません。

IPアドレスとマスクのタプルからオブジェクトを生成する

IPアドレスとマスクを要素に持つタプルからもネットワークオブジェクトを作成できます。

IPアドレスは次のいずれでかです。

  • ドット区切り形式の文字列
  • 32bitに収まる整数
  • 長さ4のbytesオブジェクト
  • IPv4Addressオブジェクト

マスクは次のどちらかです。

  • CIDR形式(プレフィックスを表す整数)
  • ドット区切り形式
>>> ipaddress.IPv4Network( ('192.168.10.0', 24) )
IPv4Network('192.168.10.0/24')
>>> ipaddress.IPv4Network( ('192.168.10.0', '255.255.255.0') )
IPv4Network('192.168.10.0/24')
>>> ipaddress.IPv4Network( (3232238080, 24) )
IPv4Network('192.168.10.0/24')
>>> ipaddress.IPv4Network( (bytes([192, 168, 10, 0]), 24) )
IPv4Network('192.168.10.0/24')

>>> ip = ipaddress.IPv4Address('192.168.10.0')
>>> ipaddress.IPv4Network( (ip, '255.255.255.0') )
IPv4Network('192.168.10.0/24')

IPvNetworkオブジェクトの属性

network_address属性

このネットワークのネットワークアドレスを表すIPv4Addressオブジェクト

>>> ipaddress.IPv4Network('192.168.10.16/28').network_address
IPv4Address('192.168.10.16')
broadcast_address属性

このネットワークのブロードキャスアドレスを表すIPv4Addressオブジェクト

>>> ipaddress.IPv4Network('192.168.10.16/28').broadcast_address
IPv4Address('192.168.10.31')
with_prefixlen属性

CIDR形式の文字列表現

>>> ipaddress.IPv4Network('192.168.10.16/28').with_prefixlen
'192.168.10.16/28'
with_netmask属性

ドット区切り形式のマスクの文字列表現

>>> ipaddress.IPv4Network('192.168.10.16/28').with_netmask
'192.168.10.16/255.255.255.240'
num_addresses属性

ネットワーク内のアドレス総数

>>> ipaddress.IPv4Network('192.168.10.16/28').num_addresses
16

IPvNetworkオブジェクトのメソッド

hosts()メソッド

IPv4Networkオブジェクトのネットワークで、ホストに使用可能なIPアドレスを戻すイテレーターを返す。

ホストアドレス部のビットがすべて0のアドレスはネットワークアドレスとして、ホストアドレス部のビットがすべて1のアドレスはブロードキャストアドレスとして使われるためホストには使用できません。これらのIPアドレスはイテレーターからは戻されません。

ただし、31ビットのマスクを持つネットワークはネットワークアドレスとブロードキャストも結果に含まれます。32ビットのマスクを持つネットワークは1つのホストアドレスだけを戻します。

次の例はネットワークオブジェクトのネットワークのすべてのIPアドレスを最初に表示します。次にホストに使用可能なIPアドレスを表示します。

>>> for i in ipaddress.IPv4Network('192.168.10.0/30'):
...   print(i)
...
192.168.10.0
192.168.10.1
192.168.10.2
192.168.10.3
>>> for i in ipaddress.IPv4Network('192.168.10.0/30').hosts():
...   print(i)
...
192.168.10.1
192.168.10.2

31ビットあるいは32ビットのマスクの場合は次のようになります。

>>> list( ipaddress.IPv4Network('192.168.10.0/31').hosts() )
[IPv4Address('192.168.10.0'), IPv4Address('192.168.10.1')]
>>> list( ipaddress.IPv4Network('192.168.10.101/32').hosts() )
[IPv4Address('192.168.10.101')]
overlaps()メソッド

ネットワーク同士で重複があるか判定する。構文は次の通りです。

overlaps(other)

カレントのIPv4Networkオブジェクトがotherに含まれる、あるいは反対にotherがこのネットワークに含まれる場合はTrueを返す。

>>> n1 = ipaddress.IPv4Network('192.168.10.0/28')
>>> n2 = ipaddress.IPv4Network('192.168.10.4/30')
>>> n1.overlaps(n2)
True
>>> n2.overlaps(n1)
True
address_exclude()メソッド

IPv4Networkオブジェクトから与えられたネットワークを削除する。削除した残りのネットワークに対応するネットワークオブジェクトを戻すイテレーターを返す。次の構文を使う。

address_exclude(network)

次の例は「192.168.10.4/30」から「192.168.10.0/28」を削除する。

>>> n1 = ipaddress.IPv4Network('192.168.10.0/28')
>>> n2 = ipaddress.IPv4Network('192.168.10.4/30')
>>> list(n1.address_exclude(n2))
[IPv4Network('192.168.10.8/29'), IPv4Network('192.168.10.0/30')]

ネットワークに含まれないnetworkを与えた場合、ValueError が発生する。

subnets()メソッド

カレントネットワークオブジェクトのサブネットを返す。構文は次の通りです。

subnets(prefixlen_diff=1, new_prefix=None)

サブネットのネットワークオブジェクトを戻すイテレータを返します。prefixlen_diffには、現在のプレフィックスからの増分を指定します。new_prefixには、新しいプレフィックスの値(現在のプレフィックスより大きい値)を指定する。

prefixlen_diffとnew_prefixはどちらか一方だけを指定します。

次の例はprefixlen_diffを使う例です。

>>> list( ipaddress.IPv4Network('192.168.1.0/24').subnets() )
[IPv4Network('192.168.1.0/25'), IPv4Network('192.168.1.128/25')]
>>> list( ipaddress.IPv4Network('192.168.1.0/24').subnets(prefixlen_diff=2) )
[IPv4Network('192.168.1.0/26'), IPv4Network('192.168.1.64/26'),
 IPv4Network('192.168.1.128/26'), IPv4Network('192.168.1.192/26')]

new_prefixにはサブネットのプレフィックスを指定する。

>>> list( ipaddress.IPv4Network('192.168.1.0/24').subnets(new_prefix=26) )
[IPv4Network('192.168.1.0/26'), IPv4Network('192.168.1.64/26'),
 IPv4Network('192.168.1.128/26'), IPv4Network('192.168.1.192/26')]

現在のネットワークオブジェクトのプレフィックスより小さい値を指定すると例外が発生します。

>>> list( ipaddress.IPv4Network('192.168.1.0/24').subnets(new_prefix=23) )
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/Cellar/python@3.9/3.9.1_6/Frameworks/Python.framework/Versions/3.9/lib/python3.9/ipaddress.py", line 963, in subnets
    raise ValueError('new prefix must be longer')
ValueError: new prefix must be longer
supernet()メソッド

カレントネットワークオブジェクトのスーパーネットを返す。構文は次の通りです。

supernet(prefixlen_diff=1, new_prefix=None)

prefixlen_diffには、現在のプレフィックスからの減分を指定します。new_prefixは、新しいプレフィックスの値(現在のプレフィックスよりも小さい値)を指定します。prefixlen_diffとnew_prefixのどちらか一方だけを設定する。

>>> ipaddress.IPv4Network('192.168.1.0/26').supernet()
IPv4Network('192.168.1.0/25')
>>> ipaddress.IPv4Network('192.168.1.0/26').supernet(prefixlen_diff=2)
IPv4Network('192.168.1.0/24')
>>> ipaddress.IPv4Network('192.168.1.0/26').supernet(new_prefix=24)
IPv4Network('192.168.1.0/24')

現在のネットワークオブジェクトのプレフィックより小さなプレフィックスを指定すると例外が発生する。

subnet_of(other)

カレントのネットワークオブジェクトが other のサブネットの場合に True を返します。

>>> n1 = ipaddress.IPv4Network('192.168.10.0/28')
>>> n2 = ipaddress.IPv4Network('192.168.10.4/30')
>>> n2.subnet_of(n1)
True
>>> n1.subnet_of(n2)
False
supernet_of(other)

カレントのネットワークオブジェクトが other のスーパーネットの場合に True を返します。

>>> n1 = ipaddress.IPv4Network('192.168.10.0/28')
>>> n2 = ipaddress.IPv4Network('192.168.10.4/30')
>>> n2.supernet_of(n1)
False
>>> n1.supernet_of(n2)
True

ネットワークオプジェクトの比較

ネットワークオブジェクトは比較演算子で比較できます。最初にネットワークアドレスが比較され、次にネットマスクで比較される。

>>> n1 = ipaddress.IPv4Network('192.168.10.0/24')
>>> n2 = ipaddress.IPv4Network('192.168.20.0/24')
>>> n3 = ipaddress.IPv4Network('192.168.20.0/26')
>>> n1 < n2
True
>>> n1 < n3
True
>>> n3 < n2
False

ネットワークオブジェクトのイテレーション

ネットワークオブジェクトは、イテラブルです。イテレートすると、そのネットワークに属するすべてのIPアドレスが順に返されます。

これにはネットワークアドレスやブロードキャストアドレスも含まれます。ホストに使用可能なアドレスだけが必要な場合はhosts()メソッドを使います。

>>> for addr in ipaddress.IPv4Network('192.168.0.0/30'):
...     addr
...
IPv4Address('192.168.0.0')
IPv4Address('192.168.0.1')
IPv4Address('192.168.0.2')
IPv4Address('192.168.0.3')

ネットワークオブジェクトをコンテナとして扱う

ネットワークオブジェクトは、リストのようなコンテナオブジェクトとして扱えます。

次のようにインデックスで参照することができます。

>>> ipaddress.IPv4Network('192.168.0.0/30')[0]
IPv4Address('192.168.0.0')
>>> ipaddress.IPv4Network('192.168.0.0/30')[-1]
IPv4Address('192.168.0.3')

inを使ってネットワークにIPアドレスが含まれるか確認もできる。

>>> ipaddress.IPv4Address('192.168.0.3') in ipaddress.IPv4Network('192.168.0.0/30')
True
>>> ipaddress.IPv4Address('192.168.0.4') in ipaddress.IPv4Network('192.168.0.0/30')
False

インターフェイスオブジェクト

ネットワークオブジェクトはネットワークアドレスのIPアドレスを保持しますが、インターフェイスオブジェクトは、あるネットワーク上のインターフェイス(ホスト)を表します。

ipaddress.IPv4Interfaceクラス

IPv4Interfaceオブジェクトを生成するには次の関数を使います。

ipaddress.IPv4Interface(address)

addressは、任意のホストアドレスを許容することを除いてIPv4Networkのコンストラクタと同じものを渡すことができます。

IPv4Interfaceの属性

IPv4InterfaceクラスはIPv4Addressクラスのサブクラスです。そのためIPv4Addressクラスのすべての属性(この記事では紹介していませんが)を継承します。その他いくつかの属性が追加されてます。

ip属性

マスク情報を持たないIPアドレス(IPv4Addressオブジェクト)

>>> interface = ipaddress.IPv4Interface('192.168.1.1/24')
>>> interface.ip
IPv4Address('192.168.1.1')
network属性

このインターフェイスが属するネットワーク(IPv4Networkオブジェクト)

>>> interface.network
IPv4Network('192.168.1.0/24')
with_prefixlen属性

CIDR形式のインターフェイスの文字列表現

>>> interface.with_prefixlen
'192.168.1.1/24'
with_netmask

ドット区切り形式のマスクを持つインターフェイスの文字列表現

>>> interface.with_netmask
'192.168.1.1/255.255.255.0'

ファクトリー関数

ipaddressモジュールには、このモジュールのオブジェクトを簡単に作成するためにファクトリー関数が提供されています。

アドレスオブジェクト、ネットワークオブジェクト、インターフェイスオブジェクトのそれぞれのオブジェクトを作成する3つのファクトリー関数があります。

アドレスオブジェクトのファクトリー関数

アドレスオブジェクトのファクトリー関数は、与えられた引数を判定して、IPv4AddresオブジェクトsかIPv6Addressのオブジェクトを作成して返します。

アドレスオブジェクトを作成するファクトリー関数の構文は次の通りです。

  ip_address(address)

addressに渡せるIPv4用の値は、IPv4Addressクラスの説明を参照してください。

32ビットに収まる整数はIPv4アドレスだと判断されます。そのためIPv6Addressオブジェクトを作成したい場合は、明示的にIPv6Addressクラスのコンストラクタを使う必要があります。

ネットワークオブジェクトのファクトリー関数

ネットワークオブジェクトのファクトリー関数は、与えられた引数を判定して、IPv4NetworkオブジェクトかIPv6Networkのオブジェクトを作成して返します。

ネットワークオブジェクトを作成するファクトリー関数構文は次の通りです。

ip_network(address, strict=True)

addressに渡せるIPv4用の値は、IPv4Networkクラスの説明を参照してください。

32ビットに収まる整数はIPv4アドレスだと判断されます。

インターフェイスオブジェクトのファクトリー関数

インターフェイスオブジェクトのファクトリー関数は、与えられた引数を判定して、IPv4InterfaceオブジェクトかIPv6Interfaceオブジェクトを作成して返します。

ファクトリー関数の構文は次の通りです。

ip_interface(address)

addressに渡せるIPv4用の値は、IPv4Interfaceクラスの説明を参照してください。

32ビットに収まる整数はIPv4アドレスだと判断されます。

まとめ

IPアドレスを扱うモジュールにはサードパーティ製のものもありますが、やはり組み込みのモジュールは安心感があります。みなさんも使ってみてはいかがでしょうか。