Doimiy vositalardan foydalangan holda nosozliklarga chidamli IPeE tarmog'i

Salom. Bu 5 ming mijozdan iborat tarmoq mavjudligini anglatadi. Yaqinda unchalik yoqimli bo'lmagan bir lahza paydo bo'ldi - tarmoqning markazida bizda Brocade RX8 bor va u juda ko'p noma'lum-unicast paketlarni jo'natishni boshladi, chunki tarmoq vlanlarga bo'lingan - bu qisman muammo emas, ammo bor. oq manzillar uchun maxsus vlanlar va boshqalar. va ular tarmoqning barcha yo'nalishlarida cho'zilgan. Endi tasavvur qiling-a, chegarada talaba sifatida o‘qimagan mijozning manziliga kiruvchi oqim keladi va bu oqim qaysidir (yoki hammasi) qishloqqa radioaloqa tomon uchadi - kanal tiqilib qolgan - mijozlar g‘azablangan - qayg‘u...

Maqsad xatoni xususiyatga aylantirishdir. Men to'liq huquqli vlan mijozi bilan q-in-q yo'nalishida o'yladim, lekin P3310 kabi barcha turdagi apparatlar, dot1q yoqilganda, DHCP-ga ruxsat berishni to'xtatadi, ular shuningdek, qinq va ko'plarni qanday tanlashni bilishmaydi. bunday tuzoqlar. IP-nomsiz nima va u qanday ishlaydi? Juda qisqacha: shlyuz manzili + interfeysdagi marshrut. Bizning vazifamiz uchun biz quyidagilarga muhtojmiz: shakllantirgichni kesish, mijozlarga manzillarni tarqatish, ma'lum interfeyslar orqali mijozlarga marshrutlarni qo'shish. Bularning barchasini qanday qilish kerak? Shaper - lisg, dhcp - db2dhcp ikkita mustaqil serverda, dhcprelay kirish serverlarida ishlaydi, ucarp ham kirish serverlarida ishlaydi - zaxira uchun. Ammo marshrutlarni qanday qo'shish kerak? Katta skript bilan hamma narsani oldindan qo'shishingiz mumkin - lekin bu to'g'ri emas. Shunday qilib, biz o'zimiz yozgan tayoqchani qilamiz.

Internetda sinchkovlik bilan qidirganimdan so'ng, men C++ uchun ajoyib yuqori darajadagi kutubxonani topdim, bu sizga trafikni chiroyli tarzda hidlash imkonini beradi. Marshrutlarni qo'shadigan dasturning algoritmi quyidagicha - biz interfeysda arp so'rovlarini tinglaymiz, agar so'ralayotgan serverda lo interfeysida manzil bo'lsa, biz ushbu interfeys orqali marshrutni qo'shamiz va statik arp qo'shamiz. bu ipga yozib qo'ying - umuman olganda, bir nechta nusxa ko'chirish, bir oz sifat va siz tugatdingiz

"Router" manbalari

#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 o'rnatish skripti

#!/bin/bash

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

Binarni yaratish buyrug'i

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

Uni qanday ishga tushirish kerak?


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

Ha - bu HUP signali asosida jadvallarni qayta tiklaydi. Nega netlinkdan foydalanmadingiz? Bu shunchaki dangasalik va Linux skriptdagi skript - shuning uchun hammasi yaxshi. Xo'sh, marshrutlar marshrutlar, keyin nima bo'ladi? Keyinchalik, biz ushbu serverdagi marshrutlarni chegaraga yuborishimiz kerak - bu erda bir xil eskirgan uskuna tufayli biz eng kam qarshilik yo'lini oldik - biz bu vazifani BGP ga topshirdik.

bgp konfiguratsiyasixost nomi *******
parol *******
jurnal fayli /var/log/bgp.log
!
# AS raqami, manzillari va tarmoqlari xayoliy
router bgp 12345
bgp router-identifikatori 1.2.3.4
ulangan qayta taqsimlash
statikni qayta taqsimlash
qo'shni 1.2.3.1 masofaviy - 12345 sifatida
qo'shni 1.2.3.1 keyingi-hop-o'zini
qo'shni 1.2.3.1 marshrut-xarita hech biri ichida
qo'shni 1.2.3.1 marshrut-xaritani eksport qilish
!
kirish ro'yxati eksport ruxsati 1.2.3.0/24
!
marshrut xaritasini eksport qilish uchun ruxsatnoma 10
IP-manzilni eksport qilish
!
marshrut xaritasi eksportini rad etish 20

Davom etaylik. Server arp so'rovlariga javob berishi uchun arp proksi-serverini yoqishingiz kerak.


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

Keling, davom etaylik - ucarp. Ushbu mo''jiza uchun ishga tushirish skriptlarini o'zimiz yozamiz.

Bitta demonni ishga tushirishga misol


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

pastga.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 interfeysda ishlashi uchun unga manzil kerak. Shuning uchun biz foydalanadigan interfeyslarga chap manzillarni qo'shamiz - masalan, 10.255.255.1/32, 10.255.255.2/32 va boshqalar. Men sizga o'rni qanday sozlashni aytmayman - hamma narsa oddiy.

Xo'sh, bizda nima bor? Shlyuzlarning zaxira nusxasi, marshrutlarni avtomatik sozlash, dhcp. Bu minimal to'plam - lisg ham uning atrofida hamma narsani o'rab oladi va bizda allaqachon shakllantiruvchi mavjud. Nima uchun hamma narsa uzoq va murakkab? Accel-pppd ni olib, umuman pppoe dan foydalanish osonroq emasmi? Yo'q, bu oddiyroq emas - odamlar pppoe haqida gapirmasa ham, marshrutizatorga patchcord sig'ishi mumkin emas. accel-ppp ajoyib narsa - lekin bu biz uchun ishlamadi - kodda juda ko'p xatolar bor - u parchalanadi, egri kesiladi va eng achinarlisi shundaki, agar u yorishib ketgan bo'lsa - odamlar qayta yuklashlari kerak hamma narsa - telefonlar qizil - bu umuman ishlamadi. Keepaliveddan ko'ra ucarpdan foydalanishning afzalligi nimada? Ha, hamma narsada - 100 ta shlyuz bor, saqlanib qolgan va konfiguratsiyada bitta xato - hamma narsa ishlamaydi. 1 shlyuz ucarp bilan ishlamaydi. Xavfsizlikka kelsak, ular chaplar o'zlari uchun manzillarni ro'yxatdan o'tkazadilar va ularni ulushda ishlatishadi - bu lahzani boshqarish uchun biz barcha kalitlarga/olts/bazalarda dhcp-snooping + source-guard + arp tekshiruvini o'rnatdik. Agar mijozda dhpc bo'lmasa, lekin statik - portda acces-list.

Bularning barchasi nima uchun qilingan? Keraksiz trafikni yo'q qilish uchun. Endi har bir kalit o'z vlaniga ega va noma'lum-unicast endi qo'rqinchli emas, chunki u faqat bitta portga o'tishi kerak va hammasiga emas... Xo'sh, yon ta'sirlar standartlashtirilgan uskuna konfiguratsiyasi, manzil maydonini ajratishda katta samaradorlikdir.

Lisgni qanday sozlash alohida mavzu. Kutubxonalarga havolalar ilova qilingan. Ehtimol, yuqoridagilar kimgadir o'z maqsadlariga erishishda yordam beradi. 6-versiya bizning tarmog'imizda hali joriy etilmayapti - lekin muammo yuzaga keladi - 6-versiya uchun lisgni qayta yozish rejalari bor va marshrutlarni qo'shadigan dasturni tuzatish kerak bo'ladi.

Linux ISG
DB2DHCP
Libtinlar

Manba: www.habr.com

a Izoh qo'shish