Rangkaian IPeE tahan kerosakan menggunakan alat yang diubahsuai

Hello. Ini bermakna terdapat rangkaian 5k pelanggan. Baru-baru ini detik yang tidak begitu menyenangkan muncul - di tengah-tengah rangkaian kami mempunyai Brocade RX8 dan ia mula menghantar banyak paket unicast yang tidak diketahui, kerana rangkaian dibahagikan kepada vlan - ini sebahagiannya tidak menjadi masalah, TETAPI terdapat vlan khas untuk alamat putih, dsb. dan mereka diregangkan ke semua arah rangkaian. Jadi sekarang bayangkan aliran masuk ke alamat pelanggan yang tidak belajar sebagai pelajar sempadan dan aliran ini terbang ke arah pautan radio ke beberapa (atau semua) kampung - saluran tersumbat - pelanggan marah - kesedihan...

Matlamatnya adalah untuk mengubah pepijat menjadi ciri. Saya berfikir ke arah q-in-q dengan vlan pelanggan sepenuhnya, tetapi semua jenis perkakasan seperti P3310, apabila dot1q didayakan, berhenti membiarkan DHCP melalui, mereka juga tidak tahu cara memilih qinq dan banyak lagi. perangkap seperti itu. Apakah ip-unnambered dan bagaimana ia berfungsi? Secara ringkas: alamat pintu masuk + laluan pada antara muka. Untuk tugas kami, kami perlu: memotong pembentuk, mengedarkan alamat kepada pelanggan, menambah laluan kepada pelanggan melalui antara muka tertentu. Bagaimana untuk melakukan semua ini? Shaper - lisg, dhcp - db2dhcp pada dua pelayan bebas, dhcprelay berjalan pada pelayan akses, ucarp juga berjalan pada pelayan akses - untuk sandaran. Tetapi bagaimana untuk menambah laluan? Anda boleh menambah segala-galanya terlebih dahulu dengan skrip yang besar - tetapi ini tidak benar. Jadi kami akan membuat tongkat yang ditulis sendiri.

Selepas carian menyeluruh di Internet, saya menjumpai perpustakaan peringkat tinggi yang menarik untuk C++, yang membolehkan anda menghidu trafik dengan indah. Algoritma untuk program yang menambah laluan adalah seperti berikut - kami mendengar permintaan arp pada antara muka, jika kami mempunyai alamat pada antara muka lo pada pelayan yang diminta, maka kami menambah laluan melalui antara muka ini dan menambah arp statik rekod ke ip ini - secara umum, beberapa copy-paste, sedikit kata sifat dan anda sudah selesai

Sumber 'router'

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

skrip pemasangan libtins

#!/bin/bash

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

Perintah untuk membina binari

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

Bagaimana untuk melancarkannya?


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

Ya - ia akan membina semula jadual berdasarkan isyarat HUP. Mengapa anda tidak menggunakan netlink? Ia hanya kemalasan dan Linux ialah skrip pada skrip - jadi semuanya baik-baik saja. Nah, laluan adalah laluan, apa yang seterusnya? Seterusnya, kami perlu menghantar laluan yang ada pada pelayan ini ke sempadan - di sini, disebabkan perkakasan lapuk yang sama, kami mengambil laluan rintangan yang paling sedikit - kami menugaskan tugas ini kepada BGP.

konfigurasi bgpnama hos *******
kata laluan *******
fail log /var/log/bgp.log
!
# Nombor AS, alamat dan rangkaian adalah rekaan
penghala bgp 12345
bgp router-id 1.2.3.4
mengagihkan semula bersambung
mengagihkan semula statik
jiran 1.2.3.1 jauh-sebagai 12345
jiran 1.2.3.1 seterusnya-hop-diri
jiran 1.2.3.1 peta laluan tiada masuk
jiran 1.2.3.1 eksport keluar peta laluan
!
permit eksport senarai akses 1.2.3.0/24
!
permit eksport peta laluan 10
padankan eksport alamat ip
!
eksport peta laluan menafikan 20

Jom sambung. Untuk membolehkan pelayan membalas permintaan arp, anda mesti mendayakan proksi arp.


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

Mari kita teruskan - ucarp. Kami sendiri menulis skrip pelancaran untuk keajaiban ini.

Contoh menjalankan satu daemon


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"

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

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

Untuk dhcprelay berfungsi pada antara muka, ia memerlukan alamat. Oleh itu, pada antara muka yang kami gunakan kami akan menambah alamat kiri - contohnya 10.255.255.1/32, 10.255.255.2/32, dsb. Saya tidak akan memberitahu anda cara mengkonfigurasi geganti - semuanya mudah.

Jadi apa yang kita ada? Sandaran get laluan, konfigurasi automatik laluan, dhcp. Ini adalah set minimum - lisg juga membungkus segala-galanya di sekelilingnya dan kami sudah mempunyai pembentuk. Kenapa semuanya panjang dan rumit? Bukankah lebih mudah untuk mengambil accel-pppd dan menggunakan pppoe sama sekali? Tidak, ia tidak lebih mudah - orang tidak boleh memasukkan patchcord ke dalam penghala, apatah lagi pppoe. accel-ppp adalah perkara yang menarik - tetapi ia tidak berfungsi untuk kami - terdapat banyak ralat dalam kod - ia runtuh, ia memotong bengkok, dan perkara yang paling menyedihkan ialah jika ia menjadi cerah - maka orang ramai perlu memuat semula semuanya - telefon berwarna merah - ia tidak berfungsi sama sekali. Apakah kelebihan menggunakan ucarp daripada keepalived? Ya, dalam segala-galanya - terdapat 100 pintu masuk, keepalived dan satu ralat dalam konfigurasi - semuanya tidak berfungsi. 1 gerbang tidak berfungsi dengan ucarp. Mengenai keselamatan, mereka mengatakan bahawa yang kiri akan mendaftarkan alamat untuk diri mereka sendiri dan menggunakannya pada bahagian - untuk mengawal detik ini, kami menyediakan dhcp-snooping + source-guard + arp inspection pada semua suis/olts/bases. Jika pelanggan tidak mempunyai dhpc tetapi statik - senarai akses pada port.

Mengapa semua ini dilakukan? Untuk memusnahkan lalu lintas yang tidak diingini. Kini setiap suis mempunyai vlan sendiri dan unicast yang tidak diketahui tidak lagi menakutkan, kerana ia hanya perlu pergi ke satu port dan bukan kepada semua... Nah, kesan sampingannya ialah konfigurasi peralatan yang standard, kecekapan yang lebih besar dalam memperuntukkan ruang alamat.

Cara mengkonfigurasi lisg ialah topik yang berasingan. Pautan ke perpustakaan dilampirkan. Mungkin perkara di atas akan membantu seseorang dalam mencapai matlamat mereka. Versi 6 belum lagi dilaksanakan pada rangkaian kami - tetapi akan ada masalah - terdapat rancangan untuk menulis semula lisg untuk versi 6, dan program yang menambah laluan perlu diperbetulkan.

Linux ISG
DB2DHCP
Libtins

Sumber: www.habr.com

Tambah komen