باستخدام Linux، كيفية تحديد بيانات واجهة الإيثرنت التي سيتم إرسالها عليها

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

  •  05-07-2019
  •  | 
  •  

سؤال

أنا أعمل على نظام خادم يستند إلى Linux حيث توجد واجهتان للشبكة، كلاهما على نفس الشبكة الفرعية (في الوقت الحالي، دعنا نقول فقط أنهما 172.17.32.10 & 172.17.32.11).عندما أرسل بيانات إلى مضيف على الشبكة، أرغب في تحديد الواجهة التي سيتم إرسال البيانات عليها على الخادم الخاص بي.أحتاج إلى أن أكون قادرًا على التبديل من واجهة إلى أخرى (أو ربما حتى الإرسال على كليهما) في البرنامج (لن تعمل قواعد التوجيه الثابتة مع هذا التطبيق).

لقد وجدت سؤالاً ذا صلة في StackOverflow يقترح استخدام مكتبة netlink لتعديل المسارات بسرعة.يبدو هذا بديهيًا أنه يجب أن ينجح، لكنني كنت أتساءل عما إذا كان هناك أي خيارات أخرى لتحقيق هذه النتيجة نفسها.

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

المحلول

لا يوجد أي إساءة مقصودة، ولكن الإجابة حول استخدام bind() خاطئة تمامًا.سيتحكم bind() في عنوان IP المصدر الموجود داخل رأس IP الخاص بالحزمة.ولا يتحكم في الواجهة التي سيتم استخدامها لإرسال الحزمة:سيتم الرجوع إلى جدول توجيه النواة لتحديد الواجهة التي لديها أقل تكلفة للوصول إلى وجهة معينة.(*انظر الملاحظة)

بدلا من ذلك، يجب عليك استخدام SO_BINDTODEVICE com.sockopt.وهذا يفعل شيئين:

  • ستخرج الحزم دائمًا من الواجهة التي حددتها، بغض النظر عما تقوله جداول توجيه kernel.
  • سيتم تسليم الحزم التي تصل إلى الواجهة المحددة فقط إلى المقبس.لن تصل الحزم على واجهات أخرى.

إذا كان لديك واجهات متعددة تريد التبديل بينها، أقترح إنشاء مقبس واحد لكل واجهة.نظرًا لأنك لن تتلقى سوى الحزم على الواجهة التي ارتبطت بها، فستحتاج إلى إضافة كل هذه المقابس إلى select()/poll()/ مهما كان ما تستخدمه.

#include <net/if.h>

struct ifreq ifr;

memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, "eth1", sizeof(ifr.ifr_name));
if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE,
            (void *)&ifr, sizeof(ifr)) < 0) {
    perror("SO_BINDTODEVICE failed");
}

(*ملحوظة)Bind() إلى عنوان IP للواجهة يمكن أن يؤدي إلى سلوك مربك ولكنه صحيح.على سبيل المثال إذا كنت bind() إلى عنوان IP الخاص بـ eth1، لكن جدول التوجيه يرسل الحزمة إلى eth0، ثم ستظهر حزمة على سلك eth0 ولكنها تحمل عنوان IP المصدر لواجهة eth1.وهذا أمر غريب ولكنه مسموح به، على الرغم من أن الحزم المرسلة إلى عنوان IP الخاص بـ eth1 سيتم توجيهها مرة أخرى إلى eth1.يمكنك اختبار ذلك باستخدام نظام Linux بواجهتي IP.عندي واحدة وقمت بتجربتها و bind() ليست فعالة في توجيه الحزمة خارج الواجهة المادية.

على الرغم من أنه مسموح به من الناحية الفنية، اعتمادًا على الهيكل، فقد لا يعمل هذا مع ذلك.للحد من هجمات رفض الخدمة الموزعة حيث يستخدم المهاجمون عناوين مصدر IP مزيفة، تقوم العديد من أجهزة التوجيه الآن بإجراء فحوصات إعادة توجيه المسار العكسي (RPF).قد يتم إسقاط الحزم التي تحتوي على عنوان IP مصدر على المسار "الخاطئ".

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top