一覧NW-05-1 · サブネットとアドレス範囲

IPv4プレフィックスとアドレス範囲

同じIPのプレフィックス長を変え、所属範囲と端の扱いを確認します。

説明

IPv4のプレフィックス長は、32ビットのうちネットワークを示す先頭部分の長さです。アドレスの見た目が近くても、マスクによって同じ範囲かどうかが変わります。

192.0.2.99/26をipaddressで解析し、マスク、範囲の先頭と末尾、利用するホストの範囲を確認します。/25・/27へ変えた場合を比較し、最後に通常のLANとは数え方が異なる/31と/32を扱います。

1端末アドレスから所属範囲を得る

ip_interfaceは端末のIPとマスクを組として扱います。まず192.0.2.99/26を解析します。

import ipaddressアドレス操作を読み込む; interface = ipaddress.ip_interface("192.0.2.99/26")端末の設定; net = interface.network; print(interface.ip, net, net.netmask)IP・範囲・マスク

所属範囲は192.0.2.64/26、マスクは255.255.255.192です。.99を先頭とする範囲ではありません。/26では末尾6ビットがホスト部分なので、範囲の幅は64アドレスです。

2マスクのAND演算を確認

IPとマスクを32ビットの整数へ変換し、ANDでネットワーク部分を残します。

address = int(interface.ip); mask = int(net.netmask)32ビット整数へ変換; print(f"{address:032b}"); print(f"{mask:032b}")同じ桁数で比較; print(ipaddress.IPv4Address(address & mask))ネットワーク部分を残す

マスクは先頭26ビットが1、残る6ビットが0です。最後のオクテットでは99=01100011と192=11000000のANDが64=01000000になり、所属範囲の先頭が得られます。

3先頭・末尾・総数

ネットワークアドレスとブロードキャストアドレス、含まれる全アドレス数を表示します。

print(net.network_address, net.broadcast_address, net.num_addresses)範囲の両端と総数

先頭.64、末尾.127、総数64です。通常のこのLANでは.64はネットワーク、.127はブロードキャストに使い、端末へ割り当てる範囲はその間になります。

4ホストとして列挙される範囲

hostsで通常のホスト範囲を取り出し、先頭と末尾と数を確認します。

hosts = list(net.hosts())ホスト範囲を列挙; print(hosts[0], hosts[-1], len(hosts))割当て候補の両端と数

192.0.2.65〜126の62アドレスです。ゲートウェイ、冗長化用の仮想IP、固定管理用の予約もこの中を使うなら、その分を端末の必要数へ含めます。62台の一般端末に加えて別のIPを無制限に割り当てられるわけではありません。

5サブネットに含まれるアドレスと端末に割り当てられるアドレス

.63・.64・.99・.127・.128を、範囲への所属と通常のホスト候補の両方で調べます。

candidates = [ipaddress.ip_address("192.0.2." + str(n)) for n in (63,64,99,127,128)]境界の前後と内部; print([(str(ip), ip in net, ip in hosts) for ip in candidates])所属と割当て候補を比較

.64と.127は範囲内ですが、この通常LANのホスト候補ではありません。.63と.128は隣の範囲です。範囲検査のTrueだけを、端末へ割当て可能という判定に使わないようにします。

6同じIPのプレフィックス長を変える

IPを.99に保ち、/25・/26・/27で所属範囲を作り直します。

variants = [ipaddress.ip_interface(f"192.0.2.99/{p}").network for p in (25,26,27)]同じIPで三種類のマスク; print([(str(n),str(n.broadcast_address),n.num_addresses) for n in variants])変化した範囲と数

/25は.0〜127の128個、/26は.64〜127の64個、/27は.96〜127の32個です。末尾が同じでも先頭と数が変わります。プレフィックスが1ビット長くなると範囲の幅が半分になります。

7ポイントツーポイントの/31

対応機器同士のポイントツーポイントリンクで192.0.2.10/31を使う場合を確認します。

link = ipaddress.ip_network("192.0.2.10/31")二端点の範囲; print(link.num_addresses, [str(ip) for ip in link.hosts()])総数と端点

総数2で、.10と.11の両方を端点として使えます。RFC 3021の/31では通常のLANのように両端を除外しません。どの接続でも無条件にこの扱いにできるのではなく、リンクと機器の対応条件を確認します。

8一つのアドレスを表す/32

一つだけを示すホスト経路の範囲を作ります。

single = ipaddress.ip_network("192.0.2.99/32")単一アドレスの範囲; print(single.num_addresses, [str(ip) for ip in single.hosts()], ipaddress.ip_address("192.0.2.100") in single)一致する一つだけを確認

含むのは.99一つで、.100は対象外です。/32のホスト経路やループバック等の用途では、通常LANの総数から2を引く計算を使いません。アドレス数はプレフィックスだけでなく、どの用途の利用可能数を数えるのかも明示します。

まとめ

プレフィックス長とマスクから、範囲の先頭・末尾・総数が決まります。

範囲内であることと、通常LANのホストへ割り当てられることは別です。

/31のポイントツーポイントや/32では、単純に総数から2を引く扱いにしません。

操作履歴と解説を振り返れます。

Python 3

1
import ipaddress; interface = ipaddress.ip_interface("192.0.2.99/26"); net = interface.network; print(interface.ip, net, net.netmask)
192.0.2.99 192.0.2.64/26 255.255.255.192
2
address = int(interface.ip); mask = int(net.netmask); print(f"{address:032b}"); print(f"{mask:032b}"); print(ipaddress.IPv4Address(address & mask))
11000000000000000000001001100011
11111111111111111111111111000000
192.0.2.64
3
print(net.network_address, net.broadcast_address, net.num_addresses)
192.0.2.64 192.0.2.127 64
4
hosts = list(net.hosts()); print(hosts[0], hosts[-1], len(hosts))
192.0.2.65 192.0.2.126 62
5
candidates = [ipaddress.ip_address("192.0.2." + str(n)) for n in (63,64,99,127,128)]; print([(str(ip), ip in net, ip in hosts) for ip in candidates])
[('192.0.2.63', False, False), ('192.0.2.64', True, False), ('192.0.2.99', True, True), ('192.0.2.127', True, False), ('192.0.2.128', False, False)]
6
variants = [ipaddress.ip_interface(f"192.0.2.99/{p}").network for p in (25,26,27)]; print([(str(n),str(n.broadcast_address),n.num_addresses) for n in variants])
[('192.0.2.0/25', '192.0.2.127', 128), ('192.0.2.64/26', '192.0.2.127', 64), ('192.0.2.96/27', '192.0.2.127', 32)]
7
link = ipaddress.ip_network("192.0.2.10/31"); print(link.num_addresses, [str(ip) for ip in link.hosts()])
2 ['192.0.2.10', '192.0.2.11']
8
single = ipaddress.ip_network("192.0.2.99/32"); print(single.num_addresses, [str(ip) for ip in single.hosts()], ipaddress.ip_address("192.0.2.100") in single)
1 ['192.0.2.99'] False

演習完了