Tere. See tähendab, et meil on 5000 kliendi võrk. Hiljuti ilmus välja mitte eriti meeldiv hetk — keskuses on meil Brocade RX8, mis hakkas saatma palju unknown-unicast pakette, kuna võrk on jaotatud VLAN-ideks — see osaliselt ei ole probleem, KUID olemas on spetsiaalsed VLAN-id valgete aadresside jaoks jne, ja need on venitatud üle kogu võrgu. Kujutage nüüd ette sissetulevat voolu kliendi aadressile, mis ei õpi bordermuxi kaudu, ja see vool suundub peale mingisse (ja tegelikult kõikidesse) külasse — kanal on täis — kliendid on pahased — kurbus...
Üks ülesanne on muuta viga funktsiooniks. Mõtlesin q-in-q suunas koos täisfunktsionaalse kliendi VLAN-iga, kuid igasugused seadmed, nagu P3310, lõpetavad dot1q lubamisel DHCP edastamise, peale selle ei osu nad selective qinq'iga ja palju muid taolisi hädasid. Mis on ip-unnumbered ja kuidas see töötab? Kui väga lühidalt — see on gangli aadress + marsruut liidesel. Meie ülesande jaoks peame: kärpima šeyperit, jagama aadresse klientidele, lisama marsruute klientidele läbi teatud liideste. Millise abil seda teha? Šeyper — lisg, dhcp — db2dhcp kahel sõltumatul serveril, juurdepääsu serverites töötab dhcprelay, samuti töötab juurdepääsu serverites ucarp — varukoopiana. Kuidas marsruute lisada? Suure skriptiga saab kõik eelnevalt lisada — kuid see ei ole tõeline. Peame siis välja mõtlema ise tehtud lahenduse.
Otsides internetis leidsin ma suurepärase kõrgema taseme teegi C++-le, mis võimaldab ilusalt traadita võrku nuhkida. Programm, mis lisab marsruute, toimib järgmiselt: kuulame liidesel ARP-päringuid. Kui meie serveril on aadress lo liidesel, mida küsitakse, lisame marsruudi selle liidese kaudu ja lisame staatilise ARP-kirje selle IP-aadressi jaoks — üldiselt paar kopeerimist ja natuke improviseerimist ning see ongi valmis.
'Marsruuditegija' lähtekoodid
#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'i installimise skript
#!/bin/bash
git clone https://github.com/mfontanini/libtins.git
cd libtins
mkdir build
cd build
cmake ../
make
make install
ldconfig
Käsk binaari ehitamiseks
g++ main.cpp -o arp-rt -O3 -std=c++11 -lpthread -ltinsKuidas seda käivitada?
start-stop-daemon --start --exec /opt/ipoe/arp-routes/arp-rt -b -m -p /opt/ipoe/arp-routes/daemons/eth0.800.pid -- eth0.800
Jah — see taastab tabelid signaali HUP korral. Miks ei kasutanud netlinki? Lihtsalt laiskus ja Linux on skript skripti peale — nii et kõik on korras. Noh, marsruudid on marsruudid, mis edasi? Jätkuvalt peame edastama serveris olevad marsruudid piirikontrollerile — kuna need vanad riistvara tõttu, valisime me võimalikult lihtsa tee — andsime selle ülesande BGP-le.
BGP konfigureeriminehostname *******
password *******
log file /var/log/bgp.log
!
# номер ас-ки, адреса и сети выдуманы
router bgp 12345
bgp router-id 1.2.3.4
redistribute connected
jaotada staatilisi
naaber 1.2.3.1 kaugas 12345
naaber 1.2.3.1 järgmine-hüppeline-endale
naaber 1.2.3.1 marsruudi-kaardiga ei mingeid sisse
naaber 1.2.3.1 marsruudi-kaardiga eksport välja
!
juhend-loend eksport luba 1.2.3.0/24
!
marsruudi-kaart eksport luba 10
sobita ip aadress eksport
!
marsruudi-kaart eksport keela 20
Jätkame. Selleks, et server vastaks ARP päringutele, tuleb lubada proxy ARP.
echo 1 > /proc/sys/net/ipv4/conf/eth0.800/proxy_arp
Liigume edasi — ucarp. Selle ime käivitamiseks kirjutame skriptid ise
Näide kiste tidone demooni käivitamisest
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
down.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
Et dhcprelay töötaks liidese peal — tal on vaja aadressi. Seetõttu lisame me kasutatavatele liidesele vale aadresse — näiteks 10.255.255.1/32, 10.255.255.2/32 jne. Kuidas raleigh'i seadistada, ei hakka rääkima — seal on kõik lihtne.
Nii, mis meil on. Varukoopiate väravad, automaatne marsruutide seadistus, dhcp. See on minimaalne komplekt — sellele lisandub veel lisg ja meil on juba ka kuju. Miks kõik on nii pikk ja keeruline? Kas ei oleks lihtsam võtta accel-pppd ja kasutada üldse pppoe? Ei, see pole lihtsam — inimesed saavad vaevu isegi patchcordi ruuterisse suruda, rääkimata pppoe'st. accel-ppp on äge asi — aga meie jaoks ei sobinud — hulk vigu koodis — laguneb, kärbib valesti, ja kõige kurvem on see, et kui see kukub — peavad inimesed kõik uuesti käivitama — telefonid punased — kokkuvõttes ei sobinud see. Mis on ucarp'i eelised võrreldes keepalived'iga? Jah kõiges — on 100 väravat, keepalived ja üks viga konfiguratsioonis — ei tööta kõik. Ucarp'i puhul ei tööta 1 värav. Turvalisuse osas, et nad kirjutavad endale vale aadresse ja kasutavad neid palli peal — selle kontrollimiseks seadistame kõigis lülitites/oltides/baasides dhcp-snooping + source-guard + arp inspection. Kui kliendil pole dhcp-d vaid staatika — access-list porti.
Miks see kõik tehti? Ebasoovitava liikluse hävitamiseks. Nüüd on igal switchil oma VLAN ja unknown-unicast ei ole enam hirmutav, sest see peab liikuma ainult ühte portsse, mitte kõikidesse ... Ja kõrvaltoimed - standardiseeritud seadmete konfiguratsioon, paremini jaotatud aadressiruumi efektiivsus.
Kuidas lisg seadistada - see on eraldi teema. Raamatukogude lingid on lisatud. Võib-olla aitab see kellelgi ülaltoodut oma ülesannete täitmisel. Versiooni 6 ei ole meie võrgus veel rakendatud - kuid seal on probleem - plaanime kirjutada lisg 6. versioonile ümber ja tuleb ka programmi korrigeerida, mis marsruute lisab.
Allikas: habr.com
