2009-02-27 24 views
17

Something nhưCó cách nào để khớp IP với IP + CIDR ngay từ truy vấn SELECT không?

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

Vì vậy, bạn không đầu tiên lấy tất cả hồ sơ từ DB và sau đó kết hợp chúng một cái một.

Nếu c> 0 thì được so khớp.

CẤM bảng:

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 và loại IPV (4 hoặc 6) được biết đến khi truy vấn.

IP là ví dụ :: 1 trong định dạng nhị phân

CẤM IP là ví dụ :: 1/64

+0

raspi, tôi biết câu hỏi này cũ, nhưng ... là cột cidr của bạn số bit trong mặt nạ mạng, vì vậy ipv6 luôn 64 và ipv4 là số từ 0 và 32? Mặc dù tôi cho rằng 0 sẽ cấm tất cả các địa chỉ ... :) – ErikE

Trả lời

22

Hãy nhớ rằng IP không phải là một địa chỉ văn bản, nhưng một ID số. Tôi có tình huống tương tự (chúng tôi đang thực hiện tra cứu địa lý-ip) và nếu bạn lưu trữ tất cả địa chỉ IP của mình dưới dạng số nguyên (ví dụ: địa chỉ IP của tôi là 192.115.22.33 do đó nó được lưu trữ dưới dạng 3228767777), thì bạn có thể tra cứu địa chỉ IP dễ dàng bằng cách sử dụng toán tử dịch chuyển phải.

Nhược điểm của tất cả các loại tra cứu này là bạn không thể hưởng lợi từ chỉ mục và bạn phải thực hiện quét toàn bộ bảng bất cứ khi nào bạn tra cứu. Đề án trên có thể được cải thiện bằng cách lưu trữ cả địa chỉ IP mạng của mạng CIDR (đầu dãy) và địa chỉ quảng bá (phần cuối của dải ô), vì vậy ví dụ để lưu trữ 192.168.1.0/24 bạn có thể lưu trữ hai cột:

network  broadcast 
3232235776, 3232236031 

và sau đó bạn có thể để phù hợp với nó, bạn chỉ cần làm

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

này sẽ cho phép bạn lưu trữ mạng CIDR trong cơ sở dữ liệu và kết hợp chúng chống lại các địa chỉ IP một cách nhanh chóng và hiệu quả bằng cách tận dụng nhanh chóng chỉ số dạng số.

Lưu ý từ cuộc thảo luận dưới đây:

MySQL 5.0 bao gồm một tối ưu hóa truy vấn dao động gọi là "index merge intersect" cho phép để tăng tốc độ truy vấn như vậy (và tránh quét bảng đầy đủ), miễn là:

  • Có một chỉ mục nhiều cột khớp chính xác với các cột trong truy vấn, theo thứ tự. Vì vậy - đối với ví dụ truy vấn ở trên, chỉ mục sẽ cần phải là (network, broadcast).
  • Tất cả dữ liệu có thể được truy xuất từ ​​chỉ mục. Điều này đúng với COUNT(*), nhưng không đúng đối với SELECT * ... LIMIT 1.

MySQL 5.6 bao gồm tối ưu hóa được gọi là MRR cũng sẽ tăng tốc độ truy xuất hàng đầy đủ, nhưng điều đó nằm ngoài phạm vi của câu trả lời này.

+0

Thật không may, MySQL không thể kết hợp hai chỉ mục với nhau. Tất nhiên nó sẽ cố gắng sử dụng chỉ mục trên một trong hai mạng hoặc phát sóng, nhưng khi địa chỉ ip được phân phối đồng đều, quét toàn bộ bảng sẽ hiệu quả hơn nhiều trong trường hợp này. – Quassnoi

+0

Huyền thoại này hơi lạc hậu :-) bắt đầu với MySQL 5.0, máy chủ có thể hợp nhất nhiều chỉ mục (http://dev.mysql.com/doc/refman/5.1/en/index-merge-optimization.html) . Bất kể, tôi không thể thấy cách quét toàn bộ bảng tốt hơn sau đó sử dụng một chỉ mục, ngay cả khi chỉ có 1 chỉ mục. – Guss

+0

Nếu bộ lọc của bạn trả về hơn 10% hoặc hàng, quét toàn bộ bảng sẽ tốt hơn. Hãy thử nó :) – Quassnoi

0

Hmmm. Bạn có thể xây dựng một bảng mặt nạ cidr, tham gia nó, và sau đó so sánh ip anded (& trong MySQL) với mặt nạ với lệnh cấm chặn ipaddress. Điều đó sẽ làm những gì bạn muốn?

Nếu bạn không muốn tạo bảng mặt nạ, bạn có thể tính toán mặt nạ là -1 << (x-cidr) với x = 64 hoặc 32 tùy thuộc.

3

Đối IPv4, bạn có thể sử dụng:

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 
+0

Cảm ơn bạn. Tôi đã khá chắc chắn tôi không cần một bảng để làm CIDRs, nhưng có thể tính toán/tạo mặt nạ trên bay như thế này. Tôi tin rằng mặt nạ có thể được đơn giản hóa ~ ((1 << cidr) -1), trong đó ((1 << cidr) -1) đặt các bit cidr bên phải chính xác, và NOT, IE: ~ đảo ngược tất cả các bit trong unsigned long để các bit cidr ngoài cùng bên phải là false và tất cả các bit bên trái là true. Win7 + calc, sử dụng giao diện Lập trình, khá hữu ích trong các vấn đề như vậy. – RocketRoy

-2

MySQL: Chuyển đổi IP Range để CIDR

Tôi đã dành vài giờ tìm kiếm một cách để sử dụng MySQL để có một dải địa chỉ IP và đầu ra một địa chỉ được định dạng CIDR bao gồm các dãy IP thích hợp cho việc duy trì một danh sách đen IP .

Các chi tiết cụ thể về môi trường và yêu cầu của tôi Tôi sử dụng OpenWeb Analytics để ghi lưu lượng truy cập trên trang web của mình và một số mà tôi quản lý. Tôi đã phát triển một quy trình trích xuất các địa chỉ IP riêng biệt được ghi bởi OWA và sau đó hợp nhất các phần tử dữ liệu địa lý vào các bản ghi mà sau đó được duy trì trong một bảng tùy chỉnh. Được trang bị bảng dữ liệu IP-to-Location này cung cấp khả năng báo cáo về lần truy cập từ các nguồn không mong muốn hoặc các nguồn không liên quan đến doanh nghiệp địa phương của tôi - Trung Quốc, Nhật Bản, Hàn Quốc, Nga, v.v. địa chỉ; nhiều trong số đó nằm trong cùng một mạng. Để giảm bớt các yêu cầu bảo trì đối với tệp .htaccess của máy chủ của tôi, nó trở nên có lợi để có thể ghi lại các địa chỉ IP được liệt kê trong định dạng CIDR. Điều đó sau đó dẫn đến sự cần thiết để có thể và sản xuất CIDR từ các địa chỉ IP đã đăng nhập.

Phương pháp tiếp cận MySQL Hầu hết các máy chủ web cung cấp quyền truy cập vào cơ sở dữ liệu MySQL. Tuy nhiên, ít nếu có cho phép khả năng tạo các hàm cơ sở dữ liệu. Điều này phức tạp mã hóa một chút.

Mẫu SQL có sẵn tại địa chỉ IPv4 http://blog.watsoninfotech.com/2012/12/mysql-convert-ip-range-to-cidr.html

+1

Tôi đang gặp sự cố khi xem trực tiếp * liên quan đến câu hỏi này. –

2

, địa chỉ mạng và netmasks đều uint32 số và được thể hiện trong hình dạng con người có thể đọc được là "chấm-Quads". Mã bảng định tuyến trong hạt nhân thực hiện so sánh và so sánh bit rất nhanh khi kiểm tra xem địa chỉ có nằm trong một không gian mạng nhất định (mạng/mặt nạ mạng) hay không. Bí quyết ở đây là lưu trữ địa chỉ IP, địa chỉ mạng và mặt nạ mạng trong bảng của bạn dưới dạng UINT32 và sau đó thực hiện cùng một bit 32 bit AND cho phù hợp của bạn. ví dụ:

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 | 
+----------------+ 
Các vấn đề liên quan