Frage

So etwas wie

  

SELECT COUNT(*) AS c FROM BANS WHERE typeid=6 AND (SELECT ipaddr,cidr FROM BANS) MATCH AGAINST 'this_ip';

So Sie holen nicht zuerst alle Datensätze aus DB und sie dann durch eineindeutig entsprechen.

Wenn c> 0 dann angepasst wurden.

BANS Tabelle:

id int auto incr PK
typeid TINYINT (1=hostname, 4=ipv4, 6=ipv6)
ipaddr BINARY(128)
cidr INT
host VARCHAR(255)

DB: MySQL 5

IP und IPv Typ (4 oder 6) bekannt ist, bei der Abfrage.

IP ist zum Beispiel :: 1 in Binär-Format

Gesperrte IP ist zum Beispiel :: 1/64

War es hilfreich?

Lösung

Beachten Sie, dass IP-Adressen sind kein Text Adresse, sondern eine numerische ID. Ich habe eine ähnliche Situation (wir Geo-IP-Lookups tun), und wenn Sie alle Ihre IP-Adressen als ganze Zahlen (zum Beispiel meine IP-Adresse 192.115.22.33 ist, so dass es als 3228767777 gespeichert ist), dann können Sie IP-Adressen nachzuschlagen leicht mit dem rechten Shift-Operatoren verwenden.

Der Nachteil all dieser Arten von Lookups ist, dass Sie nicht von Indizes profitieren können, und Sie haben einen vollständigen Tabellenscan zu tun, wenn Sie eine Lookup. Das obige Schema kann durch das Speichern sowohl die Netzwerk-IP-Adresse des CIDR-Netzwerkes (der Anfang des Bereichs) und die Broadcast-Adresse (das Ende des Bereichs) verbessert werden, so zum Beispiel 192.168.1.0/24 speichern Sie zwei speichern Spalten:

network     broadcast
3232235776, 3232236031 

Und dann können Sie es passen Sie einfach tun

SELECT count(*) FROM bans WHERE 3232235876 >= network AND 3232235876 <= broadcast

Dies würde Sie speichern CIDR Netzwerke in der Datenbank und passen sie gegen IP schnell und effizient Adressen von Vorteil der schnellen numerischen Indizes nehmen.

Hinweis von Diskussion unter :

MySQL 5.0 enthält eine Distanzabfrageoptimierung namens "

Andere Tipps

IPv4-Adressen, Netzwerkadressen und netmasks sind alle UINT32 Zahlen und werden in lesbarer Form als „punktiert-Quads“ vorgestellt. Der Routing-Tabelle Code im Kernel führt einen sehr schnellen bitweise UND-Vergleich bei der Überprüfung, ob eine Adresse in einem gegebenen Netzwerk Raum (network / netmask). Der Trick hier ist die punktierten-Quad IP-Adressen zu speichern, Netzwerkadressen und netmasks in Ihren Tabellen als UINT32, und führen Sie dann die gleichen 32-Bit-bitweise UND für Ihren Matching. zB

SET @test_addr = inet_aton('1.2.3.4');
SET @network_one = inet_aton('1.2.3.0');
SET @network_two = inet_aton('4.5.6.0');
SET @network_netmask = inet_aton('255.255.255.0');

SELECT (@test_addr & @network_netmask) = @network_one AS IS_MATCHED;
+------------+
| IS_MATCHED |
+------------+
|          1 |
+------------+

SELECT (@test_addr & @network_netmask) = @network_two AS IS_NOT_MATCHED;
+----------------+
| IS_NOT_MATCHED |
+----------------+
|              0 |
+----------------+

Für IPv4, können Sie:

SET @length = 4;

SELECT  INET_NTOA(ipaddr), INET_NTOA(searchaddr), INET_NTOA(mask)
FROM  (
  SELECT
        (1 << (@length * 8)) - 1 & ~((1 << (@length * 8 - cidr)) - 1) AS mask,
        CAST(CONV(SUBSTR(HEX(ipaddr), 1, @length * 2), 16, 10) AS DECIMAL(20)) AS ipaddr,
        CAST(CONV(SUBSTR(HEX(@myaddr), 1, @length * 2), 16, 10) AS DECIMAL(20)) AS searchaddr
  FROM  ip
) ipo
WHERE ipaddr & mask = searchaddr & mask

Hmmm. Sie könnten eine Tabelle der cidr Masken bauen, verbinden, und dann die IP vergleichen anded (& in MySQL) mit dem Maske mit dem Verbot Block ipaddress. Wäre das tun, was Sie wollen?

Wenn Sie nicht über einen Maskentisch bauen wollen, können Sie die Maske als -1 << (x-cidr) berechnen mit x = 64 oder 32 abhängig.

Generieren von IP-Adressbereiche als Ganze Zahlen

  

Wenn Ihre Datenbank keine Lust bitweise Operationen nicht unterstützt, können Sie eine vereinfachte Integer-basierten Ansatz.

Im folgenden Beispiel wird mit PostgreSQL:

select (cast(split_part(split_part('4.0.0.0/8', '/', 1), '.', 1) as bigint) * (256 * 256 * 256) +
        cast(split_part(split_part('4.0.0.0/8', '/', 1), '.', 2) as bigint) * (256 * 256      ) +
        cast(split_part(split_part('4.0.0.0/8', '/', 1), '.', 3) as bigint) * (256            ) +
        cast(split_part(split_part('4.0.0.0/8', '/', 1), '.', 4) as bigint)) 
        as network,

       (cast(split_part(split_part('4.0.0.0/8', '/', 1), '.', 1) as bigint) * (256 * 256 * 256) +
        cast(split_part(split_part('4.0.0.0/8', '/', 1), '.', 2) as bigint) * (256 * 256      ) +
        cast(split_part(split_part('4.0.0.0/8', '/', 1), '.', 3) as bigint) * (256            ) +
        cast(split_part(split_part('4.0.0.0/8', '/', 1), '.', 4) as bigint)) + cast(
          pow(256, (32 - cast(split_part('4.0.0.0/8', '/', 2) as bigint)) / 8) - 1 as bigint
        ) as broadcast;
scroll top