Fejltolerant IPeE-netværk ved hjælp af improviserede værktøjer

Hej. Det betyder, at der er et netværk af 5k klienter. For nylig dukkede et ikke særlig behageligt øjeblik op - i midten af ​​netværket har vi en Brocade RX8, og den begyndte at sende en masse ukendte unicast-pakker, da netværket er opdelt i vlans - dette er delvist ikke et problem, MEN der er specielle vlaner til hvide adresser mv. og de strækkes i alle retninger af netværket. Så forestil dig nu et indgående flow til adressen på en klient, der ikke læser som grænsestuderende, og denne strøm flyver mod en radioforbindelse til en eller anden (eller alle) landsby - kanalen er tilstoppet - klienterne er vrede - tristhed...

Målet er at gøre en fejl til en funktion. Jeg tænkte i retning af q-in-q med et fuldgyldigt klient-vlan, men al slags hardware som P3310, når dot1q er aktiveret, stopper med at lade DHCP slippe igennem, de ved heller ikke hvordan man selektiv qinq og mange faldgruber af den slags. Hvad er ip-unummereret, og hvordan virker det? Meget kort: gateway-adresse + rute på interfacet. Til vores opgave skal vi: skære shaperen, distribuere adresser til klienter, tilføje ruter til klienter gennem bestemte grænseflader. Hvordan gør man alt dette? Shaper - lisg, dhcp - db2dhcp på to uafhængige servere, dhcprelay kører på adgangsserverne, ucarp kører også på adgangsserverne - til backup. Men hvordan tilføjer man ruter? Du kan tilføje alt på forhånd med et stort script – men det er ikke sandt. Så vi vil lave en selvskrevet krykke.

Efter en grundig søgning på internettet fandt jeg et vidunderligt bibliotek på højt niveau til C++, som giver dig mulighed for smukt at snuse til trafik. Algoritmen for programmet, der tilføjer ruter, er som følger - vi lytter til arp-anmodninger på grænsefladen, hvis vi har en adresse på lo-grænsefladen på den server, der anmodes om, så tilføjer vi en rute gennem denne grænseflade og tilføjer en statisk arp optag til denne ip - generelt et par copy-pastes, et lille adjektiv og du er færdig

Kilder til 'routeren'

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

#!/bin/bash

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

Kommando til at bygge den binære

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

Hvordan starter man 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 genopbygge tabellerne baseret på HUP-signalet. Hvorfor brugte du ikke netlink? Det er bare dovenskab og Linux er et script på et script – så alt er fint. Nå, ruter er ruter, hvad er det næste? Dernæst skal vi sende de ruter, der er på denne server, til grænsen - her tog vi på grund af den samme forældede hardware vejen med mindst modstand - vi tildelte denne opgave til BGP.

bgp konfigurationværtsnavn *******
adgangskode *******
logfil /var/log/bgp.log
!
# AS-nummer, adresser og netværk er fiktive
router bgp 12345
bgp router-id 1.2.3.4
omfordele forbundet
omfordele statisk
nabo 1.2.3.1 fjernbetjening-som 12345
nabo 1.2.3.1 næste-hop-selv
nabo 1.2.3.1 rutekort ingen i
nabo 1.2.3.1 rute-kort eksport ud
!
adgangsliste eksporttilladelse 1.2.3.0/24
!
rutekort eksporttilladelse 10
match ip-adresse eksport
!
rute-kort eksport nægte 20

Lad os fortsætte. For at serveren kan reagere på arp-anmodninger, skal du aktivere arp-proxyen.


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

Lad os komme videre - ucarp. Vi skriver selv lanceringsmanuskripterne til dette mirakel.

Eksempel på at køre en dæmon


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å en grænseflade, skal den have en adresse. Derfor vil vi på de grænseflader, vi bruger, tilføje venstre adresser - for eksempel 10.255.255.1/32, 10.255.255.2/32 osv. Jeg vil ikke fortælle dig, hvordan du konfigurerer relæet - alt er enkelt.

Så hvad har vi? Backup af gateways, auto-konfiguration af ruter, dhcp. Dette er minimumssættet - lisg vikler også alt omkring det, og vi har allerede en shaper. Hvorfor er alt så langt og forvirrende? Er det ikke nemmere at tage accel-pppd og bruge pppoe helt? Nej, det er ikke nemmere - folk kan næsten ikke passe en patchcord i en router, for ikke at nævne pppoe. accel-ppp er en fed ting - men det virkede ikke for os - der er mange fejl i koden - den smuldrer, den skærer skævt, og det mest sørgelige er, at hvis det lysnede op - så skal folk genindlæse alt - telefonerne er røde - det virkede slet ikke. Hvad er fordelen ved at bruge ucarp frem for keepalive? Ja, i alt - der er 100 gateways, keepalived og en fejl i konfigurationen - alt virker ikke. 1 gateway virker ikke med ucarp. Angående sikkerhed siger de, at de venstre vil registrere adresser for sig selv og bruge dem på aktien - for at kontrollere dette øjeblik sætter vi dhcp-snooping + source-guard + arp inspektion op på alle switche/olts/baser. Hvis klienten ikke har dhpc men statisk - adgangsliste på porten.

Hvorfor blev alt dette gjort? At ødelægge uønsket trafik. Nu har hver switch sit eget vlan, og ukendt-unicast er ikke længere skræmmende, da det kun skal gå til én port og ikke til alle... Tja, bivirkningerne er en standardiseret udstyrskonfiguration, større effektivitet ved tildeling af adresserum.

Hvordan man konfigurerer lisg er et separat emne. Links til biblioteker er vedhæftet. Måske vil ovenstående hjælpe nogen med at nå deres mål. Version 6 er endnu ikke implementeret på vores netværk - men der vil være et problem - der er planer om at omskrive lisg til version 6, og det vil være nødvendigt at rette programmet, der tilføjer ruter.

Linux ISG
DB2DHCP
Libtins

Kilde: www.habr.com

Tilføj en kommentar