Doğaçlama araçları kullanan hataya dayanıklı IPeE ağı

Merhaba. Bu, 5 bin istemciden oluşan bir ağ olduğu anlamına gelir. Son zamanlarda pek hoş olmayan bir an yaşandı - ağın merkezinde bir Brocade RX8'imiz var ve ağ vlan'lara bölünmüş olduğundan çok sayıda bilinmeyen tek noktaya yayın paketi göndermeye başladı - bu kısmen bir sorun değil, AMA var beyaz adresler vb. için özel vlan'lar ve ağın her yönüne gerilirler. Şimdi, sınır öğrencisi olarak eğitim görmeyen bir müşterinin adresine gelen bir akışı hayal edin ve bu akış, köyün bir kısmına (veya tamamına) radyo bağlantısına doğru uçuyor - kanal tıkalı - müşteriler kızgın - üzüntü...

Amaç bir hatayı bir özelliğe dönüştürmektir. Tam teşekküllü bir istemci vlan'ı ile q-in-q yönünde düşünüyordum, ancak P3310 gibi her türlü donanım, dot1q etkinleştirildiğinde DHCP'nin geçişine izin vermiyor, onlar da qinq'i nasıl seçeceklerini bilmiyorlar ve birçok bu tür tuzaklar. Adlandırılmamış ip nedir ve nasıl çalışır? Çok kısaca: arayüzdeki ağ geçidi adresi + rota. Görevimiz için şunları yapmamız gerekiyor: şekillendiriciyi kesmek, istemcilere adresleri dağıtmak, belirli arayüzler aracılığıyla istemcilere rotalar eklemek. Bütün bunlar nasıl yapılır? Shaper - lisg, dhcp - db2dhcp iki bağımsız sunucuda, dhcprelay erişim sunucularında çalışır, ucarp ayrıca yedekleme için erişim sunucularında çalışır. Peki rota nasıl eklenir? Büyük bir komut dosyasıyla her şeyi önceden ekleyebilirsiniz - ancak bu doğru değildir. Böylece kendi kendine yazılmış bir koltuk değneği yapacağız.

İnternette kapsamlı bir arama yaptıktan sonra, C++ için trafiği güzel bir şekilde koklamanıza olanak tanıyan harika bir üst düzey kitaplık buldum. Route ekleyen programın algoritması şu şekildedir - arayüzdeki arp isteklerini dinliyoruz, eğer talep edilen sunucudaki lo arayüzünde bir adresimiz varsa, daha sonra bu arayüz üzerinden bir rota ekliyoruz ve statik bir arp ekliyoruz bu ip'e kaydedin - genel olarak birkaç kopyala-yapıştır, biraz sıfat ve işiniz bitti

'Yönlendiricinin' kaynakları

#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 kurulum betiği

#!/bin/bash

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

İkiliyi oluşturma komutu

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

Nasıl başlatılır?


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

Evet - tabloları HUP sinyaline göre yeniden oluşturacaktır. Netlink'i neden kullanmadınız? Bu sadece tembellik ve Linux bir senaryo üzerine yazılmış bir senaryo - yani her şey yolunda. Peki rotalar rotadır, sırada ne var? Daha sonra bu sunucudaki rotaları sınıra göndermemiz gerekiyor - burada aynı eski donanım nedeniyle en az dirençli yolu seçtik - bu görevi BGP'ye atadık.

bgp yapılandırmasıana bilgisayar adı *****
şifre *******
günlük dosyası /var/log/bgp.log
!
# AS numarası, adresler ve ağlar hayalidir
yönlendirici bgp 12345
bgp yönlendirici kimliği 1.2.3.4
bağlı yeniden dağıt
statiği yeniden dağıt
komşu 1.2.3.1 uzak-as 12345
1.2.3.1 sonraki atlamalı benlik
komşu 1.2.3.1 yol haritası yok
komşu 1.2.3.1 yol haritası dışa aktarımı
!
erişim listesi dışa aktarma izni 1.2.3.0/24
!
rota haritası ihracat izni 10
IP adresini dışa aktarmayla eşleş
!
rota haritası dışa aktarma reddi 20

Devam edelim. Sunucunun arp isteklerine yanıt verebilmesi için arp proxy'sini etkinleştirmeniz gerekir.


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

Devam edelim - uçarp. Bu mucizenin lansman senaryolarını kendimiz yazıyoruz.

Bir arka plan programının çalıştırılmasına örnek


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"

yukarı.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

aşağı.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

Dhcprelay'in bir arayüzde çalışması için bir adrese ihtiyacı vardır. Bu nedenle, kullandığımız arayüzlere soldaki adresleri ekleyeceğiz - örneğin 10.255.255.1/32, 10.255.255.2/32, vb. Röleyi nasıl yapılandıracağınızı size söylemeyeceğim - her şey basit.

Peki neyimiz var? Ağ geçitlerinin yedeklenmesi, rotaların otomatik yapılandırılması, dhcp. Bu minimum settir - lisg ayrıca etrafındaki her şeyi sarar ve zaten bir şekillendiricimiz vardır. Neden her şey bu kadar uzun ve kafa karıştırıcı? Accel-pppd'yi alıp pppoe'yi hep birlikte kullanmak daha kolay değil mi? Hayır, daha basit değil - insanlar pppoe'den bahsetmeye bile gerek yok, bir yönlendiriciye yama kablosunu neredeyse hiç sığdıramıyorlar. accel-ppp harika bir şey - ama bizim için işe yaramadı - kodda çok fazla hata var - ufalanıyor, çarpık bir şekilde kesiliyor ve en üzücü şey şu ki, eğer parlarsa - o zaman insanların yeniden yüklemesi gerekiyor her şey - telefonlar kırmızı - hiç işe yaramadı. Canlı tutmak yerine ucarp kullanmanın avantajı nedir? Evet, her şeyde - 100 ağ geçidi var, canlı tutuluyor ve yapılandırmada bir hata var - her şey çalışmıyor. 1 ağ geçidi ucarp ile çalışmıyor. Güvenlikle ilgili olarak, soldakilerin adresleri kendileri için kaydedeceklerini ve bunları paylaşımda kullanacaklarını söylüyorlar - bu anı kontrol etmek için tüm anahtarlarda/oltlarda/tabanlarda dhcp-snooping + source-guard + arp denetleme ayarladık. İstemcide dhpc yoksa bağlantı noktasında statik erişim listesi varsa.

Bütün bunlar neden yapıldı? İstenmeyen trafiği yok etmek. Artık her anahtarın kendi vlan'ı var ve bilinmeyen tek noktaya yayın artık korkutucu değil, çünkü hepsine değil yalnızca tek bir bağlantı noktasına gitmesi gerekiyor... Yan etkiler, standartlaştırılmış bir ekipman yapılandırması, adres alanı tahsisinde daha fazla verimliliktir.

Lisg'nin nasıl yapılandırılacağı ayrı bir konudur. Kütüphanelere bağlantılar ektedir. Belki yukarıdakiler birisinin hedeflerine ulaşmasına yardımcı olacaktır. Sürüm 6 henüz ağımızda uygulanmıyor - ancak bir sorun olacak - sürüm 6 için lisg'nin yeniden yazılması planlanıyor ve rota ekleyen programın düzeltilmesi gerekecek.

Linux ISG'si
DB2DHCP
Libtinler

Kaynak: habr.com

Yorum ekle