IPv4、IPv6、または両方のタイプのいずれかの単一の CIDR 範囲が格納された MySQL ブラックリスト テーブルがあります。
私のテーブルは次のようになります。
+-----------+-------------+
| Name | Type |
+-----------+-------------+
| IpAddress | VARCHAR(46) |
+-----------+-------------+
| Mask | INT(2) |
+-----------+-------------+
ここで、特定の IP アドレスが保存された CIDR 範囲のいずれかに含まれているかどうかを確認したいと思います。大量のページを数日間調査した後、私はすでにこれを達成し、最終的に次のソリューションを MySQL に移植しました: PHP5 は cidr プレフィックスから IPv6 範囲を計算しますか?
そこで、IP + CIDR マスクをその範囲の最初と最後の IP に変換し、INET6_ATON を使用して数値に変換し、BETWEEN 演算子と比較します。
私の実装:
最後の IP を取得する
FUNCTION (`Ip` VARCHAR(46), `Mask` INT(2) UNSIGNED) RETURNS varchar(39)
BEGIN
DECLARE IpNumber VARBINARY(16);
DECLARE Last VARCHAR(39) DEFAULT '';
DECLARE FlexBits, Counter, Deci, NewByte INT UNSIGNED;
DECLARE HexIp VARCHAR(32);
SET IpNumber = INET6_ATON(Ip);
SET HexIp = HEX(IpNumber);
SET FlexBits = 128 - Mask;
SET Counter = 32;
WHILE (FlexBits > 0) DO
SET Deci = CONV(SUBSTR(HexIp, Counter, 1), 16, 10);
SET NewByte = Deci | (POW(2, LEAST(4, FlexBits)) - 1);
SET Last = CONCAT(CONV(NewByte, 10, 16), Last);
IF FlexBits >= 4 THEN SET FlexBits = FlexBits - 4;
ELSE SET FlexBits = 0;
END IF;
SET Counter = Counter - 1;
END WHILE;
SET Last = CONCAT(SUBSTR(HexIp, 1, Counter), Last);
RETURN INET6_NTOA(UNHEX(Last));
END
最初のIPを取得
FUNCTION (`Ip` VARCHAR(46), `Mask` INT(2) UNSIGNED, `WithMask` BOOLEAN) RETURNS varchar(39)
BEGIN
DECLARE First VARCHAR (42) DEFAULT '';
SET First = INET6_NTOA(UNHEX(RPAD(SUBSTR(HEX(INET6_ATON(Ip)), 1, Mask / 4), 32, 0)));
IF (WithMask = 1) THEN
SET First = CONCAT(First, '/', CAST(Mask AS CHAR));
END IF;
RETURN First;
END
これはうまくいきます!私は、巧妙なビット操作を使用して、より効率的に実行できるという考えを持っています。このトピックに関するたくさんの質問を読みましたが、具体的な解決策を実際には見つけられませんでした。正しい方向への助けをいただければ幸いです。
注: IPv6 の場合のみ、IPv4 を正しい方法で実装しました。