Síť IPeE odolná proti chybám pomocí improvizovaných nástrojů

Ahoj. To znamená, že existuje síť 5 8 klientů. Nedávno přišel nepříliš příjemný moment - v centru sítě máme Brocade RXXNUMX a začal posílat spoustu neznámých-unicast paketů, protože síť je rozdělena na vlany - to částečně není problém, ALE existují speciální vlany pro bílé adresy atd. a jsou nataženy ve všech směrech sítě. Nyní si tedy představte příchozí tok na adresu klienta, který nestuduje jako pohraniční student a tento tok letí směrem k rádiovému spojení do nějaké (nebo celé) vesnice - kanál je ucpaný - klienti jsou naštvaní - smutek...

Cílem je proměnit chybu ve funkci. Uvažoval jsem ve směru q-in-q s plnohodnotnou klientskou vlan, ale všelijaký hardware jako P3310, když je povolena dot1q, přestane propouštět DHCP, také neví, jak selektivní qinq a mnoho úskalí tohoto druhu. Co je to ip-unnamed a jak to funguje? Velmi stručně: adresa brány + trasa na rozhraní. Pro náš úkol potřebujeme: oříznout tvarovač, distribuovat adresy klientům, přidat cesty ke klientům přes určitá rozhraní. Jak to všechno udělat? Shaper - lisg, dhcp - db2dhcp na dvou nezávislých serverech, dhcprelay běží na přístupových serverech, ucarp také běží na přístupových serverech - pro zálohování. Ale jak přidat trasy? Vše můžete přidat předem velkým skriptem – ale není to pravda. Vyrobíme si tedy vlastnoručně psanou berličku.

Po důkladném hledání na internetu jsem našel nádhernou knihovnu na vysoké úrovni pro C++, která umožňuje krásně čichat provoz. Algoritmus pro program, který přidává trasy, je následující - posloucháme požadavky arp na rozhraní, pokud máme požadovanou adresu na rozhraní lo na serveru, přidáme trasu přes toto rozhraní a přidáme statické arp záznam na tuto ip - obecně pár copy-paste, trochu přídavného jména a je hotovo

Zdroje „routeru“

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

instalační skript libtins

#!/bin/bash

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

Příkaz k sestavení binárního souboru

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

Jak to spustit?


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

Ano - přestaví tabulky na základě signálu HUP. Proč jsi nepoužil netlink? Je to jen lenost a Linux je skript na skriptu - takže vše v pořádku. No, trasy jsou trasy, co dál? Dále musíme poslat cesty, které jsou na tomto serveru, na hranici - zde jsme se kvůli stejně zastaralému hardwaru vydali cestou nejmenšího odporu - tento úkol jsme zadali BGP.

konfigurace bgpnázev hostitele ********
Heslo *******
soubor protokolu /var/log/bgp.log
!
# Číslo AS, adresy a sítě jsou fiktivní
router bgp 12345
bgp router-id 1.2.3.4
přerozdělit připojeno
redistribuovat statickou elektřinu
soused 1.2.3.1 vzdálený-jako 12345
soused 1.2.3.1 next-hop-self
soused 1.2.3.1 route-map no in
soused 1.2.3.1 export mapy trasy ven
!
povolení k exportu přístupového seznamu 1.2.3.0/24
!
povolení k exportu mapy tras 10
export shody IP adresy
!
odmítnutí exportu mapy 20

Pokračujme. Aby server odpovídal na požadavky arp, musíte povolit arp proxy.


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

Jdeme dál – ucarp. Spouštěcí skripty pro tento zázrak si píšeme sami.

Příklad spuštění jednoho 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

dolů.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í, potřebuje adresu. Proto na rozhraní, která používáme, přidáme levé adresy - například 10.255.255.1/32, 10.255.255.2/32 atd. Neřeknu vám, jak nakonfigurovat relé - vše je jednoduché.

Tak co máme? Zálohování bran, automatická konfigurace tras, dhcp. Jedná se o minimální sadu - lisg také vše obtočí a už máme tvarovač. Proč je všechno tak dlouhé a nepřehledné? Není jednodušší vzít accel-pppd a používat pppoe úplně? Ne, není to jednodušší – lidé stěží vejdou patchcord do routeru, nemluvě o pppoe. accel-ppp je super věc - ale u nás to nefungovalo - v kódu je spousta chyb - drolí se, křivě se to řeže a nejsmutnější je, že pokud se to rozjasnilo - tak lidi potřebují znovu načíst vše - telefony jsou červené - vůbec to nefungovalo. Jaká je výhoda použití ucarp spíše než keepalived? Ano, ve všem - je 100 bran, keepalived a jedna chyba v konfiguraci - vše nefunguje. 1 brána nefunguje s ucarp. Ohledně zabezpečení říkají, že ti leví si budou registrovat adresy pro sebe a používat je na share - pro kontrolu tohoto okamžiku jsme nastavili dhcp-snooping + source-guard + arp kontrolu na všech switchích/oltech/bázích. Pokud klient nemá dhpc, ale statický - seznam přístupů na portu.

Proč se to všechno dělalo? Chcete-li zničit nežádoucí provoz. Nyní má každý přepínač svou vlastní vlan a neznámý-unicast již není děsivý, protože potřebuje jít pouze na jeden port a ne na všechny... Vedlejším efektem je standardizovaná konfigurace zařízení, větší efektivita při přidělování adresního prostoru.

Jak nakonfigurovat lisg je samostatné téma. Odkazy na knihovny jsou přiloženy. Možná, že výše uvedené někomu pomůže dosáhnout jeho cílů. Verze 6 se v naší síti zatím neimplementuje - ale bude problém - plánuje se přepsání lisg pro verzi 6 a bude nutné opravit program, který přidává trasy.

Linux ISG
DB2DHCP
Libtins

Zdroj: www.habr.com

Přidat komentář