شبکه IPeE مقاوم در برابر خطا با استفاده از ابزارهای بداهه

سلام. این بدان معناست که شبکه ای از 5k مشتری وجود دارد. اخیراً یک لحظه نه چندان خوشایند رخ داد - در مرکز شبکه یک Brocade RX8 داریم و شروع به ارسال بسته های ناشناخته-یونیکاست زیادی کرد، زیرا شبکه به vlan ها تقسیم شده است - این تا حدی مشکلی نیست، اما وجود دارد. vlan های ویژه برای آدرس های سفید و غیره و در تمام جهات شبکه کشیده شده اند. پس حالا تصور کنید یک جریان ورودی به آدرس یک مشتری که به عنوان دانشجوی مرزی تحصیل نمی کند و این جریان به سمت یک لینک رادیویی به فلان (یا همه) روستا می رود - کانال مسدود است - مشتری ها عصبانی هستند - ناراحتی ...

هدف این است که یک اشکال را به یک ویژگی تبدیل کنید. من به سمت q-in-q با یک کلاینت vlan کامل فکر می کردم، اما انواع سخت افزارهایی مانند P3310، وقتی dot1q فعال است، اجازه عبور DHCP را نمی دهند، آنها همچنین نمی دانند چگونه qinq انتخابی و بسیاری از آنها را انتخاب کنند. از این دست دام ها ip-unnamebered چیست و چگونه کار می کند؟ به طور خلاصه: آدرس دروازه + مسیر در رابط. برای وظیفه ما، ما نیاز داریم: شکل دهنده را برش دهیم، آدرس ها را به مشتریان توزیع کنیم، مسیرها را از طریق واسط های خاص به کلاینت ها اضافه کنیم. چگونه می توان همه اینها را انجام داد؟ Shaper - lisg، dhcp - db2dhcp در دو سرور مستقل، dhcprelay روی سرورهای دسترسی اجرا می شود، ucarp نیز روی سرورهای دسترسی - برای پشتیبان گیری اجرا می شود. اما چگونه می توان مسیرها را اضافه کرد؟ شما می توانید همه چیز را از قبل با یک اسکریپت بزرگ اضافه کنید - اما این درست نیست. بنابراین ما یک عصا خودنویس می سازیم.

پس از جستجوی کامل در اینترنت، یک کتابخانه فوق العاده سطح بالا برای C++ پیدا کردم که به شما امکان می دهد به زیبایی ترافیک را بو کنید. الگوریتم برنامه ای که مسیرها را اضافه می کند به شرح زیر است - ما به درخواست های arp در اینترفیس گوش می دهیم، اگر آدرسی در رابط lo در سرور درخواست شده داشته باشیم، سپس یک مسیر از طریق این رابط اضافه می کنیم و یک arp ثابت اضافه می کنیم. ضبط به این آی پی - به طور کلی، چند کپی پیست، یک صفت کوچک و شما تمام شده است

منابع "روتر"

#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 محول کردیم.

پیکربندی bgpنام میزبان *******
کلمه عبور *******
فایل log /var/log/bgp.log
!
شماره AS، آدرس ها و شبکه ها ساختگی هستند
روتر bgp 12345
bgp router-id 1.2.3.4
توزیع مجدد متصل
استاتیک را دوباره توزیع کنید
همسایه 1.2.3.1 remote-as 12345
همسایه 1.2.3.1 next-hop-self
همسایه 1.2.3.1 مسیر-نقشه هیچ در
همسایه 1.2.3.1 صادرات نقشه مسیر
!
مجوز صادرات لیست دسترسی 1.2.3.0/24
!
مجوز صادرات نقشه مسیر 10
مطابقت صادرات آدرس IP
!
route-map صادرات انکار 20

بیا ادامه بدهیم. برای اینکه سرور به درخواست های arp پاسخ دهد، باید پراکسی arp را فعال کنید.


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

بیایید حرکت کنیم - ucarp. ما خودمان اسکریپت های راه اندازی این معجزه را می نویسیم.

نمونه ای از اجرای یک دیمون


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

پایین.ش


#!/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 به جای keepalved چیست؟ بله، در همه چیز - 100 دروازه، نگهدارنده و یک خطا در پیکربندی وجود دارد - همه چیز کار نمی کند. 1 گیت وی با ucarp کار نمی کند. در مورد امنیت، می گویند که سمت چپ ها آدرس ها را برای خود ثبت می کنند و از آنها در اشتراک استفاده می کنند - برای کنترل این لحظه، ما dhcp-snooping + source-guard + arp inspection را روی همه سوئیچ ها/ولت ها/پایه ها راه اندازی کردیم. اگر کلاینت dhpc ندارد اما static - acces-list در پورت دارد.

چرا این همه انجام شد؟ برای از بین بردن ترافیک ناخواسته حالا هر سوییچ vlan مخصوص به خود را دارد و Unknown-unicast دیگر ترسناک نیست، زیرا فقط باید به یک پورت برود نه به همه ... خب، عوارض جانبی آن تنظیمات استاندارد تجهیزات، کارایی بیشتر در تخصیص فضای آدرس است.

نحوه پیکربندی lisg یک موضوع جداگانه است. پیوندهای کتابخانه ها پیوست شده است. شاید موارد فوق به کسی در دستیابی به اهداف خود کمک کند. نسخه 6 هنوز در شبکه ما پیاده سازی نشده است - اما مشکلی وجود خواهد داشت - برنامه هایی برای بازنویسی لیست برای نسخه 6 وجود دارد و لازم است برنامه ای که مسیرها را اضافه می کند اصلاح شود.

لینوکس ISG
DB2DHCP
لیبتین ها

منبع: www.habr.com

اضافه کردن نظر