Windows (intel CPU)では整数はリトルエンディアンでの表現ですが、IPアドレスはビッグエンディアンでの表現です。そのため、バイトの並びを逆にする必要があります。
詳しくはこちらの記事を参照してください。
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 |
ビット列になった状態で、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");
}
}
}
テスト結果は下図です。テストは通過しています。