docker容器抓包
当docker容器的网络模式不是--net=host(如果启动容器的时候使用host模式,那么这个容器将不会获得一个独立的Network Namespace,而是和宿主机共用一个Network Namespace。容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主
机的IP和端口)时,容器和宿主机的网络互相独立,而容器一般也不会有安装tcpdump。因此,无法直接抓取容器内的包。
一、docker 获取容器的相关信息
1、查看docker容器的网络类型
docker inspect --format='{{json .NetworkSettings.Networks}}' pgadmin {"bridge":{"IPAMConfig":null,"Links":null,"Aliases":null,"NetworkID":"f64b74cb9fa4ba72d6c041e6ccebfeaf4de028b8d665fbd353bcd489b3c092cf","EndpointID":"2fe58fec718f546b752e45e3dcca6099bb365d3b628df37b7589d6c59c785681","Gateway":"172.17.0.1","IPAddress":"172.17.0.3","IPPrefixLen":16,"IPv6Gateway":"","GlobalIPv6Address":"","GlobalIPv6PrefixLen":0,"MacAddress":"02:42:ac:11:00:03","DriverOpts":null}}
2、获取容器的pid
docker inspect --format "{{.State.Pid}}" container_id/name 获取PID
二、tcpdump和nsenter抓包
1、在docker容器内安装tcpdump工具来直接抓包
-
获取docker id
docker ps | grep xxx
-
copy tcpdump安装包和依赖包到容器内
docker cp libpcap0-0.9.8-50.10.1.x86_64.rpm container_id:/tmp/ docker cp tcpdump-3.9.8-1.21.x86_64.rpm container_id:/tmp/
-
进入容器 安装tcpdump后进行抓包
docker exec -it -u root container_id bash rpm -ivh *.rpm
也可直接使用这个tcpdump文件(已编译好 免安装 可直接使用)
docker cp /file/to/path/tcpdump container_id:/tmp/ sh /tmp/tcpdump -i any -s 0 host x.x.x.x
2、使用宿主机上的tcpdump工具对容器进程抓包
如果宿主机上已安装了tcpdump抓包工具,那我们就可以通过宿主机上的nsenter工具来对docker容器进行抓包。
nsenter 包含在绝大部分 Linux 发行版预置的 util-linux 工具包中。
使用它可以进入指定进程的关联命名空间。包括文件命名空间(mount namespace)、主机名命名空间(UTS namespace)、IPC 命名空间(IPC namespace)、网络命名空间
(network namespace)、进程命名空间(pid namespace)和用户命名空间(user namespace)。
what is nsenter
It is a small tool allowing to enter into namespaces. Technically, it can enter existing namespaces, or spawn a process into a new set of namespaces. "What are those namespaces you're blabbering about?" We are talking about container namespaces. nsenter can do many useful things, but the main reason why I'm so excited about it is because it lets you enter into a Docker container.
参数
nsenter --help 用法: nsenter [options] <program> [<argument>...] Run a program with namespaces of other processes. 选项: -t, --target <pid> 要获取名字空间的目标进程 -m, --mount[=<file>] enter mount namespace -u, --uts[=<file>] enter UTS namespace (hostname etc) -i, --ipc[=<file>] enter System V IPC namespace -n, --net[=<file>] enter network namespace -p, --pid[=<file>] enter pid namespace -U, --user[=<file>] enter user namespace -S, --setuid <uid> set uid in entered namespace -G, --setgid <gid> set gid in entered namespace --preserve-credentials do not touch uids or gids -r, --root[=<dir>] set the root directory -w, --wd[=<dir>] set the working directory -F, --no-fork 执行 <程序> 前不 fork -Z, --follow-context set SELinux context according to --target PID -h, --help 显示此帮助并退出 -V, --version 输出版本信息并退出 更多信息请参阅 nsenter(1)。
如何使用nsenter来抓包
-
获取容器进程id,即PID
docker ps | grep xxx 获取容器id/name docker inspect --format "{{.State.Pid}}" container_id/name 获取PID
-
使用nsenter切换网络命名空间
nsenter -n -t container_id/name 可在切换前后执行ifconfig来对比变化
现在就已进入容器的网络命名空间,就可以使用宿主机上的tcpdump来对容器进行抓包了
三、通过iflink找到网卡对应关系
1. 在宿主机上执行命令ip link
ip link 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 2: ens33: <BROADCAST,MULTICAST,SLAVE,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master bond0 state UP mode DEFAULT group default qlen 1000 link/ether 00:0c:29:c3:35:79 brd ff:ff:ff:ff:ff:ff 3: ens37: <BROADCAST,MULTICAST,SLAVE,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast master bond0 state UP mode DEFAULT group default qlen 1000 link/ether 00:0c:29:c3:35:79 brd ff:ff:ff:ff:ff:ff 4: bond0: <BROADCAST,MULTICAST,MASTER,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000 link/ether 00:0c:29:c3:35:79 brd ff:ff:ff:ff:ff:ff 5: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default link/ether 02:42:f7:6d:1c:51 brd ff:ff:ff:ff:ff:ff 7: veth5092b87@if6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP mode DEFAULT group default link/ether 32:79:aa:d3:7f:2c brd ff:ff:ff:ff:ff:ff link-netnsid 0 9: veth34be698@if8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP mode DEFAULT group default link/ether ae:d6:54:b3:50:93 brd ff:ff:ff:ff:ff:ff link-netnsid 1
2、在容器内查看iflink文件
docker exec -it pgadmin sh /pgadmin4 $ cat /sys/class/net/eth0/iflink 9 或者通过ethtool来查看 在容器中执行:ethtool -S eth0 root@336043b07211:/# ethtool -S eth0 NIC statistics: peer_ifindex: 9
这样就可以确定:
pgadmin这个容器在物理机上对应的veth pair是veth34be698@if8
(9对应宿主机9:)
容器外查看 ps -ef 查看端口
ps -ef | grep 5080 root 2053 1356 0 17:05 ? 00:00:00 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 5080 -container-ip 172.17.0.3 -container-port 80 root 2059 1356 0 17:05 ? 00:00:00 /usr/bin/docker-proxy -proto tcp -host-ip :: -host-port 5080 -container-ip 172.17.0.3 -container-port 80 root 2348 1913 0 17:24 pts/1 00:00:00 grep --color=auto 5080
容器内通过netstat -r 查看连接情况
/pgadmin4 $ netstat –r Active Internet connections (w/o servers) Proto Recv-Q Send-Q Local Address Foreign Address State tcp 0 0 5b7f4fff015b:32830 192.168.40.132:postgresql ESTABLISHED tcp 0 0 5b7f4fff015b:32834 192.168.40.132:postgresql ESTABLISHED tcp 0 0 5b7f4fff015b:32838 192.168.40.132:postgresql ESTABLISHED tcp 0 0 5b7f4fff015b:32842 192.168.40.132:postgresql ESTABLISHED tcp 0 0 5b7f4fff015b:http ::ffff:192.168.40.200:6165 TIME_WAIT tcp 0 0 5b7f4fff015b:http ::ffff:192.168.40.200:6461 ESTABLISHED Active UNIX domain sockets (w/o servers) Proto RefCnt Flags Type State I-Node Path
tcpdump -i any
tcpdump -i any tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes 22:01:27.432382 IP 192.168.40.200.10859 > root.http: Flags [P.], seq 2426513533:2426514255, ack 2732166892, win 4106, length 722: HTTP: GET /dashboard/dashboard_stats/1/16384?chart_names=session_stats,tps_stats,ti_stats,to_stats,bio_stats HTTP/1.1 22:01:27.433384 IP root.49538 > public1.114dns.com.domain: 16551+ PTR? 3.0.17.172.in-addr.arpa. (41) 22:01:27.444500 IP root.32834 > 192.168.40.132.postgres: Flags [P.], seq 1629397589:1629399809, ack 3287353308, win 1424, options [nop,nop,TS val 17857857 ecr 17856872], length 2220 22:01:27.444595 IP 192.168.40.132.postgres > root.32834: Flags [.], ack 2220, win 1432, options [nop,nop,TS val 17857857 ecr 17857857], length 0 22:01:27.457255 IP 192.168.40.132.postgres > root.32834: Flags [P.], seq 1:394, ack 2220, win 1432, options [nop,nop,TS val 17857870 ecr 17857857], length 393 22:01:27.457263 IP root.32834 > 192.168.40.132.postgres: Flags [.], ack 394, win 1424, options [nop,nop,TS val 17857870 ecr 17857870], length 0 22:01:27.458350 IP public1.114dns.com.domain > root.49538: 16551 NXDomain 0/1/0 (118) 22:01:27.458360 IP root.http > 192.168.40.200.10859: Flags [P.], seq 1:419, ack 722, win 1432, length 418: HTTP: HTTP/1.1 200 OK 22:01:27.458485 IP root.http > 192.168.40.200.10859: Flags [P.], seq 419:673, ack 722, win 1432, length 254: HTTP 22:01:27.458568 IP 192.168.40.200.10859 > root.http: Flags [.], ack 673, win 4103, length 0 22:01:27.459127 IP root.33689 > public1.114dns.com.domain: 20618+ PTR? 200.40.168.192.in-addr.arpa. (45) 22:01:27.487509 IP public1.114dns.com.domain > root.33689: 20618 NXDomain* 0/1/0 (80) 22:01:27.487691 IP root.46946 > public1.114dns.com.domain: 55017+ PTR? 114.114.114.114.in-addr.arpa. (46) 22:01:27.514467 IP public1.114dns.com.domain > root.46946: 55017 1/0/0 PTR public1.114dns.com. (78) 22:01:27.514595 IP root.49870 > public1.114dns.com.domain: 5779+ PTR? 132.40.168.192.in-addr.arpa. (45) 22:01:27.551436 IP public1.114dns.com.domain > root.49870: 5779 NXDomain 0/1/0 (122) 22:01:28.442007 IP 192.168.40.200.10859 > root.http: Flags [P.], seq 722:1444, ack 673, win 4103, length 722: HTTP: GET /dashboard/dashboard_stats/1/16384?chart_names=session_stats,tps_stats,ti_stats,to_stats,bio_stats HTTP/1.1
tcpdump -i docker0 -vvv -w ip.txt
将抓包结果放到文本中