Sieť IPeE odolná voči chybám pomocou improvizovaných nástrojov

Ahoj. To znamená, že existuje sieť 5 8 klientov. Nedávno prišiel nie veľmi príjemný moment - v strede siete máme Brocade RXXNUMX a začal posielať veľa neznámych-unicast paketov, keďže sieť je rozdelená na vlany - čiastočne to nie je problém, ALE existujú špeciálne vlany pre biele adresy atď. a sú roztiahnuté vo všetkých smeroch siete. Tak si teraz predstavte prichádzajúci tok na adresu klienta, ktorý neštuduje ako pohraničný študent a tento tok letí smerom k rádiovému spoju do nejakej (alebo celej) dediny - kanál je upchatý - klienti sú nahnevaní - smútok...

Cieľom je premeniť chybu na funkciu. Myslel som v smere q-in-q s plnohodnotným klientskym vlan, ale všelijaký hardvér ako P3310, keď je povolená dot1q, prestane prepúšťať DHCP, tiež nevedia, ako selektívne qinq a mnoho úskalia tohto druhu. Čo je to ip-unnamed a ako to funguje? Veľmi stručne: adresa brány + trasa na rozhraní. Pre našu úlohu potrebujeme: orezať tvarovač, distribuovať adresy klientom, pridať trasy ku klientom cez určité rozhrania. Ako to všetko urobiť? Shaper - lisg, dhcp - db2dhcp na dvoch nezávislých serveroch, dhcprelay beží na prístupových serveroch, ucarp beží aj na prístupových serveroch - pre zálohovanie. Ale ako pridať trasy? Všetko môžete pridať vopred pomocou veľkého skriptu – nie je to však pravda. Vyrobíme si teda vlastnoručne napísanú barličku.

Po dôkladnom pátraní na internete som našiel nádhernú knižnicu na vysokej úrovni pre C++, ktorá vám umožňuje krásne čuchať návštevnosť. Algoritmus programu, ktorý pridáva trasy, je nasledujúci - počúvame požiadavky arp na rozhraní, ak máme požadovanú adresu na rozhraní lo na serveri, potom pridáme trasu cez toto rozhranie a pridáme statické arp záznam na túto ip - vo všeobecnosti pár copy-paste, trochu prídavného mena a hotovo

Zdroje „smerovača“

#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;
    }
}

inštalačný skript libtins

#!/bin/bash

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

Príkaz na zostavenie binárneho súboru

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

Ako to spustiť?


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

Áno – prebuduje tabuľky na základe signálu HUP. Prečo si nepoužil netlink? Je to len lenivosť a Linux je skript na skripte - takže je všetko v poriadku. Nuž, trasy sú trasy, čo ďalej? Ďalej musíme poslať trasy, ktoré sú na tomto serveri, na hranicu – tu sme sa kvôli rovnako zastaranému hardvéru vybrali cestou najmenšieho odporu – túto úlohu sme pridelili BGP.

konfigurácia bgpmeno hosťa *******
heslo ********
log súbor /var/log/bgp.log
!
# Číslo AS, adresy a siete sú fiktívne
smerovač bgp 12345
bgp router-id 1.2.3.4
prerozdeliť pripojený
prerozdeliť statickú energiu
sused 1.2.3.1 vzdialený-ako 12345
sused 1.2.3.1 next-hop-self
sused 1.2.3.1 route-map no in
sused 1.2.3.1 exportovať mapu trasy von
!
povolenie na export prístupového zoznamu 1.2.3.0/24
!
povolenie na vývoz mapy trás 10
export zhody IP adresy
!
odmietnutie exportu mapy trasy 20

Pokračujme. Aby server odpovedal na požiadavky arp, musíte povoliť arp proxy.


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

Ideme ďalej - ucarp. Spúšťacie skripty tohto zázraku si píšeme sami.

Príklad spustenia jedného démona


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

dole.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

Aby dhcprelay fungovalo na rozhraní, potrebuje adresu. Preto na rozhraniach, ktoré používame, pridáme ľavé adresy - napríklad 10.255.255.1/32, 10.255.255.2/32 atď. Nepoviem vám, ako nakonfigurovať relé - všetko je jednoduché.

Čo teda máme? Zálohovanie brán, automatická konfigurácia trás, dhcp. Toto je minimálna sada - lisg aj všetko omotá a už máme tvarovačku. Prečo je všetko také dlhé a mätúce? Nie je jednoduchšie vziať accel-pppd a použiť pppoe úplne? Nie, nie je to jednoduchšie – ľudia len ťažko zmestia patchcord do smerovača, nehovoriac o pppoe. accel-ppp je vyborna vec - ale nam to nefungovalo - v kode je vela chyb - drobi sa to, krivo sa to seka a najsmutnejsie na tom je, ze ak sa to rozjasnilo - tak ludia musia znova načítat všetko - telefóny sú červené - vôbec to nefungovalo. Aká je výhoda používania ucarp namiesto udržiavania? Áno, vo všetkom - je tam 100 brán, keepalived a jedna chyba v konfigurácii - všetko nefunguje. 1 brána nefunguje s ucarp. Ohladom bezpecnosti sa hovori, ze ľavi si zaregistrujú adresy pre seba a použijú ich na share - na kontrolu tohto momentu sme nastavili dhcp-snooping + source-guard + kontrolu arp na vsetkych switchoch/oltoch/bazach. Ak klient nemá dhpc, ale statické - zoznam prístupových práv na porte.

Prečo sa to všetko urobilo? Zničiť nechcenú premávku. Teraz má každý prepínač svoju vlastnú vlan a neznámy-unicast už nie je strašidelný, keďže potrebuje ísť len na jeden port a nie na všetky... Vedľajším efektom je štandardizovaná konfigurácia zariadenia, väčšia efektivita pri prideľovaní adresného priestoru.

Ako nakonfigurovať lisg je samostatná téma. Odkazy na knižnice sú priložené. Možno vyššie uvedené niekomu pomôžu pri dosahovaní ich cieľov. Verzia 6 sa v našej sieti zatiaľ neimplementuje - bude však problém - plánuje sa prepísanie lisgu pre verziu 6 a bude potrebné opraviť program, ktorý pridáva trasy.

Linux ISG
DB2DHCP
Libtins

Zdroj: hab.com

Pridať komentár