HallÄ. Det betyder att det finns ett nÀtverk av 5k klienter. Nyligen dök ett inte sÀrskilt trevligt ögonblick upp - i mitten av nÀtverket har vi en Brocade RX8 och den började skicka en massa okÀnda-unicast-paket, eftersom nÀtverket Àr uppdelat i vlans - detta Àr delvis inte ett problem, MEN det finns speciella vlans för vita adresser osv. och de strÀcks Ät alla hÄll i nÀtverket. SÄ förestÀll dig nu ett inkommande flöde till adressen till en klient som inte studerar som grÀnsstudent och detta flöde flyger mot en radiolÀnk till nÄgon (eller hela) by - kanalen Àr igensatt - klienterna Àr arga - sorg...
MÄlet Àr att förvandla en bugg till en funktion. Jag tÀnkte i riktning mot q-in-q med ett fullfjÀdrat klient-vlan, men all möjlig hÄrdvara som P3310, nÀr dot1q Àr aktiverad, slutar slÀppa igenom DHCP, de vet inte heller hur man selektiv qinq och mÄnga fallgropar av det slaget. Vad Àr ip-numrerat och hur fungerar det? Mycket kortfattat: gatewayadress + rutt pÄ grÀnssnittet. För vÄr uppgift behöver vi: skÀra ut formaren, distribuera adresser till klienter, lÀgga till rutter till klienter genom vissa grÀnssnitt. Hur gör man allt detta? Shaper - lisg, dhcp - db2dhcp pÄ tvÄ oberoende servrar, dhcprelay körs pÄ Ätkomstservrarna, ucarp körs ocksÄ pÄ Ätkomstservrarna - för sÀkerhetskopiering. Men hur lÀgger man till rutter? Du kan lÀgga till allt i förvÀg med ett stort skript - men det Àr inte sant. SÄ vi ska göra en egenskriven krycka.
Efter en grundlig sökning pÄ Internet hittade jag ett underbart högnivÄbibliotek för C++, som lÄter dig sniffa trafik pÄ ett vackert sÀtt. Algoritmen för programmet som lÀgger till rutter Àr som följer - vi lyssnar pÄ arp-förfrÄgningar pÄ grÀnssnittet, om vi har en adress pÄ lo-grÀnssnittet pÄ servern som efterfrÄgas, sÄ lÀgger vi till en rutt genom detta grÀnssnitt och lÀgger till en statisk arp spela in till denna ip - i allmÀnhet nÄgra copy-pastes, ett litet adjektiv och du Àr klar
KĂ€llor till "routern"
#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 installationsskript
#!/bin/bash
git clone https://github.com/mfontanini/libtins.git
cd libtins
mkdir build
cd build
cmake ../
make
make install
ldconfig
Kommando för att bygga binÀren
g++ main.cpp -o arp-rt -O3 -std=c++11 -lpthread -ltinsHur startar 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 - det kommer att bygga om tabellerna baserat pÄ HUP-signalen. Varför anvÀnde du inte netlink? Det Àr bara lathet och Linux Àr ett skript pÄ ett script - sÄ allt Àr bra. NÄvÀl, rutter Àr rutter, vad hÀnder hÀrnÀst? DÀrefter mÄste vi skicka rutterna som finns pÄ den hÀr servern till grÀnsen - hÀr, pÄ grund av samma förÄldrade hÄrdvara, tog vi vÀgen för minsta motstÄnd - vi tilldelade denna uppgift till BGP.
bgp configvÀrdnamn *******
Lösenord *******
loggfilen /var/log/bgp.log
!
# AS-nummer, adresser och nÀtverk Àr fiktiva
router bgp 12345
bgp router-id 1.2.3.4
omfördela ansluten
omfördela statisk
granne 1.2.3.1 fjÀrr-som 12345
granne 1.2.3.1 nÀsta-hopp-jag
granne 1.2.3.1 ruttkarta ingen i
granne 1.2.3.1 ruttkarta export ut
!
exporttillstÄnd för Ätkomstlista 1.2.3.0/24
!
ruttkarta exporttillstÄnd 10
matcha ip-adressexport
!
ruttkarta export neka 20
LÄt oss fortsÀtta. För att servern ska kunna svara pÄ arp-förfrÄgningar mÄste du aktivera arp-proxyn.
echo 1 > /proc/sys/net/ipv4/conf/eth0.800/proxy_arp
LÄt oss gÄ vidare - ucarp. Vi skriver sjÀlva lanseringsskripten för detta mirakel.
Exempel pÄ att köra 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
ned.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Ä ett grÀnssnitt behöver det en adress. DÀrför kommer vi att lÀgga till vÀnsteradresser pÄ grÀnssnitten som vi anvÀnder - till exempel 10.255.255.1/32, 10.255.255.2/32, etc. Jag kommer inte att berÀtta hur du konfigurerar relÀet - allt Àr enkelt.
SĂ„ vad har vi? SĂ€kerhetskopiering av gateways, automatisk konfiguration av rutter, dhcp. Detta Ă€r minimiuppsĂ€ttningen - lisg sveper ocksĂ„ allt runt sig och vi har redan en shaper. Varför Ă€r allt sĂ„ lĂ„ngt och komplicerat? Ăr det inte lĂ€ttare att ta accel-pppd och anvĂ€nda pppoe helt och hĂ„llet? Nej, det Ă€r inte enklare - folk kan knappast passa en patchkabel i en router, för att inte tala om pppoe. accel-ppp Ă€r en cool grej - men det fungerade inte för oss - det finns mĂ„nga fel i koden - den smulas sönder, den skĂ€r snett, och det trĂ„kigaste Ă€r att om det ljusnade - sĂ„ mĂ„ste folk ladda om allt - telefonerna Ă€r röda - det fungerade inte alls. Vad Ă€r fördelen med att anvĂ€nda ucarp istĂ€llet för att hĂ„lla liv? Ja, i allt - det finns 100 gateways, keepalived och ett fel i konfigurationen - allt fungerar inte. 1 gateway fungerar inte med ucarp. AngĂ„ende sĂ€kerheten sĂ„ sĂ€ger de att de vĂ€nstra kommer att registrera adresser Ă„t sig sjĂ€lva och anvĂ€nda dem pĂ„ aktien - för att kontrollera detta moment stĂ€ller vi upp dhcp-snooping + source-guard + arp-inspektion pĂ„ alla switchar/olts/baser. Om klienten inte har dhpc utan statisk - Ă„tkomstlista pĂ„ porten.
Varför gjordes allt detta? För att förstöra oönskad trafik. Nu har varje switch sitt eget vlan och unknown-unicast Àr inte lÀngre skrÀmmande, eftersom den bara behöver gÄ till en port och inte till alla... Tja, biverkningarna Àr en standardiserad utrustningskonfiguration, större effektivitet vid allokering av adressutrymme.
Hur man konfigurerar lisg Àr ett separat Àmne. LÀnkar till bibliotek bifogas. Kanske kommer ovanstÄende att hjÀlpa nÄgon att nÄ sina mÄl. Version 6 implementeras inte pÄ vÄrt nÀtverk Ànnu - men det kommer att bli ett problem - det finns planer pÄ att skriva om lisg för version 6, och det kommer att bli nödvÀndigt att korrigera programmet som lÀgger till rutter.
KĂ€lla: will.com
