IPアドレスがCIDR表記のネットワークアドレスに含まれるか判定する

IPアドレスがCIDR表記のネットワークアドレスに含まれるか判定するコードの紹介です。

概要

IPアドレス(192.168.0.100)の文字列が、CIDR表記(192.168.0.0/24)の文字列であらわされる、ネットワークアドレスに含まれるか判定したい場合があります。

入力IP 判定CIDR 含まれるか
192.168.0.100 192.168.0.0/24 True
10.0.0.16 10.0.0.0/28 False
172.16.24.45 172.16.22.0/30 False
172.16.18.3 172.16.18.0/30 True

実装

以下のコードを記述します。

using System.Net;
using System.Text.RegularExpressions;

namespace iPentec.Lib.IPUtils
{
  public class IPUtils
  {
    public bool IsIPInNetwork(string ipAddress, string networkPrefix)
    {
      string[] parts = networkPrefix.Split('/');
      IPAddress ipNetwork = IPAddress.Parse(parts[0]);
      int bits = Int32.Parse(parts[1]);

      uint mask = 0xffffffff << (32 - bits);

      byte[] ipNetworkBytes = ipNetwork.GetAddressBytes();
      Array.Reverse(ipNetworkBytes);
      uint ipNetworkValue = BitConverter.ToUInt32(ipNetworkBytes, 0);

      IPAddress ip = IPAddress.Parse(ipAddress);
      byte[] ipBytes = ip.GetAddressBytes();
      Array.Reverse(ipBytes);
      uint ipValue = BitConverter.ToUInt32(ipBytes, 0);

      return (ipNetworkValue & mask) == (ipValue & mask);
    }

  }
}

解説

CIDR表記のアドレスを "/" で分割してIP部分とマスク部分に分けます。

string[] parts = networkPrefix.Split('/');
IPAddress ipNetwork = IPAddress.Parse(parts[0]);
int bits = Int32.Parse(parts[1]);

入力IP 入力 CIDR ipNetwork bits
192.168.128.10 192.168.128.0/24 192.168.128.0 24


ネットワークアドレスのマスクを作成します。

  uint mask = 0xffffffff << (32 - bits);

入力IP 入力 CIDR ipNetwork bits mask
192.168.128.10 192.168.128.0/24 192.168.128.0 24 0xffffffff00


CIDRのIPアドレスをバイト配列(ビット列)に変換します。

  byte[] ipNetworkBytes = ipNetwork.GetAddressBytes();
  Array.Reverse(ipNetworkBytes);
  uint ipNetworkValue = BitConverter.ToUInt32(ipNetworkBytes, 0);
入力IP ipNetwork bits mask ipNetworkBytes ipNetworkBytes(reverse) ipNetworkValue
192.168.128.10 192.168.128.0 24 0xffffffff00 C0 A8 80 00 : 11000000 10101000 10000000 00000000 00 80 A8 C0 : 00000000 10000000 10101000 11000000 c0a88000


IPアドレスをバイト配列(ビット列)に変換します。

  IPAddress ip = IPAddress.Parse(ipAddress);
  byte[] ipBytes = ip.GetAddressBytes();
  Array.Reverse(ipBytes);
  uint ipValue = BitConverter.ToUInt32(ipBytes, 0);
入力IP ipBytes ipBytes (reverse) ipValue
192.168.128.10 C0 A8 80 0A : 11000000 10101000 10000000 00001010 0A 80 A8 C0 : 00001010 10000000 10101000 11000000 c0a8800a


Array.Reverse() について
Windows (intel CPU)では整数はリトルエンディアンでの表現ですが、IPアドレスはビッグエンディアンでの表現です。そのため、バイトの並びを逆にする必要があります。 詳しくはこちらの記事を参照してください。


ビット列になった状態で、CIDRのIPアドレス値と、入力のIPアドレスの値をそれぞれマスクして一致すれば、IPアドレスはCIDRのネットワークアドレス範囲に含まれていると判定します。

  return (ipNetworkValue & mask) == (ipValue & mask);
ipNetworkValue ipValue ipNetworkValue & mask ipValue & mask
c0a88000 c0a8800a c0a88000 c0a88000

テストコード ・ 実行結果

テストコードと実行結果です。

namespace IPUtilsTest
{
  public class UnitTest1
  {
    [Theory]
    [InlineData("192.168.128.10", "192.168.128.0/24", true)]
    [InlineData("192.168.1.10", "192.168.1.0/24", true)]
    [InlineData("192.168.1.255", "192.168.1.0/24", true)]
    [InlineData("192.168.2.1", "192.168.1.0/24", false)]
    [InlineData("10.0.0.1", "10.0.0.0/8", true)]
    [InlineData("10.255.255.255", "10.0.0.0/8", true)]
    [InlineData("172.16.0.1", "172.16.0.0/12", true)]
    [InlineData("172.31.255.254", "172.16.0.0/12", true)]
    [InlineData("192.168.0.100", "192.168.0.0/24", true)]
    [InlineData("10.6.2.32", "10.1.0.0/16", false)]
    [InlineData("192.168.1.1", "192.168.2.0/24", false)]
    [InlineData("172.16.0.0", "172.16.0.0/12", true)]
    [InlineData("172.16.255.255", "172.16.0.0/12", true)]
    [InlineData("123.45.67.89", "123.45.0.0/16", true)]
    public void Test1(string IPAddr, string CIDR, bool Result)
    {
      iPentec.Lib.IPUtils.IPUtils u = new iPentec.Lib.IPUtils.IPUtils();
      bool value = u.IsIPInNetwork(IPAddr, CIDR);

      Assert.True(value == Result, "NG");

    }

    [Theory]
    [InlineData("192.168.1.0", "192.168.1.0/24", true)]
    [InlineData("192.168.1.255", "192.168.1.0/24", true)]
    [InlineData("192.168.1.1", "192.168.1.0/24", true)]
    [InlineData("192.168.1.254", "192.168.1.0/24", true)]
    [InlineData("192.168.1.0", "192.168.2.0/24", false)]
    [InlineData("192.168.1.255", "192.168.2.0/24", false)]
    [InlineData("10.0.0.0", "10.0.0.0/8", true)]
    [InlineData("10.255.255.255", "10.0.0.0/8", true)]
    [InlineData("10.0.0.1", "10.0.0.0/8", true)]
    [InlineData("10.255.255.254", "10.0.0.0/8", true)]
    [InlineData("10.0.0.0", "10.0.1.0/24", false)]
    [InlineData("10.255.255.255", "10.0.1.0/24", false)]
    [InlineData("172.16.0.0", "172.16.0.0/12", true)]
    [InlineData("172.31.255.255", "172.16.0.0/12", true)]
    [InlineData("172.16.0.1", "172.16.0.0/12", true)]
    [InlineData("172.31.255.254", "172.16.0.0/12", true)]
    [InlineData("172.16.0.0", "172.16.1.0/24", false)]
    [InlineData("172.31.255.255", "172.16.1.0/24", false)]
    public void Test2(string IPAddr, string CIDR, bool Result)
    {
      iPentec.Lib.IPUtils.IPUtils u = new iPentec.Lib.IPUtils.IPUtils();
      bool value = u.IsIPInNetwork(IPAddr, CIDR);

      Assert.True(value == Result, "NG");
    }

  }
}


テスト結果は下図です。テストは通過しています。
IPアドレス(192.168.0.100)がCIDR表記(192.168.0.0/24)のネットワークアドレスに含まれるか判定する:画像1


AuthorPortraitAlt
著者
iPentecのプログラマー、最近はAIの積極的な活用にも取り組み中。
とっても恥ずかしがり。
作成日: 2024-05-22
Copyright © 1995–2025 iPentec all rights reserverd.