如何在容器中進行抓包?
nsenter 命令是一個可以在指定程式的命令空間下執行指定程式的命令。它位於 util-linux 包中。
用途
一個最典型的用途就是進入容器的網路命令空間。相當多的容器為了輕量級,是不包含較為基礎的命令的,比如說
ip address
,
ping
,
telnet
,
ss
,
tcpdump
等等命令,這就給除錯容器網路帶來相當大的困擾:只能透過
docker inspect ContainerID
命令獲取到容器 IP,以及無法測試和其他網路的連通性。這時就可以使用 nsenter 命令僅進入該容器的網路名稱空間,使用宿主機的命令除錯容器網路。
此外,nsenter 也可以進入
mnt
,
uts
,
ipc
,
pid
,
user
命令空間,以及指定根目錄和工作目錄。
使用
首先看下 nsenter 命令的語法:
nsenter [options] [program [arguments]]
options:
-t, --target pid:指定被進入名稱空間的目標程式的pid
-m, --mount[=file]:進入mount命令空間。如果指定了file,則進入file的命令空間
-u, --uts[=file]:進入uts命令空間。如果指定了file,則進入file的命令空間
-i, --ipc[=file]:進入ipc命令空間。如果指定了file,則進入file的命令空間
-n, --net[=file]:進入net命令空間。如果指定了file,則進入file的命令空間
-p, --pid[=file]:進入pid命令空間。如果指定了file,則進入file的命令空間
-U, --user[=file]:進入user命令空間。如果指定了file,則進入file的命令空間
-G, --setgid gid:設定執行程式的gid
-S, --setuid uid:設定執行程式的uid
-r, --root[=directory]:設定根目錄
-w, --wd[=directory]:設定工作目錄
如果沒有給出program,則預設執行$SHELL。
示例:
執行一個 nginx 容器,檢視該容器的 pid:
[root@staight ~]# docker inspect -f {{.State.Pid}} nginx5645
然後,使用 nsenter 命令進入該容器的網路命令空間:
[root@staight ~]# nsenter -n -t5645[root@staight ~]# ip addr1: 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 forever18: eth0@if19: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0 valid_lft forever preferred_lft forever
進入成功~
在 Kubernetes 中,在得到容器 pid 之前還需獲取容器的 ID,可以使用如下命令獲取:
[root@node1 test]# kubectl get pod test -oyaml|grep containerID - containerID: docker://cf0873782d587dbca6aa32f49605229da3748600a9926e85b36916141597ec85
或者更為精確地獲取 containerID :
[root@node1 test]# kubectl get pod test -o template --template='{{range .status.containerStatuses}}{{.containerID}}{{end}}'docker://cf0873782d587dbca6aa32f49605229da3748600a9926e85b36916141597ec85
原理
namespace
Linux在不斷的新增名稱空間,目前有:
-
mount : 掛載名稱空間,使程式有一個獨立的掛載檔案系統,始於Linux 2.4.19
-
ipc : ipc名稱空間,使程式有一個獨立的ipc,包括訊息佇列,共享記憶體和訊號量,始於Linux 2.6.19
-
uts : uts名稱空間,使程式有一個獨立的hostname和domainname,始於Linux 2.6.19
-
net : network命令空間,使程式有一個獨立的網路棧,始於Linux 2.6.24
-
pid : pid名稱空間,使程式有一個獨立的pid空間,始於Linux 2.6.24
-
user : user名稱空間,是程式有一個獨立的user空間,始於Linux 2.6.23,結束於Linux 3.8
-
cgroup : cgroup名稱空間,使程式有一個獨立的cgroup控制組,始於Linux 4.6
[root@staight ns]# pwd/proc/1/ns[root@staight ns]# lltotal 0lrwxrwxrwx 1 root root 0 Sep 23 19:53 ipc -> ipc:[4026531839]lrwxrwxrwx 1 root root 0 Sep 23 19:53 mnt -> mnt:[4026531840]lrwxrwxrwx 1 root root 0 Sep 23 19:53 net -> net:[4026531956]lrwxrwxrwx 1 root root 0 Sep 23 19:53 pid -> pid:[4026531836]lrwxrwxrwx 1 root root 0 Sep 23 19:53 user -> user:[4026531837]lrwxrwxrwx 1 root root 0 Sep 23 19:53 uts -> uts:[4026531838]
clone
clone 和 fork 比較類似,但更為精細化,比如說使用 clone 建立出的子程式可以共享父程式的虛擬地址空間,檔案描述符表,訊號處理表等等。不過這裡要強調的是,clone 函式還能為新程式指定名稱空間。
#define _GNU_SOURCE
#include <sched.h>
int clone(int (*fn)(void *), void *child_stack,
int flags, void *arg, ...
/* pid_t *ptid, void *newtls, pid_t *ctid */ );
其中 flags 即可指定名稱空間,包括:
-
CLONE_NEWCGROUP: cgroup
-
CLONE_NEWIPC: ipc
-
CLONE_NEWNET: net
-
CLONE_NEWNS: mount
-
CLONE_NEWPID: pid
-
CLONE_NEWUSER: user
-
CLONE_NEWUTS: uts
使用示例:
pid = clone(childFunc, stackTop, CLONE_NEWUTS | SIGCHLD, argv[1]);
setns
# define _GNU_SOURCE /* See feature_test_macros(7) */
# include <sched.h>
int setns ( int fd, int nstype);
fd引數是一個指向一個名稱空間的檔案描述符,位於/proc/PID/ns/目錄。
nstype指定了允許進入的名稱空間,一般可設定為 0,表示允許進入所有名稱空間。
因此,往往該函式的用法為:
-
呼叫setns函式: 指定該執行緒的名稱空間。
-
呼叫execvp函式: 執行指定路徑的程式,建立子程式並替換父程式。
這樣,就可以指定名稱空間執行新的程式了。
程式碼示例:
#define _GNU_SOURCE
#include <fcntl.h>
#include <sched.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \
} while (0)
int
main(int argc, char *argv[])
{
int fd;
if (argc < 3) {
fprintf(stderr, "%s /proc/PID/ns/FILE cmd args...\n", argv[0]);
exit(EXIT_FAILURE);
}
fd = open(argv[1], O_RDONLY); /* Get file descriptor for namespace */
if (fd == -1)
errExit("open");
if (setns(fd, 0) == -1) /* Join that namespace */
errExit("setns");
execvp(argv[2], &argv[2]); /* Execute a command in namespace */
errExit("execvp");
}
使用示例:
./ns_exec /proc/3550/ns/uts /bin/bash
nsenter
那麼,最後就是 nsenter 了,nsenter 相當於在setns的示例程式之上做了一層封裝,使我們無需指定名稱空間的檔案描述符,而是指定程式號即可。
指定程式號PID以及需要進入的名稱空間後,nsenter會幫我們找到對應的名稱空間檔案描述符/proc/PID/ns/FD,然後使用該名稱空間執行新的程式。
參考文件
-
容器內抓包定位網路問題:
-
man-page:nsenter:
-
man-page:clone:
-
man-page:setns:
來源:%E5%91%BD%E4%BB%A4%E7%AE%80%E4%BB%8B/
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70013542/viewspace-2916347/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 最新使用Charles進行HTTPS抓包的方法HTTP
- 在Linux中,如何在Linux中使用LXD進行容器管理?Linux
- 如何對手機http進行抓包?Fiddler工具超好用HTTP
- SpringBoot 專案如何在tomcat容器中執行Spring BootTomcat
- [Tools] 使用 Charles 對 Android 應用進行 HTTPS 資料抓包AndroidHTTP
- 如何優雅的在 Kubernetes Pod 內進行網路抓包
- 使用Fiddler對iPhone蘋果手機進行資料抓包分析iPhone蘋果
- 如何在Django ORM中進行not查詢?DjangoORM
- tcpdump抓包TCP
- Https抓包HTTP
- 搞定某APP的TCP抓包,並直接呼叫so檔案進行Hook抓取APPTCPHook
- 如何在Linux中進行檔案切割操作?Linux
- 如何在Python中對dicts列表進行排序Python排序
- mitmproxy grpc 抓包MITRPC
- BLE抓包分析
- iOS防止抓包iOS
- iOS Wireshark抓包iOS
- iOS Charles抓包iOS
- 使用小黃鳥(HttpCanary)+模擬器(VMOS Pro)對手機APP進行抓包HTTPPCAAPP
- https 真的安全嗎,可以抓包嗎,如何防止抓包嗎HTTP
- 談談HTTPS安全認證,抓包與反抓包策略HTTP
- tshark 抓包 mysql 協議包MySql協議
- 容器進階:OCI與容器執行時
- Flutter中http請求抓包解決方案FlutterHTTP
- 同步容器(如Vector)並不是所有操作都執行緒安全!~執行緒
- 前端抓包神器Charles前端
- APP抓包神器dronyAPP
- iperf測試抓包
- wireshark抓包學習
- IPSEC隧道抓包分析
- Python 爬蟲、抓包Python爬蟲
- Charles 手機抓包
- Wireshark網路抓包
- Android https 抓包指南AndroidHTTP
- 在Linux中,如何在Linux中進行系統映象管理?Linux
- 在Linux中,如何在Linux中進行資源配額管理?Linux
- 在Linux中,如何進行容器技術的應用?Linux
- 使用容器Docker進行開發Docker