Есть ли способ сопоставить IP с IP+CIDR прямо из запроса SELECT?
что-то вроде
SELECT COUNT(*) AS c FROM BANS WHERE typeid=6 AND (SELECT ipaddr,cidr FROM BANS) MATCH AGAINST 'this_ip';
таким образом, вы не сначала извлекаете все записи из БД, а затем сопоставляете их один за другим.
если c > 0, то были сопоставимы.
баны стол:
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 и IPv (4 или 6) известен при запросе.
IP, например:: 1 в двоичном формате
запрещенный IP, например:: 1/64
5 ответов
помните, что IPs-это не текстовый адрес, а числовой идентификатор. У меня аналогичная ситуация (мы делаем гео-ip-поиск), и если вы храните все свои IP-адреса как целые числа (например, мой IP-адрес 192.115.22.33, поэтому он хранится как 3228767777), то вы можете легко искать IP-адреса, используя операторы сдвига вправо.
недостатком всех этих типов поиска является то, что вы не можете извлечь выгоду из индексов, и вам нужно выполнить полное сканирование таблицы всякий раз, когда вы делаете поиск. Вышеупомянутое схема может быть улучшена путем хранения как сетевого IP-адреса сети CIDR (начало диапазона), так и широковещательного адреса (конец диапазона), поэтому, например, для хранения 192.168.1.0/24 вы можете хранить два столбца:
network broadcast
3232235776, 3232236031
и тогда вы можете соответствовать ему вы просто делаете
SELECT count(*) FROM bans WHERE 3232235876 >= network AND 3232235876 <= broadcast
Это позволит вам хранить сети CIDR в базе данных и сопоставлять их с IP-адресами быстро и эффективно, используя быстрые числовые индексы.
Записки из обсуждения ниже:
MySQL 5.0 включает оптимизацию запросов в диапазоне под названием"индекс слияния пересекаются", что позволяет ускорить такие запросы (и избежать полного сканирования таблицы), как:
- существует многоколоночный индекс, который точно соответствует столбцам в запросе по порядку. Итак - для приведенного выше примера запроса индекс должен быть
(network, broadcast)
. - все данные могут быть получены из индекса. Это верно для
COUNT(*)
, но не верно дляSELECT * ... LIMIT 1
.
MySQL 5.6 включает оптимизацию под названием MRR, которая также ускорит полное извлечение строки, но это выходит за рамки этого ответа.
IPv4-адреса, сетевые адреса и сетевые маски являются номерами UINT32 и представлены в удобочитаемой форме как "пунктирные квадратики". Код таблицы маршрутизации в ядре выполняет очень быстрый бит и сравнение при проверке, находится ли адрес в заданном сетевом пространстве (сеть/маска сети). Трюк здесь состоит в том, чтобы хранить IP-адреса, сетевые адреса и сетевые маски в ваших таблицах как UINT32, а затем выполнять те же 32-битные бит-мудрые и для вашего соответствия. например!--2-->
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 |
+----------------+
на IPv4
, вы можете использовать:
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
Хммм. Вы можете создать таблицу масок cidr, присоединиться к ней, а затем сравнить ip anded (&
в MySQL) с маской с блоком запрета ipaddress. Это сделает то, что ты хочешь?
если вы не хотите создавать таблицу масок, вы можете вычислить маску как -1 << (x-cidr)
С x = 64
или 32
в зависимости от.
MySQL: преобразование диапазона IP в CIDR
Я потратил несколько часов на поиск способа использовать MySQL для получения диапазона IP-адресов и вывода адреса в формате CIDR, который охватывает диапазон IP, подходящий для поддержания черного списка IP.
особенности моей среды и требования Я использую OpenWeb Analytics для регистрации трафика на моем веб-сайте и нескольких, которыми я управляю. Я разработал процесс извлечения различных IP-адресов, зарегистрированных OWA, а затем объединить географические данные элементы записей, которые затем сохраняются в пользовательской таблице. Вооруженный этой таблицей данных IP-to-Location предоставляет возможность сообщать о попаданиях из нежелательных источников или источников, не имеющих отношения к моему местному бизнесу-Китай, Япония, Корея, Россия и т. д. Это привело к росту списка IP-адресов; многие из которых попадают в одну и ту же сеть. Чтобы облегчить требования к обслуживанию моего сервера .htaccess файл становится полезным, чтобы иметь возможность записывать черный список IP-адресов в CIDR формат. Это приводит к необходимости иметь возможность и производить CIDR из уже зарегистрированных IP-адресов.
Подход MySQL Большинство веб-узлов предоставляют доступ к базам данных MySQL. Однако немногие, если таковые имеются, позволяют создавать функции базы данных. Это немного усложнило кодирование.
образец SQL доступен по адресуhttp://blog.watsoninfotech.com/2012/12/mysql-convert-ip-range-to-cidr.html