Veakindel IPeE-võrk, kasutades improviseeritud tööriistu

Tere. See tähendab, et võrgustikus on 5 8 klienti. Hiljuti tuli ette mitte eriti meeldiv hetk - võrgu keskel on meil Brocade RXXNUMX ja see hakkas saatma palju tundmatuid unicast pakette, kuna võrk on jagatud vlanideks - see pole osaliselt probleem, AGA on spetsiaalsed vlanid valgete aadresside jaoks jne. ja need on võrgu kõigis suundades venitatud. Nii et kujutage nüüd ette saabuvat voogu kliendi aadressile, kes ei õpi piiriüliõpilasena ja see voog lendab raadiolingi poole mõnesse (või kogu) külasse - kanal on ummistunud - kliendid on vihased - kurbus...

Eesmärk on muuta viga funktsiooniks. Ma mõtlesin q-in-q suunas täisväärtusliku kliendi vlaniga, aga igasugune riistvara nagu P3310, kui dot1q on lubatud, ei lase enam DHCP-d läbi, ei oska ka selektiivset qinq-d ja paljud sedalaadi lõkse. Mis on nimeta ip ja kuidas see töötab? Väga lühidalt: lüüsi aadress + marsruut liidesel. Oma ülesande täitmiseks peame: lõikama kujundajat, levitama klientidele aadresse, lisama klientidele marsruute teatud liideste kaudu. Kuidas seda kõike teha? Shaper - lisg, dhcp - db2dhcp kahel sõltumatul serveril, dhcprelay jookseb juurdepääsuserverites, ucarp jookseb ka juurdepääsuserverites - varundamiseks. Kuidas aga marsruute lisada? Suure skriptiga saab kõike ette lisada – aga see pole tõsi. Seega teeme isekirjutatud kargu.

Pärast põhjalikku internetiotsingut leidsin C++ jaoks imelise kõrgetasemelise raamatukogu, mis võimaldab ilusti liiklust nuusutada. Marsruute lisava programmi algoritm on järgmine - kuulame liideses arp päringuid, kui meil on serveris lo liideses aadress, mida küsitakse, siis lisame marsruudi läbi selle liidese ja lisame staatilise arp salvesta sellele ip-le – üldiselt paar copy-paste’i, väike omadussõna ja ongi valmis

"ruuteri" allikad

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

libtinsi installiskript

#!/bin/bash

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

Käsk kahendfaili ehitamiseks

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

Kuidas seda käivitada?


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

Jah – see ehitab tabelid ümber HUP signaali põhjal. Miks sa netlinki ei kasutanud? See on lihtsalt laiskus ja Linux on skript skripti peal – nii et kõik on korras. Noh, marsruudid on marsruudid, mis saab edasi? Järgmiseks peame saatma siin serveris olevad marsruudid piirile - siin läksime sama vananenud riistvara tõttu vähima vastupanu teed - määrasime selle ülesande BGP-le.

bgp konfiguratsioonhostinimi *******
parool *****
logifail /var/log/bgp.log
!
# AS-i number, aadressid ja võrgud on fiktiivsed
ruuter bgp 12345
bgp ruuteri ID 1.2.3.4
ümber jagada ühendatud
staatiline ümber jaotada
naaber 1.2.3.1 kaug-as 12345
naaber 1.2.3.1 next-hop-ise
naaber 1.2.3.1 marsruudikaart puudub
naaber 1.2.3.1 marsruudikaardi eksport välja
!
juurdepääsuloendi ekspordiluba 1.2.3.0/24
!
marsruudikaardi ekspordiluba 10
sobitada IP-aadressi eksport
!
marsruudikaardi ekspordi keelamine 20

Jätkame. Selleks, et server vastaks arp-päringutele, peate lubama arp-puhverserveri.


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

Liigume edasi – ucarp. Selle ime käivitamise skriptid kirjutame ise.

Näide ühe deemoni käitamisest


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"

üles.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

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

Et dhcprelay liidesel töötaks, vajab see aadressi. Seetõttu lisame kasutatavatele liidestele vasakpoolsed aadressid - näiteks 10.255.255.1/32, 10.255.255.2/32 jne. Ma ei ütle teile, kuidas releed konfigureerida - kõik on lihtne.

Mis meil siis on? Lüüside varundamine, marsruutide automaatne konfigureerimine, dhcp. See on minimaalne komplekt - lisg mähib ka kõik enda ümber ja vormija on meil juba olemas. Miks on kõik nii pikk ja keeruline? Kas pole lihtsam võtta accel-pppd ja kasutada üldse pppoe-d? Ei, see pole lihtsam – inimesed vaevalt mahutavad ruuterisse patchcordi, rääkimata pppoest. accel-ppp on lahe asi - aga see ei toiminud meil - koodis on palju vigu - mureneb, lõikab kõveraks ja kõige kurvem on see, et kui see läks heledamaks - siis inimesed peavad uuesti laadima kõik - telefonid on punased - see ei töötanud üldse. Mis on ukarpi kasutamise eelised elushoidmise asemel? Jah, kõiges - seal on 100 lüüsi, Keepalived ja üks viga konfiguratsioonis - kõik ei tööta. 1 värav ei tööta ucarpiga. Turvalisuse kohta ütlevad nad, et vasakpoolsed registreerivad enda jaoks aadressid ja kasutavad neid jagamisel - selle hetke kontrollimiseks panime kõikidele switchidele/oltidele/baasidele dhcp-snooping + source-guard + arp kontroll. Kui kliendil pole dhpc-d, vaid staatiline - pordis acces-list.

Miks seda kõike tehti? Soovimatu liikluse hävitamiseks. Nüüd on igal kommutaatoril oma vlan ja tundmatu-unicast pole enam hirmutav, kuna see peab minema ainult ühte porti ja mitte kõigisse... Noh, kõrvalmõjudeks on standardiseeritud seadmete konfiguratsioon, suurem efektiivsus aadressiruumi eraldamisel.

Kuidas lisg-i konfigureerida, on eraldi teema. Raamatukogude lingid on lisatud. Võib-olla aitab ülaltoodu kellelgi oma eesmärke saavutada. Versiooni 6 meie võrgus veel ei juuruta - aga tekib probleem - plaanis on lisg versiooni 6 jaoks ümber kirjutada ja vaja on parandada marsruute lisavat programmi.

Linux ISG
DB2DHCP
Libtiinid

Allikas: www.habr.com

Lisa kommentaar