前言

k8s 中对 Pod 进行抓包一文中,通过找 veth 网卡方式进行抓包。还有另一个更强大命令同样可以达到抓包的目的。

简介

nsenter是一个可以进入到其他进程的命名空间(Namespace)的程序。

比如进入到一个不含网络调试工具的容器的 Network 命名空间中,使用宿主机的进行各种调试命令甚至抓包工具对这个 Network Namespace 进行操作,从而达到对这个容器的网络调试。nsenter还可以进入 Mount、UTS、IPC、PID、User 等命名空间,以及指定根目录和工作目录。

nsenter命令位于 util-linux 软件包中。

基本用法

Usage:
 nsenter [options] [<program> [<argument>...]]

Run a program with namespaces of other processes.

Options:
 -a, --all              进入所有命名空间
 -t, --target <pid>     从目标进程获取命名空间
 -m, --mount[=<file>]   进入 mount 命名空间
 -u, --uts[=<file>]     进入 UTS 命名空间(主机名等)
 -i, --ipc[=<file>]     进入 System V IPC 命名空间
 -n, --net[=<file>]     进入 network 命名空间
 -p, --pid[=<file>]     进入 pid 命名空间
 -C, --cgroup[=<file>]  进入 cgroup 命名空间
 -U, --user[=<file>]    进入 user 命名空间
 -S, --setuid <uid>     进入命名空间时设置 uid
 -G, --setgid <gid>     进入命名空间时设置 gid
     --preserve-credentials 不更改 uid 或 gid
 -r, --root[=<dir>]     设置根目录
 -w, --wd[=<dir>]       设置工作目录
 -F, --no-fork          在执行<程序>之前不创建子进程
 -Z, --follow-context   根据目标 PID 设置 SELinux 上下文

示例用法

比如在 Kubernetes 的 default 命名空间下存在一个 busybox 容器,使用nsenter进入到 Network Namespace 中进行抓包。

pod 信息如下:

# kubectl get pods -o wide
NAME           READY   STATUS    RESTARTS   AGE   IP              NODE          NOMINATED NODE   READINESS GATES
busybox        1/1     Running   0          59s   10.104.157.89   k8s-node01    <none>           <none>

获取容器的 containerID:

# kubectl get pods busybox -o yaml | grep -i " containerid"
  - containerID: containerd://c6ebc5c1b3dae94ef81fe40607a853d8f7fd35f8db886ea7b3788a5d776c6815

找到 containerID 后,登录到容器的宿主机(k8s-node01)上,查看 busybox 容器的 PID:

# ctr -n k8s.io tasks ls | grep c6ebc5c1b3dae94ef81fe40607a853d8f7fd35f8db886ea7b3788a5d776c6815
c6ebc5c1b3dae94ef81fe40607a853d8f7fd35f8db886ea7b3788a5d776c6815    3224184    RUNNING

查看到 PID 是 3224184 后,使用nsenter进入到 busybox 的 Network 命名空间中:

nsenter -n -t 3224184

此时查看 IP 已不再是宿主机的 IP,而是 busybox 的 IP:

# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: tunl0@NONE: <NOARP> mtu 1480 qdisc noop state DOWN group default qlen 1000
    link/ipip 0.0.0.0 brd 0.0.0.0
3: eth0@if463: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1480 qdisc noqueue state UP group default qlen 1000
    link/ether 16:67:cd:1f:5b:74 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 10.104.157.89/32 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::1467:cdff:fe1f:5b74/64 scope link 
       valid_lft forever preferred_lft forever
#
# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1480
        inet 10.104.157.89  netmask 255.255.255.255  broadcast 0.0.0.0
        inet6 fe80::1467:cdff:fe1f:5b74  prefixlen 64  scopeid 0x20<link>
        ether 16:67:cd:1f:5b:74  txqueuelen 1000  (Ethernet)
        RX packets 5  bytes 446 (446.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 13  bytes 1006 (1006.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

现在就可以通过宿主机的 tcpdump 命令对这个命名空间进行抓包:

tcpdump -i eth0 -vv -w /tmp/busybox.cap

操作完后,执行exit命令就可以退出这个 Network 命名空间:

# exit
logout

退出回到宿主机的命名空间后便可以使用scp等工具把/tmp/busybox.cap 这个文件拷贝出来,利用 wireshark 分析。