هل هناك طريقة لتتناسب مع IP مع IP + CIDR مباشرة من تحديد الاستعلام؟

StackOverflow https://stackoverflow.com/questions/595748

سؤال

شيء مثل

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

لذلك لا يمكنك أولا إحضار جميع السجلات من DB ثم تطابقها واحدا.

إذا تم مطابقة 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

هل كانت مفيدة؟

المحلول

تذكر أن IPS ليس عنوانا نصيا، ولكن معرف رقمي. لدي موقف مماثل (نحن نقوم بإجراء بحث GEO-IP)، وإذا قمت بتخزين جميع عناوين IP الخاصة بك كعضوية (على سبيل المثال، فإن عنوان IP الخاص بي هو 192.1115.22.33 لذلك يتم تخزينه 32287677777)، ثم يمكنك البحث عن IPS بسهولة باستخدام مشغلي التحول الصحيح.

الجانب السلبي لجميع هذه الأنواع من عمليات البحث هو أنه لا يمكنك الاستفادة من الفهارس وعليك إجراء فحص طاولة كاملة كلما قمت بإجراء بحث. يمكن تحسين المخطط أعلاه من خلال تخزين كل من عنوان 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 وعناوين الشبكة و NetMasks جميع أرقام UINT32 ويتم عرضها في شكل قابلة للقراءة بشرية ك "Quads-Quads". يؤدي رمز جدول التوجيه في Kernel إلى حكيمة سريعة للغاية ومقارنة عند التحقق من وجود عنوان في مساحة شبكة معينة (شبكة / NetMask). تتمثل الخدعة هنا في تخزين عناوين IP الرباعية المنقط وعناوين الشبكة و NetMasks في جداولك مثل UINT32، ثم قم بتنفيذ نفس المستوى 32 بت وغير مطابقتك. على سبيل المثال

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 اعتمادا.

توليد عنوان IP يتراوح كعدادات صحيحة

إذا كانت قاعدة البيانات الخاصة بك لا تدعم عمليات Bitwise Fancy، فيمكنك استخدام نهج قائم على عدد صحيح مبسط.

المثال التالي يستخدم 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;
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top