网络包排错指南-类linux 平台

发布时间:2020-06-04 19:16:11 作者:yoke88
来源:网络 阅读:8349

网络包排错指南-类linux 平台

背景信息

最近一直在测试k8s,如果你了解或者解接触过docker,那你一定知道docker 相关的网络很大部分在桥接、路由、Iptables 上做文章。如果你凑巧接触过k8s,并且了解其后面的原理,那你一定知道kube-proxy 把iptables 玩的简直要飞起来。当然你可能会想到一些排错工具,比如我之前常用的抓包工具,或者路由跟踪工具,但这些工具在目前这样复杂的环境下,是不太趁手的,特别是包在本机的多个网卡或者虚拟网卡里转来转去,还有很多个iptables策略,路由等让包在内核空间中转来转去。抓包工具抓不到这些信息,traceroute 跟踪路由时你会发现你需要跟踪一个src,dst 还有port的包的路由信息是没有法达成的。

这里介绍一些新的排错工具:

Iptables 跟踪排错

说到Iptables 排错,我不得不拿出这张逻辑非常清晰的图出来,建议Iptables 排错时常常对照下这张图,看下数据包的传递路径。在我之前的IPtables 知识范畴里,我以为它多个表之间传递时是没有路由选择这个操作的,结果实际的排错加上这样图来看。原来在不同的table 之间可能经过Routing decision.

请参考我的这篇K8s Issue 中的排错过程。

网络包排错指南-类linux 平台

然后我不得不说下Iptables 的TRACE Target,没有了解到这个Target之前,我用LOG Target,结果发现要写好多个IPtables你也不一定能跟踪的全每个包经过的策略,以及策略如何处理的。

我目前演示的在ubuntu 上面:

######### 检查是TRACE相关的mod 是否载入
modprobe nf_log_ipv4

########## TRACE Target 只能应用于RAW Table

sudo iptables -t raw -I PREROUTING -p tcp -m tcp --dport 8081   -j TRACE
sudo iptables -t raw -I OUTPUT -p tcp -m tcp --dport 8081   -j TRACE

########### grep TRACE in /var/log/kern.log

grep TRACE /var/log/kern.log

ubuntu@ceph4:~$ grep TRACE /var/log/kern.log|grep 2213090174
May  8 16:30:29 ceph4 kernel: [324781.838361] TRACE: raw:OUTPUT:policy:2 IN= OUT=enp3s0 SRC=192.168.235.13 DST=10.43.206.251 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=57266 DF PROTO=TCP SPT=18130 DPT=8081 SEQ=2213090174 ACK=0 WINDOW=29200 RES=0x00 SYN URGP=0 OPT (020405B40402080A04D5CCCC0000000001030307) UID=1000 GID=1000
May  8 16:30:29 ceph4 kernel: [324781.838389] TRACE: nat:OUTPUT:rule:1 IN= OUT=enp3s0 SRC=192.168.235.13 DST=10.43.206.251 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=57266 DF PROTO=TCP SPT=18130 DPT=8081 SEQ=2213090174 ACK=0 WINDOW=29200 RES=0x00 SYN URGP=0 OPT (020405B40402080A04D5CCCC0000000001030307) UID=1000 GID=1000
May  8 16:30:29 ceph4 kernel: [324781.838417] TRACE: nat:KUBE-SERVICES:rule:9 IN= OUT=enp3s0 SRC=192.168.235.13 DST=10.43.206.251 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=57266 DF PROTO=TCP SPT=18130 DPT=8081 SEQ=2213090174 ACK=0 WINDOW=29200 RES=0x00 SYN URGP=0 OPT (020405B40402080A04D5CCCC0000000001030307) UID=1000 GID=1000
May  8 16:30:29 ceph4 kernel: [324781.838439] TRACE: nat:KUBE-SVC-ZP4VKUJYTBCROZYY:rule:1 IN= OUT=enp3s0 SRC=192.168.235.13 DST=10.43.206.251 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=57266 DF PROTO=TCP SPT=18130 DPT=8081 SEQ=2213090174 ACK=0 WINDOW=29200 RES=0x00 SYN URGP=0 OPT (020405B40402080A04D5CCCC0000000001030307) UID=1000 GID=1000
May  8 16:30:29 ceph4 kernel: [324781.838454] TRACE: nat:KUBE-SEP-OR6JECCPPINGGGRC:rule:2 IN= OUT=enp3s0 SRC=192.168.235.13 DST=10.43.206.251 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=57266 DF PROTO=TCP SPT=18130 DPT=8081 SEQ=2213090174 ACK=0 WINDOW=29200 RES=0x00 SYN URGP=0 OPT (020405B40402080A04D5CCCC0000000001030307) UID=1000 GID=1000
May  8 16:30:29 ceph4 kernel: [324781.838479] TRACE: filter:OUTPUT:rule:1 IN= OUT=enp3s0 SRC=192.168.235.13 DST=10.0.1.12 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=57266 DF PROTO=TCP SPT=18130 DPT=8081 SEQ=2213090174 ACK=0 WINDOW=29200 RES=0x00 SYN URGP=0 OPT (020405B40402080A04D5CCCC0000000001030307) UID=1000 GID=1000
May  8 16:30:29 ceph4 kernel: [324781.838493] TRACE: filter:KUBE-SERVICES:return:2 IN= OUT=enp3s0 SRC=192.168.235.13 DST=10.0.1.12 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=57266 DF PROTO=TCP SPT=18130 DPT=8081 SEQ=2213090174 ACK=0 WINDOW=29200 RES=0x00 SYN URGP=0 OPT (020405B40402080A04D5CCCC0000000001030307) UID=1000 GID=1000
May  8 16:30:29 ceph4 kernel: [324781.838505] TRACE: filter:OUTPUT:rule:2 IN= OUT=enp3s0 SRC=192.168.235.13 DST=10.0.1.12 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=57266 DF PROTO=TCP SPT=18130 DPT=8081 SEQ=2213090174 ACK=0 WINDOW=29200 RES=0x00 SYN URGP=0 OPT (020405B40402080A04D5CCCC0000000001030307) UID=1000 GID=1000
May  8 16:30:29 ceph4 kernel: [324781.838518] TRACE: filter:KUBE-FIREWALL:return:2 IN= OUT=enp3s0 SRC=192.168.235.13 DST=10.0.1.12 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=57266 DF PROTO=TCP SPT=18130 DPT=8081 SEQ=2213090174 ACK=0 WINDOW=29200 RES=0x00 SYN URGP=0 OPT (020405B40402080A04D5CCCC0000000001030307) UID=1000 GID=1000
May  8 16:30:29 ceph4 kernel: [324781.838531] TRACE: filter:OUTPUT:rule:4 IN= OUT=enp3s0 SRC=192.168.235.13 DST=10.0.1.12 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=57266 DF PROTO=TCP SPT=18130 DPT=8081 SEQ=2213090174 ACK=0 WINDOW=29200 RES=0x00 SYN URGP=0 OPT (020405B40402080A04D5CCCC0000000001030307) UID=1000 GID=1000
May  8 16:30:29 ceph4 kernel: [324781.838551] TRACE: filter:OUTPUT:policy:6 IN= OUT=enp3s0 SRC=192.168.235.13 DST=10.0.1.12 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=57266 DF PROTO=TCP SPT=18130 DPT=8081 SEQ=2213090174 ACK=0 WINDOW=29200 RES=0x00 SYN URGP=0 OPT (020405B40402080A04D5CCCC0000000001030307) UID=1000 GID=1000
May  8 16:30:29 ceph4 kernel: [324781.838564] TRACE: nat:POSTROUTING:rule:1 IN= OUT=enp5s0 SRC=192.168.235.13 DST=10.0.1.12 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=57266 DF PROTO=TCP SPT=18130 DPT=8081 SEQ=2213090174 ACK=0 WINDOW=29200 RES=0x00 SYN URGP=0 OPT (020405B40402080A04D5CCCC0000000001030307) UID=1000 GID=1000
May  8 16:30:29 ceph4 kernel: [324781.838577] TRACE: nat:KUBE-POSTROUTING:return:2 IN= OUT=enp5s0 SRC=192.168.235.13 DST=10.0.1.12 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=57266 DF PROTO=TCP SPT=18130 DPT=8081 SEQ=2213090174 ACK=0 WINDOW=29200 RES=0x00 SYN URGP=0 OPT (020405B40402080A04D5CCCC0000000001030307) UID=1000 GID=1000
May  8 16:30:29 ceph4 kernel: [324781.838589] TRACE: nat:POSTROUTING:rule:8 IN= OUT=enp5s0 SRC=192.168.235.13 DST=10.0.1.12 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=57266 DF PROTO=TCP SPT=18130 DPT=8081 SEQ=2213090174 ACK=0 WINDOW=29200 RES=0x00 SYN URGP=0 OPT (020405B40402080A04D5CCCC0000000001030307) UID=1000 GID=1000
May  8 16:30:29 ceph4 kernel: [324781.838609] TRACE: nat:POSTROUTING:policy:10 IN= OUT=enp5s0 SRC=192.168.235.13 DST=10.0.1.12 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=57266 DF PROTO=TCP SPT=18130 DPT=8081 SEQ=2213090174 ACK=0 WINDOW=29200 RES=0x00 SYN URGP=0 OPT (020405B40402080A04D5CCCC0000000001030307) UID=1000 GID=1000

解释一下,每个trace 会记录表名字比如raw:OUTPUT:policy:2或者nat:OUTPUT:rule:1,表明为Table:Chain:显式策略为Rule,Table默认策略为Policy:rule 编号。我一般用grep ID=57266 这种方法去过滤同一个包。

以上都抓取的iptables 的日志,如果中间遇到路由问题呢,比如我这个问题包日志如下,包到了nat:PREROUTING:policy:3 就没有下文了,本来应该继续进mangle:INPUT 或者filter:INPUT,结果都没有,参考以上数据包图,可以发现这里有个route decision的过程。那么接下来我看看如果排除本地路由的问题。

ubuntu@ceph3:~$ grep TRACE /var/log/kern.log|grep 1726587944
May  8 15:51:07 ceph3 kernel: [309854.514762] TRACE: raw:PREROUTING:policy:2 IN=enp5s0 OUT= MAC=00:23:7d:5b:96:ec:00:21:5a:ef:39:fe:08:00 SRC=192.168.235.13 DST=10.0.1.12 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=28265 DF PROTO=TCP SPT=14024 DPT=8081 SEQ=1726587944 ACK=0 WINDOW=29200 RES=0x00 SYN URGP=0 OPT (020405B40402080A04CCCA410000000001030307)
May  8 15:51:07 ceph3 kernel: [309854.514799] TRACE: nat:PREROUTING:rule:1 IN=enp5s0 OUT= MAC=00:23:7d:5b:96:ec:00:21:5a:ef:39:fe:08:00 SRC=192.168.235.13 DST=10.0.1.12 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=28265 DF PROTO=TCP SPT=14024 DPT=8081 SEQ=1726587944 ACK=0 WINDOW=29200 RES=0x00 SYN URGP=0 OPT (020405B40402080A04CCCA410000000001030307)
May  8 15:51:07 ceph3 kernel: [309854.514841] TRACE: nat:KUBE-SERVICES:rule:13 IN=enp5s0 OUT= MAC=00:23:7d:5b:96:ec:00:21:5a:ef:39:fe:08:00 SRC=192.168.235.13 DST=10.0.1.12 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=28265 DF PROTO=TCP SPT=14024 DPT=8081 SEQ=1726587944 ACK=0 WINDOW=29200 RES=0x00 SYN URGP=0 OPT (020405B40402080A04CCCA410000000001030307)
May  8 15:51:07 ceph3 kernel: [309854.514861] TRACE: nat:KUBE-NODEPORTS:return:1 IN=enp5s0 OUT= MAC=00:23:7d:5b:96:ec:00:21:5a:ef:39:fe:08:00 SRC=192.168.235.13 DST=10.0.1.12 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=28265 DF PROTO=TCP SPT=14024 DPT=8081 SEQ=1726587944 ACK=0 WINDOW=29200 RES=0x00 SYN URGP=0 OPT (020405B40402080A04CCCA410000000001030307)
May  8 15:51:07 ceph3 kernel: [309854.514881] TRACE: nat:KUBE-SERVICES:return:14 IN=enp5s0 OUT= MAC=00:23:7d:5b:96:ec:00:21:5a:ef:39:fe:08:00 SRC=192.168.235.13 DST=10.0.1.12 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=28265 DF PROTO=TCP SPT=14024 DPT=8081 SEQ=1726587944 ACK=0 WINDOW=29200 RES=0x00 SYN URGP=0 OPT (020405B40402080A04CCCA410000000001030307)
May  8 15:51:07 ceph3 kernel: [309854.514897] TRACE: nat:PREROUTING:rule:2 IN=enp5s0 OUT= MAC=00:23:7d:5b:96:ec:00:21:5a:ef:39:fe:08:00 SRC=192.168.235.13 DST=10.0.1.12 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=28265 DF PROTO=TCP SPT=14024 DPT=8081 SEQ=1726587944 ACK=0 WINDOW=29200 RES=0x00 SYN URGP=0 OPT (020405B40402080A04CCCA410000000001030307)
May  8 15:51:07 ceph3 kernel: [309854.514914] TRACE: nat:DOCKER:return:2 IN=enp5s0 OUT= MAC=00:23:7d:5b:96:ec:00:21:5a:ef:39:fe:08:00 SRC=192.168.235.13 DST=10.0.1.12 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=28265 DF PROTO=TCP SPT=14024 DPT=8081 SEQ=1726587944 ACK=0 WINDOW=29200 RES=0x00 SYN URGP=0 OPT (020405B40402080A04CCCA410000000001030307)
May  8 15:51:07 ceph3 kernel: [309854.514930] TRACE: nat:PREROUTING:policy:3 IN=enp5s0 OUT= MAC=00:23:7d:5b:96:ec:00:21:5a:ef:39:fe:08:00 SRC=192.168.235.13 DST=10.0.1.12 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=28265 DF PROTO=TCP SPT=14024 DPT=8081 SEQ=1726587944 ACK=0 WINDOW=29200 RES=0x00 SYN URGP=0 OPT (020405B40402080A04CCCA410000000001030307)

本地路由 排错

一般情况下本地路由并没有多少条,所以一般传统方法是逐条对下路由条目,然后人工判断最终会丢到那里,如果没有发现路由能处理,就会被DROP了。新版本的linux 上用ip rule 和ip route 显示和操作路由表,ip 属于iproute2 包中的套件,后面大致看了下文档,才发现有种还有这种操作的的感觉。

######## ip rule to list ip route tables
ubuntu@ceph3:~$ ip rule
0:      from all lookup local
32766:  from all lookup main
32767:  from all lookup default

######## 这里有三个table ,先查0编号的local,然后查32766的main,然后查32767的default
######## 列出每个table 中的rule
ubuntu@ceph3:~$ ip route list table local
broadcast 10.0.1.0 dev enp5s0  proto kernel  scope link  src 10.0.1.12
local 10.0.1.12 dev enp5s0  proto kernel  scope host  src 10.0.1.12
broadcast 10.0.1.255 dev enp5s0  proto kernel  scope link  src 10.0.1.12
local 10.42.2.0 dev flannel.1  proto kernel  scope host  src 10.42.2.0
broadcast 10.42.2.0 dev cni0  proto kernel  scope link  src 10.42.2.1
local 10.42.2.1 dev cni0  proto kernel  scope host  src 10.42.2.1
broadcast 10.42.2.255 dev cni0  proto kernel  scope link  src 10.42.2.1
broadcast 127.0.0.0 dev lo  proto kernel  scope link  src 127.0.0.1
local 127.0.0.0/8 dev lo  proto kernel  scope host  src 127.0.0.1
local 127.0.0.1 dev lo  proto kernel  scope host  src 127.0.0.1
broadcast 127.255.255.255 dev lo  proto kernel  scope link  src 127.0.0.1
broadcast 172.17.0.0 dev docker0  proto kernel  scope link  src 172.17.0.1 linkdown
local 172.17.0.1 dev docker0  proto kernel  scope host  src 172.17.0.1
broadcast 172.17.255.255 dev docker0  proto kernel  scope link  src 172.17.0.1 linkdown
broadcast 192.168.235.0 dev enp3s0  proto kernel  scope link  src 192.168.235.12
local 192.168.235.12 dev enp3s0  proto kernel  scope host  src 192.168.235.12
broadcast 192.168.235.255 dev enp3s0  proto kernel  scope link  src 192.168.235.12

ubuntu@ceph3:~$ ip route list table main
default via 192.168.235.2 dev enp3s0 onlink
10.0.1.0/24 dev enp5s0  proto kernel  scope link  src 10.0.1.12
10.42.0.0/24 via 10.42.0.0 dev flannel.1 onlink
10.42.1.0/24 via 10.42.1.0 dev flannel.1 onlink
10.42.2.0/24 dev cni0  proto kernel  scope link  src 10.42.2.1
10.42.3.0/24 via 10.42.3.0 dev flannel.1 onlink
10.42.4.0/24 via 10.42.4.0 dev flannel.1 onlink
172.17.0.0/16 dev docker0  proto kernel  scope link  src 172.17.0.1 linkdown
192.168.235.0/24 dev enp3s0  proto kernel  scope link  src 192.168.235.12

ubuntu@ceph3:~$ ip route list table default
ubuntu@ceph3:~$

前面说了一般方法是逐条对路由来看路由条目对特定的包是否有规则对应,但这种方法需要你对路由规则非常熟悉,而且人工容易判断漏。那么这里介绍一个测试路由规则的命令ip route get

###### 偷懒摘抄下man 8 ip 里的说明
ip route get - get a single route

this command gets a single route to a destination and prints its contents exactly as the kernel sees it.

to ADDRESS (default) #the destination address.
from ADDRESS #the source address.
tos TOS
dsfield TOS # TOS=the Type Of Service.
iif NAME #the device from which this packet is expected to arrive.
oif NAME #force the output device on which this packet will be routed.

以上面iptables 跟踪部分的这条日志为例

May  8 15:51:07 ceph3 kernel: [309854.514930] TRACE: nat:PREROUTING:policy:3 IN=enp5s0 OUT= MAC=00:23:7d:5b:96:ec:00:21:5a:ef:39:fe:08:00 SRC=192.168.235.13 DST=10.0.1.12 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=28265 DF PROTO=TCP SPT=14024 DPT=8081 SEQ=1726587944 ACK=0 WINDOW=29200 RES=0x00 SYN URGP=0 OPT (020405B40402080A04CCCA410000000001030307)

假设我们要判断这个包的路由选择会匹配哪条路由,我们可以下面命令来看,初一看结果会第一反应是不是我命令语法有问题报错呢?来看看我当时参考了rp_filter_kernel_setting后的运行结果

ubuntu@ceph3:~$ ip route get from 192.168.235.13 to 10.0.1.12 iif enp5s0 tos 0x00
RTNETLINK answers: Invalid cross-device link

######### change rp_filter kernel setting
ubuntu@ceph3:~$ sudo bash
root@ceph3:~# echo 2 > /proc/sys/net/ipv4/conf/default/rp_filter
root@ceph3:~# echo 2 > /proc/sys/net/ipv4/conf/all/rp_filter

######### Ok 在更改rp_filter 内核参数后,我们的同样的命令有匹配结果了。

root@ceph3:~# ip route get from 192.168.235.13 to 10.0.1.12 iif enp5s0 tos 0x00
local 10.0.1.12 from 192.168.235.13 dev lo
    cache <local>  iif enp5s0
root@ceph3:~#

到这里我想你可以再尝试一些其他的ip route get 命令来连连手,看看输出结果,比如

ubuntu@ceph3:~$ ip route get from 172.18.0.3 to 10.0.1.12
RTNETLINK answers: Invalid argument # 本机根本没法从172.18.0.3 路由到10.0.1.12
ubuntu@ceph3:~$ ip route get from 192.168.235.3 to 10.0.1.12
RTNETLINK answers: Invalid argument # 本机也没法从192.168.235.3 路由到10.0.1.12
ubuntu@ceph3:~$ ip route get from 192.168.235.12 to 10.0.1.12 #从本地的一个卡为192.168.235.12 可以从lo 上路由到10.0.1.12
local 10.0.1.12 from 192.168.235.12 dev lo
    cache <local>
ubuntu@ceph3:~$ ip route get from 192.168.235.12 to 10.0.1.13 #从本地的一个卡为192.168.235.12 可以从enp5s0 上路由到10.0.1.13(另外一个主机)
10.0.1.13 from 192.168.235.12 dev enp5s0
    cache

最后我们详细解读下路由规则的显示意思,具体可以参考【iproute2 doc】

以这条比较长的broadcast 10.0.1.0 dev enp5s0 proto kernel scope link src 10.0.1.12为例

一些网络相关的内核参数设置

OK,快到最后不得不提下linux 的内核参数设置,这些参数能在内核中可以设置,往往是提炼了又提炼的精华部分。那么问题来了?

几个重要的内核参数

其他补充

推荐阅读:
  1. Office 365 排错:Exchange Online Active Sync异常排错方法
  2. VMware虚拟化平台排错--存储

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

iptables troubleshotting route

上一篇:conftest.py文件的使用方法

下一篇:walle出现out of pty devices错误的原因和解决方法

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》