Gedimams atsparus IPeE tinklas naudojant improvizuotus įrankius

Sveiki. Tai reiškia, kad yra 5 tūkst. klientų tinklas. Neseniai atėjo ne itin maloni akimirka - tinklo centre turime Brocade RX8 ir jis pradėjo siųsti daug nežinomų unicast paketų, nes tinklas yra padalintas į vlan - tai iš dalies nėra problema, BET yra specialūs vlanai baltiems adresams ir kt. ir jie ištempti į visas tinklo puses. Taigi dabar įsivaizduokite įeinantį srautą kliento, kuris nesimoko pasienio studentu, adresu ir šis srautas nuskrenda link radijo ryšio į kurį nors (ar visą) kaimą - kanalas užsikimšęs - klientai pikti - liūdesys...

Tikslas yra paversti klaidą funkcija. Galvojau q-in-q kryptimi su pilnaverčiu kliento vlan, bet visa aparatinė įranga kaip P3310, kai įjungtas dot1q, nustoja perduoti DHCP, jie taip pat nemoka pasirinkti qinq ir daug spąstų tokios rūšies. Kas yra ip be vardų ir kaip jis veikia? Labai trumpai: vartų adresas + maršrutas sąsajoje. Savo užduočiai atlikti turime: iškirpti formuotoją, paskirstyti adresus klientams, pridėti maršrutus klientams per tam tikras sąsajas. Kaip visa tai padaryti? Shaper - lisg, dhcp - db2dhcp dviejuose nepriklausomuose serveriuose, dhcprelay veikia prieigos serveriuose, ucarp taip pat veikia prieigos serveriuose - atsarginei kopijai. Bet kaip pridėti maršrutus? Galite pridėti viską iš anksto naudodami didelį scenarijų, bet tai netiesa. Taigi pasigaminsime savarankiškai parašytą ramentą.

Po nuodugnios paieškos internete radau nuostabią aukšto lygio biblioteką, skirtą C++, kuri leidžia gražiai uostyti srautą. Programos, kuri prideda maršrutus, algoritmas yra toks - mes klausomės arp užklausų sąsajoje, jei serverio lo sąsajoje turime adresą, kurio prašoma, tada pridedame maršrutą per šią sąsają ir pridedame statinį arp įrašyti į šį IP – apskritai keli copy-paste, truputis būdvardžio ir viskas

„Maršrutizatoriaus“ šaltiniai

#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 diegimo scenarijus

#!/bin/bash

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

Komanda sukurti dvejetainį failą

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

Kaip jį paleisti?


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

Taip – ​​jis atkurs lenteles pagal HUP signalą. Kodėl nenaudojate netlink? Tai tik tinginystė, o Linux yra scenarijus ant scenarijaus – taigi viskas gerai. Na, maršrutai yra maršrutai, o kas toliau? Toliau reikia nusiųsti maršrutus, kurie yra šiame serveryje į pasienį – čia dėl tos pačios pasenusios aparatūros pasukome mažiausio pasipriešinimo keliu – šią užduotį skyrėme BGP.

bgp konfigūracijaprieglobos vardas *******
Slaptažodis *******
žurnalo failas /var/log/bgp.log
!
# AS numeris, adresai ir tinklai yra fiktyvūs
Maršrutizatorius bgp 12345
bgp maršrutizatoriaus ID 1.2.3.4
perskirstyti prijungtas
perskirstyti statinį
kaimynas 1.2.3.1 nuotolinis-as 12345
kaimynas 1.2.3.1 next-hop-self
kaimynas 1.2.3.1 maršruto žemėlapis nėra
kaimynas 1.2.3.1 maršruto žemėlapis eksportuoti
!
prieigos sąrašo eksporto leidimas 1.2.3.0/24
!
maršruto žemėlapio eksporto leidimas 10
atitikti IP adreso eksportą
!
maršruto žemėlapio eksporto atsisakymas 20

Tęskime. Kad serveris atsakytų į ARP užklausas, turite įjungti arp tarpinį serverį.


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

Eime toliau – ukarpas. Šio stebuklo paleidimo scenarijus rašome patys.

Vieno demono paleidimo pavyzdys


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"

aukštyn.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

žemyn.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

Kad dhcprelay veiktų sąsajoje, jai reikia adreso. Todėl mūsų naudojamose sąsajose pridėsime kairiuosius adresus - pavyzdžiui, 10.255.255.1/32, 10.255.255.2/32 ir kt. Aš jums nesakysiu, kaip sukonfigūruoti relę - viskas paprasta.

Taigi ką mes turime? Atsarginės šliuzų kopijos, automatinis maršrutų konfigūravimas, dhcp. Tai yra minimalus rinkinys – lisg taip pat viską apvynioja ir formuotoją jau turime. Kodėl viskas taip ilga ir sudėtinga? Ar ne lengviau paimti accel-pppd ir iš viso naudoti pppoe? Ne, tai nėra paprasčiau – žmonės vargu ar gali įtaisyti patchcord į maršrutizatorių, jau nekalbant apie pppoe. accel-ppp šaunus dalykas - bet mums netiko - daug klaidų kode - trupa, kreivai pjauna, o liūdniausia, kad jei paryškėjo - tada žmonėms reikia perkrauti viskas - telefonai raudoni - visai neveikė. Koks yra ucarp, o ne nuolatinio gyvavimo pranašumas? Taip, visame kame - yra 100 vartų, "Keepalived" ir viena klaida konfigūracijoje - viskas neveikia. 1 vartai neveikia su ucarp. Dėl saugumo sako, kad kairieji užsiregistruos adresus sau ir naudos juos share - kad suvaldytume šį momentą, visuose komutatoriuose/oltuose/bazėse nustatėme dhcp-snooping + source-guard + arp patikra. Jei klientas turi ne dhpc, o statinį – prievado prieigų sąrašas.

Kodėl visa tai buvo padaryta? Norėdami sunaikinti nepageidaujamą eismą. Dabar kiekvienas komutatorius turi savo vlan ir unknown-unicast nebėra baisu, nes reikia tik į vieną prievadą, o ne į visus... Na, o šalutinis poveikis yra standartizuota įrangos konfigūracija, didesnis adresų erdvės paskirstymo efektyvumas.

Kaip sukonfigūruoti lisg yra atskira tema. Pridedamos nuorodos į bibliotekas. Galbūt tai, kas išdėstyta aukščiau, kam nors padės pasiekti savo tikslus. 6 versija mūsų tinkle kol kas nediegiama - bet bus bėda - planuojama perrašyti lisg 6 versijai ir reikės pataisyti maršrutus pridedančią programą.

Linux ISG
DB2DHCP
Libtinai

Šaltinis: www.habr.com

Добавить комментарий