How to check if an IP address is within a particular subnet

后端 未结 7 1435
深忆病人
深忆病人 2020-12-01 12:15

I have a subnet in the format 10.132.0.0/20 and an IP address from the ASP.Net request object.

Is there a .NET framework function to check to see if the IP address i

相关标签:
7条回答
  • 2020-12-01 12:19

    I have also created a class which calculates the network and broadcast address and checks if the IP is neither broadcast nor network address.

    private static IPValidationFailedReason PerformIPRangeValidation(string ipAddress, string subnetMask)
            {
                IPValidationFailedReason ipValidationType = IPValidationFailedReason.None;
                string networkaddress = string.Empty;
                string broadcastAddress = string.Empty;
                string networkAddressBinary = string.Empty;
                string broadcastAddressBinary = string.Empty;
                int zerosCountInSubnetMask = 0;
    
                Array.ForEach(subnetMask.Split(SplitterChar), (eachOctet) => Array.ForEach(IPInterfaceHelper.GetOctetWithPadding(eachOctet).Where(c => c == CharZero).ToArray(), (k) => zerosCountInSubnetMask++));
    
                if (zerosCountInSubnetMask == 0)
                {
                    return ipValidationType;
                }
    
                string ipAddressBinary = IPInterfaceHelper.ToBinary(ipAddress);
                networkAddressBinary = GetNetworkAddressInBinaryFormat(zerosCountInSubnetMask, ipAddressBinary);
                broadcastAddressBinary = GetBroadcastAddressInBinaryFormat(zerosCountInSubnetMask, ipAddressBinary);
    
                networkaddress = ToIPFromBinary(networkAddressBinary);
                broadcastAddress = ToIPFromBinary(broadcastAddressBinary);
    
                if (ipAddress == networkaddress)
                {
                    ipValidationType = IPValidationFailedReason.NetworkAddressZero;
                    return ipValidationType;
                }
                if (ipAddress == broadcastAddress)
                {
                    ipValidationType = IPValidationFailedReason.BroadcastAddressNotPermiited;
                    return ipValidationType;
                }
    
                return ipValidationType;
            }
    
    
    private static string GetNetworkAddressInBinaryFormat(int zeroCountInSubnetMask, string ipAddressBinary)
        {
            string networkAddressBinary = string.Empty;
            int countOfOnesInSubnetMask = TotalBitCount - zeroCountInSubnetMask;
            StringBuilder sb = new StringBuilder(ipAddressBinary);
            //When Subnet is like 255.255.255.0
            if (zeroCountInSubnetMask >= 1 && zeroCountInSubnetMask <= 8)
            {
                networkAddressBinary = sb.Replace(CharOne, CharZero, countOfOnesInSubnetMask + 3, zeroCountInSubnetMask).ToString();
            }
            //When Subnet is like 255.255.0.0
            if (zeroCountInSubnetMask > 8 && zeroCountInSubnetMask <= 16)
            {
                networkAddressBinary = sb.Replace(CharOne, CharZero, countOfOnesInSubnetMask + 2, zeroCountInSubnetMask + 1).ToString();
            }
            //When Subnet is like 255.0.0.0
            if (zeroCountInSubnetMask > 16 && zeroCountInSubnetMask <= 24)
            {
                networkAddressBinary = sb.Replace(CharOne, CharZero, countOfOnesInSubnetMask + 1, zeroCountInSubnetMask + 2).ToString();
            }
            //When Subnet is like 128.0.0.0
            if (zeroCountInSubnetMask > 24 && zeroCountInSubnetMask < 32)
            {
                networkAddressBinary = sb.Replace(CharOne, CharZero, countOfOnesInSubnetMask , zeroCountInSubnetMask + 3).ToString();
            }
            return networkAddressBinary;
        }
    
    
     private static string GetBroadcastAddressInBinaryFormat(int zeroCountInSubnetMask, string ipAddressBinary)
        {
            string broadcastAddressBinary = string.Empty;
            int countOfOnesInSubnetMask = TotalBitCount - zeroCountInSubnetMask;
            StringBuilder sb = new StringBuilder(ipAddressBinary);
            //When Subnet is like 255.255.255.0
            if (zeroCountInSubnetMask >= 1 && zeroCountInSubnetMask <= 8)
            {
                broadcastAddressBinary = sb.Replace(CharZero, CharOne, countOfOnesInSubnetMask + 3, zeroCountInSubnetMask).ToString();
            }
            //When Subnet is like 255.255.0.0
            if (zeroCountInSubnetMask > 8 && zeroCountInSubnetMask <= 16)
            {
                broadcastAddressBinary = sb.Replace(CharZero, CharOne, countOfOnesInSubnetMask + 2, zeroCountInSubnetMask + 1).ToString();
            }
            //When Subnet is like 255.0.0.0
            if (zeroCountInSubnetMask > 16 && zeroCountInSubnetMask <= 24)
            {
                broadcastAddressBinary = sb.Replace(CharZero, CharOne, countOfOnesInSubnetMask + 1, zeroCountInSubnetMask + 2).ToString();
            }
            //When Subnet is like 128.0.0.0
            if (zeroCountInSubnetMask > 24 && zeroCountInSubnetMask < 32)
            {
                broadcastAddressBinary = sb.Replace(CharZero, CharOne, countOfOnesInSubnetMask , zeroCountInSubnetMask + 3).ToString();
            }
            return broadcastAddressBinary;
        }
    
    private static string ToIPFromBinary(string ipAddressBinary)
            {
                string addrTemp = string.Empty;
                string[] networkAddressBinaryOctets = ipAddressBinary.Split(SplitterChar);
                foreach (var eachOctet in networkAddressBinaryOctets)
                {
                    string temp = Convert.ToUInt32(eachOctet, 2).ToString(CultureInfo.InvariantCulture);
                    addrTemp += temp + SplitterChar;
                }
                // remove last '.'
                string ipAddress = addrTemp.Substring(0, addrTemp.Length - 1);
                return ipAddress;
            }
    
    0 讨论(0)
  • 2020-12-01 12:21

    The solution is to convert the IP Address into bytes using System.Net.IPAddress and perform bitwise comparisons on the address, subnet, and mask octets.

    The Binary AND Operator & copies a bit to the result if it exists in both operands.

    The code:

    using System.Net;   // Used to access IPAddress
    
    bool IsAddressOnSubnet(string address, string subnet, string mask)
    {
        try
        {
            IPAddress Address = IPAddress.Parse(address);
            IPAddress Subnet = IPAddress.Parse(subnet);
            IPAddress Mask = IPAddress.Parse(mask);            
    
            Byte[] addressOctets = Address.GetAddressBytes();
            Byte[] subnetOctets = Mask.GetAddressBytes();
            Byte[] networkOctets = Subnet.GetAddressBytes();
    
            return
                ((networkOctets[0] & subnetOctets[0]) == (addressOctets[0] & subnetOctets[0])) &&
                ((networkOctets[1] & subnetOctets[1]) == (addressOctets[1] & subnetOctets[1])) &&
                ((networkOctets[2] & subnetOctets[2]) == (addressOctets[2] & subnetOctets[2])) &&
                ((networkOctets[3] & subnetOctets[3]) == (addressOctets[3] & subnetOctets[3]));
        }
        catch (System.Exception ex)
        {
            return false;                
        }
    }
    

    Special thanks to Reference

    0 讨论(0)
  • 2020-12-01 12:25

    Bit manipulation works. Stuff the IP into a 32-bits unsigned integer, do the same with the subnet's address, &-mask both with 0xFFFFFFFF << (32-20) and compare:

    unsigned int net = ..., ip = ...;
    int network_bits = 20;
    unsigned int mask = 0xFFFFFFFF << (32 - network_bits);
    if ((net & mask) == (ip & mask)) {
      // ...
    }
    
    0 讨论(0)
  • 2020-12-01 12:31

    Since the MSDN blog code relies on a broadcast and IPv6 doesn't have one, I don't know if it works with IPv6.

    I ended up with these methods (thanks to nu everest). You can get the subnet and mask from a CIDR notation ("1.2.3.4/5") and check whether an adress is within this network or not.

    This works for IPv4 and IPv6:

    public static class IpAddresses
    {
        public static Tuple<IPAddress, IPAddress> GetSubnetAndMaskFromCidr(string cidr)
        {
            var delimiterIndex = cidr.IndexOf('/');
            string ipSubnet = cidr.Substring(0, delimiterIndex);
            string mask = cidr.Substring(delimiterIndex + 1);
    
            var subnetAddress = IPAddress.Parse(ipSubnet);
    
            if (subnetAddress.AddressFamily == AddressFamily.InterNetworkV6)
            {
                // ipv6
                var ip = BigInteger.Parse("00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", NumberStyles.HexNumber) << (128 - int.Parse(mask));
    
                var maskBytes = new[]
                {
                    (byte)((ip & BigInteger.Parse("00FF000000000000000000000000000000", NumberStyles.HexNumber)) >> 120),
                    (byte)((ip & BigInteger.Parse("0000FF0000000000000000000000000000", NumberStyles.HexNumber)) >> 112),
                    (byte)((ip & BigInteger.Parse("000000FF00000000000000000000000000", NumberStyles.HexNumber)) >> 104),
                    (byte)((ip & BigInteger.Parse("00000000FF000000000000000000000000", NumberStyles.HexNumber)) >> 96),
                    (byte)((ip & BigInteger.Parse("0000000000FF0000000000000000000000", NumberStyles.HexNumber)) >> 88),
                    (byte)((ip & BigInteger.Parse("000000000000FF00000000000000000000", NumberStyles.HexNumber)) >> 80),
                    (byte)((ip & BigInteger.Parse("00000000000000FF000000000000000000", NumberStyles.HexNumber)) >> 72),
                    (byte)((ip & BigInteger.Parse("0000000000000000FF0000000000000000", NumberStyles.HexNumber)) >> 64),
                    (byte)((ip & BigInteger.Parse("000000000000000000FF00000000000000", NumberStyles.HexNumber)) >> 56),
                    (byte)((ip & BigInteger.Parse("00000000000000000000FF000000000000", NumberStyles.HexNumber)) >> 48),
                    (byte)((ip & BigInteger.Parse("0000000000000000000000FF0000000000", NumberStyles.HexNumber)) >> 40),
                    (byte)((ip & BigInteger.Parse("000000000000000000000000FF00000000", NumberStyles.HexNumber)) >> 32),
                    (byte)((ip & BigInteger.Parse("00000000000000000000000000FF000000", NumberStyles.HexNumber)) >> 24),
                    (byte)((ip & BigInteger.Parse("0000000000000000000000000000FF0000", NumberStyles.HexNumber)) >> 16),
                    (byte)((ip & BigInteger.Parse("000000000000000000000000000000FF00", NumberStyles.HexNumber)) >> 8),
                    (byte)((ip & BigInteger.Parse("00000000000000000000000000000000FF", NumberStyles.HexNumber)) >> 0),
                };
    
                return Tuple.Create(subnetAddress, new IPAddress(maskBytes));
            }
            else
            {
                // ipv4
                uint ip = 0xFFFFFFFF << (32 - int.Parse(mask));
    
                var maskBytes = new[]
                {
                    (byte)((ip & 0xFF000000) >> 24),
                    (byte)((ip & 0x00FF0000) >> 16),
                    (byte)((ip & 0x0000FF00) >> 8),
                    (byte)((ip & 0x000000FF) >> 0),
                };
    
                return Tuple.Create(subnetAddress, new IPAddress(maskBytes));
            }
        }
    
        public static bool IsAddressOnSubnet(IPAddress address, IPAddress subnet, IPAddress mask)
        {
            byte[] addressOctets = address.GetAddressBytes();
            byte[] subnetOctets = mask.GetAddressBytes();
            byte[] networkOctets = subnet.GetAddressBytes();
    
            // ensure that IPv4 isn't mixed with IPv6
            if (addressOctets.Length != subnetOctets.Length
                || addressOctets.Length != networkOctets.Length)
            {
                return false;
            }
    
            for (int i = 0; i < addressOctets.Length; i += 1)
            {
                var addressOctet = addressOctets[i];
                var subnetOctet = subnetOctets[i];
                var networkOctet = networkOctets[i];
    
                if (networkOctet != (addressOctet & subnetOctet))
                {
                    return false;
                }
            }
            return true;
        }
    }
    

    Example usage:

    var subnetAndMask = IpAddresses.GetSubnetAndMaskFromCidr("10.132.0.0/20");
    bool result = IpAddresses.IsAddressOnSubnet(
        IPAddress.Parse("10.132.12.34"),
        subnetAndMask.Item1,
        subnetAndMask.Item2);
    
    0 讨论(0)
  • 2020-12-01 12:32

    Using the answers from Thomas and Chris together with Ciscos Subnetting Examples I finally got something to work for IPv4 and IPv6 if you use the CIDR notation (IPAddress/PrefixLength). My IPv6-Implementation might be a bit too straight forward but as there is no UInt128-datatype I couldn't adapt Thomas's solution. Here is the code that seems to work well:

    public static bool IsInSubnet(this IPAddress address, string subnetMask)
            {
                var slashIdx = subnetMask.IndexOf("/");
                if (slashIdx == -1)
                { // We only handle netmasks in format "IP/PrefixLength".
                    throw new NotSupportedException("Only SubNetMasks with a given prefix length are supported.");
                }
    
                // First parse the address of the netmask before the prefix length.
                var maskAddress = IPAddress.Parse(subnetMask.Substring(0, slashIdx));
    
                if (maskAddress.AddressFamily != address.AddressFamily)
                { // We got something like an IPV4-Address for an IPv6-Mask. This is not valid.
                    return false;
                }
    
                // Now find out how long the prefix is.
                int maskLength = int.Parse(subnetMask.Substring(slashIdx + 1));
    
                if (maskAddress.AddressFamily == AddressFamily.InterNetwork)
                {
                    // Convert the mask address to an unsigned integer.
                    var maskAddressBits = BitConverter.ToUInt32(maskAddress.GetAddressBytes().Reverse().ToArray(), 0);
    
                    // And convert the IpAddress to an unsigned integer.
                    var ipAddressBits = BitConverter.ToUInt32(address.GetAddressBytes().Reverse().ToArray(), 0);
    
                    // Get the mask/network address as unsigned integer.
                    uint mask = uint.MaxValue << (32 - maskLength);
    
                    // https://stackoverflow.com/a/1499284/3085985
                    // Bitwise AND mask and MaskAddress, this should be the same as mask and IpAddress
                    // as the end of the mask is 0000 which leads to both addresses to end with 0000
                    // and to start with the prefix.
                    return (maskAddressBits & mask) == (ipAddressBits & mask);
                }
    
                if (maskAddress.AddressFamily == AddressFamily.InterNetworkV6)
                {
                    // Convert the mask address to a BitArray.
                    var maskAddressBits = new BitArray(maskAddress.GetAddressBytes());
    
                    // And convert the IpAddress to a BitArray.
                    var ipAddressBits = new BitArray(address.GetAddressBytes());
    
                    if (maskAddressBits.Length != ipAddressBits.Length)
                    {
                        throw new ArgumentException("Length of IP Address and Subnet Mask do not match.");
                    }
    
                    // Compare the prefix bits.
                    for (int maskIndex = 0; maskIndex < maskLength; maskIndex++)
                    {
                        if (ipAddressBits[maskIndex] != maskAddressBits[maskIndex])
                        {
                            return false;
                        }
                    }
    
                    return true;
                }
    
                throw new NotSupportedException("Only InterNetworkV6 or InterNetwork address families are supported.");
            }
    

    And this are the XUnit tests I tested it with:

    public class IpAddressExtensionsTests
        {
            [Theory]
            [InlineData("192.168.5.85/24", "192.168.5.1")]
            [InlineData("192.168.5.85/24", "192.168.5.254")]
            [InlineData("10.128.240.50/30", "10.128.240.48")]
            [InlineData("10.128.240.50/30", "10.128.240.49")]
            [InlineData("10.128.240.50/30", "10.128.240.50")]
            [InlineData("10.128.240.50/30", "10.128.240.51")]
            public void IpV4SubnetMaskMatchesValidIpAddress(string netMask, string ipAddress)
            {
                var ipAddressObj = IPAddress.Parse(ipAddress);
                Assert.True(ipAddressObj.IsInSubnet(netMask));
            }
    
            [Theory]
            [InlineData("192.168.5.85/24", "192.168.4.254")]
            [InlineData("192.168.5.85/24", "191.168.5.254")]
            [InlineData("10.128.240.50/30", "10.128.240.47")]
            [InlineData("10.128.240.50/30", "10.128.240.52")]
            [InlineData("10.128.240.50/30", "10.128.239.50")]
            [InlineData("10.128.240.50/30", "10.127.240.51")]
            public void IpV4SubnetMaskDoesNotMatchInvalidIpAddress(string netMask, string ipAddress)
            {
                var ipAddressObj = IPAddress.Parse(ipAddress);
                Assert.False(ipAddressObj.IsInSubnet(netMask));
            }
    
            [Theory]
            [InlineData("2001:db8:abcd:0012::0/64", "2001:0DB8:ABCD:0012:0000:0000:0000:0000")]
            [InlineData("2001:db8:abcd:0012::0/64", "2001:0DB8:ABCD:0012:FFFF:FFFF:FFFF:FFFF")]
            [InlineData("2001:db8:abcd:0012::0/64", "2001:0DB8:ABCD:0012:0001:0000:0000:0000")]
            [InlineData("2001:db8:abcd:0012::0/64", "2001:0DB8:ABCD:0012:FFFF:FFFF:FFFF:FFF0")]
            [InlineData("2001:db8:abcd:0012::0/128", "2001:0DB8:ABCD:0012:0000:0000:0000:0000")]
            public void IpV6SubnetMaskMatchesValidIpAddress(string netMask, string ipAddress)
            {
                var ipAddressObj = IPAddress.Parse(ipAddress);
                Assert.True(ipAddressObj.IsInSubnet(netMask));
            }
    
            [Theory]
            [InlineData("2001:db8:abcd:0012::0/64", "2001:0DB8:ABCD:0011:FFFF:FFFF:FFFF:FFFF")]
            [InlineData("2001:db8:abcd:0012::0/64", "2001:0DB8:ABCD:0013:0000:0000:0000:0000")]
            [InlineData("2001:db8:abcd:0012::0/64", "2001:0DB8:ABCD:0013:0001:0000:0000:0000")]
            [InlineData("2001:db8:abcd:0012::0/64", "2001:0DB8:ABCD:0011:FFFF:FFFF:FFFF:FFF0")]
            [InlineData("2001:db8:abcd:0012::0/128", "2001:0DB8:ABCD:0012:0000:0000:0000:0001")]
            public void IpV6SubnetMaskDoesNotMatchInvalidIpAddress(string netMask, string ipAddress)
            {
                var ipAddressObj = IPAddress.Parse(ipAddress);
                Assert.False(ipAddressObj.IsInSubnet(netMask));
            }
        }
    

    As base for the tests I used Ciscos Subnetting Examples and IBMs IPV6 address examples.

    I hope someone finds this helpful ;)

    0 讨论(0)
  • Take a look at IP Address Calculations with C# on MSDN blogs. It contains an extension method (IsInSameSubnet) that should meet your needs as well as some other goodies.

    public static class IPAddressExtensions
    {
        public static IPAddress GetBroadcastAddress(this IPAddress address, IPAddress subnetMask)
        {
            byte[] ipAdressBytes = address.GetAddressBytes();
            byte[] subnetMaskBytes = subnetMask.GetAddressBytes();
    
            if (ipAdressBytes.Length != subnetMaskBytes.Length)
                throw new ArgumentException("Lengths of IP address and subnet mask do not match.");
    
            byte[] broadcastAddress = new byte[ipAdressBytes.Length];
            for (int i = 0; i < broadcastAddress.Length; i++)
            {
                broadcastAddress[i] = (byte)(ipAdressBytes[i] | (subnetMaskBytes[i] ^ 255));
            }
            return new IPAddress(broadcastAddress);
        }
    
        public static IPAddress GetNetworkAddress(this IPAddress address, IPAddress subnetMask)
        {
            byte[] ipAdressBytes = address.GetAddressBytes();
            byte[] subnetMaskBytes = subnetMask.GetAddressBytes();
    
            if (ipAdressBytes.Length != subnetMaskBytes.Length)
                throw new ArgumentException("Lengths of IP address and subnet mask do not match.");
    
            byte[] broadcastAddress = new byte[ipAdressBytes.Length];
            for (int i = 0; i < broadcastAddress.Length; i++)
            {
                broadcastAddress[i] = (byte)(ipAdressBytes[i] & (subnetMaskBytes[i]));
            }
            return new IPAddress(broadcastAddress);
        }
    
        public static bool IsInSameSubnet(this IPAddress address2, IPAddress address, IPAddress subnetMask)
        {
            IPAddress network1 = address.GetNetworkAddress(subnetMask);
            IPAddress network2 = address2.GetNetworkAddress(subnetMask);
    
            return network1.Equals(network2);
        }
    }
    
    0 讨论(0)
提交回复
热议问题