chaosblade-io / chaosblade

An easy to use and powerful chaos engineering experiment toolkit.(阿里巴巴开源的一款简单易用、功能强大的混沌实验注入工具)
https://chaosblade.io
Apache License 2.0
5.95k stars 946 forks source link

网络放火,包留白名单端口失效导致机器失联 #986

Open ZMbiubiubiu opened 9 months ago

ZMbiubiubiu commented 9 months ago

我想要模拟断网场景——本地端口、远程端口、目标ip均不填写。但是留有后门,让我们能够通过远程登录、联系放火的机器,进而停止掉本次故障。 为此,我做的配置如下:

blade create network loss --exclude-port {our-whitelist-port} --interface eth0 --percent 100 --timeout 1800

但是,最终却以机器失联告终,我无法通过保留的白名单端口与机器联系,无法停止故障(直到到达初始设置的超时时间)。

为了探究原因,故追踪实现逻辑。上述设置会走如下的逻辑

// file:exec/network/tc/network_tc.go
// only contains excludePort or excludeIP
if localPort == "" && remotePort == "" && destIp == "" && protocol == "" {
  // Add class rule to 1,2,3 band, exclude port and exclude ip are added to 4 band
  args := buildNetemToDefaultBandsArgs(netInterface, classRule)
  excludeFilters := buildExcludeFilterToNewBand(netInterface, excludePortRanges, excludeIp)
  response := cl.Run(ctx, "tc", args+excludeFilters)
  if !response.Success {
   stopNet(ctx, netInterface, cl)
  }
  return response
}

翻译成tc规则大致如下:

qdisc add dev eth0 root handle 1: prio bands 4 
qdisc add dev eth0 parent 1:1 netem loss 100% && \
tc qdisc add dev eth0 parent 1:2 netem loss 100% && \
tc qdisc add dev eth0 parent 1:3 netem loss 100% && \
tc qdisc add dev eth0 parent 1:4 handle 40: prio  && \
tc filter add dev eth0 parent 1: prio 4 protocol ip u32 match ip dport 2016 0xffff flowid 1:4 && \
tc filter add dev eth0 parent 1: prio 4 protocol ip u32 match ip sport 2016 0xffff flowid 1:4 && \
tc filter add dev eth0 parent 1: prio 4 protocol ip u32 match ip dport 2090 0xffff flowid 1:4 && \
tc filter add dev eth0 parent 1: prio 4 protocol ip u32 match ip sport 2090 0xffff flowid 1:4 && \
tc filter add dev eth0 parent 1: prio 4 protocol ip u32 match ip dport 8000 0xffff flowid 1:4 && \
tc filter add dev eth0 parent 1: prio 4 protocol ip u32 match ip sport 8000 0xffff flowid 1:4

根据上述规则,arp包确实是无法发出的。

我所在的网络环境,局域网的路由器每隔20min发一次ARP广播包,更新一下机器的<ip-mac>信息。设置上述规则,我的机器虽然能够收到路由器的arp广播包,但是无法回复。导致路由器认为局域网内没有我们这台机器,它接收到的外网上发往这台机器的数据包都无法到达。 最终,我们无法通过远端消除掉本次网络故障,进而物理机失联。

补充一个抓包截图: image

将目标ip为空改写为0.0.0.0/0,以此达到同样的目的。如此修改,会走不同的逻辑,最终生成的tc规则,如下:

qdisc add dev eth0 root handle 1: prio bands 4 
qdisc add dev eth0 parent 1:4 handle 40: netem loss 100% && \
tc filter add dev eth0 parent 1: prio 4 protocol ip u32 match ip dst 0.0.0.0/0  flowid 1:4 && \
tc filter add dev eth0 parent 1: prio 3 protocol ip u32 match ip dport 2016 0xffff  flowid 1:3 && \
tc filter add dev eth0 parent 1: prio 3 protocol ip u32 match ip sport 2016 0xffff  flowid 1:3

arp数据包不会匹配到丢包的规则,所以arp通信完整,机器能够随时通过留有的

我不确定这是否算是程序的bug,但我觉得,既然设置了白名单端口,但是因为禁止了arp的缘故没有达到目的。这最起码不像是一个正常的逻辑。期待你的回信。

ZMbiubiubiu commented 9 months ago

@xcaspar

spencercjh commented 4 months ago

发现了同样的问题。

ZMbiubiubiu commented 4 months ago

把目标ip写成0.0.0.0就不会将arp包过滤掉了,哈哈

spencercjh commented 4 months ago

把目标ip写成0.0.0.0就不会将arp包过滤掉了,哈哈

原因是什么呢?我看两者的区别是不写--destination-ip 的话会把 1:1,1:2,1:3 3 个队列变成 classRule 受影响队列,1:4 是白名单优先级队列。填了 destIP 的话会有相反的逻辑,1:3 是白名单优先级队列,1:4 是 classRule 受影响队列,黑/白名单 filter 各自加到各自队列。

我描述的可能会有些谬误和稚嫩。但问题是否就是因为队列顺序导致的呢?

spencercjh commented 4 months ago

我问了一下 copilot chat,它说是因为 buildNetemToDefaultBandsArgs 没有指定 protocol,导致 arp 包被定向到了 1:1,受 classRule 影响的队列中,丢包 100%的话就全部丢弃了。

ZMbiubiubiu commented 4 months ago

是这样的,兄弟。如果指定了destIp,就不会走这个逻辑。