Jaringan IPeE yang toleran terhadap kesalahan menggunakan alat improvisasi

Halo. Ini berarti ada jaringan 5k klien. Baru-baru ini muncul momen yang tidak menyenangkan - di tengah jaringan kami memiliki Brocade RX8 dan mulai mengirimkan banyak paket unicast yang tidak diketahui, karena jaringan dibagi menjadi vlan - ini sebagian tidak menjadi masalah, TAPI ada vlan khusus untuk alamat putih, dll. dan mereka membentang ke segala arah jaringan. Jadi sekarang bayangkan aliran masuk ke alamat klien yang tidak belajar sebagai siswa perbatasan dan aliran ini terbang menuju link radio ke beberapa (atau semua) desa - saluran tersumbat - klien marah - sedih...

Tujuannya adalah mengubah bug menjadi fitur. Saya berpikir ke arah q-in-q dengan vlan klien lengkap, tetapi semua jenis perangkat keras seperti P3310, ketika dot1q diaktifkan, berhenti membiarkan DHCP lewat, mereka juga tidak tahu cara memilih qinq dan banyak lagi jebakan semacam itu. Apa itu ip-unnambered dan bagaimana cara kerjanya? Secara singkat: alamat gateway + rute pada antarmuka. Untuk tugas kita, kita perlu: memotong pembentuk, mendistribusikan alamat ke klien, menambahkan rute ke klien melalui antarmuka tertentu. Bagaimana cara melakukan semua ini? Pembentuk - lisg, dhcp - db2dhcp di dua server independen, dhcprelay berjalan di server akses, ucarp juga berjalan di server akses - untuk cadangan. Tapi bagaimana cara menambahkan rute? Anda dapat menambahkan semuanya terlebih dahulu dengan skrip besar - tetapi ini tidak benar. Jadi kita akan membuat kruk yang ditulis sendiri.

Setelah pencarian menyeluruh di Internet, saya menemukan perpustakaan tingkat tinggi yang luar biasa untuk C++, yang memungkinkan Anda mengendus lalu lintas dengan indah. Algoritma untuk program yang menambahkan rute adalah sebagai berikut - kita mendengarkan permintaan arp pada antarmuka, jika kita memiliki alamat pada antarmuka lo di server yang diminta, maka kita menambahkan rute melalui antarmuka ini dan menambahkan arp statis rekam ke ip ini - secara umum, beberapa salin-tempel, sedikit kata sifat dan 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 instalasi libtins

#!/bin/bash

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

Perintah untuk membangun biner

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

Bagaimana cara meluncurkannya?


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 - ini akan membangun kembali tabel berdasarkan sinyal HUP. Mengapa Anda tidak menggunakan netlink? Itu hanya kemalasan dan Linux adalah skrip di atas skrip - jadi semuanya baik-baik saja. Ya, rute tetaplah rute, apa selanjutnya? Selanjutnya, kita perlu mengirim rute yang ada di server ini ke perbatasan - di sini, karena perangkat keras usang yang sama, kami mengambil jalur yang paling sedikit hambatannya - kami menugaskan tugas ini ke BGP.

konfigurasi bgpnama host *******
kata sandi *******
file log /var/log/bgp.log
!
# Nomor AS, alamat dan jaringan adalah fiktif
router bgp 12345
bgp router-id 1.2.3.4
mendistribusikan kembali terhubung
mendistribusikan ulang statis
tetangga 1.2.3.1 jarak jauh-sebagai 12345
tetangga 1.2.3.1 hop berikutnya
tetangga 1.2.3.1 peta rute tidak ada di
tetangga 1.2.3.1 ekspor peta rute keluar
!
izin ekspor daftar akses 1.2.3.0/24
!
izin ekspor peta rute 10
cocok dengan ekspor alamat ip
!
ekspor peta rute ditolak 20

Ayo lanjutkan. Agar server merespons permintaan arp, Anda harus mengaktifkan proxy arp.


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

Mari kita lanjutkan - ucarp. Kami sendiri yang menulis skrip peluncuran 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"

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

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

Agar dhcprelay dapat bekerja pada sebuah antarmuka, ia memerlukan sebuah alamat. Oleh karena itu, pada antarmuka yang kami gunakan kami akan menambahkan alamat kiri - misalnya 10.255.255.1/32, 10.255.255.2/32, dll. Saya tidak akan memberi tahu Anda cara mengkonfigurasi relai - semuanya sederhana.

Jadi apa yang kita punya? Cadangan gateway, konfigurasi rute otomatis, dhcp. Ini adalah set minimum - lisg juga membungkus segala sesuatu di sekitarnya dan kita sudah memiliki pembentuknya. Mengapa semuanya begitu panjang dan rumit? Bukankah lebih mudah menggunakan accel-pppd dan menggunakan pppoe sama sekali? Tidak, ini tidak lebih sederhana - orang hampir tidak dapat memasukkan kabel patch ke dalam router, apalagi pppoe. accel-ppp adalah hal yang keren - tetapi tidak berhasil bagi kami - ada banyak kesalahan dalam kode - hancur, terpotong miring, dan yang paling menyedihkan adalah jika cerah - maka orang perlu memuat ulang semuanya - teleponnya merah - tidak berfungsi sama sekali. Apa keuntungan menggunakan ucarp dibandingkan keepalive? Ya, semuanya - ada 100 gateway, tetap hidup dan satu kesalahan dalam konfigurasi - semuanya tidak berfungsi. 1 gateway tidak berfungsi dengan ucarp. Mengenai keamanan, mereka mengatakan bahwa yang kiri akan mendaftarkan alamat untuk diri mereka sendiri dan akan menggunakannya pada share - untuk mengontrol momen ini, kami menyiapkan dhcp-snooping + source-guard + inspeksi arp di semua switch/olts/bases. Jika klien tidak memiliki dhpc tetapi statis - daftar akses di port.

Mengapa semua ini dilakukan? Untuk menghancurkan lalu lintas yang tidak diinginkan. Sekarang setiap switch memiliki vlannya sendiri dan tidak diketahui-unicast tidak lagi menakutkan, karena hanya perlu menuju ke satu port dan tidak ke semua... Nah, efek sampingnya adalah konfigurasi peralatan standar, efisiensi yang lebih besar dalam mengalokasikan ruang alamat.

Cara mengkonfigurasi lisg adalah topik terpisah. Tautan ke perpustakaan terlampir. Mungkin hal di atas akan membantu seseorang dalam mencapai tujuannya. Versi 6 belum diimplementasikan di jaringan kami - tetapi akan ada masalah - ada rencana untuk menulis ulang lisg untuk versi 6, dan program yang menambahkan rute perlu diperbaiki.

LinuxISG
DB2DHCP
Libtin

Sumber: www.habr.com

Tambah komentar