3

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 を正しい方法で実装しました。

4

2 に答える 2

1

Get last ip関数にバグが見つかりました。

これの代わりに:

SET FlexBits = FlexBits - 4;

これを使って:

IF FlexBits >= 4 THEN SET FlexBits = FlexBits - 4;
ELSE SET FlexBits = 0;
END IF;

そうしないと、次のようなエラー メッセージが表示されます。

ERROR 1690 (22003): BIGINT UNSIGNED value is out of range in '(FlexBits@4 - 4)'

これらの IPv6 範囲 (マスクを 4 で割ることができない) の最後の IP を取得しようとすると、次のようになります。

SELECT getLastIp("2001:200:1::", 47);
SELECT getLastIp("2001:200:0:8000", 49);
SELECT getLastIp("2001:470:1f06:2000::", 51);
SELECT getLastIp("2001:470:0:284:2::", 79);
SELECT getLastIp("2001:470:1f08:415::8:0", 109);
SELECT getLastIp("2001:550:0:1000::8275:8000", 113);
SELECT getLastIp("2001:550:0:1000::9a19:300", 123);
SELECT getLastIp("2001:550:0:1000::9a19:320", 126);
于 2016-10-06T19:41:50.340 に答える
1

約 1 年前に同じ方法で MySQL にこれを実装しました。だからアイデアはいい。ただし、コードには小さいながらも重大なバグがあります。

この線:

SET Last = CONCAT(Last, CONV(NewByte, 10, 16));

むしろ次のようにする必要があります。

SET Last = CONCAT(CONV(NewByte, 10, 16), Last);

于 2013-06-04T13:46:28.487 に答える