Fault-tolerant IPeE network gamit ang mga improvised na tool

Kamusta. Nangangahulugan ito na mayroong isang network ng 5k kliyente. Kamakailan ay dumating ang isang hindi kasiya-siyang sandali - sa gitna ng network mayroon kaming Brocade RX8 at nagsimula itong magpadala ng maraming hindi kilalang-unicast na mga packet, dahil ang network ay nahahati sa mga vlan - ito ay bahagyang hindi isang problema, PERO mayroong mga espesyal na vlan para sa mga puting address, atbp. at sila ay nakaunat sa lahat ng direksyon ng network. Kaya ngayon isipin ang isang papasok na daloy sa address ng isang kliyente na hindi nag-aaral bilang isang mag-aaral sa hangganan at ang daloy na ito ay lumilipad patungo sa isang link sa radyo sa ilan (o lahat) na nayon - ang channel ay barado - ang mga kliyente ay nagagalit - kalungkutan...

Ang layunin ay gawing tampok ang isang bug. I was thinking in the direction of q-in-q with a full-fledged client vlan, but all kinds of hardware like P3310, when dot1q is enabled, stop passing DHCP, they also don't know how to selective qinq and many pitfalls of ganyang klase. Ano ang ip-unnambered at paano ito gumagana? Napakaikli: address ng gateway + ruta sa interface. Para sa aming gawain, kailangan naming: i-cut ang shaper, ipamahagi ang mga address sa mga kliyente, magdagdag ng mga ruta sa mga kliyente sa pamamagitan ng ilang mga interface. Paano gawin ang lahat ng ito? Shaper - lisg, dhcp - db2dhcp sa dalawang independiyenteng server, ang dhcprelay ay tumatakbo sa mga access server, ang ucarp ay tumatakbo din sa mga access server - para sa backup. Ngunit paano magdagdag ng mga ruta? Maaari mong idagdag ang lahat nang maaga gamit ang isang malaking script - ngunit hindi ito totoo. Kaya gagawa tayo ng self-written crutch.

Pagkatapos ng masusing paghahanap sa Internet, nakakita ako ng isang napakagandang library na may mataas na antas para sa C++, na nagbibigay-daan sa iyong magandang singhutin ang trapiko. Ang algorithm para sa programa na nagdaragdag ng mga ruta ay ang mga sumusunod - nakikinig kami sa mga kahilingan ng arp sa interface, kung mayroon kaming isang address sa lo interface sa server na hiniling, pagkatapos ay nagdaragdag kami ng isang ruta sa pamamagitan ng interface na ito at nagdaragdag ng isang static na arp i-record sa ip na ito - sa pangkalahatan, ilang copy-paste, kaunting adjective at tapos ka na

Mga mapagkukunan ng '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;
    }
}

script ng pag-install ng libtins

#!/bin/bash

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

Utos na buuin ang binary

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

Paano ito ilunsad?


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

Oo - ito ay muling bubuo ng mga talahanayan batay sa signal ng HUP. Bakit hindi ka gumamit ng netlink? Ito ay katamaran lamang at ang Linux ay isang script sa isang script - kaya lahat ay maayos. Well, ang mga ruta ay mga ruta, ano ang susunod? Susunod, kailangan naming ipadala ang mga ruta na nasa server na ito sa hangganan - dito, dahil sa parehong hindi napapanahong hardware, kinuha namin ang landas ng hindi bababa sa paglaban - itinalaga namin ang gawaing ito sa BGP.

bgp confighostname *******
password *******
log file /var/log/bgp.log
!
# AS number, address at network ay kathang-isip lamang
router bgp 12345
bgp router-id 1.2.3.4
muling ipamahagi ang konektado
muling ipamahagi ang static
kapitbahay 1.2.3.1 remote-bilang 12345
kapitbahay 1.2.3.1 next-hop-self
kapitbahay 1.2.3.1 ruta-mapa wala sa
kapitbahay 1.2.3.1 ruta-mapa export out
!
access-list export permit 1.2.3.0/24
!
permiso sa pag-export ng mapa ng ruta 10
tumugma sa pag-export ng ip address
!
pagtanggi sa pag-export ng ruta-mapa 20

Ituloy natin. Upang tumugon ang server sa mga kahilingan sa arp, dapat mong paganahin ang arp proxy.


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

Ipagpatuloy natin - ucarp. Kami mismo ang sumulat ng mga script ng paglulunsad para sa himalang ito.

Halimbawa ng pagpapatakbo ng isang 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"

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

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

Para gumana ang dhcprelay sa isang interface, kailangan nito ng address. Samakatuwid, sa mga interface na ginagamit namin ay magdaragdag kami ng mga kaliwang address - halimbawa 10.255.255.1/32, 10.255.255.2/32, atbp. Hindi ko sasabihin sa iyo kung paano i-configure ang relay - lahat ay simple.

Kaya ano ang mayroon tayo? Backup ng mga gateway, auto-configuration ng mga ruta, dhcp. Ito ang minimum na hanay - binabalot din ng lisg ang lahat sa paligid nito at mayroon na tayong shaper. Bakit napakahaba at nakakalito ang lahat? Hindi ba mas madaling kumuha ng accel-pppd at gumamit ng pppoe nang buo? Hindi, hindi ito mas simple - halos hindi magkasya ang mga tao ng patchcord sa isang router, bukod pa sa pppoe. Ang accel-ppp ay isang cool na bagay - ngunit hindi ito gumana para sa amin - mayroong maraming mga error sa code - ito ay gumuho, ito ay pumutol nang baluktot, at ang pinakamalungkot na bagay ay na kung ito ay lumiwanag - pagkatapos ay ang mga tao ay kailangang mag-reload lahat - ang mga telepono ay pula - hindi ito gumana sa lahat. Ano ang bentahe ng paggamit ng ucarp kaysa keepalived? Oo, sa lahat ng bagay - mayroong 100 gateway, keepalived at isang error sa config - lahat ay hindi gumagana. 1 gateway ay hindi gumagana sa ucarp. Tungkol sa seguridad, sinasabi nila na ang mga kaliwa ay magrerehistro ng mga address para sa kanilang sarili at gamitin ang mga ito sa pagbabahagi - upang kontrolin ang sandaling ito, nag-set up kami ng dhcp-snooping + source-guard + arp inspection sa lahat ng switch/olts/bases. Kung ang kliyente ay walang dhpc ngunit static - acces-list sa port.

Bakit ginawa ang lahat ng ito? Upang sirain ang hindi gustong trapiko. Ngayon ang bawat switch ay may sariling vlan at hindi na nakakatakot-unicast, dahil kailangan lang nitong pumunta sa isang port at hindi sa lahat... Well, ang mga side effect ay isang standardized equipment config, mas mahusay na paglalaan ng address space.

Paano i-configure ang lisg ay isang hiwalay na paksa. Naka-attach ang mga link sa mga aklatan. Marahil ang nasa itaas ay makakatulong sa isang tao sa pagkamit ng kanilang mga layunin. Hindi pa ipinapatupad ang Bersyon 6 sa aming network - ngunit magkakaroon ng problema - may mga planong muling isulat ang lisg para sa bersyon 6, at kakailanganing itama ang program na nagdaragdag ng mga ruta.

Linux ISG
DB2DHCP
Libtins

Pinagmulan: www.habr.com

Magdagdag ng komento