Jeśli zawsze będziesz sprawdzenie jednego adresu IP w tym czasie i twoje zakazane zakresy nigdy się nie przecinają, powinieneś przechowywać adresy początkowe i końcowe zakresów, aby zablokować w formacie liczbowym.
Powiedz, że chcesz zablokować 192.168.1.0
na 192.168.1.15
, który jest 192.168.1.0/28
.
utworzyć tabelę tak:
CREATE TABLE ban (start_ip INT UNSIGNED NOT NULL PRIMARY KEY, end_ip INT UNSIGNED NOT NULL)
włóż zasięg tam:
INSERT
INTO ban
VALUES (INET_ATON('192.168.1.0'), INET_ATON('192.168.1.0') + POWER(2, 32 - 28) - 1)
następnie sprawdzić:
SELECT (
SELECT end_ip
FROM ban
WHERE start_ip <= INET_ATON('192.168.1.14')
ORDER BY
start_ip DESC
LIMIT 1
) >= INET_ATON('192.168.1.14')
W ORDER BY
i LIMIT
części są wymagane dla zapytanie jest skuteczne.
To, jak wcześniej stwierdzono, zakłada nie przecinające się bloki i jedno IP na raz.
Jeśli bloki się przecinają (na przykład jednocześnie blokujesz 192.168.1.0/28
i 192.168.1.0/24
), zapytanie może zwrócić fałszywe negatywy.
Jeśli chcesz kwerendy więcej niż jeden adres IP w czasie (powiedzmy, aktualizować tabelę z długiej listy adresów IP), a następnie ta kwerenda będzie nieefektywne (MySQL
nie zoptymalizować range
w skorelowanych podkwerend dobrze)
W obu tych przypadkach należy trzeba przechowywać swoje zakresy jak LineString
i używać indeksów przestrzennych dla szybkich wyszukiwań:
CREATE TABLE ban (id INT NOT NULL PRIMARY KEY AUTO_INCREMENT, range LINESTRING NOT NULL) ENGINE=MyISAM;
CREATE SPATIAL INDEX sx_ban_range ON ban (range);
INSERT
INTO ban (range)
VALUES (
LineString
(
Point(INET_ATON('192.168.1.0'), -1),
Point(INET_ATON('192.168.1.0') + POWER(2, 32 - 28) - 1), 1)
)
);
SELECT *
FROM ban
WHERE MBRContains(range, Point(INET_ATON('192.168.1.14'), 0))
Tutaj widzimy Quassnoi ucieleśniający głos doświadczenia. Jeśli nie przechowujesz adresów IP w formacie liczbowym, prawdopodobnie robisz to źle. – TehShrike