[英]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
您可以閱讀示例,或按照以下步驟操作:
bin/GeoLite2-Country-CSV.mysql.default.ini
,例如bin/GeoLite2-Country-CSV.mysql.Your Project Name.ini
或使用默認值。[windows_loader]
或[unix_loader]
部分(設置 MySQL 主機:端口、用戶和密碼)。chmod +x maxmind-geoip2-csv2sql-converter
maxmind-geoip2-csv2sql-converter.bat -c "GeoLite2-Country-CSV.mysql.Your Project Name.ini" -k Your_License_Key -i 4,6
bin/converted/loader.bat
和bin/converted/loader.sh
將可用。chmod +x loader.sh
loader.bat
或loader.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.