Подтвердить что ты не робот

Как узнать, принадлежит ли IP-адрес внутри диапазона IP-адресов, используя нотацию CIDR?

Здесь у меня есть статическая ссылка диапазонов, которые мне нужно проверить:

private static List<string> Ip_Range = new List<string>()
{
    "12.144.86.0/23",
    "31.201.1.176/30",
    "46.36.198.101/32",
    "46.36.198.102/31",
    "46.36.198.104/31",
    "46.136.172.0/24",
    "63.65.11.0/24",
    "63.65.12.0/25",
    "63.65.12.128/26",
    "63.65.12.192/27",
    "63.65.12.224/28",
    "63.65.12.240/29",
    "63.65.12.248/30",
    "63.65.12.252/31",
    "63.65.12.254/32",
    "65.173.56.0/21",
    "67.23.241.179/32",
    "67.23.241.180/30",
    "67.23.241.184/29",
    "67.23.241.192/30",
    "67.23.241.196/31",
    "67.23.241.198/32",
    "72.32.164.56/29",
    "72.46.244.32/28",
    "74.91.16.48/29",
    "74.91.16.208/29",
    "74.91.20.48/28",
    "74.91.20.64/29",
    "74.112.134.120/29",
    "74.112.135.104/29",
    "74.205.37.16/29",
    "78.24.205.32/28",
    "98.129.27.88/29",
    "98.129.91.40/29",
    "166.114.0.0/16",
    "167.157.0.0/16",
    "174.143.165.80/29",
    "186.0.156.0/22",
    "186.2.0.0/17",
    "186.27.0.0/17",
    "190.0.248.0/21",
    "190.3.184.0/21"
};

Вот какой-то псевдо-код о том, как я его вижу:

public static bool IpIsWithinRange(string ip) //Something like 127.0.0.1 or 184.56.26.35
{
    IPAddress incomingIp = IPAddress.Parse(ip);
    foreach (var subnet in Ip_Range)
    {
        IPAddress sub = IPAddress.Parse(subnet); ?????
        if (incomingIp "is in" sub) ?
            return true;            
    }
    return false;
}

Любые предложения о том, как закодировать эту функциональность?

4b9b3361

Ответ 1

Решил ответить на мой собственный вопрос, чтобы люди могли извлечь выгоду. Если это можно улучшить, сделайте это!

Я использовал IPNetwork library, и это получилось фантастически! Ниже приведен код, который я использовал:

using System.Net;

public static class RedirectHelpers
{
    public static bool IpIsWithinBoliviaRange(string ip)
    {
        IPAddress incomingIp = IPAddress.Parse(ip);
        foreach (var subnet in Bolivia_Ip_Range)
        {
            IPNetwork network = IPNetwork.Parse(subnet);

            if (IPNetwork.Contains(network, incomingIp))
                return true;
        }
        return false;
    }

    private static List<string> Bolivia_Ip_Range = new List<string>()
    {
        "12.144.86.0/23",
        "31.201.1.176/30",
        "46.36.198.101/32",
        "46.36.198.102/31",
        "46.36.198.104/31",
        "46.136.172.0/24",
        "63.65.11.0/24",
        "63.65.12.0/25",
        "63.65.12.128/26",
        "63.65.12.192/27",
        "63.65.12.224/28",
        "63.65.12.240/29",
        "63.65.12.248/30",
        "63.65.12.252/31",
        "63.65.12.254/32",
        "65.173.56.0/21",
        "67.23.241.179/32",
        "67.23.241.180/30",
        "67.23.241.184/29",
        "67.23.241.192/30",
        "67.23.241.196/31",
        "67.23.241.198/32",
        "72.32.164.56/29",
        "72.46.244.32/28",
        "74.91.16.48/29",
        "74.91.16.208/29",
        "74.91.20.48/28",
        "74.91.20.64/29",
        "74.112.134.120/29",
        "74.112.135.104/29",
        "74.205.37.16/29",
        "78.24.205.32/28",
        "98.129.27.88/29",
        "98.129.91.40/29",
        "166.114.0.0/16",
        "167.157.0.0/16",
        "174.143.165.80/29",
        "186.0.156.0/22",
        "186.2.0.0/17",
        "186.27.0.0/17",
        "190.0.248.0/21",
        "190.3.184.0/21",
        "166.114.0.0/16",
        "167.157.0.0/16",
        "186.2.0.0/18",
        "190.11.64.0/20",
        "190.11.80.0/20",
        "190.103.64.0/20",
        "190.104.0.0/19",
        "190.107.32.0/20",
        "190.129.0.0/17",
        "190.181.0.0/18",
        "190.186.0.0/18",
        "190.186.64.0/18",
        "190.186.128.0/18",
        "200.7.160.0/20",
        "200.58.64.0/20",
        "200.58.80.0/20",
        "200.58.160.0/20",
        "200.58.176.0/20",
        "200.75.160.0/20",
        "200.85.128.0/20",
        "200.87.0.0/17",
        "200.87.128.0/17",
        "200.105.128.0/19",
        "200.105.160.0/19",
        "200.105.192.0/19",
        "200.112.192.0/20",
        "200.119.192.0/20",
        "200.119.208.0/20",
        "201.222.64.0/19",
        "201.222.96.0/19"
    };
}

Ответ 2

Если вы не хотите/не можете добавить в свой проект еще одну библиотеку (как IPnetwork), и вам просто нужно иметь дело с диапазонами CIDR IPv4, здесь быстрое решение вашей проблемы

// true if ipAddress falls inside the CIDR range, example
// bool result = IsInRange("10.50.30.7", "10.0.0.0/8");
private bool IsInRange(string ipAddress, string CIDRmask)
{
    string[] parts = CIDRmask.Split('/');

    int IP_addr = BitConverter.ToInt32(IPAddress.Parse(parts[0]).GetAddressBytes(), 0);
    int CIDR_addr = BitConverter.ToInt32(IPAddress.Parse(ipAddress).GetAddressBytes(), 0);
    int CIDR_mask = IPAddress.HostToNetworkOrder(-1 << (32 - int.Parse(parts[1])));

    return ((IP_addr & CIDR_mask) == (CIDR_addr & CIDR_mask));
}

вышеуказанное позволит вам быстро проверить, попадает ли данный IPv4-адрес в данный диапазон CIDR; обратите внимание, что приведенный выше код является barebone, вам нужно проверить правильность заданного диапазона IP (строки) и CIDR, прежде чем загружать их в функцию (вы можете просто использовать tryparse или что-то еще...)

Ответ 3

К счастью, большая часть работы уже сделана для вас (так что нам не нужно). Просмотрите проект IPNetwork. Вы проанализируете все свои CIDR-адреса с помощью IPNetwork.Parse. Затем, чтобы увидеть, находится ли конкретный IPAddress в диапазоне, используйте метод IPNetwork.Contains.


Мне стало скучно, поэтому здесь вы можете использовать метод, чтобы проверить, находится ли IP-адрес в диапазоне или нет:

private Dictionary<string, IPNetwork> netCache = null;
public bool IsInRange(string ipAddress)
{
    if (netCache == null)
        netCache = Ip_Range.ToDictionary((keyItem) => keyItem, (valueItem) => IPNetwork.Parse(valueItem));

    return netCache.Values.Any(net => IPNetwork.Contains(net, IPAddress.Parse(ipAddress)));
}

Это зависит от списка Ip_Range от вашего вопроса, но переводит их в экземпляры IPNetwork (для краткости не хватает проверок здравомыслия).

Использование:

List<string> addrList = new List<string> { "12.144.86.1", "10.254.6.172" };
addrList.ForEach(addr => Console.WriteLine("{0}: {1}", addr, IsInRange(addr)));

Выход теста:

12.144.86.1: True
10.254.6.172: False

Конечно, есть еще многое, что (и, вероятно, должно) должно быть сделано с ним, но это доказывает концепцию.

Ответ 4

Если вы понимаете нотацию CIDR, вы можете легко выполнить математику в своем методе анализа.

В основном вы знаете, что IPv4-адрес имеет длину 32 бита и что обозначение CIDR означает, что количество бит за "/" - это биты сетевых адресов (т.е. маскированные биты), поэтому оставшиеся биты представляют собой число хостов в подсети.

Из wikipedia статья:

Количество адресов подсети, определяемых маской или префиксом, может рассчитывается как размер 2address - размер префикса, в котором адрес размер для IPv6 составляет 128 и 32 для IPv4. Например, в IPv4 префикс размер /29 дает: 232-29 = 23 = 8 адресов.

Итак, вы можете (нет, я не собираюсь описывать детали для вас), конвертировать ваши адреса в двоичные файлы и использовать двоичный И с заданной маской (также в двоичной форме), затем у вас есть адрес сетевого адреса оставшегося IP-адреса, который должен совпадать с любым адресом, который вы проверяете, чтобы увидеть, находится ли он в определенной подсети.

Ответ 5

Для начала вы должны использовать это:

IPNetwork ipnetwork = IPNetwork.Parse("192.168.168.100/29");
Console.WriteLine("CIDR: {0}", ipnetwork.Cidr);

Выход

CIDR: 29

Ответ 6

Я использую метод ниже, чтобы определить, является ли данный IP-адрес общедоступным или частным/внутренним:

private bool IsInternalIpAddress(string ipAddress)
    {
        // notes: http://whatismyipaddress.com/private-ip

        var internalIpRanges = Enumerable
            .Range(16, 31)
            .Select(i => "172.{0}.".FormatWith(i))
            .Concat(new[] {"192.168.", "10.", "127."})
            .ToArray();

        return ipAddress.StartsWith(internalIpRanges);
    }

Ответ 7

    public static bool IpIsInRange(string subnet, string ip)
    {
        var splitSubnet = subnet.Split('/');
        var maskBits = 32 - int.Parse(splitSubnet[1]);
        if (maskBits == 32)
        {
            return true;
        }
        var subnetIp = BitConverter.ToInt32(IPAddress.Parse(splitSubnet[0]).GetAddressBytes().Reverse().ToArray(), 0) >> maskBits << maskBits;
        var clientIp = BitConverter.ToInt32(IPAddress.Parse(ip).GetAddressBytes().Reverse().ToArray(), 0) >> maskBits << maskBits;
        return subnetIp == clientIp;
    }