Добрый день!
По условиям задачи требуется получать адреса из базы напрямую. Пока все было на IPv4, проблем небыло, и вот настала пора IPv6 и тут...
Кто-нибудь реализовывал выборку IPv6 в человеческом виде из базы напрямую? Проблема в том, что первые 64-бита адреса хранятся в поле ip_ext, младшие 64-бит в поле ip (это пример из ip_groups)
Метод хранения адресов IPv6 и как всем этим пользоваться?
В общем, пришлось колхозить в скрипте такие конструкции:
Код: Выделить всё
$proto = 0;
if ($ip_ext == 0)
{
$proto = 4;
$a = sprintf("%u.%u.%u.%u",
(($ip>>24) & 255),
(($ip>>16) & 255),
(($ip>>8) & 255),
( $ip & 255));
$m = sprintf("%u.%u.%u.%u",
(($mask>>24) & 255),
(($mask>>16) & 255),
(($mask>>8) & 255),
( $mask & 255));
$addr = NetAddr::IP::Lite->new($a."/".$m);
}
else
{
$proto = 6;
$a = sprintf("%x:%x:%x:%x:%x:%x:%x:%x",
(($ip_ext>>48) & 65535),
(($ip_ext>>32) & 65535),
(($ip_ext>>16) & 65535),
( $ip_ext & 65535),
(($ip>>48) & 65535),
(($ip>>32) & 65535),
(($ip>>16) & 65535),
( $ip & 65535));
$m = sprintf("%x:%x:%x:%x:%x:%x:%x:%x",
(($mask_ext>>48) & 65535),
(($mask_ext>>32) & 65535),
(($mask_ext>>16) & 65535),
( $mask_ext & 65535),
(($mask>>48) & 65535),
(($mask>>32) & 65535),
(($mask>>16) & 65535),
( $mask & 65535));
$addr = NetAddr::IP::Lite->new6($a."/".$m);
}
Код: Выделить всё
SELECT
ipg.ip_group_id,
LOWER(
CONCAT(
IF (
ipg.ip_ext != 0,
CONCAT_WS(
':',
SUBSTR(LPAD(HEX(ipg.ip_ext), 16, '0'), 1, 4),
SUBSTR(LPAD(HEX(ipg.ip_ext), 16, '0'), 5, 4),
SUBSTR(LPAD(HEX(ipg.ip_ext), 16, '0'), 9, 4),
RIGHT(LPAD(HEX(ipg.ip_ext), 16, '0'), 4)
),
""
),
IF (
ipg.ip_ext != 0,
CONCAT_WS(
':',
SUBSTR(LPAD(HEX(ipg.ip), 16, '0'), 1, 4),
SUBSTR(LPAD(HEX(ipg.ip), 16, '0'), 5, 4),
SUBSTR(LPAD(HEX(ipg.ip), 16, '0'), 9, 4),
RIGHT(LPAD(HEX(ipg.ip), 16, '0'), 4)
),
INET_NTOA(ipg.ip & 0xffffffff)
)
)
) AS ip
FROM
UTM5.ip_groups AS ipg;
Доработаный для PG вариант с хранимой процедурой:
пример запроса:
Код: Выделить всё
CREATE FUNCTION inet_ntoa_ipv6(ip bigint, ip_ext bigint) RETURNS text
LANGUAGE sql
AS $_$
SELECT
LOWER(
CONCAT(
CASE
WHEN ip_ext != 0 THEN
CONCAT_WS(
':',
SUBSTR(LPAD(TO_HEX(ip_ext), 16, '0'), 1, 4),
SUBSTR(LPAD(TO_HEX(ip_ext), 16, '0'), 5, 4),
SUBSTR(LPAD(TO_HEX(ip_ext), 16, '0'), 9, 4),
RIGHT(LPAD(TO_HEX(ip_ext), 16, '0'), 4)
)
END,
CASE
WHEN ip_ext != 0 THEN
':'
END,
CASE
WHEN ip_ext != 0 THEN
CONCAT_WS(
':',
SUBSTR(LPAD(TO_HEX(ip), 16, '0'), 1, 4),
SUBSTR(LPAD(TO_HEX(ip), 16, '0'), 5, 4),
SUBSTR(LPAD(TO_HEX(ip), 16, '0'), 9, 4),
RIGHT(LPAD(TO_HEX(ip), 16, '0'), 4)
)
ELSE INET_NTOA(ip & x'ffffffff'::bigint)
END
)
)
as result
$_$;
Код: Выделить всё
select
inet_ntoa_ipv6(ip, ip_ext) as ip,
inet_ntoa_ipv6(mask, mask_ext) as mask
from
ip_groups
where
uname ='USER_LOGIN' and is_deleted=0;
Функция для MySQL
Код: Выделить всё
DROP FUNCTION net_ntoa_ipv6;
DELIMITER $$
CREATE DEFINER = root@localhost FUNCTION `net_ntoa_ipv6` (ip BIGINT, ip_ext BIGINT) RETURNS CHAR(48) CHARSET utf8 COLLATE utf8_unicode_ci DETERMINISTIC
BEGIN
# Example: SELECT net_ntoa_ipv6(ip,ip_ext) FROM UTM5.ip_groups;
SELECT
LOWER(
CONCAT(
IF (
ip_ext != 0,
CONCAT_WS(
':',
SUBSTR(LPAD(HEX(ip_ext), 16, '0'), 1, 4),
SUBSTR(LPAD(HEX(ip_ext), 16, '0'), 5, 4),
SUBSTR(LPAD(HEX(ip_ext), 16, '0'), 9, 4),
RIGHT(LPAD(HEX(ip_ext), 16, '0'), 4)
),
""
),
IF (ip_ext != 0, ':', ""),
IF (
ip_ext != 0,
CONCAT_WS(
':',
SUBSTR(LPAD(HEX(ip), 16, '0'), 1, 4),
SUBSTR(LPAD(HEX(ip), 16, '0'), 5, 4),
SUBSTR(LPAD(HEX(ip), 16, '0'), 9, 4),
RIGHT(LPAD(HEX(ip), 16, '0'), 4)
),
INET_NTOA(ip & 0xffffffff)
)
)
) AS result INTO @result ;
RETURN @result ;
END $$
DELIMITER ;
Последний раз редактировалось Magnum72 Ср мар 23, 2016 13:13, всего редактировалось 1 раз.