Rrjeti IPeE tolerant ndaj gabimeve duke përdorur mjete të improvizuara

Përshëndetje. Kjo do të thotë se ekziston një rrjet prej 5 mijë klientësh. Kohët e fundit doli një moment jo shumë i këndshëm - në qendër të rrjetit kemi një Brocade RX8 dhe ai filloi të dërgojë shumë paketa të panjohura-unicast, pasi rrjeti është i ndarë në vlan - kjo pjesërisht nuk është problem, POR ka vlanet speciale per adresat e bardha etj. dhe ato shtrihen në të gjitha drejtimet e rrjetit. Pra, tani imagjinoni një fluks hyrës në adresën e një klienti që nuk studion si student kufitar dhe ky fluks fluturon drejt një lidhjeje radio në ndonjë (ose të gjithë) fshat - kanali është i bllokuar - klientët janë të zemëruar - trishtim...

Qëllimi është të ktheni një gabim në një veçori. Po mendoja në drejtimin e q-in-q me një klient vlan të plotë, por të gjitha llojet e pajisjeve si P3310, kur aktivizohet dot1q, ndalon së kaluari DHCP, ata gjithashtu nuk dinë të bëjnë qinq selektiv dhe shumë gracka të atë lloj. Çfarë është ip-pa emërtim dhe si funksionon? Shumë shkurt: adresa e portës + rruga në ndërfaqe. Për detyrën tonë, ne duhet: të presim formësuesin, të shpërndajmë adresat tek klientët, të shtojmë rrugë tek klientët përmes ndërfaqeve të caktuara. Si të bëhet e gjithë kjo? Shaper - lisg, dhcp - db2dhcp në dy serverë të pavarur, dhcprelay funksionon në serverët e aksesit, ucarp gjithashtu funksionon në serverët e aksesit - për kopje rezervë. Por si të shtohen rrugët? Ju mund të shtoni gjithçka paraprakisht me një skenar të madh - por kjo nuk është e vërtetë. Pra, ne do të bëjmë një patericë të shkruar vetë.

Pas një kërkimi të plotë në internet, gjeta një bibliotekë të mrekullueshme të nivelit të lartë për C++, e cila ju lejon të nuhasni bukur trafikun. Algoritmi për programin që shton rrugët është si më poshtë - ne dëgjojmë kërkesat arp në ndërfaqe, nëse kemi një adresë në ndërfaqen lo në server që kërkohet, atëherë shtojmë një rrugë përmes kësaj ndërfaqe dhe shtojmë një arp statik regjistroni në këtë ip - në përgjithësi, disa copy-paste, pak mbiemër dhe keni mbaruar

Burimet e 'ruterit'

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

Skripti i instalimit të libtins

#!/bin/bash

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

Komanda për të ndërtuar binarin

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

Si ta nisni atë?


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

Po - do të rindërtojë tabelat bazuar në sinjalin HUP. Pse nuk keni përdorur netlink? Është thjesht dembelizëm dhe Linux është një skrip në një skenar - kështu që gjithçka është në rregull. Epo, rrugët janë rrugë, çfarë ka më pas? Tjetra, ne duhet të dërgojmë rrugët që janë në këtë server në kufi - këtu, për shkak të të njëjtit harduer të vjetëruar, morëm rrugën e rezistencës më të vogël - ia caktuam këtë detyrë BGP.

konfigurimi bgpemri i hostit *******
fjalëkalimi *******
skedari i regjistrit /var/log/bgp.log
!
Numri # AS, adresat dhe rrjetet janë fiktive
ruteri bgp 12345
bgp router-id 1.2.3.4
rishpërndajnë lidhur
rishpërndajnë statike
fqinji 1.2.3.1 në distancë - si 12345
fqinji 1.2.3.1 hop tjetër
fqinji 1.2.3.1 harta e rrugës asnjë në
fqinji 1.2.3.1 eksporti i hartës së rrugës
!
leje eksporti me listë aksesi 1.2.3.0/24
!
Leje eksporti me hartën e rrugës 10
përputhet me eksportin e adresës ip
!
mohimi i eksportit të hartës së rrugës 20

Le te vazhdojme. Në mënyrë që serveri t'i përgjigjet kërkesave arp, duhet të aktivizoni përfaqësuesin arp.


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

Le të vazhdojmë - ucarp. Ne i shkruajmë vetë skriptet e nisjes për këtë mrekulli.

Shembull i drejtimit të një demon


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"

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

poshtë.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

Që dhcprelay të funksionojë në një ndërfaqe, i duhet një adresë. Prandaj, në ndërfaqet që përdorim ne do të shtojmë adresat e majta - për shembull 10.255.255.1/32, 10.255.255.2/32, etj. Unë nuk do t'ju tregoj se si ta konfiguroni stafetën - gjithçka është e thjeshtë.

Pra, çfarë kemi ne? Rezervimi i portave, konfigurimi automatik i rrugëve, dhcp. Ky është grupi minimal - lisg gjithashtu mbështjell gjithçka rreth tij dhe ne tashmë kemi një formësues. Pse është gjithçka kaq e gjatë dhe e ndërlikuar? A nuk është më e lehtë të marrësh accel-pppd dhe të përdorësh krejtësisht pppoe? Jo, nuk është më e thjeshtë - njerëzit vështirë se mund të vendosin një patchcord në një ruter, për të mos përmendur pppoe. accel-ppp është një gjë e lezetshme - por nuk funksionoi për ne - ka shumë gabime në kod - ai shkërmoqet, prishet shtrembër, dhe gjëja më e trishtueshme është se nëse ndriçohet - atëherë njerëzit duhet të ringarkojnë gjithçka - telefonat janë të kuq - nuk funksionoi fare. Cili është avantazhi i përdorimit të ucarp-it në vend që të ruhet? Po, në çdo gjë - ka 100 porta, të ruajtura dhe një gabim në konfigurim - gjithçka nuk funksionon. 1 portë nuk funksionon me ucarp. Për sa i përket sigurisë, thonë se të majtët do të regjistrojnë adresat për vete dhe do t'i përdorin ato në share - për të kontrolluar këtë moment, kemi vendosur dhcp-snooping + source-guard + arp inspection në të gjithë çelësat/olt/bazat. Nëse klienti nuk ka dhpc por statike - lista e aksesit në port.

Pse u bë e gjithë kjo? Për të shkatërruar trafikun e padëshiruar. Tani çdo switch ka vlan-in e vet dhe i panjohur-unicast nuk është më i frikshëm, pasi duhet të shkojë vetëm në një port dhe jo në të gjithë... Epo, efektet anësore janë një konfigurim i standardizuar i pajisjes, efikasitet më i madh në ndarjen e hapësirës së adresave.

Si të konfiguroni lisg është një temë më vete. Lidhjet me bibliotekat janë bashkangjitur. Ndoshta sa më sipër do të ndihmojë dikë në arritjen e qëllimeve të tij. Versioni 6 nuk po zbatohet ende në rrjetin tonë - por do të ketë një problem - ka plane për të rishkruar lisg për versionin 6, dhe do të jetë e nevojshme të korrigjohet programi që shton rrugët.

Linux ISG
DB2DHCP
Libtins

Burimi: www.habr.com

Shto një koment