Импровизацияланған құралдарды пайдаланатын ақауларға төзімді IPeE желісі

Сәлеметсіз бе. Бұл 5 мың клиенттік желі бар дегенді білдіреді. Жақында өте жағымды емес сәт болды - желінің ортасында бізде Brocade RX8 бар және ол көптеген белгісіз-уникаст пакеттерін жібере бастады, өйткені желі вландарға бөлінген - бұл ішінара проблема емес, БІРАҚ бар. ақ мекенжайларға арналған арнайы вландар және т.б. және олар желінің барлық бағыттарына созылған. Енді шекаралық студент ретінде оқымайтын клиенттің мекенжайына келетін ағынды елестетіп көріңіз және бұл ағын кейбір (немесе барлық) ауылға радиобайланысқа қарай ұшады - арна бітеліп қалды - клиенттер ашулы - қайғы...

Мақсат - қатені мүмкіндікке айналдыру. Мен толыққанды клиенттік vlan-мен q-in-q бағытын ойладым, бірақ P3310 сияқты аппараттық құралдардың барлық түрлері, dot1q қосылған кезде, DHCP-ге рұқсат беруді тоқтатады, олар сонымен қатар qinq және көптеген таңдауды білмейді. осындай тұзақтар. IP-аталмаған деген не және ол қалай жұмыс істейді? Өте қысқаша: шлюз мекенжайы + интерфейстегі маршрут. Біздің тапсырмамыз үшін бізге қажет: пішіндегішті кесу, клиенттерге мекенжайларды тарату, белгілі бір интерфейстер арқылы клиенттерге маршруттарды қосу. Мұның бәрін қалай жасауға болады? Shaper - lisg, dhcp - db2dhcp екі тәуелсіз серверде, dhcprelay кіру серверлерінде жұмыс істейді, ucarp сонымен қатар кіру серверлерінде жұмыс істейді - сақтық көшірме жасау үшін. Бірақ маршруттарды қалай қосуға болады? Барлығын үлкен сценариймен алдын ала қосуға болады - бірақ бұл дұрыс емес. Ендеше біз өзіміз жазған балдақ жасаймыз.

Интернетте мұқият іздегеннен кейін мен C++ үшін трафикті әдемі иіскеуге мүмкіндік беретін тамаша жоғары деңгейлі кітапхананы таптым. Маршруттарды қосатын бағдарламаның алгоритмі келесідей - интерфейсте arp сұрауларын тыңдаймыз, егер сұралатын серверде lo интерфейсінде адресіміз болса, онда осы интерфейс арқылы маршрут қосамыз және статикалық arp қосамыз. осы IP-ге жазыңыз - жалпы, бірнеше көшіру-паста, кішкене сын есім және сіз аяқтадыңыз

Маршрутизатордың көздері

#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 орнату сценарийі

#!/bin/bash

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

Екілік жүйені құру командасы

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

Оны қалай іске қосу керек?


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

Иә - ол HUP сигналы негізінде кестелерді қайта құрады. Неліктен netlink қолданбадыңыз? Бұл жай ғана жалқаулық және Linux - сценарийдегі сценарий - сондықтан бәрі жақсы. Ал, маршруттар - бұл маршруттар, енді не болады? Әрі қарай, біз осы серверде орналасқан маршруттарды шекараға жіберуіміз керек - мұнда бірдей ескірген жабдыққа байланысты біз ең аз қарсылық жолын таңдадық - біз бұл тапсырманы BGP-ге тағайындадық.

bgp конфигурациясыхост аты *******
пароль *******
журнал файлы /var/log/bgp.log
!
# AS нөмірі, мекенжайлары және желілері жалған
маршрутизатор bgp 12345
bgp маршрутизатор идентификаторы 1.2.3.4
қосылған қайта бөлу
статикалықты қайта бөлу
көрші 1.2.3.1 қашықтағы-12345 сияқты
көрші 1.2.3.1 next-hop-self
көрші 1.2.3.1 маршрут-карта жоқ
көрші 1.2.3.1 маршрут-картаны экспорттау
!
рұқсат тізімін экспорттау рұқсаты 1.2.3.0/24
!
маршруттық карта экспортына рұқсат 10
IP мекенжайын экспорттау
!
маршрут картасын экспорттаудан бас тарту 20

жалғастырайық. Сервер arp сұрауларына жауап беруі үшін arp проксиін қосу керек.


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

Әрі қарай жүрейік - ucarp. Біз бұл ғажайыптың іске қосылу сценарийлерін өзіміз жазамыз.

Бір демонды іске қосу мысалы


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

төмен.ш


#!/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

dhcprelay интерфейсте жұмыс істеуі үшін оған мекенжай қажет. Сондықтан біз қолданатын интерфейстерге сол жақ мекенжайларды қосамыз - мысалы 10.255.255.1/32, 10.255.255.2/32 және т.б. Мен сізге релені қалай конфигурациялау керектігін айтпаймын - бәрі қарапайым.

Сонымен, бізде не бар? Шлюздердің сақтық көшірмесі, маршруттардың автоконфигурациясы, dhcp. Бұл ең аз жиынтық – lisg де оның айналасына барлығын орап алады және бізде пішіндеу құралы бар. Неліктен бәрі ұзақ және күрделі? Accel-pppd алып, pppoe-ді толығымен пайдалану оңай емес пе? Жоқ, бұл оңай емес - адамдар pppoe туралы айтпағанда, маршрутизаторға патчкордты әрең сыйғызады. accel-ppp керемет нәрсе - бірақ ол біз үшін жұмыс істемеді - кодта көптеген қателер бар - ол ыдырап, қисық кесіп тастайды, ең өкініштісі, егер ол жарқырап кетсе - адамдар қайта жүктеуі керек. бәрі - телефондар қызыл - бұл мүлдем жұмыс істемеді. Keepalived емес, ucarp пайдаланудың артықшылығы неде? Иә, барлығында - 100 шлюз бар, сақталған және конфигурацияда бір қате - бәрі жұмыс істемейді. 1 шлюз ucarp-пен жұмыс істемейді. Қауіпсіздікке келетін болсақ, олар сол жақтағылар мекенжайларды өздері тіркеп, оларды бөлісуде пайдаланады деп айтады - осы сәтті басқару үшін біз барлық қосқыштар/олттар/негіздерде dhcp-snooping + source-guard + arp инспекциясын орнаттық. Егер клиентте dhpc болмаса, бірақ портта статикалық - acces-list.

Мұның бәрі не үшін жасалды? Қажетсіз трафикті жою үшін. Енді әр коммутатордың өз vlan-ы бар және белгісіз-уникаст бұдан былай қорқынышты емес, өйткені ол тек бір портқа өту керек және барлығына емес... Ал, жанама әсерлері стандартталған жабдық конфигурациясы, мекенжай кеңістігін бөлудің жоғары тиімділігі болып табылады.

Лисгті қалай конфигурациялау керек - бұл бөлек тақырып. Кітапханаларға сілтемелер қоса беріледі. Мүмкін жоғарыда айтылғандар біреуге өз мақсаттарына жетуге көмектеседі. Біздің желіде 6-нұсқа әлі енгізілмейді - бірақ мәселе туындайды - 6-нұсқа үшін lisg қайта жазу жоспарлары бар және маршруттарды қосатын бағдарламаны түзету қажет болады.

Linux ISG
DB2DHCP
Либтиндер

Ақпарат көзі: www.habr.com

пікір қалдыру