在Docker容器中tcpdump抓包探秘Traceroute
在上一篇文章《通过Wireshark重新认识Traceroute》中,我在MAC电脑上进行抓包来对MAC上的Traceroute过程进行分析。但是MAC电脑上运行了多个应用,我在抓完报文后,使用过滤器将其他报文过滤掉了,但是也很可能把Traceroute产生的报文给删掉了。
为了打造一个纯净的Traceroute环境,我又使用容器来做一次测试。
本文记录以下内容:
- 创建一个包含traceroute、ping、whois等工具的容器,取名traceroute
- 创建一个只包含tcpdump的容器,对traceroute容器抓包
- 简略的分析抓包文件—-不是本文重点
创建Traceroute容器镜像
Dockerfile准备
如果我们执行docker run -it ubuntu,想在该容器中执行ping、traceroute命令,抱歉,找不到该命令。
1 | ➜ docker pull ubuntu |
这时候,您可以直接在容器里执行:
1 | root@631c227046f7:/# apt-get update && apt-get install traceroute iputils-ping --no-install-recommends |
当然,您也可以创建一个容器镜像,如下:
1 | mkdir traceroute |
Dockerfile 内容如下:
1 | FROM ubuntu:latest |
注:上述要安装的软件包,是我经过尝试后,一个个增加的。
最开始我只安装了traceroute,当我执行traceroute -A 8.8.8.8时,提示如下错误信息:
1
whois.radb.net/nicname: Servname not supported for ai_socktype
我想起traceroute可能需要调用whois来查询BGP AS号,于是我继续安装whois,仍然报错。—-经过验证,如果不安装whois软件包,traceroute -A 8.8.8.8 可正常工作。
只能在网上搜索答案了,果然有人遇到过类似问题:
1
2
3https://stackoverflow.com/questions/56430294/bash-script-that-uses-whois-command-gets-servname-not-supported-error-on-do
解决办法:
apt-get update && apt-get install -y --no-install-recommends netbase安装iproute2的目的是为了执行ip a, ip link 这些命令。
根据Dockerfile创建容器镜像
根据上述的Dockerfile创建容器镜像,执行命令:docker image build -t traceroute:latest . 注意末尾的小点,表示当前目录。
1 | ➜ traceroute docker image build -t traceroute:latest . |
如何抓取容器的网络报文
接下来,需要考虑的问题是在MAC电脑上如何抓取容器的网络报文呢?
Wireshark on macOS如何抓包?
我执行了docker run -it –name traceroute traceroute 启动了一个名为tracertoute的容器,打开Wireshark,哪一个接口对应的是这个容器的接口呢?
上面的接口眼花缭乱的,找不出是哪一个接口,en0和lo0上有流量,但是并不是容器连接的端口,只得寻求其他方法。
基于 Container 网络共享机制来抓包
通过搜索”how to tcpdump in docker”,找到一篇文章How to TCPdump effectively in Docker,获益匪浅。
该文章介绍了一种Docker的网络模式,container模式。
In the
--net=container:id
all traffic in/out a specific container (or group of containers) can be captured.
另一篇文章:https://www.freeaihub.com/article/container-module-in-docker-network.html
Docker网络container模式是指,创建新容器的时候,通过
--net container
参数,指定其和已经存在的某个容器共享一个 Network Namespace。如下图所示,右方黄色新创建的container,其网卡共享左边容器。因此就不会拥有自己独立的 IP,而是共享左边容器的 IP 172.17.0.2,端口范围等网络资源,两个容器的进程通过 lo 网卡设备通信。但这两个容器在其他的资源上,如文件系统、进程列表等还是隔离的。
专门创建一个安装了tcpdump的容器,对上文创建的traceroute容器进行抓包。
参考How to TCPdump effectively in Docker,在Terminal中执行以下命令,创建一个tcpdump的容器镜像
1 | docker build -t tcpdump - <<EOF |
创建过程如下:
1 | [+] Building 0.1s (6/6) FINISHED |
镜像列表:
1 | ➜ traceroute docker images |
启动traceroute容器:
1 | ➜ docker run -it --name traceroute traceroute |
启动tcpdump容器,进行抓包:
1 | ➜ ~ docker run -it --net=container:traceroute tcpdump |
在traceroute容器发起traceroute:
1 | root@fbe3eb98ae63:/# traceroute -A -q 1 -N 1 -z 500 -e 8.8.8.8 |
traceroute -A -q 1 -N 1 -z 500 -e 8.8.8.8 参数解释如下:
- -A: 向radb.net查找对应节点IP所在的AS Path信息,并将查询信息输出
- -q 1: 将缺省发送3个探测包改为1个
- -N 1: 将并发16个探测改为一次一个,以便于逐个分析
- -z 500: 表示每次等待500毫秒再发出下一个探测
- -e: 显示ICMP的扩展消息,如果有的话
按下CTRL+C,停止tcpdump容器的抓包:
1 | ➜ ~ docker run -it --net=container:traceroute tcpdump |
该容器在抓完包后自动停止,并将抓包文件存储在容器内部的/var/traceroute-ubuntu.pcapng,通过docker cp命令将抓包文件拷贝出来。
1 | ➜ ~ docker ps -a |
简略分析抓包文件
以下是本次抓取的237个报文的头36个报文,如下:
上图中,Wireshare直接分析出来Whois报文。
过程概述如下:
- 向8.8.8.8发起UDP报文,目的端口为33434,TTL设置为1
- 收到路由器的ICMP TTL超时消息,获取路由器对应的IP地址
- 尝试向DNS服务器查询路由器IP地址的反向域名解析,如果得到域名,就将其显示在Traceroute的输出结果中。
- 发起DNS查询,查询whois.radb.net域名,得到应答为198.108.0.18
- 发起TCP连接请求,与198.108.0.18建立TCP连接。
- 向whois.radb.net发起查询,询问路由器IP地址对应的AS号,并得到回应,如果是私有地址,其AS号为0。
- 重复上述第1、2、3、6步,每次将TTL加1,直至目标地址接收到探测报文,并返回ICMP Port Unreachable消息。
番外篇
ThousandEyes的介绍可参考这篇文章《在AWS上部署TE Agent并进行测试》。
ThousandEyes可将探针部署到容器中,而且安装十分简单,从ThousandEyes的Cloud & Enterprise Agents中,选择Agent Settings,再选择Enterprise Agents,再点击Add New Enterprise Agent,切换到Docker这个TAB。
将下面的文字复制粘贴到Terminal终端:
1 | docker pull thousandeyes/enterprise-agent > /dev/null 2>&1 |
安装完后,ThousandEyes即可使用该Agent进行测试了。
创建一个简单的探测如下:
在ThousandEyes的界面,可观测上述的探测结果:
时延比较稳定,维持在50ms左右。
路径可视化分析中,当我们把鼠标落在某个节点上,网页会弹出交互式的信息,包括:
- 网络前缀信息,如:124.65.192.0/18
- 运营商AS信息,如:CNCGROUP Beijing Province (AS 4808)
- 地理位置,如:Beijing, Beijing, China
- DSCP
- 平均时延,指从探测的Agent到对应节点的平均时延
ThousandEyes的探针所收集的数据是常规的网络工具都能收集到的,ThousandEyes的平台对收集到的数据进行存储、分析、交叉关联,为用户的数字体验提供全方位的洞见。
本节是突发奇想的内容,故而放到番外篇。
全文完。