Feiltolerant IPeE-nettverk ved hjelp av improviserte verktøy

Hallo. Dette betyr at det er et nettverk av 5k klienter. Nylig dukket det opp et lite hyggelig øyeblikk - i midten av nettverket har vi en Brocade RX8 og den begynte å sende mange ukjente unicast-pakker, siden nettverket er delt inn i vlans - dette er delvis ikke et problem, MEN det er spesielle vlans for hvite adresser, etc. og de er strukket i alle retninger av nettverket. Så forestill deg nå en innkommende strøm til adressen til en klient som ikke studerer som grensestudent, og denne strømmen flyr mot en radiolink til en eller annen (eller hele) landsby - kanalen er tett - klientene er sinte - tristhet...

Målet er å gjøre en feil om til en funksjon. Jeg tenkte i retning av q-in-q med en fullverdig klient-vlan, men all slags maskinvare som P3310, når dot1q er aktivert, slutter å slippe DHCP gjennom, de vet heller ikke hvordan de skal selektive qinq og mange fallgruver av den typen. Hva er ip-unummerert og hvordan fungerer det? Veldig kort: gateway-adresse + rute på grensesnittet. For vår oppgave må vi: kutte formen, distribuere adresser til klienter, legge til ruter til klienter gjennom visse grensesnitt. Hvordan gjøre alt dette? Shaper - lisg, dhcp - db2dhcp på to uavhengige servere, dhcprelay kjører på tilgangsserverne, ucarp kjører også på tilgangsserverne - for backup. Men hvordan legge til ruter? Du kan legge til alt på forhånd med et stort skript - men dette er ikke sant. Så vi skal lage en selvskreven krykke.

Etter et grundig søk på Internett fant jeg et fantastisk høynivåbibliotek for C++, som lar deg snuse på trafikk. Algoritmen for programmet som legger til ruter er som følger - vi lytter til arp-forespørsler på grensesnittet, hvis vi har en adresse på lo-grensesnittet på serveren som er forespurt, så legger vi til en rute gjennom dette grensesnittet og legger til en statisk arp ta opp til denne ip-en - generelt noen få copy-pastes, et lite adjektiv og du er ferdig

Kilder til "ruteren"

#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 installasjonsskript

#!/bin/bash

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

Kommando for å bygge binæren

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

Hvordan starte den?


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

Ja - det vil gjenoppbygge tabellene basert på HUP-signalet. Hvorfor brukte du ikke netlink? Det er bare latskap og Linux er et script på et script - så alt er bra. Vel, ruter er ruter, hva er det neste? Deretter må vi sende rutene som er på denne serveren til grensen - her, på grunn av den samme utdaterte maskinvaren, tok vi minst motstands vei - vi tildelte denne oppgaven til BGP.

bgp konfigvertsnavn *******
passord *******
loggfil /var/log/bgp.log
!
# AS-nummer, adresser og nettverk er fiktive
ruter bgp 12345
bgp-ruter-id 1.2.3.4
omfordele tilkoblet
omfordele statisk
nabo 1.2.3.1 fjernkontroll-as 12345
nabo 1.2.3.1 neste-hopp-selv
nabo 1.2.3.1 rutekart ingen i
nabo 1.2.3.1 rute-kart eksport ut
!
tilgangsliste eksporttillatelse 1.2.3.0/24
!
rutekart eksporttillatelse 10
match ip-adresseeksport
!
rute-kart eksport nekte 20

La oss fortsette. For at serveren skal svare på arp-forespørsler, må du aktivere arp-proxyen.


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

La oss gå videre - ucarp. Vi skriver lanseringsskriptene for dette miraklet selv.

Eksempel på å kjøre en demon


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

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

For at dhcprelay skal fungere på et grensesnitt, trenger det en adresse. Derfor, på grensesnittene vi bruker, vil vi legge til venstre adresser - for eksempel 10.255.255.1/32, 10.255.255.2/32, etc. Jeg vil ikke fortelle deg hvordan du konfigurerer reléet - alt er enkelt.

Så hva har vi? Sikkerhetskopiering av gatewayer, autokonfigurasjon av ruter, dhcp. Dette er minimumssettet - lisg legger også alt rundt seg, og vi har allerede en shaper. Hvorfor er alt så langt og forvirrende? Er det ikke lettere å ta accel-pppd og bruke pppoe helt? Nei, det er ikke enklere - folk kan knapt passe en patchcord i en ruter, for ikke å snakke om pppoe. accel-ppp er en kul ting - men det fungerte ikke for oss - det er mange feil i koden - den smuldrer, den skjærer skjevt, og det tristeste er at hvis det ble lysere - så må folk laste inn på nytt alt - telefonene er røde - det fungerte ikke i det hele tatt. Hva er fordelen med å bruke ucarp i stedet for keepalive? Ja, i alt - det er 100 gatewayer, keepalived og en feil i konfigurasjonen - alt fungerer ikke. 1 gateway fungerer ikke med ucarp. Angående sikkerhet sier de at de venstre vil registrere adresser for seg selv og bruke dem på aksjen - for å kontrollere dette øyeblikket setter vi opp dhcp-snooping + source-guard + arp inspeksjon på alle brytere/olter/baser. Hvis klienten ikke har dhpc men statisk - tilgangsliste på porten.

Hvorfor ble alt dette gjort? For å ødelegge uønsket trafikk. Nå har hver switch sitt eget vlan og ukjent-unicast er ikke lenger skummelt, siden den bare trenger å gå til én port og ikke til alle... Vel, bivirkningene er en standardisert utstyrskonfigurasjon, større effektivitet i tildeling av adresserom.

Hvordan konfigurere lisg er et eget emne. Lenker til bibliotek er vedlagt. Kanskje vil ovenstående hjelpe noen med å nå sine mål. Versjon 6 er ikke implementert på vårt nettverk ennå - men det vil være et problem - det er planer om å omskrive lisg for versjon 6, og det vil være nødvendig å korrigere programmet som legger til ruter.

Linux ISG
DB2DHCP
Libtins

Kilde: www.habr.com

Legg til en kommentar