Hello. Jadi, kami mempunyai rangkaian 5 pelanggan. Baru-baru ini, kami menghadapi situasi yang agak tidak menyenangkan: kami mempunyai Brocade RX8 di tengah rangkaian, dan ia mula menghantar banyak paket unicast yang tidak diketahui. Memandangkan rangkaian dibahagikan kepada VLAN, ini tidak menjadi masalah, tetapi terdapat VLAN khas untuk alamat putih, dsb., dan ia merentangi seluruh rangkaian. Jadi, bayangkan trafik masuk ke alamat pelanggan yang tidak dilatih oleh protokol sempadan, dan trafik ini dihantar ke pautan radio ke beberapa (atau semua) kampung. Saluran tersumbat, pelanggan marah, dan sedih...
Matlamatnya adalah untuk mengubah pepijat menjadi ciri. Saya sedang mempertimbangkan Q-in-Q dengan klien VLAN yang lengkap, tetapi perkakasan seperti P3310 berhenti menghantar DHCP apabila dot1q didayakan. Mereka juga tidak menyokong Q-in-Q terpilih, dan terdapat banyak perangkap lain di sepanjang baris tersebut. Apakah ip-unnamed dan bagaimana ia berfungsi? Ringkasnya, ia adalah alamat get laluan + laluan pada antara muka. Untuk tugas kami, kami perlu memotong pembentuk, mengedarkan alamat kepada pelanggan dan menambah laluan kepada pelanggan melalui antara muka tertentu. Bagaimana kita melakukan semua ini? Pembentuk adalah lisg, dhcp adalah db2dhcp pada dua pelayan bebas, dhcprelay berjalan pada pelayan akses, dan ucarp juga berjalan pada pelayan akses untuk sandaran. Tetapi bagaimana kita menambah laluan? Kami boleh menambah segala-galanya terlebih dahulu dengan skrip besar, tetapi itu tidak benar. Jadi kita perlu membina hack buatan sendiri.
Selepas beberapa carian internet yang meluas, saya menemui perpustakaan peringkat tinggi yang menarik untuk C++ yang membolehkan penghidu trafik yang elegan. Program penambahan laluan berfungsi seperti berikut: dengar permintaan ARP pada antara muka. Jika pelayan mempunyai alamat pada antara muka LO yang diminta, kami menambah laluan melalui antara muka itu dan menambah entri ARP statik untuk alamat IP tersebut. Pada asasnya, beberapa salinan pasta, sedikit mengutak-atik, dan anda sudah selesai.
Kod sumber untuk 'marshrutchik'
#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;
}
}skrip pemasangan libtins
#!/bin/bash
git clone https://github.com/mfontanini/libtins.git
cd libtins
mkdir build
cd build
cmake ../
make
make install
ldconfig
Perintah untuk membina binari
g++ main.cpp -o arp-rt -O3 -std=c++11 -lpthread -ltinsBagaimana untuk melancarkannya?
start-stop-daemon --start --exec /opt/ipoe/arp-routes/arp-rt -b -m -p /opt/ipoe/arp-routes/daemons/eth0.800.pid -- eth0.800
Ya, ia membina semula jadual pada isyarat HUP. Mengapa anda tidak menggunakan NetLink? Saya hanya malas, dan Linux ialah skrip dalam skrip, jadi semuanya baik-baik saja. Jadi, laluan adalah laluan, apa seterusnya? Seterusnya, kita perlu menghantar laluan yang wujud pada pelayan ini ke sempadan. Di sini, disebabkan perkakasan lapuk yang sama, kami mengambil jalan dengan rintangan paling sedikit dan menyerahkan tugas ini kepada BGP.
Konfigurasi BGPnama hos *******
kata laluan *******
fail log /var/log/bgp.log
!
# Nombor ICQ, alamat dan rangkaian adalah rekaan.
penghala bgp 12345
bgp router-id 1.2.3.4
mengagihkan semula bersambung
mengagihkan semula statik
jiran 1.2.3.1 jauh-sebagai 12345
jiran 1.2.3.1 seterusnya-hop-diri
jiran 1.2.3.1 peta laluan tiada masuk
jiran 1.2.3.1 eksport keluar peta laluan
!
permit eksport senarai akses 1.2.3.0/24
!
permit eksport peta laluan 10
sepadan dengan eksport alamat IP
!
eksport peta laluan menafikan 20
Jom sambung. Untuk membolehkan pelayan membalas permintaan ARP, anda perlu mendayakan proksi ARP.
echo 1 > /proc/sys/net/ipv4/conf/eth0.800/proxy_arp
Mari kita beralih kepada ucarp. Kami sendiri akan menulis skrip pelancaran untuk keajaiban ini.
Contoh menjalankan satu 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"
atas.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
turun.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
Untuk dhcprelay berfungsi pada antara muka, ia memerlukan alamat. Oleh itu, pada antara muka yang kami gunakan, kami akan menambah alamat sewenang-wenangnya—contohnya, 10.255.255.1/32, 10.255.255.2/32, dsb. Saya tidak akan menerangkan cara mengkonfigurasi geganti—semuanya mudah.
Jadi, apa yang kita ada? Sandaran gerbang, konfigurasi laluan automatik, DHCP. Itulah jumlah minimum—lisg turut ditambah di atasnya dan kami sudah mempunyai pembentuk. Kenapa semuanya panjang dan rumit? Bukankah lebih mudah untuk hanya menggunakan accel-pppd dan hanya menggunakan PPPOE? Tidak, ia bukan lebih mudah—orang hampir tidak boleh memasukkan tali tampal ke dalam penghala, apatah lagi PPPOE. accel-ppp memang bagus, tetapi ia tidak berfungsi untuk kami—terdapat banyak ralat dalam kod—ia ranap, konfigurasi tidak betul, dan perkara yang paling teruk ialah jika ranap, orang perlu but semula semuanya—telefon berwarna merah—ia tidak berfungsi. Apakah kelebihan menggunakan ucarp berbanding keepalived? Ini segala-galanya—terdapat 100 get laluan, keepalived dan satu ralat dalam konfigurasi—semuanya tidak berfungsi. Dengan ucarp, hanya satu pintu masuk tidak berfungsi. Mengenai keselamatan, mereka mungkin mendaftarkan alamat palsu dan menggunakannya di Sharika. Untuk mengawal ini, kami mengkonfigurasi dhcp-snooping + source-guard + arp inspection pada semua suis/OLT/pangkalan data. Jika pelanggan tidak mempunyai dhpc tetapi alamat IP statik, gunakan senarai akses pada port.
Mengapa semua ini dilakukan? Untuk menghapuskan lalu lintas yang tidak diingini. Kini setiap suis mempunyai VLAN sendiri, dan unicast yang tidak diketahui tidak lagi menjadi masalah, kerana ia hanya perlu mengakses satu port dan bukannya kesemuanya... Dan kesan sampingan termasuk konfigurasi perkakasan piawai dan kecekapan yang lebih besar dalam pengagihan ruang alamat.
Mengkonfigurasi lisg ialah topik yang berasingan. Pautan ke perpustakaan disertakan. Mungkin perkara di atas akan membantu seseorang dengan keperluan mereka sendiri. Versi 6 belum lagi dilaksanakan dalam rangkaian kami, tetapi akan ada masalah—kami merancang untuk menulis semula lisg untuk versi 6, dan kami perlu melaraskan atur cara yang menambah laluan.
Sumber: www.habr.com
