Omrežje IPeE, ki je odporno na napake, uporablja improvizirana orodja

Zdravo. To pomeni, da obstaja omrežje 5k strank. Pred kratkim se je pojavil ne preveč prijeten trenutek - v središču omrežja imamo Brocade RX8 in je začel pošiljati veliko neznanih unicast paketov, ker je omrežje razdeljeno na vlane - to deloma ni problem, AMPAK obstajajo posebni vlan za bele naslove itd. in so raztegnjeni v vse smeri mreže. Torej zdaj si predstavljajte dohodni tok na naslov stranke, ki ne študira kot mejni študent in ta tok leti proti radijski povezavi v neko (ali vse) vasi - kanal je zamašen - stranke jezne - žalost ...

Cilj je hrošča spremeniti v funkcijo. Razmišljal sem v smeri q-in-q s polnopravnim odjemalskim vlan-om, vendar vse vrste strojne opreme, kot je P3310, ko je omogočen dot1q, ne pusti več DHCP-ja, prav tako ne znajo selektivnega qinq-ja in mnogih tovrstne pasti. Kaj je ip-unnambered in kako deluje? Zelo na kratko: naslov prehoda + pot na vmesniku. Za našo nalogo moramo: rezati oblikovalnik, distribuirati naslove odjemalcem, dodajati poti odjemalcem preko določenih vmesnikov. Kako vse to narediti? Shaper - lisg, dhcp - db2dhcp na dveh neodvisnih strežnikih, dhcprelay teče na dostopnih strežnikih, ucarp tudi na dostopnih strežnikih - za backup. Toda kako dodati poti? Vse lahko dodate vnaprej z velikim skriptom - vendar to ni res. Izdelali bomo torej samopisno berglo.

Po temeljitem iskanju po internetu sem našel čudovito visokonivojsko knjižnico za C++, ki omogoča čudovito vohanje prometa. Algoritem programa, ki dodaja poti je sledeč - poslušamo arp zahteve na vmesniku, če imamo naslov na lo vmesniku na strežniku, ki je zahtevan, potem dodamo pot preko tega vmesnika in dodamo statični arp zapis na ta ip - na splošno, nekaj copy-paste, malo pridevnika in končali ste

Viri 'usmerjevalnika'

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

namestitveni skript libtins

#!/bin/bash

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

Ukaz za izdelavo dvojiške datoteke

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

Kako ga zagnati?


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

Da - znova bo zgradil tabele na podlagi signala HUP. Zakaj nisi uporabil netlinka? To je le lenoba in Linux je skript na skripti - torej je vse v redu. No, poti so poti, kaj je naslednje? Nato moramo poti, ki so na tem strežniku, poslati na mejo - tukaj smo zaradi iste zastarele strojne opreme ubrali pot najmanjšega odpora - to nalogo smo dodelili BGP.

bgp configime gostitelja *******
geslo *******
dnevniška datoteka /var/log/bgp.log
!
# Številka AS, naslovi in ​​omrežja so izmišljeni
usmerjevalnik bgp 12345
bgp usmerjevalnik-id 1.2.3.4
prerazporediti povezane
prerazporedi statiko
sosed 1.2.3.1 oddaljeni kot 12345
sosed 1.2.3.1 next-hop-self
sosed 1.2.3.1 zemljevid poti brez v
sosed 1.2.3.1 izvoz zemljevida poti ven
!
dovoljenje za izvoz dostopnega seznama 1.2.3.0/24
!
dovoljenje za izvoz zemljevida poti 10
ujemaj izvoz naslova ip
!
zavrnitev izvoza zemljevida poti 20

Nadaljujmo. Če želite, da se strežnik odzove na zahteve arp, morate omogočiti arp proxy.


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

Gremo naprej – ukarp. Zagonske skripte za ta čudež pišemo sami.

Primer izvajanja enega demona


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

Da dhcprelay deluje na vmesniku, potrebuje naslov. Zato bomo na vmesnikih, ki jih uporabljamo, dodali leve naslove - na primer 10.255.255.1/32, 10.255.255.2/32 itd. Ne bom vam povedal, kako konfigurirati rele - vse je preprosto.

Torej, kaj imamo? Varnostno kopiranje prehodov, samodejna konfiguracija poti, dhcp. To je minimalni nabor - tudi lisg vse ovije in že imamo oblikovalec. Zakaj je vse tako dolgo in zapleteno? Ali ni lažje vzeti accel-pppd in v celoti uporabiti pppoe? Ne, ni enostavnejše - ljudje komajda vtaknejo patchcord v usmerjevalnik, da ne omenjam pppoe. accel-ppp je kul zadeva - pri nas pa ni delovalo - veliko je napak v kodi - drobi se, narobe reže in kar je najbolj žalostno, če se je razvedrilo - potem morajo ljudje na novo naložiti vse - telefoni so rdeči - sploh ni delovalo. Kakšna je prednost uporabe ucarp namesto keepalived? Da, v vsem - obstaja 100 prehodov, keepalived in ena napaka v konfiguraciji - vse ne deluje. 1 prehod ne deluje z ucarp. Glede varnosti pa pravijo, da si bodo levi registrirali naslove in jih uporabljali na share-u za kontrolo tega trenutka smo na vseh switchih/oltih/bazah postavili dhcp-snooping + source-guard + arp inspekcijo. Če odjemalec nima dhpc ampak statični - seznam dostopov na vratih.

Zakaj je bilo vse to storjeno? Za uničenje neželenega prometa. Zdaj ima vsako stikalo svoj vlan in unknown-unicast ni več strašen, saj mora iti samo na ena vrata in ne na vsa... No, stranski učinki so standardizirana konfiguracija opreme, večja učinkovitost pri dodeljevanju naslovnega prostora.

Kako konfigurirati lisg je posebna tema. Povezave do knjižnic so priložene. Morda bo našteto komu pomagalo pri doseganju ciljev. Različica 6 še ni implementirana v našem omrežju - vendar bo problem - v načrtu je prepis lisg za različico 6 in treba bo popraviti program, ki dodaja poti.

Linux ISG
DB2DHCP
Libtins

Vir: www.habr.com

Dodaj komentar