شبكة IPeE المتسامحة مع الأخطاء باستخدام أدوات مرتجلة

مرحبًا. هذا يعني أن هناك شبكة مكونة من 5 آلاف عميل. ظهرت مؤخرًا لحظة ليست ممتعة للغاية - في وسط الشبكة لدينا Brocade RX8 وبدأ في إرسال الكثير من الحزم غير المعروفة أحادية البث، نظرًا لأن الشبكة مقسمة إلى شبكات محلية ظاهرية - وهذه ليست مشكلة جزئيًا، ولكن هناك شبكات محلية ظاهرية خاصة للعناوين البيضاء، وما إلى ذلك. وهي ممتدة في كل اتجاهات الشبكة. تخيل الآن تدفقًا واردًا إلى عنوان عميل لا يدرس كطالب حدودي وهذا التدفق يتجه نحو رابط راديو لبعض (أو كل) القرية - القناة مسدودة - العملاء غاضبون - حزن...

الهدف هو تحويل الخطأ إلى ميزة. كنت أفكر في اتجاه q-in-q مع شبكة محلية ظاهرية كاملة للعميل، ولكن جميع أنواع الأجهزة مثل P3310، عند تمكين dot1q، تتوقف عن تمرير DHCP، كما أنهم لا يعرفون كيفية اختيار qinq والعديد من المخاطر هذا النوع. ما هو IP غير المسمى وكيف يعمل؟ باختصار شديد: عنوان البوابة + المسار على الواجهة. بالنسبة لمهمتنا، نحتاج إلى: قص المشكل، وتوزيع العناوين على العملاء، وإضافة مسارات للعملاء من خلال واجهات معينة. كيف تفعل كل هذا؟ Shaper - lisg، dhcp - db2dhcp على خادمين مستقلين، يعمل dhcprelay على خوادم الوصول، ويعمل ucarp أيضًا على خوادم الوصول - للنسخ الاحتياطي. ولكن كيف تضيف الطرق؟ يمكنك إضافة كل شيء مسبقًا باستخدام برنامج نصي كبير - لكن هذا ليس صحيحًا. لذلك سوف نصنع عكازًا مكتوبًا ذاتيًا.

بعد بحث شامل على الإنترنت، وجدت مكتبة رائعة عالية المستوى لـ C++، والتي تتيح لك التعرف على حركة المرور بشكل جميل. خوارزمية البرنامج الذي يضيف المسارات هي كما يلي - نستمع إلى طلبات arp على الواجهة، إذا كان لدينا عنوان على الواجهة lo على الخادم المطلوب، فإننا نضيف مسارًا من خلال هذه الواجهة ونضيف arp ثابتًا سجل على عنوان IP هذا - بشكل عام، عدد قليل من عمليات النسخ واللصق، والقليل من الصفة، وبذلك تكون قد انتهيت

مصادر "جهاز التوجيه"

#include <stdio.h>
#include <sys/types.h>
#include <ifaddrs.h>
#include <netinet/in.h>
#include <string.h>
#include <arpa/inet.h>

#include <tins/tins.h>
#include <map>
#include <iostream>
#include <functional>
#include <sstream>

using std::cout;
using std::endl;
using std::map;
using std::bind;
using std::string;
using std::stringstream;

using namespace Tins;

class arp_monitor {
public:
    void run(Sniffer &sniffer);
    void reroute();
    void makegws();
    string iface;
    map <string, string> gws;
private:
    bool callback(const PDU &pdu);
    map <string, string> route_map;
    map <string, string> mac_map;
    map <IPv4Address, HWAddress<6>> addresses;
};

void  arp_monitor::makegws() {
    struct ifaddrs *ifAddrStruct = NULL;
    struct ifaddrs *ifa = NULL;
    void *tmpAddrPtr = NULL;
    gws.clear();
    getifaddrs(&ifAddrStruct);
    for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) {
        if (!ifa->ifa_addr) {
            continue;
        }
        string ifName = ifa->ifa_name;
        if (ifName == "lo") {
            char addressBuffer[INET_ADDRSTRLEN];
            if (ifa->ifa_addr->sa_family == AF_INET) { // check it is IP4
                // is a valid IP4 Address
                tmpAddrPtr = &((struct sockaddr_in *) ifa->ifa_addr)->sin_addr;
                inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN);
            } else if (ifa->ifa_addr->sa_family == AF_INET6) { // check it is IP6
                // is a valid IP6 Address
                tmpAddrPtr = &((struct sockaddr_in6 *) ifa->ifa_addr)->sin6_addr;
                inet_ntop(AF_INET6, tmpAddrPtr, addressBuffer, INET6_ADDRSTRLEN);
            } else {
                continue;
            }
            gws[addressBuffer] = addressBuffer;
            cout << "GW " << addressBuffer << " is added" << endl;
        }
    }
    if (ifAddrStruct != NULL) freeifaddrs(ifAddrStruct);
}

void arp_monitor::run(Sniffer &sniffer) {
    cout << "RUNNED" << endl;
    sniffer.sniff_loop(
            bind(
                    &arp_monitor::callback,
                    this,
                    std::placeholders::_1
            )
    );
}

void arp_monitor::reroute() {
    cout << "REROUTING" << endl;
    map<string, string>::iterator it;
    for ( it = route_map.begin(); it != route_map.end(); it++ ) {
        if (this->gws.count(it->second) && !this->gws.count(it->second)) {
            string cmd = "ip route replace ";
            cmd += it->first;
            cmd += " dev " + this->iface;
            cmd += " src " + it->second;
            cmd += " proto static";
            cout << cmd << std::endl;
            cout << "REROUTE " << it->first << " SRC " << it->second << endl;
            system(cmd.c_str());
            cmd = "arp -s ";
            cmd += it->first;
            cmd += " ";
            cmd += mac_map[it->first];
            cout << cmd << endl;
            system(cmd.c_str());

        }
    }
    for ( it = gws.begin(); it != gws.end(); it++ ) {
	string cmd = "arping -U -s ";
	cmd += it->first;
	cmd += " -I ";
	cmd += this->iface;
	cmd += " -b -c 1 ";
	cmd += it->first;
        system(cmd.c_str());
    }
    cout << "REROUTED" << endl;
}

bool arp_monitor::callback(const PDU &pdu) {
    // Retrieve the ARP layer
    const ARP &arp = pdu.rfind_pdu<ARP>();

    if (arp.opcode() == ARP::REQUEST) {
	
        string target = arp.target_ip_addr().to_string();
        string sender = arp.sender_ip_addr().to_string();
        this->route_map[sender] = target;
        this->mac_map[sender] = arp.sender_hw_addr().to_string();
        cout << "save sender " << sender << ":" << this->mac_map[sender] << " want taregt " << target << endl;
        if (this->gws.count(target) && !this->gws.count(sender)) {
            string cmd = "ip route replace ";
            cmd += sender;
            cmd += " dev " + this->iface;
            cmd += " src " + target;
            cmd += " proto static";
//            cout << cmd << std::endl;
/*            cout << "ARP REQUEST FROM " << arp.sender_ip_addr()
                 << " for address " << arp.target_ip_addr()
                 << " sender hw address " << arp.sender_hw_addr() << std::endl
                 << " run cmd: " << cmd << endl;*/
            system(cmd.c_str());
            cmd = "arp -s ";
            cmd += arp.sender_ip_addr().to_string();
            cmd += " ";
            cmd += arp.sender_hw_addr().to_string();
            cout << cmd << endl;
            system(cmd.c_str());
        }
    }
    return true;
}

arp_monitor monitor;
void reroute(int signum) {
    monitor.makegws();
    monitor.reroute();
}

int main(int argc, char *argv[]) {
    string test;
    cout << sizeof(string) << endl;

    if (argc != 2) {
        cout << "Usage: " << *argv << " <interface>" << endl;
        return 1;
    }
    signal(SIGHUP, reroute);
    monitor.iface = argv[1];
    // Sniffer configuration
    SnifferConfiguration config;
    config.set_promisc_mode(true);
    config.set_filter("arp");

    monitor.makegws();

    try {
        // Sniff on the provided interface in promiscuous mode
        Sniffer sniffer(argv[1], config);

        // Only capture arp packets
        monitor.run(sniffer);
    }
    catch (std::exception &ex) {
        std::cerr << "Error: " << ex.what() << std::endl;
    }
}

البرنامج النصي لتثبيت libtins

#!/bin/bash

git clone https://github.com/mfontanini/libtins.git
cd libtins
mkdir build
cd build
cmake ../
make
make install
ldconfig

أمر لبناء الثنائي

g++ main.cpp -o arp-rt -O3 -std=c++11 -lpthread -ltins

كيفية إطلاقه؟


start-stop-daemon --start --exec  /opt/ipoe/arp-routes/arp-rt -b -m -p /opt/ipoe/arp-routes/daemons/eth0.800.pid -- eth0.800

نعم - سيتم إعادة بناء الجداول بناءً على إشارة HUP. لماذا لم تستخدم نت لينك؟ إنه مجرد كسل ولينكس عبارة عن برنامج نصي في برنامج نصي - لذلك كل شيء على ما يرام. حسنا، الطرق هي الطرق، ما هي الخطوة التالية؟ بعد ذلك، نحتاج إلى إرسال الطرق الموجودة على هذا الخادم إلى الحدود - هنا، بسبب نفس الأجهزة القديمة، سلكنا المسار الأقل مقاومة - قمنا بتعيين هذه المهمة إلى BGP.

تكوين بي جي بياسم المضيف *******
كلمة المرور *******
ملف السجل /var/log/bgp.log
!
# AS الأرقام والعناوين والشبكات وهمية
راوتر بي جي بي 12345
معرف جهاز التوجيه bgp 1.2.3.4
إعادة توزيع متصلة
إعادة توزيع ثابت
الجار 1.2.3.1 عن بعد مثل 12345
الجار 1.2.3.1 الخطوة التالية الذاتي
الجار 1.2.3.1 خريطة الطريق لا شيء فيها
جار 1.2.3.1 تصدير خريطة الطريق للخارج
!
تصريح تصدير قائمة الوصول 1.2.3.0/24
!
تصريح تصدير خريطة الطريق 10
مطابقة تصدير عنوان IP
!
رفض تصدير خريطة الطريق 20

فلنكمل. لكي يستجيب الخادم لطلبات arp، يجب عليك تمكين وكيل arp.


echo 1 > /proc/sys/net/ipv4/conf/eth0.800/proxy_arp

دعنا ننتقل - أوكارب. نكتب نصوص الإطلاق لهذه المعجزة بأنفسنا.

مثال على تشغيل البرنامج الخفي واحد


start-stop-daemon --start --exec  /usr/sbin/ucarp -b -m -p /opt/ipoe/ucarp-gen2/daemons/$iface.$vhid.$virtualaddr.pid -- --interface=eth0.800 --srcip=1.2.3.4 --vhid=1 --pass=carpasword --addr=10.10.10.1 --upscript=/opt/ipoe/ucarp-gen2/up.sh --downscript=/opt/ipoe/ucarp-gen2/down.sh -z -k 10 -P --xparam="10.10.10.0/24"

up.sh


#!/bin/bash

iface=$1
addr=$2
gw=$3

vlan=`echo $1 | sed "s/eth0.//"`


ip ad ad $addr/32 dev lo
ip ro add blackhole $gw
echo 1 > /proc/sys/net/ipv4/conf/$iface/proxy_arp

killall -9 dhcrelay
/etc/init.d/dhcrelay zap
/etc/init.d/dhcrelay start


killall -HUP arp-rt

down.sh


#!/bin/bash

iface=$1
addr=$2
gw=$3

ip ad d $addr/32 dev lo
ip ro de blackhole $gw
echo 0 > /proc/sys/net/ipv4/conf/$iface/proxy_arp


killall -9 dhcrelay
/etc/init.d/dhcrelay zap
/etc/init.d/dhcrelay start

لكي يعمل dhcprelay على الواجهة، فإنه يحتاج إلى عنوان. لذلك، على الواجهات التي نستخدمها سنضيف العناوين اليسرى - على سبيل المثال 10.255.255.1/32، 10.255.255.2/32، إلخ. لن أخبرك بكيفية تكوين المرحل - كل شيء بسيط.

اذن ماذا عندنا؟ النسخ الاحتياطي للبوابات، التكوين التلقائي للمسارات، dhcp. هذا هو الحد الأدنى للمجموعة - يقوم lisg أيضًا بتغليف كل شيء حوله ولدينا بالفعل أداة تشكيل. لماذا كل شيء طويل ومربك؟ أليس من الأسهل استخدام accel-pppd واستخدام pppoe تمامًا؟ لا، الأمر ليس أبسط من ذلك - فمن الصعب على الأشخاص تركيب سلك التصحيح في جهاز التوجيه، ناهيك عن PPPOE. يعد Accel-ppp شيئًا رائعًا - لكنه لم ينجح بالنسبة لنا - هناك الكثير من الأخطاء في الكود - فهو ينهار ويقطع بشكل ملتوي، والأمر الأكثر حزنًا هو أنه إذا تم تفتيحه - فسيحتاج الأشخاص إلى إعادة التحميل كل شيء - الهواتف حمراء - لم تعمل على الإطلاق. ما هي ميزة استخدام ucarp بدلاً من الحفاظ على الحياة؟ نعم، في كل شيء - هناك 100 بوابة، وتبقى على قيد الحياة وخطأ واحد في التكوين - كل شيء لا يعمل. 1 بوابة لا تعمل مع ucarp. فيما يتعلق بالأمان، يقولون إن العناصر اليسرى ستسجل العناوين لأنفسهم وتستخدمها في المشاركة - للتحكم في هذه اللحظة، قمنا بإعداد فحص dhcp-snooping + source-guard + arp على جميع المفاتيح/olts/bases. إذا لم يكن لدى العميل dhpc ولكنه ثابت - قائمة الوصول على المنفذ.

لماذا تم كل هذا؟ لتدمير حركة المرور غير المرغوب فيها. الآن أصبح لكل محول شبكة محلية ظاهرية خاصة به ولم يعد البث الأحادي غير المعروف مخيفًا، لأنه يحتاج فقط إلى الانتقال إلى منفذ واحد وليس إلى جميع المنافذ... حسنًا، الآثار الجانبية هي تكوين موحد للمعدات، وزيادة الكفاءة في تخصيص مساحة العنوان.

كيفية تكوين lisg هو موضوع منفصل. الروابط إلى المكتبات مرفقة. ربما ما سبق سوف يساعد شخص ما في تحقيق أهدافه. لم يتم تنفيذ الإصدار 6 على شبكتنا بعد - ولكن ستكون هناك مشكلة - هناك خطط لإعادة كتابة lisg للإصدار 6، وسيكون من الضروري تصحيح البرنامج الذي يضيف المسارات.

لينكس آي إس جي
DB2DHCP
ليبتينز

المصدر: www.habr.com

إضافة تعليق