容错IPoE网络在手

你好 因此,有一个5k客户网络。 最近出现了一个不太愉快的时刻-在网络的中心,我们有了Brocade RX8,它开始发送很多未知单播数据包,因为网络被划分为多个VLAN-这部分不是问题,但是对于白色地址等而言,存在特殊的VLAN等。 并且它们在网络的各个方向上延伸。 因此,现在想象有一个进入流,该流到达了一个不以寄宿生身份就读的客户的地址,并且该流朝着通往某些村庄(等等)的无线电链路飞行-信道被阻塞-客户是邪恶的-很难过...


任务是将错误变成功能。 我以为带有完整的客户端VLAN的q-in-q方向已经开始,但是当我打开dot1q时,像P3310这样的各种铁片都停止通过DHCP,他们仍然不知道如何选择qinq和诸如此类的许多水下拐杖。 ip-unnambered是什么,它如何工作? 如果非常简短-接口上的网关地址+路由。 对于我们的任务,我们需要:切割成型机,将地址分配给客户端,通过特定的接口添加到客户端的路由。 怎么做? Shaper-lisg,dhcp-db2dhcp在两个独立的服务器上,dhcprelay在访问服务器上运行,ucarp也在访问服务器上运行-用于备份。 但是如何添加路线? 您可以预先在大型脚本中添加所有内容-但这不是事实。 因此,我们将围起来一个自制的拐杖。


在Internet上彻底翻遍之后,我发现了一个很棒的c ++高级库,它使您可以精美地嗅探流量。 添加路由的程序的算法如下-我们侦听arp接口请求,如果我们在请求的lo接口上有服务器地址,则通过该接口添加路由,并向该ip添加静态arp条目-通常,复制粘贴一些,稍加插科打and,您就完成了


“小巴”的来源
#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? 懒惰是肯定的,Linux是脚本上的脚本-因此一切都很好。 路线不错,路线下一步是什么? 接下来,我们需要将该服务器上的路由发送到边界-在这里,由于一块铁已经过时,我们以最小的阻力走了这条路-我们将此任务放在BGP上。


Bgp配置
主机名*******
密码*******
日志文件/var/log/bgp.log

#发明的地址数,地址和网络
路由器bgp 12345
bgp路由器ID 1.2.3.4
重新分配已连接
重新分配静态
邻居1.2.3.1 remote-as 12345
邻居1.2.3.1 next-hop-self
邻居1.2.3.1路由映射无
邻居1.2.3.1路由图导出

出口清单出口许可证1.2.3.0/24

路线图出口许可证10
匹配IP地址导出

路线图导出拒绝20

我们继续。 为了使服务器响应arp请求,您需要启用arp代理。



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

继续-u皮。 创造奇迹的脚本,我们自己编写


启动单个守护程序的示例
 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是一件很酷的事情-但它对我们不起作用-代码中有很多错误-它会滚动,弯曲,弯曲,可悲的是,如果它变亮了,那么人们需要重新启动所有设备-手机是红色的-一般来说,它不合适。 使用果皮而不是保持生命的好处是什么? 是的,在所有内容中-有100个网关,保持连接状态,并且配置中有一个错误-一切均不起作用。 1个网关不适用于ucarp。 关于安全性,他们说这些地址将是左撇子,并且将被用在球上-为了控制这一时刻,我们在所有交换机/ alt / base上配置了dhcp-snooping + source-guard + arp inspection。 如果客户端没有dhpc但有静态变量-端口上的acces-list。


为什么都完成了? 破坏交通我们不喜欢。 现在,每个交换机都有其自己的VLAN,并且不再担心未知单播,因为它只需要访问一个端口,而不必访问所有端口。嗯,副作用是标准化的硬件配置和高效率的地址空间分配。


如何配置lisg是一个单独的主题。 附加到库的链接。 也许有人会在执行任务中帮助上述工作。 我们尚未在网络上引入版本6-但是会出现问题-有计划很好地重写版本6的lisg,您将需要调整程序,增加路由。


Linux ISG
DB2DHCP
脂蛋白

UPD

事实证明一切都有些复杂……我不得不写一个或多或少的普通恶魔。 并且无需代理arp。 现在,我的守护程序会回答arp,它还会添加/删除子网中通往客户端的路由,我还必须学习如何使用netlink。 结果发现一个功能-当Linux识别到某个地址的arp,然后找到接口后-它使用最后一个遇到的第一个地址(有些客户不响应)使用arptables解决。

通常,链接已经有一个正常的选择-顺便说一句,在那里实现了监听路由和地址的更改并通过netlink添加路由删除(对于后者,令人头疼的是非常糟糕的)

的github

Source: https://habr.com/ru/post/zh-CN462885/


All Articles