Хиймэл хэрэгслүүдийг ашиглан гэмтэлд тэсвэртэй IPeE сүлжээ

Сайн уу. Энэ нь 5к үйлчлүүлэгчтэй сүлжээтэй гэсэн үг. Саяхан тийм ч таатай бус мөч гарч ирэв - сүлжээний төвд Brocade RX8 байгаа бөгөөд сүлжээ нь vlan-д хуваагдсан тул үл мэдэгдэх олон пакетуудыг илгээж эхэлсэн - энэ нь хэсэгчлэн асуудал биш, ГЭВЧ байдаг. цагаан хаягт зориулсан тусгай vlan гэх мэт. мөн тэдгээр нь сүлжээний бүх чиглэлд сунадаг. Тэгэхээр одоо хилийн оюутны мэргэжлээр сурдаггүй үйлчлүүлэгчийн хаяг руу орж ирж буй урсгалыг төсөөлөөд үз дээ, энэ урсгал нь зарим (эсвэл бүх) тосгон руу радио холбоос руу нисч байна - суваг бөглөрсөн - үйлчлүүлэгчид ууртай - уйтгар гуниг...

Зорилго нь алдааг функц болгон хувиргах явдал юм. Би q-in-q чиглэлийг бүрэн хэмжээний клиент vlan-тай бодож байсан боловч P3310 гэх мэт бүх төрлийн техник хангамжууд нь dot1q идэвхжсэн үед DHCP-г дамжуулахаа больдог тул тэд мөн qinq-г хэрхэн сонгохоо мэддэггүй, мөн олон бэрхшээлүүд байдаг. ийм төрлийн. IP нэргүй гэж юу вэ, энэ нь хэрхэн ажилладаг вэ? Маш товчхондоо: гарцын хаяг + интерфэйс дээрх маршрут. Бидний даалгаврын хувьд бид дараах зүйлсийг хийх хэрэгтэй: хэлбэржүүлэгчийг таслах, үйлчлүүлэгчдэд хаяг тараах, тодорхой интерфейсээр дамжуулан үйлчлүүлэгчдэд чиглүүлэлт нэмэх. Энэ бүгдийг яаж хийх вэ? Shaper - lisg, dhcp - db2dhcp нь бие даасан хоёр сервер дээр, dhcprelay нь хандалтын серверүүд дээр, ucarp нь хандалтын серверүүд дээр ажилладаг - нөөцлөх. Гэхдээ маршрутыг хэрхэн нэмэх вэ? Та бүх зүйлийг том скриптээр урьдчилан нэмж болно - гэхдээ энэ нь үнэн биш юм. Тиймээс бид өөрөө бичсэн таяг хийх болно.

Интернэтээс сайтар хайсны эцэст би C++-д зориулсан гайхалтай өндөр түвшний номын санг олсон бөгөөд энэ нь танд замын хөдөлгөөнийг сайхан үнэрлэх боломжийг олгодог. Маршрут нэмдэг программын алгоритм нь дараах байдалтай байна - бид интерфэйс дээрх arp хүсэлтийг сонсдог, хэрэв бид хүссэн сервер дээрх lo интерфэйс дээр хаягтай бол бид энэ интерфейсээр дамжуулан маршрутыг нэмж, статик arp нэмнэ. Энэ ip дээр бичээрэй - ерөнхийдөө хэд хэдэн хуулж буулгах, бага зэрэг нэр үг, та дууслаа

"чиглүүлэгч"-ийн эх сурвалжууд

#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 суулгах скрипт

#!/bin/bash

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

Хоёртын файлыг бүтээх тушаал

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

Үүнийг хэрхэн эхлүүлэх вэ?


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

Тийм - энэ нь HUP дохио дээр үндэслэн хүснэгтүүдийг дахин бүтээх болно. Та яагаад netlink ашиглаагүй юм бэ? Энэ бол зүгээр л залхуурал бөгөөд Линукс бол скрипт дээрх скрипт тул бүх зүйл сайхан байна. За, маршрут бол маршрут, дараа нь яах вэ? Дараа нь бид энэ сервер дээр байгаа маршрутуудыг хил рүү илгээх хэрэгтэй - энд ижил хуучирсан техник хангамжийн улмаас бид хамгийн бага эсэргүүцэлтэй замыг сонгосон - бид энэ ажлыг BGP-д өгсөн.

bgp тохиргоохостын нэр *******
нууц үг *******
бүртгэлийн файл /var/log/bgp.log
!
# AS дугаар, хаяг, сүлжээнүүд нь зохиомол
чиглүүлэгч bgp 12345
bgp чиглүүлэгчийн дугаар 1.2.3.4
холбогдсон дахин хуваарилах
статикийг дахин хуваарилах
хөрш 1.2.3.1 алсаас-12345
хөрш 1.2.3.1 Next-hop-self
хөрш 1.2.3.1 route-map none in
хөрш 1.2.3.1 маршрут-газрын зураг экспортлох
!
хандалтын жагсаалт экспортын зөвшөөрөл 1.2.3.0/24
!
маршрутын зураг экспортлох зөвшөөрөл 10
IP хаягийн экспортыг тааруулах
!
route-map экспортыг үгүйсгэх 20

Үргэлжлүүлье. Сервер arp хүсэлтэд хариу өгөхийн тулд та arp проксиг идэвхжүүлэх ёстой.


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

Үргэлжлүүлье - ucarp. Бид энэ гайхамшгийг эхлүүлэх скриптийг өөрсдөө бичдэг.

Нэг дэмон ажиллуулах жишээ


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

доошоо.ш


#!/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 интерфэйс дээр ажиллахын тулд түүнд хаяг хэрэгтэй. Тиймээс бидний ашигладаг интерфейсүүд дээр бид зүүн хаягуудыг нэмэх болно - жишээлбэл 10.255.255.1/32, 10.255.255.2/32 гэх мэт. Би реле хэрхэн тохируулахыг хэлэхгүй - бүх зүйл энгийн.

Тэгэхээр бидэнд юу байгаа вэ? Гарцын нөөцлөлт, маршрутын автомат тохиргоо, dhcp. Энэ бол хамгийн бага багц юм - lisg нь бүх зүйлийг тойрон эргэлддэг бөгөөд бид аль хэдийн хэлбэржүүлэгчтэй болсон. Яагаад бүх зүйл ийм урт бөгөөд төвөгтэй байдаг вэ? Accel-pppd аваад pppoe-г бүхэлд нь ашиглах нь илүү хялбар биш гэж үү? Үгүй ээ, энэ нь тийм ч энгийн зүйл биш юм - хүмүүс pppoe-г дурдахад чиглүүлэгчид пачкорд бараг тааруулж чадахгүй. accel-ppp бол гайхалтай зүйл - гэхдээ энэ нь бидэнд тохирохгүй - кодонд маш олон алдаа байгаа - энэ нь сүйрч, муруй тайрдаг, хамгийн гунигтай нь хэрэв гэрэл гэгээтэй бол - хүмүүс дахин ачаалах хэрэгтэй. бүх зүйл - утаснууд нь улаан өнгөтэй - энэ нь огт ажиллахгүй байсан. Keepalived гэхээсээ илүү ucarp хэрэглэх нь ямар давуу талтай вэ? Тийм ээ, бүх зүйлд - 100 гарц, хадгалагдсан, тохиргоонд нэг алдаа байдаг - бүх зүйл ажиллахгүй байна. 1 гарц нь ucarp-тай ажиллахгүй. Аюулгүй байдлын тухайд тэд зүүн хүмүүс хаягаа бүртгүүлж, хувьцаанд ашиглах болно гэж хэлдэг - энэ мөчийг хянахын тулд бид бүх унтраалга/олт/бааз дээр dhcp-snooping + source-guard + arp шалгалтыг тохируулсан. Хэрэв үйлчлүүлэгчид dhpc байхгүй, гэхдээ статик - порт дээрх acces-list.

Энэ бүгдийг яагаад хийсэн бэ? Хүсээгүй урсгалыг устгах. Одоо шилжүүлэгч бүр өөрийн гэсэн vlan-тай бөгөөд үл мэдэгдэх-unicast нь аймшигтай байхаа больсон, учир нь энэ нь зөвхөн нэг порт руу орохоос гадна бүгдэд нь биш ... За, гаж нөлөө нь стандартчилагдсан тоног төхөөрөмжийн тохиргоо, хаягийн зайг хуваарилахад илүү үр дүнтэй байдаг. .

Lisg-г хэрхэн тохируулах нь тусдаа сэдэв юм. Номын сангуудын холбоосыг хавсаргав. Магадгүй дээр дурдсан зүйлс хэн нэгэнд зорилгодоо хүрэхэд нь туслах болно. 6-р хувилбар нь манай сүлжээнд хараахан хэрэгжээгүй байна - гэхдээ асуудал гарах болно - 6-р хувилбарын хувьд lisg-ийг дахин бичихээр төлөвлөж байгаа бөгөөд маршрут нэмдэг програмыг засах шаардлагатай болно.

Linux ISG
DB2DHCP
Либтинс

Эх сурвалж: www.habr.com

сэтгэгдэл нэмэх