テスト用のIPアドレスジェネレーターの役割は1つだけです。フィクスチャが主張するスコープに対して有効なアドレスを返し、かつ重要なマシンを誤って指さないことです。後半こそ、ほとんどのジェネレーターが失敗する部分です。構文的にパブリックなアドレスでも、銀行、クラウドプロバイダー、あるいは自社のオフィス回線に属している可能性があります。
このガイドでは、ジェネレーターがサポートするスコープ、すべてのバリデーターが知っておくべき特殊用途の範囲、構文的にパブリックなアドレスとルーティング可能なアドレスの違い、そして実際のネットワークと衝突しないフィクスチャセットの構築方法を扱います。IPv6についても取り上げます。IPv6はスコープのルールが十分に異なるため、IPv4のメンタルモデルをそのまま持ち込むと壊れたテストが生まれます。
ジェネレーターが返すもの
IPv4では、ジェネレーターは4つのスコープの値を生成します:パブリック、プライベート、ループバック、リンクローカルです。IPv6でも同様に4つのスコープを生成します:グローバル、ユニークローカル(ULA)、リンクローカル、ループバックです。スコープは出力から推測するものではなくリクエストの一部です。同じドット区切りの数値が、ある文脈ではプライベートであり、別の文脈ではプライベートネットワーク上の有効なホストになり得るからです。
スコープはフィクスチャのラベルであり、到達可能性の主張ではありません。生成されたパブリックスコープのアドレスはプライベートおよび特殊用途のブロックの外側にありますが、インターネット上のどこかの実際の割り当てと一致する可能性はあります。生成されたアドレスにトラフィックを送信しないでください。実際の何かと通信しないことをテストで確実にする必要がある場合は、パブリックスコープの出力ではなく、後述するドキュメント用範囲を使用してください。
- IPv4スコープ:パブリック、プライベート、ループバック、リンクローカル
- IPv6スコープ:グローバル、ユニークローカル、リンクローカル、ループバック
- どのスコープも、そのアドレスへのトラフィック送信が安全であることを意味しない
- 厳密な分離には、パブリックスコープの出力ではなくドキュメント用範囲を使用する
IPv4の特殊用途範囲
以下のブロックは、バリデーターやフィクスチャビルダーが明示的に処理しなければならないものです。プライベート空間は10.0.0.0/8、172.16.0.0/12、192.168.0.0/16で、約1,780万個のアドレスがあります。ループバックは127.0.0.1だけでなく127.0.0.0/8ブロック全体であり、リンクローカルは169.254.0.0/16で、DHCPが失敗したときのAPIPA範囲としておなじみです。
これらに加えて、テストで重要なブロックがいくつかあります。100.64.0.0/10はキャリアグレードNAT空間で、多くのネットワークではプライベート空間のように振る舞います。192.0.2.0/24、198.51.100.0/24、203.0.113.0/24はドキュメント用に予約されており、実際のホストに決して到達してはならないフィクスチャに最適です。198.18.0.0/15はベンチマーク用に予約されています。0.0.0.0/8は「このホスト」を意味し、224.0.0.0/4はマルチキャスト、240.0.0.0/4は予約済みです。
| スコープ | CIDR | アドレス数 | 典型的な用途 |
|---|---|---|---|
| プライベート | 10.0.0.0/8 | 16,777,216 | 大規模プライベートネットワーク |
| プライベート | 172.16.0.0/12 | 1,048,576 | Dockerおよび中規模ネットワーク |
| プライベート | 192.168.0.0/16 | 65,536 | 家庭および小規模オフィスLAN |
| ループバック | 127.0.0.0/8 | 16,777,216 | ローカルホストのみ |
| リンクローカル | 169.254.0.0/16 | 65,536 | DHCP失敗時のAPIPA |
| キャリアNAT | 100.64.0.0/10 | 4,194,304 | ISP共有アドレス空間 |
| ドキュメント | 192.0.2.0/24 | 256 | 安全なフィクスチャ範囲(TEST-NET-1) |
| ベンチマーク | 198.18.0.0/15 | 131,072 | ネットワークテスト機器 |
| マルチキャスト | 224.0.0.0/4 | 268,435,456 | グループ配信 |
プライベート空間と10/8の疑問
3つのプライベートブロックはRFC 1918で定義されており、パブリックインターネット上ではルーティングされません。どれを使うかは規模と慣習の問題です。10/8は何にでも十分な大きさの単一フラット空間を提供し、172.16/12はコンテナネットワークで一般的で、192.168/16はコンシューマールーターのデフォルトです。ブロックは重複しないため、すべてのプライベートアドレスが10で始まると仮定するテストは、空間の3分の2について間違っています。
テストを壊す微妙な点:プライベートアドレスはプライベートネットワーク内では普通のアドレスです。CIランナーが10.0.0.0/8上にある場合、そのブロック内で生成されたプライベートアドレスは、メタデータサービスや管理パネルを含む実際の内部ホストを指す可能性があります。192.168.0.0/16範囲から、あるいはテストを分離する必要がある場合はドキュメント用範囲から生成してください。
- RFC 1918ブロック:10/8、172.16/12、192.168/16
- テストを実行するネットワークと重複しない範囲を選ぶ
- クラウドのメタデータエンドポイントはよく知られたプライベートアドレスにある
- 内部ホストも外部ホストと同じくらい現実的である
ループバック、リンクローカル、そしてそれらの適切な場所
ループバックアドレスはホストから出ることはありません。127.0.0.1が一般的ですが、ほとんどのスタックでは127.0.0.0/8ブロック全体がループバックであり、127.0.0.53はローカルDNSのためにsystemd-resolvedが使用します。127.0.0.1をサーバーアドレスとしてハードコードするテストは、同じポートを使うマシン上の他の何かと衝突します。そのため並列テスト実行ではポートを動的に割り当てるべきです。
169.254.0.0/16のリンクローカルIPv4アドレスは、DHCPサーバーが応答しないときに自動的に割り当てられます。本番ログでこれを見かけることは、顧客が奇妙なネットワークにいるのではなく、DHCPが失敗したことをほぼ常に意味します。IPv6では同等のものがfe80::/10で、動作が異なります。すべてのIPv6インターフェースがリンクローカルアドレスを持ち、近隣探索に必要であり、同じアドレスがすべてのリンクに存在するためゾーンインデックスなしでは使用できません。
| アドレス | スコープ | ホストから出られるか | よくある間違い |
|---|---|---|---|
| 127.0.0.1 | IPv4ループバック | いいえ | これだけがループバックだと仮定する |
| 127.0.0.53 | IPv4ループバック | いいえ | ローカルリゾルバーと衝突する |
| 169.254.1.1 | IPv4リンクローカル | 同じリンクのみ | パブリックアドレスとして扱う |
| ::1 | IPv6ループバック | いいえ | ::1/128をホスト範囲として書く |
| fe80::1 | IPv6リンクローカル | 同じリンクのみ | ゾーンインデックスを省略する |
IPv4のメンタルモデルなしでIPv6スコープを扱う
IPv6にはブロードキャストもNATの要件もなく、スコープのルールはプレフィックスに含まれています。グローバルユニキャストは現在2000::/3にあり、これは2000::から3fff:ffff:ffff:ffff:ffff:ffff:ffff:ffffまでの全範囲です。ユニークローカルアドレスはfc00::/7にあり、慣習的にfd00::/8から生成されます。リンクローカルはfe80::/10で、::1/128はループバック、::/128は未指定アドレスです。
ジェネレーターはこれら4つのスコープのアドレスを返します。テストで重要な点が2つあります。ULAアドレスはグローバルにルーティング可能ではなく、プライベートとして扱わなければなりません。またリンクローカルアドレスはゾーン識別子(例:fe80::1%eth0)とともにのみ意味を持ちます。コードがIPv6アドレスを保存する場合は、ゾーンをテキストに貼り付けず別に保存してください。URL内のパーセント記号は別の意味を持つからです。
| スコープ | プレフィックス | ルーティング可能 | 例 |
|---|---|---|---|
| グローバルユニキャスト | 2000::/3 | 原則として可能 | 2001:db8::1 |
| ユニークローカル | fc00::/7 | 不可、プライベート | fd12:3456::1 |
| リンクローカル | fe80::/10 | 同じリンクのみ | fe80::1 |
| ループバック | ::1/128 | 不可 | ::1 |
| ドキュメント | 2001:db8::/32 | ドキュメント用に予約 | 2001:db8::1 |
移行アドレスとその他の罠
IPv4マップドIPv6アドレスは::ffff:192.0.2.1の形式を取り、デュアルスタックソケットがIPv4ピアをIPv6として報告するときに現れます。これらは汎用のIPv6アドレスではなく、そのように扱うとプレフィックスを比較するレートリミッターやアクセスルールにバグを生みます。2002::/16の6to4アドレスと2001::/32のTeredoアドレスは独自の構造を持つ移行メカニズムです。通常のグローバルアドレスのように生成しないでください。
他の罠はより古いものですが依然として存在します。010.1.1.1のようにIPv4オクテットに先頭のゼロがあると、一部のパーサーは8進数として解釈し、他は拒否します。フィクスチャで決して受け入れないでください。省略形の127.1は一部のスタックで127.0.0.1として受け入れられます。ポートは別のフィールドであり、アドレス値に連結してはなりません。
- ::ffff:0:0/96はIPv4マップドであり、通常のIPv6範囲ではない
- 2001:db8::/32はドキュメント空間であり、フィクスチャの安全なデフォルトである
- 基数を推測せず、先頭にゼロがあるオクテットを拒否する
- スタック固有の展開に依存する127.1のような形式を拒否する
- ポートはアドレスフィールドの外に保ち、別の整数として検証する
衝突し得ないフィクスチャセットの構築
ソケットを一切開かない単体テストには、ドキュメント用範囲を使用してください:IPv4は192.0.2.0/24、198.51.100.0/24、203.0.113.0/24、IPv6は2001:db8::/32です。これらは例やテストが実際のホストに到達できないようにするためにまさに予約されています。パーサーはこれらを構文的に有効なパブリックスコープのアドレスとして受け入れるべきであり、分類ロジックの良いテストにもなります。
ソケットを開く統合テストには、ループバックにバインドし、8080をハードコードするのではなくオペレーティングシステムからポートを割り当ててください。もっともらしいリモートピアが必要なテストには、ドキュメント用範囲を使用し、クライアントがそれらに接続しようとすると拒否するようにしてください。この組み合わせにより、現実的な値と、設定ミスが予期しない場所にトラフィックを送れないという強固な保証が得られます。
| ニーズ | 使用するもの | 理由 |
|---|---|---|
| パースとフォーマット | 192.0.2.0/24、2001:db8::/32 | 予約済みでホストに到達できない |
| プライベートスコープのロジック | 192.168.0.0/16 | CIネットワークと重複する可能性が低い |
| ループバックサーバー | 127.0.0.1とOS割り当てポート | 固定ポートの衝突がない |
| リンクローカルロジック | 169.254.0.0/16とfe80::/10 | 正しい分岐をトリガーする |
| スコープ分類 | 1つのテーブルに4つのスコープすべて | 誤ったマスクやプレフィックスを検出する |
テストに到達する前に出力を検証する
生成されたすべてのアドレスは、アプリケーションが使用するのと同じバリデーターを通過すべきです。それが生成する意味です。ファミリーが要求されたスコープと一致すること、アドレスが期待されるブロック内にあること、テキスト形式が同じビットにパースし直されることをアサートしてください。ラウンドトリップはIPv6のゼロ圧縮エラーを検出します。2001:db8:0:0:0:0:0:1は2001:db8::1に正規化されなければならず、それ以外はありません。
また、アドレスが何でないかもアサートしてください。プライベートスコープのフィクスチャはパブリックブロック内にあってはならず、ループバックフィクスチャは127.0.0.0/8内か正確に::1でなければならず、テストが明示的にそれらのケースについてでない限り、どのフィクスチャもマルチキャスト、ブロードキャスト、未指定アドレスであってはなりません。これらの否定アサーションは安価で、最も恥ずかしいジェネレーターバグを検出します。
- ラウンドトリップ:パース、フォーマット、パース、文字列ではなくビットを比較する
- ファミリーチェック:値が要求されたIPバージョンとしてパースされる
- スコープチェック:プレフィックス文字列比較ではなくブロックへの包含
- 否定チェック:マルチキャストでない、ブロードキャストでない、未指定でない
- 正規化:IPv6出力は正規の圧縮形式を使用する
よくある質問
- IPv4はパブリック、プライベート、ループバック、リンクローカル、IPv6はグローバル、ユニークローカル、リンクローカル、ループバックです。スコープは出力から推測するのではなく明示的に選択します。
- いいえ。パブリックスコープはプライベートおよび特殊ブロックの外側を意味し、未割り当てを意味しません。テストが実際のホストに到達してはならない場合は、ドキュメント用範囲192.0.2.0/24と2001:db8::/32を使用してください。
- 100.64.0.0/10です。RFC 1918のプライベート空間ではありませんが、グローバルにルーティング可能でもないため、分類ロジックではプライベートとして扱ってください。
- fe80::/10範囲はすべてのリンクに別々に存在するため、同じアドレスが異なるホストを指す可能性があります。パーセント記号とインターフェース名のようなゾーン識別子が、どのリンクを意味するかを示します。
- 文書化された4つのIPv6スコープを生成します。::ffff:192.0.2.1のようなIPv4マップド形式は移行表現であり、通常のフィクスチャとして使用するのではなく、パーサーで処理すべきです。
ジェネレーターはどのスコープを生成できますか?+
生成されたパブリックIPアドレスに接続しても安全ですか?+
キャリアグレードNATはどのIPv4ブロックですか?+
IPv6リンクローカルアドレスにゾーンインデックスが必要なのはなぜですか?+
ジェネレーターはIPv4マップドIPv6アドレスを作成できますか?+
例は合成データです。生成された住所を本人確認、アカウント登録、配送に使用しないでください。