Kļūmju izturīgs IPeE tīkls, izmantojot improvizētus rīkus

Sveiki. Tas nozÄ«mē, ka pastāv 5 8 klientu tÄ«kls. Nesen pienāca ne pārāk patÄ«kams brÄ«dis - tÄ«kla centrā mums ir Brocade RXXNUMX un tas sāka sÅ«tÄ«t daudz nezināmu-unicast pakeÅ”u, jo tÄ«kls ir sadalÄ«ts vlanos - tā daļēji nav problēma, BET ir speciālie vlani baltajām adresēm utt. un tie ir izstiepti visos tÄ«kla virzienos. Tātad tagad iedomājieties ienākoÅ”o plÅ«smu uz klienta adresi, kurÅ” nemācās kā pierobežas students un Ŕī plÅ«sma lido uz radiosaiti uz kādu (vai visu) ciematu - kanāls ir aizsērējis - klienti ir dusmÄ«gi - skumjas...

MērÄ·is ir pārvērst kļūdu par lÄ«dzekli. Es domāju q-in-q virzienā ar pilnvērtÄ«gu klienta vlan, bet visāda aparatÅ«ra kā P3310, kad dot1q ir iespējots, beidz laist DHCP cauri, viņi arÄ« nemāk selektÄ«vo qinq un daudzi Ŕāda veida slazdiem. Kas ir ip unnambered un kā tas darbojas? Ä»oti Ä«si: vārtejas adrese + marÅ”ruts saskarnē. MÅ«su uzdevumam ir nepiecieÅ”ams: izgriezt veidotāju, izplatÄ«t adreses klientiem, pievienot klientiem marÅ”rutus, izmantojot noteiktas saskarnes. Kā to visu izdarÄ«t? Shaper - lisg, dhcp - db2dhcp uz diviem neatkarÄ«giem serveriem, piekļuves serveros darbojas dhcprelay, piekļuves serveros darbojas arÄ« ucarp - dublÄ“Å”anai. Bet kā pievienot marÅ”rutus? JÅ«s varat pievienot visu iepriekÅ”, izmantojot lielu skriptu, taču tā nav taisnÄ«ba. Tātad mēs taisÄ«sim paÅ”rakstÄ«tu kruÄ·i.

Pēc pamatÄ«gas meklÄ“Å”anas internetā atradu brÄ«niŔķīgu augsta lÄ«meņa bibliotēku priekÅ” C++, kas ļauj smuki izŔņaukt trafiku. Programmas, kas pievieno marÅ”rutus, algoritms ir Ŕāds - mēs klausāmies arp pieprasÄ«jumus interfeisā, ja mums ir adrese uz lo interfeisa serverÄ«, kas tiek pieprasÄ«ta, tad mēs pievienojam marÅ”rutu caur Å”o saskarni un pievienojam statisku arp ieraksti uz Å”o ip - vispār pāris copy-paste, nedaudz Ä«paŔības vārda un darÄ«ts

'marÅ”rutētāja' avoti

#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 instalācijas skripts

#!/bin/bash

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

Komanda izveidot bināro

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

Kā to palaist?


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

Jā - tas pārbÅ«vēs tabulas, pamatojoties uz HUP signālu. Kāpēc neizmantoji netlink? Tas ir tikai slinkums un Linux ir skripts uz skripta ā€“ tātad viss kārtÄ«bā. Nu, marÅ”ruti ir marÅ”ruti, kas tālāk? Tālāk mums ir jānosÅ«ta marÅ”ruti, kas atrodas Å”ajā serverÄ«, uz robežu - Å”eit tās paÅ”as novecojuŔās aparatÅ«ras dēļ mēs izvēlējāmies mazākās pretestÄ«bas ceļu - mēs uzdevām Å”o uzdevumu BGP.

bgp konfigurācijaresursdatora nosaukums *******
parole *****
žurnāla fails /var/log/bgp.log
!
# AS numurs, adreses un tīkli ir fiktīvi
marÅ”rutētājs bgp 12345
bgp router-id 1.2.3.4
pārdalīt savienots
pārdalīt statisko
kaimiņŔ 1.2.3.1 tālvadÄ«bas pults ā€” kā 12345
kaimiņŔ 1.2.3.1 next-hop-self
kaimiņŔ 1.2.3.1 marÅ”ruta karte nav iekŔā
kaimiņŔ 1.2.3.1 marÅ”ruta kartes eksports ārā
!
piekļuves saraksta izveŔanas atļauja 1.2.3.0/24
!
marŔruta kartes izveŔanas atļauja 10
atbilst IP adreses eksportam
!
marŔruta kartes eksporta aizliegums 20

Turpināsim. Lai serveris atbildētu uz ARP pieprasījumiem, ir jāiespējo arp starpniekserveris.


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

Ejam tālāk - ucarp. Mēs paÅ”i rakstām Ŕī brÄ«numa palaiÅ”anas skriptus.

Viena dēmona palaiÅ”anas piemērs


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

uz leju.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

Lai dhcprelay darbotos saskarnē, tai ir nepiecieÅ”ama adrese. Tāpēc mÅ«su izmantotajās saskarnēs mēs pievienosim kreisās adreses - piemēram, 10.255.255.1/32, 10.255.255.2/32 utt. Es jums neteikÅ”u, kā konfigurēt releju - viss ir vienkārÅ”i.

Kas tad mums ir? Vārteju dublÄ“Å”ana, marÅ”rutu automātiska konfigurÄ“Å”ana, dhcp. Tas ir minimālais komplekts - lisg arÄ« apvij visu un mums jau ir veidotājs. Kāpēc viss ir tik garÅ” un mulsinoÅ”i? Vai nav vieglāk paņemt accel-pppd un lietot pppoe vispār? Nē, tas nav vienkārŔāk ā€” cilvēki diez vai var ievietot ielāpu vadu marÅ”rutētājā, nemaz nerunājot par pppoe. accel-ppp ir forÅ”a lieta - bet mums nederēja - daudz kļūdu kodā - drÅ«p, Ŕķībi griež, un pats skumjākais ir tas, ka ja uzgaismoja - tad cilvēkiem vajag pārlādēt viss - telefoni ir sarkani - tas vispār nedarbojās. Kāda ir ucarp izmantoÅ”anas priekÅ”rocÄ«ba, nevis saglabāŔana? Jā, visā - ir 100 vārtejas, Keepalived un viena kļūda konfigurācijā - viss nedarbojas. 1 vārteja nedarbojas ar ucarp. Par droŔību saka, ka kreisie reÄ£istrēs sev adreses un izmantos uz share - lai kontrolētu Å”o momentu, uzstādÄ«jām dhcp-snooping + source-guard + arp pārbaude uz visiem slēdžiem/oltiem/bāzēm. Ja klientam nav dhpc, bet statisks - piekļuves saraksts portā.

Kāpēc tas viss tika darÄ«ts? Lai iznÄ«cinātu nevēlamu satiksmi. Tagad katram slēdzim ir savs vlan un nezināmais-unicast vairs nav biedējoÅ”i, jo jāiet tikai uz vienu portu, nevis uz visiem... Nu, blakusefekti ir standartizēta aprÄ«kojuma konfigurācija, lielāka efektivitāte adreÅ”u telpas pieŔķirÅ”anā.

Kā konfigurēt lisg ir atseviŔķa tēma. Saites uz bibliotēkām ir pievienotas. Iespējams, iepriekÅ”minētais kādam palÄ«dzēs sasniegt savus mērÄ·us. 6. versija vēl netiek ieviesta mÅ«su tÄ«klā - taču bÅ«s problēma - ir plānots pārrakstÄ«t lisg 6. versijai, un bÅ«s jālabo programma, kas pievieno marÅ”rutus.

Linux ISG
DB2DHCP
LibtiņŔ

Avots: www.habr.com

Pievieno komentāru