# c# 根据ip范围找到最合适的子网CIDR网络号

摘要

大概就是比如我给出一个ip范围 192.168.1.66-192.168.1.90,怎么快速算出合适的网络192.168.1.64/27,也就是 192.168.1.64->192.168.1.95

1、口算

  1. 网络:192.168.1.66,66最近的2的次方数64
  2. IP数:192.168.1.90-192.168.1.66=24
  3. IP数:24+1=25,比25大的2的次方数,2^5=32
  4. 掩码:32-5=27
  5. 结果:192.168.1.64/27

2、代码

using System.Buffers.Binary;
using System.Net;
using System.Numerics;

namespace StunNATDetector
{
    class Program
    {
        static async Task Main(string[] args)
        {
            //主网络掩码
            byte mainPrefixLength = 24;
            uint mainPrefixValue = mainPrefixLength < 1 ? 0 : 0xffffffff << (32 - mainPrefixLength);

            //按范围找到最接近的子网段
            uint startIpValue = BinaryPrimitives.ReadUInt32BigEndian(IPAddress.Parse("192.168.0.66").GetAddressBytes());
            uint endIpValue = BinaryPrimitives.ReadUInt32BigEndian(IPAddress.Parse("192.168.0.90").GetAddressBytes());

            //开始 66
            uint originStart = startIpValue & ~mainPrefixValue;
            //结束 90
            uint originEnd = endIpValue & ~mainPrefixValue;
            //开始最近二次幂数 64
            uint start = FindNearestPowerOfTwo(originStart);
            //掩码26
            byte prefixLength = (byte)(32 - (int)Math.Log2(FindNearestPowerOfTwo(originEnd - start + 1 )));
            uint prefixLengthValue = prefixLength < 1 ? 0 : 0xffffffff << (32 - prefixLength);

            //网络号 192.168.0.64
            uint networkValue = (startIpValue & prefixLengthValue) | start;
            IPAddress networkIp = new IPAddress(BinaryPrimitives.ReverseEndianness(networkValue));

            //广播号 192.168.0.95
            uint broadcastValue = startIpValue | ~prefixLengthValue;
            IPAddress broadcastIp = new IPAddress(BinaryPrimitives.ReverseEndianness(broadcastValue));

            Console.WriteLine($"{networkIp}/{prefixLength},{networkIp}->{broadcastIp}");
        }
        /// <summary>
        /// 最近的二次幂数
        /// </summary>
        /// <param name="number"></param>
        /// <returns></returns>
        public static uint FindNearestPowerOfTwo(uint number)
        {
            if (number <= 1)
            {
                return 1;
            }
            // 31 - 左边1之前的全0个数 = 最后一个1的位置
            // 66 01100000 -> 6  1<<6=64 和 1<<7=128
            int highestBit = 31 - BitOperations.LeadingZeroCount(number);

            uint lower = 1U << highestBit;
            uint upper = 1U << (highestBit + 1);

            return (number - lower <= upper - number) ? lower : upper;
        }
    }
}