Hej. Det finns ett nÀtverk med 5k kunder. Nyligen uppstod ett mindre trevligt problem - i centrum av nÀtverket har vi en Brocade RX8 och den har börjat skicka en massa unknown-unicast paket, eftersom nÀtverket Àr uppdelat i VLAN - det hÀr Àr delvis inte ett problem MEN det finns speciella VLAN för vita adresser osv. och de Àr strÀckt i alla riktningar av nÀtverket. SÄ, tÀnk er nu det inkommande flödet till kundens adress, som grÀnslandet inte kÀnner igen och det flödet flyger mot en radio lÀnk till nÄgot (och sÄ till hela) by - kanalen Àr blockerad - kunderna Àr arga - sorgligt...
Uppgiften - att förvandla en bugg till en funktion. Jag tÀnkte i riktning mot q-in-q med en fullstÀndig klient-vlan men olika hÄrdvaror som P3310 slutar att passera DHCP nÀr dot1q aktiveras, de kan inte heller selective qinq och det finns mÄnga underliggande problem av denna typ. Vad Àr ip-unnumbered och hur fungerar det? Om vi ska vara kortfattade - gateway-adressen + rutt pÄ grÀnssnittet. För vÄr uppgift behöver vi: skÀra shaper, dela ut adresser till kunder, lÀgga till rutter till kunder via specifika grÀnssnitt. Vad ska vi göra allt detta med? Shaper - lisg, dhcp - db2dhcp pÄ tvÄ oberoende servrar, pÄ Ätkomstservrarna körs dhcprelay, och pÄ Ätkomstservrarna fungerar ocksÄ ucarp - för backup. Men hur lÀgger vi till rutter? Man kan anvÀnda ett stort skript för att pÄ förhand lÀgga till allt - men det Àr inte riktigt sant. SÄ vi kommer att bygga en egen lösning.
Efter att ha sökt ordentligt pÄ internet har jag hittat ett fantastiskt hög nivÄ bibliotek för c++, som gör det möjligt att snyggt sniffa trafik. Algoritmen för programmet som lÀgger till rutter Àr följande - vi lyssnar pÄ ARP-förfrÄgningar pÄ grÀnssnittet, om vi har en adress pÄ servern pÄ grÀnssnittet lo, som efterfrÄgas sÄ lÀgger vi till en rutt genom detta grÀnssnitt och lÀgger till en statisk ARP-post för denna ip - sammanfattningsvis nÄgra kopior av koden, lite egenhet och klart.
KÀllkod för 'rutten'
#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;
}
}Installationsskript för libtins
#!/bin/bash
git clone https://github.com/mfontanini/libtins.git
cd libtins
mkdir build
cd build
cmake ../
make
make install
ldconfig
Kommandot för att bygga binÀrfilen
g++ main.cpp -o arp-rt -O3 -std=c++11 -lpthread -ltinsHur kör man den?
start-stop-daemon --start --exec /opt/ipoe/arp-routes/arp-rt -b -m -p /opt/ipoe/arp-routes/daemons/eth0.800.pid -- eth0.800
Ja â den byggs om av HUP-signal för att omstrukturera tabellerna. Varför anvĂ€nda netlink? Det Ă€r bara lathet, och Linux Ă€r skript pĂ„ skript â sĂ„ det Ă€r helt okej. NĂ„vĂ€l, rutter Ă€r rutterna, vad hĂ€nder nu? Vidare mĂ„ste vi skicka rutter till border som finns pĂ„ den hĂ€r servern â hĂ€r, pĂ„ grund av samma förĂ„ldrade hĂ„rdvara, valde vi den enklaste vĂ€gen â vi lĂ€gger den hĂ€r uppgiften pĂ„ BGP.
BGP-konfigurationvÀrdnamn *******
lösenord *******
loggfil /var/log/bgp.log
!
# ĐœĐŸĐŒĐ”Ń Đ°Ń-ĐșĐž, аЎŃĐ”Ńа Đž ŃĐ”ŃĐž ĐČŃĐŽŃĐŒĐ°ĐœŃ
router bgp 12345
bgp router-id 1.2.3.4
redistribuera ansluten
redistribuera statiska
granne 1.2.3.1 remote-as 12345
granne 1.2.3.1 next-hop-self
granne 1.2.3.1 route-map none in
granne 1.2.3.1 route-map export out
!
Ätkomstlista export tillÄt 1.2.3.0/24
!
route-map export tillÄt 10
matcha IP-adress export
!
route-map export neka 20
Vi fortsÀtter. För att servern ska svara pÄ ARP-förfrÄgningar behöver vi aktivera proxy ARP.
echo 1 > /proc/sys/net/ipv4/conf/eth0.800/proxy_arp
Vi gĂ„r vidare â ucarp. Skripten för att starta detta underverk skriver vi sjĂ€lva.
Exempel pÄ att starta en demon
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
För att dhcprelay ska fungera pĂ„ grĂ€nssnittet â behöver det en adress. SĂ„ vi kommer att lĂ€gga till falska adresser pĂ„ grĂ€nssnitten som vi anvĂ€nder â till exempel 10.255.255.1/32, 10.255.255.2/32 och sĂ„ vidare. Jag kommer inte att gĂ„ in pĂ„ hur man konfigurerar relay â det Ă€r enkelt.
SĂ„, vad har vi? Backup-gateways, automatisk ruttkonfiguration, DHCP. Detta Ă€r den minimala uppsĂ€ttningen â ovanpĂ„ detta lĂ€gger vi till lisg och vi har redan en shaper. Varför Ă€r allt sĂ„ lĂ„ngt och komplicerat? Skulle det inte vara lĂ€ttare att ta accel-pppd och anvĂ€nda PPPoE istĂ€llet? Nej, det Ă€r inte enklare â folk har svĂ„rt att fĂ„ en patchkabel i routern, för att inte tala om PPPoE. accel-ppp Ă€r bra â men det fungerade inte för oss â massor av fel i koden â det kraschar, skĂ€r illa, och det mest sorgliga Ă€r att nĂ€r det kraschar behöver folk alltid starta om â telefonerna ringer â i allmĂ€nhet passade det inte. Vad Ă€r fördelen med att anvĂ€nda ucarp istĂ€llet för keepalived? Jo, allt â det finns 100 gateways, keepalived och ett fel i konfigurationen â allt fungerar inte. Med ucarp fungerar inte 1 gateway. NĂ€r det gĂ€ller sĂ€kerhet, att folk kan skriva in frĂ€mmande adresser och anvĂ€nda dem pĂ„ nĂ€tet â för att kontrollera detta konfigurerar vi dhcp-snooping + source-guard + arp-inspektion pĂ„ alla switchar/oltar/servrar. Om kunden inte har DHCP utan statiska adresser â access-list pĂ„ porten.
Varför gjordes allt detta? För att förstöra oönskad trafik. Nu har varje switch sin egen VLAN, och unknown-unicast Ă€r inte lĂ€ngre ett problem, eftersom det bara behöver gĂ„ till en port och inte till alla... Och biverkningarna â standardiserad konfiguration av utrustningen, större effektivitet i fördelningen av adresser.
Hur man konfigurerar lisg â det Ă€r ett separat Ă€mne. LĂ€nkar till biblioteken ingĂ„r. Kanske hjĂ€lper det nĂ„gon i ovanstĂ„ende med att genomföra sina uppgifter. Version 6 har vi inte implementerat i vĂ„rt nĂ€t Ă€n â men det kommer att bli ett problem â vi planerar att skriva om lisg för version 6, och dĂ„ mĂ„ste programmet som lĂ€gger till rutter justeras.
KĂ€lla: habr.com
