Vikasietoinen IPeE-verkko improvisoiduilla työkaluilla

Hei. Tämä tarkoittaa, että verkostossa on 5 8 asiakasta. Äskettäin koettiin ei kovin miellyttävä hetki - verkon keskellä meillä on Brocade RXXNUMX ja se alkoi lähettää paljon tuntemattomia unicast-paketteja, koska verkko on jaettu vlaneihin - tämä ei ole osittain ongelma, MUTTA on olemassa erityiset vlanit valkoisille osoitteille jne. ja ne ovat venyneet verkon kaikkiin suuntiin. Kuvittele nyt siis tulevaa virtaa sellaisen asiakkaan osoitteeseen, joka ei opiskele raja-opiskelijana ja tämä virta lentää kohti radiolinkkiä johonkin (tai kaikkiin) kylään - kanava on tukossa - asiakkaat ovat vihaisia ​​- surua...

Tavoitteena on tehdä bugista ominaisuus. Ajattelin q-in-q:n suuntaan täydellä asiakasvlanilla, mutta kaikenlaiset laitteet, kuten P3310, kun dot1q on päällä, lakkaa päästämästä DHCP:tä läpi, eivät myöskään osaa valikoida qinqia ja monet tuollaisia ​​sudenkuoppia. Mikä on ip-unnambered ja miten se toimii? Hyvin lyhyesti: yhdyskäytävän osoite + reitti käyttöliittymässä. Tehtäväämme varten meidän on leikattava muotoilija, jaettava osoitteita asiakkaille, lisättävä reittejä asiakkaille tiettyjen rajapintojen kautta. Miten tämä kaikki tehdään? Shaper - lisg, dhcp - db2dhcp kahdella itsenäisellä palvelimella, dhcprelay toimii pääsypalvelimissa, ucarp toimii myös pääsypalvelimissa - varmuuskopiointia varten. Mutta miten reittejä lisätään? Voit lisätä kaiken etukäteen suurella skriptillä - mutta tämä ei ole totta. Joten teemme itse kirjoitetun kainalosauvan.

Perusteellisen Internet-haun jälkeen löysin upean korkean tason kirjaston C++:lle, jonka avulla voit haistella liikennettä kauniisti. Reittejä lisäävän ohjelman algoritmi on seuraava - kuuntelemme arp-pyyntöjä käyttöliittymässä, jos meillä on pyydetty osoite lo-rajapinnassa palvelimella, niin lisäämme reitin tämän rajapinnan kautta ja lisäämme staattisen arp tallenna tähän IP-osoitteeseen - yleensä muutama copy-paste, pieni adjektiivi ja olet valmis

'reitittimen' lähteet

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

#!/bin/bash

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

Komento rakentaa binääri

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

Kuinka käynnistää se?


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

Kyllä – se rakentaa taulukot uudelleen HUP-signaalin perusteella. Mikset käyttänyt netlinkkiä? Se on vain laiskuutta ja Linux on skripti skriptin päällä - joten kaikki on hyvin. No, reitit ovat reittejä, mitä seuraavaksi? Seuraavaksi meidän on lähetettävä tällä palvelimella olevat reitit rajalle - tässä saman vanhentuneen laitteiston vuoksi valitsimme pienimmän vastuksen polun - annoimme tämän tehtävän BGP:lle.

bgp-asetusisäntänimi *******
Salasana *******
lokitiedosto /var/log/bgp.log
!
# AS-numero, osoitteet ja verkot ovat kuvitteellisia
reititin bgp 12345
bgp-reitittimen tunnus 1.2.3.4
jakaa uudelleen yhdistettynä
jakaa staattista sähköä uudelleen
naapuri 1.2.3.1 kauko-as 12345
naapuri 1.2.3.1 next-hop-self
naapuri 1.2.3.1 reittikartta ei sisällä
naapuri 1.2.3.1 reittikartan vienti ulos
!
pääsyluettelon vientilupa 1.2.3.0/24
!
reittikartan vientilupa 10
vastaa ip-osoitteen vientiä
!
reittikartan vientikielto 20

Jatketaan. Jotta palvelin voi vastata arp-pyyntöihin, sinun on otettava käyttöön arp-välityspalvelin.


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

Jatketaan - ucarp. Kirjoitamme tämän ihmeen käynnistysskriptit itse.

Esimerkki yhden demonin suorittamisesta


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

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

Jotta dhcprelay toimisi käyttöliittymässä, se tarvitsee osoitteen. Siksi käyttämiimme liitäntöihin lisäämme vasemmat osoitteet - esimerkiksi 10.255.255.1/32, 10.255.255.2/32 jne. En kerro sinulle, kuinka rele määritetään - kaikki on yksinkertaista.

Mitä meillä on? Yhdyskäytävien varmuuskopiointi, reittien automaattinen konfigurointi, dhcp. Tämä on minimisarja - lisg myös kietoo kaiken ympärilleen ja meillä on jo muotoilija. Miksi kaikki on niin pitkää ja monimutkaista? Eikö ole helpompaa ottaa accel-pppd ja käyttää pppoea kokonaan? Ei, se ei ole yksinkertaisempaa – ihmiset tuskin pystyvät sovittamaan patchcordia reitittimeen, pppoesta puhumattakaan. accel-ppp on hieno juttu - mutta se ei toiminut meillä - koodissa on paljon virheitä - se murenee, se leikkaa vinosti ja surullisinta on, että jos se kirkastui - niin ihmisten täytyy ladata uudelleen kaikki - puhelimet ovat punaisia ​​- se ei toiminut ollenkaan. Mitä hyötyä on ucarpin käyttämisestä elämisen säilymisen sijaan? Kyllä, kaikessa - on 100 yhdyskäytävää, Keepalved ja yksi virhe konfiguraatiossa - kaikki ei toimi. 1 yhdyskäytävä ei toimi ucarpin kanssa. Turvallisuudesta sanotaan, että vasemmanpuoleiset rekisteröivät itselleen osoitteet ja käyttävät niitä jakoon - tämän hetken hallitsemiseksi asensimme dhcp-snooping + source-guard + arp-tarkastuksen kaikkiin kytkimiin/olteihin/baseisiin. Jos asiakkaalla ei ole dhpc:tä, vaan staattista - portissa acces-list.

Miksi tämä kaikki tehtiin? Ei-toivotun liikenteen tuhoamiseksi. Nyt jokaisella kytkimellä on oma vlan ja tuntematon-unicast ei ole enää pelottava, koska sen tarvitsee mennä vain yhteen porttiin eikä kaikkiin... No, sivuvaikutuksia ovat standardoitu laitekonfiguraatio, tehostunut osoitetilan varaaminen.

Lisg:n määrittäminen on erillinen aihe. Liitteenä on linkit kirjastoihin. Ehkä yllä oleva auttaa jotakuta saavuttamaan tavoitteensa. Versio 6 ei ole vielä käytössä verkossamme - mutta tulee ongelma - lisg on tarkoitus kirjoittaa versiolle 6 ja reittejä lisäävä ohjelma on korjattava.

Linux ISG
DB2DHCP
Libtins

Lähde: will.com

Lisää kommentti