如何将独立IP与CIDR匹配?

时间:2016-10-14 16:03:24

标签: c# mysql mysql-5.6

我使用Maxmind的地理位置表(特别是城市/国家/地区级别),其中一个表格具有以下结构:

enter image description here

我将服务用户的IP存储在另一个表中;我创建了latitudelongitude列,并希望将这些IP的适用纬度和经度存储在users表中(在IP的相应行中)。

可以看出,MaxMind表中的IP以CIDR格式存储,这意味着无法直接检查IP是否符合CIDR给出的IP范围

是否可以仅使用MySQL语句将常规IP与CIDR格式匹配?

我试过了,但是却找到了以下内容:

  • 是可能的,但我需要子网掩码(我没有)
  • 可以从原始IP获取子网掩码,但它需要CIDR ......

users表中的IP与MaxMind表中的CIDR表示法相匹配需要一段时间,我使用标准的C#CLI程序来处理批处理,我承认我可以做这样:

  1. 整个 MaxMind表格检索到数据阅读器
  2. 浏览每一行并将CIDR转换为IP范围
  3. 同时,打开数据阅读器到users表并将给定的IP与IP范围匹配
  4. UPDATE users中相应的记录,其纬度和经度与之前的CIDR相匹配
  5. 正如你所看到的,我的方法似乎(对我而言)非常低效,可能需要的时间比它应该要多得多。

    我可以使用MySQL语句将常规IP与CIDR匹配吗?如果没有,我可以计算IP范围而不用子网掩码然后匹配IP吗?

    users表中相关的列如下:

    enter image description here

1 个答案:

答案 0 :(得分:0)

如果它有帮助,我前段时间写了这个类来检查IP地址是否在一个范围内。您只需要在CIDR字符串中拆分网络和掩码,解析它们并将它们传递给构造函数。然后,您只需使用ContainsIP()查看该IP地址是否属于该网络。它可能使用另一个接受CIDR字符串的构造函数来处理拆分/解析。

public class IPNetwork
{
    private readonly IPAddress _networkMask;
    private readonly int _networkMaskLength;
    private readonly uint _networkMaskValue;

    public IPNetwork(IPAddress networkMask, int networkMaskLength)
    {
        if (networkMask.AddressFamily != AddressFamily.InterNetwork)
            throw new InvalidOperationException("Only IPv4 networks are supported.");

        _networkMask = networkMask;
        _networkMaskLength = networkMaskLength;
        _networkMaskValue = GetMaskedAddress(networkMask);
    }

    public bool ContainsIP(IPAddress ipAddress)
    {
        return GetMaskedAddress(ipAddress) == _networkMaskValue;
    }

    private uint GetMaskedAddress(IPAddress ipAddress)
    {
        byte[] bytes = ipAddress.GetAddressBytes();
        int addressLength = bytes.Length * 8;
        uint addressValue = BytesToValue(bytes);

        uint maskedAddress = 0;
        for (int i = addressLength - _networkMaskLength; i < addressLength; ++i)
            maskedAddress |= addressValue & (1U << i);

        return maskedAddress;
    }

    private uint BytesToValue(byte[] bytes)
    {
        uint value = 0;

        for (int i = 0; i < bytes.Length; ++i)
            value |= (uint)(bytes[bytes.Length - i - 1] << (i * 8));

        return value;
    }
}