Réseau IPeE tolérant aux pannes utilisant des outils improvisés

Bonjour. Cela signifie qu'il existe un réseau de 5 8 clients. Récemment, un moment pas très agréable est arrivé - au centre du réseau, nous avons un Brocade RXXNUMX et il a commencé à envoyer beaucoup de paquets monodiffusion inconnus, puisque le réseau est divisé en VLAN - ce n'est en partie pas un problème, MAIS il y en a vlans spéciaux pour les adresses blanches, etc. et ils sont étendus dans toutes les directions du réseau. Alors imaginez maintenant un flux entrant à l'adresse d'un client qui n'étudie pas en tant qu'étudiant frontalier et ce flux se dirige vers une liaison radio vers un (ou tous) village - le canal est bouché - les clients sont en colère - tristesse...

Le but est de transformer un bug en fonctionnalité. Je pensais à q-in-q avec un vlan client à part entière, mais toutes sortes de matériels comme P3310, lorsque dot1q est activé, arrêtent de laisser passer DHCP, ils ne savent pas non plus comment sélectionner qinq et bien d'autres. des pièges de ce genre. Qu'est-ce qu'IP-Unnamed et comment ça marche ? Très brièvement : adresse de la passerelle + itinéraire sur l'interface. Pour notre tâche, nous devons : couper le shaper, distribuer des adresses aux clients, ajouter des routes aux clients via certaines interfaces. Comment faire tout cela ? Shaper - lisg, dhcp - db2dhcp sur deux serveurs indépendants, dhcprelay s'exécute sur les serveurs d'accès, ucarp s'exécute également sur les serveurs d'accès - pour la sauvegarde. Mais comment ajouter des itinéraires ? Vous pouvez tout ajouter à l'avance avec un gros script - mais ce n'est pas vrai. Nous allons donc fabriquer une béquille auto-écrite.

Après une recherche approfondie sur Internet, j'ai trouvé une merveilleuse bibliothèque de haut niveau pour C++, qui vous permet de détecter magnifiquement le trafic. L'algorithme du programme qui ajoute des routes est le suivant - nous écoutons les requêtes arp sur l'interface, si nous avons une adresse sur l'interface lo sur le serveur qui est demandée, alors nous ajoutons une route via cette interface et ajoutons un arp statique enregistrez sur cette ip - en général, quelques copier-coller, un petit adjectif et le tour est joué

Sources du « routeur »

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

script d'installation de libtins

#!/bin/bash

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

Commande pour construire le binaire

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

Comment le lancer ?


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

Oui, il reconstruira les tables en fonction du signal HUP. Pourquoi n'as-tu pas utilisé NetLink ? C'est juste de la paresse et Linux est un script sur un script - donc tout va bien. Eh bien, les itinéraires sont des itinéraires, quelle est la prochaine étape ? Ensuite, nous devons envoyer les routes qui se trouvent sur ce serveur à la frontière - ici, en raison du même matériel obsolète, nous avons emprunté le chemin de la moindre résistance - nous avons confié cette tâche à BGP.

configuration BGPnom d'hôte *******
mot de passe *******
fichier journal /var/log/bgp.log
!
# Le numéro AS, les adresses et les réseaux sont fictifs
routeur bgp 12345
ID de routeur BGP 1.2.3.4
redistribuer connecté
redistribuer statique
voisin 1.2.3.1 distant-comme 12345
voisin 1.2.3.1 prochain saut-auto
voisin 1.2.3.1 route-map aucun dans
voisin 1.2.3.1 exportation de la feuille de route
!
permis d'exportation liste d'accès 1.2.3.0/24
!
permis d'exportation sur carte routière 10
correspondre à l'exportation de l'adresse IP
!
exportation de la feuille de route refuser 20

Nous allons continuer. Pour que le serveur réponde aux requêtes arp, vous devez activer le proxy arp.


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

Passons à autre chose - ucarp. Nous écrivons nous-mêmes les scripts de lancement de ce miracle.

Exemple d'exécution d'un démon


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

vers le bas.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

Pour que dhcprelay fonctionne sur une interface, il lui faut une adresse. Par conséquent, sur les interfaces que nous utilisons, nous ajouterons des adresses de gauche - par exemple 10.255.255.1/32, 10.255.255.2/32, etc. Je ne vous dirai pas comment configurer le relais - tout est simple.

Alors qu'est-ce que nous avons? Sauvegarde des passerelles, auto-configuration des routes, DHCP. C'est l'ensemble minimum - lisg enroule également tout autour et nous avons déjà un shaper. Pourquoi tout est si long et compliqué ? N'est-il pas plus facile de prendre accel-pppd et d'utiliser complètement pppoe ? Non, ce n'est pas plus simple : les gens peuvent difficilement insérer un cordon de brassage dans un routeur, sans parler du pppoe. accel-ppp est une chose sympa - mais cela n'a pas fonctionné pour nous - il y a beaucoup d'erreurs dans le code - il s'effondre, il coupe de travers, et le plus triste est que s'il s'éclaire - alors les gens doivent recharger tout - les téléphones sont rouges - ça n'a pas fonctionné du tout. Quel est l'avantage d'utiliser ucarp plutôt que keepalived ? Oui, dans tout - il y a 100 passerelles, keepalived et une erreur dans la configuration - tout ne fonctionne pas. 1 passerelle ne fonctionne pas avec ucarp. Concernant la sécurité, ils disent que ceux de gauche enregistreront des adresses pour eux-mêmes et les utiliseront sur le partage - pour contrôler ce moment, nous avons mis en place DHCP-snooping + source-guard + arp inspection sur tous les commutateurs/olts/bases. Si le client n'a pas DHCP mais statique - liste d'accès sur le port.

Pourquoi tout cela a-t-il été fait ? Pour détruire le trafic indésirable. Désormais, chaque commutateur a son propre VLAN et la monodiffusion inconnue ne fait plus peur, puisqu'elle n'a besoin d'être transmise qu'à un seul port et pas à tous... Eh bien, les effets secondaires sont une configuration d'équipement standardisée, une plus grande efficacité dans l'allocation de l'espace d'adressage.

Comment configurer lisg est un sujet distinct. Les liens vers les bibliothèques sont joints. Peut-être que ce qui précède aidera quelqu'un à atteindre ses objectifs. La version 6 n'est pas encore implémentée sur notre réseau - mais il y aura un problème - il est prévu de réécrire lisg pour la version 6, et il faudra corriger le programme qui ajoute des routes.

GSI Linux
DB2DHCP
Libtins

Source: habr.com

Ajouter un commentaire