簡體   English   中英

將 CIDR 格式的 IPv6 范圍轉換為 MySQL 中的 IPv6 地址范圍(開始和結束 ips)

[英]Convert IPv6 range in CIDR format to an IPv6 address range (start and end ips) in MySQL

我正在嘗試將 GeoLite2 ip 到國家 csv 文件導入到我的 MySQL 數據庫。 我成功地做到了,但是,要使用它在我的查詢中搜索 IP,我需要在 ipv4 和 ipv6 表中再創建兩個字段來存儲給定的每個 CIDR 范圍的 start_ip 和 end_ip 值(GeoLite csv 文件僅指定 CIDR 格式的范圍)。

我能夠使用此處給出的解決方案將其正確轉換為 ipv4 地址范圍Importing MaxMind's GeoLite2 to MySQL

所以我用

INET_ATON(SUBSTRING(network, 1, LOCATE('/', network) - 1))

對於 start_ip 和

INET_ATON(SUBSTRING(network, 1, LOCATE('/', network) - 1)) + (POW(2, (32-CONVERT(SUBSTRING(network, LOCATE('/', network) + 1), UNSIGNED INT)))-1)

對於 end_ip。 network 是存儲 CIDR 范圍的字段的名稱。

但是,這不適用於 CIDR 格式的 IPv6 地址范圍。 我嘗試使用 INET6_ATON 而不是 INET_ATON 但它給了我一個數值超出范圍的錯誤。 我對 IPv6 地址了解不多,所以自己找到一個公式並不容易。

任何幫助表示贊賞。

You can use my tool for converting MaxMind GeoLite2 country/city CSV to MySQL/PostgreSQL/Microsoft SQL Server 2019 from GitHub https://github.com/mbto/maxmind-geoip2-csv2sql-converter

您可以閱讀示例,或按照以下步驟操作:

  1. https://support.maxmind.com/account-faq/license-keys/how-do-i-generate-a-license-key/獲取 MaxMind API(如果沒有)的免費許可證密鑰
  2. Install Java 11 (if not installed) at adoptopenjdk.net or github.com/raphw/raphw.github.io or oracle.com/java
  3. 發行版下載工具(.zip 或 .tar)
  4. 解壓到你的目錄
  5. 使用您的配置文件名稱復制/粘貼.ini 模板bin/GeoLite2-Country-CSV.mysql.default.ini ,例如bin/GeoLite2-Country-CSV.mysql.Your Project Name.ini或使用默認值。
  6. 使用記事本打開.ini 模板並更改[windows_loader][unix_loader]部分(設置 MySQL 主機:端口、用戶和密碼)。
  7. 對於 unix:執行chmod +x maxmind-geoip2-csv2sql-converter
  8. 運行轉換: maxmind-geoip2-csv2sql-converter.bat -c "GeoLite2-Country-CSV.mysql.Your Project Name.ini" -k Your_License_Key -i 4,6
  9. 轉換后,腳本bin/converted/loader.batbin/converted/loader.sh將可用。
  10. 對於 unix:執行chmod +x loader.sh
  11. 執行loader.batloader.sh來導入模式。

完畢

圖式

使用類型為 VARBINARY(16) 的列來存儲值。 您可以將 INET6_ATON 用於 IPv4 和 IPv6 地址。

參考: https://dev.mysql.com/doc/refman/5.6/en/miscellaneous-functions.html#function_inet6-aton

我遇到了同樣的問題,並找到了以下博客文章,其中建議了如何獲得您正在尋找的東西。 我從那篇文章中獲得靈感,但對其進行了一些修改。 這是我的解決方案:

    DELIMITER //

    -- Returns the network address using an IPv4 address and the network length.
    CREATE FUNCTION ipv4_subnet(ip BINARY(4), net_len int) RETURNS BINARY(4)
        DETERMINISTIC
    BEGIN
        DECLARE zeroIp BINARY(4) DEFAULT b'0';
        RETURN ip & (~zeroIp << (32 - net_len));
    END
    //

    -- Returns the host mask of an IPv4 address given the network length.
    CREATE FUNCTION ipv4_host_mask(net_len int) RETURNS BINARY(4)
        DETERMINISTIC
    BEGIN
        DECLARE zeroIp BINARY(4) DEFAULT b'0';
        RETURN ~zeroIp >> net_len;
    END
    //

    -- Returns the network address using an IPv6 address and the network length.
    CREATE FUNCTION ipv6_subnet(ip BINARY(16), net_len int) RETURNS 
    BINARY(16)
        DETERMINISTIC
    BEGIN
        DECLARE zeroIp BINARY(16) DEFAULT b'0';
        RETURN ip & ((~zeroIp << (128 - net_len)));
    END
    //

    -- Returns the host mask of an IPv6 address given the network length.
    CREATE FUNCTION ipv6_host_mask(net_len int) RETURNS binary(16)
        DETERMINISTIC
    BEGIN
        DECLARE zeroIp BINARY(16) DEFAULT b'0';
        RETURN (~zeroIp >> net_len);
    END
    //

請注意,我計划將 IPv4 和 IPv6 從地址和到地址存儲在聲明為VARBINARY(16)的同一個表中。 此外,我切換到為我聲明的函數聲明BINARY(4|16)而不是調用INET6_ATON因為我發現INET6_ATON('0.0.0.0'); 返回0x00並將返回聲明為BINARY保證它將用您想要的方法填充零,並且不依賴於INET6_ATON function 的行為。 我懷疑這個實現在性能上也可能更好,但我沒有做任何測試來證明這一點,但在我看來,聲明一個特定大小的BINARY並將其設置為0比取決於另一個 function 的行為,它返回一個VARBINARY來為您執行此操作。

然后,您可以確定 IPv4 地址和 IPv6 地址的范圍,類似於博客文章中的建議。 如果你想為它們定義函數:

    -- Determine from range for IPv4 address in CIDR format.
    CREATE FUNCTION ipv4_from_addr(ip BINARY(4), net_len int) RETURNS BINARY(4)
        DETERMINISTIC
    BEGIN
        RETURN ipv4_subnet(ip, net_len);
    END
    //

    -- Determine to range for IPv4 address in CIDR format.
    CREATE FUNCTION ipv4_to_addr(ip BINARY(4), net_len int) RETURNS BINARY(4)
        DETERMINISTIC
    BEGIN
        RETURN ipv4_subnet(ip, net_len) | ipv4_host_mask(net_len);
    END
    //

    -- Determine from range for IPv6 address in CIDR format.
    CREATE FUNCTION ipv6_from_addr(ip BINARY(16), net_len int) RETURNS BINARY(16)
        DETERMINISTIC
    BEGIN
        RETURN ipv6_subnet(ip, net_len);
    END
    //

    -- Determine to range for IPv6 address in CIDR format.
    CREATE FUNCTION ipv6_to_addr(ip BINARY(16), net_len int) RETURNS BINARY(16)
        DETERMINISTIC
    BEGIN
        RETURN ipv6_subnet(ip, net_len) | ipv6_host_mask(net_len);
    END
    //

我知道您的問題只是關於 IPv6,但由於一個回復建議您可以使用INET6_ATON來同時執行 IPv4 和 IPv6,我想我也會回答他的想法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM