// 2. 使用 unshare 脱离当前的 Network 和 Mount 命名空间 printf("2. Calling unshare(CLONE_NEWNET | CLONE_NEWNS)...\n"); if (unshare(CLONE_NEWNET | CLONE_NEWNS) == -1) { perror("unshare"); fprintf(stderr, "Do you have root privileges?\n"); exit(EXIT_FAILURE); } printf("unshare() succeeded.\n");
// 3. 再次显示命名空间,应该已经改变 printf("3. Namespaces after unshare:\n"); print_current_namespaces();
// 4. 在新的 Network 命名空间中,网络接口视图是隔离的 printf("4. --- Network Isolation ---\n"); printf("Running 'ip link show' in new network namespace:\n"); // 使用 system 调用执行命令来查看网络接口 int ret = system("ip link show"); if (ret == -1) { perror("system ip link"); } printf("Note: You should only see the 'lo' (loopback) interface.\n"); printf("\n");
// 5. 在新的 Mount 命名空间中,挂载操作是隔离的 printf("5. --- Mount Isolation ---\n"); const char *mount_point = "/tmp/unshare_test_mount"; if (mkdir(mount_point, 0755) == -1 && errno != EEXIST) { perror("mkdir mount point"); } else { printf("Created directory %s\n", mount_point); }
if (mount("tmpfs", mount_point, "tmpfs", 0, NULL) == -1) { perror("mount tmpfs"); } else { printf("Mounted tmpfs on %s\n", mount_point); printf("This mount is only visible inside this process's mount namespace.\n"); }
// 6. 演示挂载隔离:在新的命名空间中创建一个文件 char test_file_path[256]; snprintf(test_file_path, sizeof(test_file_path), "%s/test_file.txt", mount_point); FILE *f = fopen(test_file_path, "w"); if (f) { fprintf(f, "Hello from process in its own mount namespace!\n"); fclose(f); printf("Created file %s\n", test_file_path); } else { perror("fopen test_file.txt"); }
printf("\n--- Summary ---\n"); printf("1. The main process called unshare() to get new, isolated Network and Mount namespaces.\n"); printf("2. Network namespace: 'ip link show' only displays the loopback interface.\n"); printf("3. Mount namespace: A tmpfs mounted on %s is private to this process.\n", mount_point); printf("4. If you run 'mount' or 'ip link show' in another terminal (outside this process),\n"); printf(" you will see the global network interfaces and mounts, not these isolated ones.\n");
# (你现在在一个新的 shell 中,提示符可能略有不同) # $ ip link show # 1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000 # link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 # (只有 lo 接口)
# $ mount -t tmpfs tmpfs /tmp/isolated_tmp # $ mount | grep isolated_tmp # tmpfs on /tmp/isolated_tmp type tmpfs (rw,relatime) # (这个挂载只在这个 unshare 的会话中可见)
# $ exit # (退出隔离的 shell)
# 2. 回到原 shell,检查隔离效果 # $ ip link show # (你会看到所有正常的网络接口,如 eth0, wlan0 等) # $ mount | grep isolated_tmp # (应该找不到这个挂载点)
--- Demonstrating unshare --- Main process PID: 12345 1. Initial namespaces: Current namespaces for PID 12345: Network: net:[4026531992] Mount: mnt:[4026531991]
2. Calling unshare(CLONE_NEWNET | CLONE_NEWNS)... unshare() succeeded. 3. Namespaces after unshare: Current namespaces for PID 12345: Network: net:[4026532222] <-- Changed Mount: mnt:[4026532223] <-- Changed
4. --- Network Isolation --- Running 'ip link show' in new network namespace: 1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 Note: You should only see the 'lo' (loopback) interface.
5. --- Mount Isolation --- Created directory /tmp/unshare_test_mount Mounted tmpfs on /tmp/unshare_test_mount This mount is only visible inside this process's mount namespace. Created file /tmp/unshare_test_mount/test_file.txt
--- Summary --- 1. The main process called unshare() to get new, isolated Network and Mount namespaces. 2. Network namespace: 'ip link show' only displays the loopback interface. 3. Mount namespace: A tmpfs mounted on /tmp/unshare_test_mount is private to this process. 4. If you run 'mount' or 'ip link show' in another terminal (outside this process), you will see the global network interfaces and mounts, not these isolated ones.
Program finished. The isolated namespaces cease to exist when this process exits.
12. 总结
unshare 是 Linux 命名空间功能的关键系统调用之一。
核心作用:让当前运行的进程脱离现有的命名空间,并加入新创建的、空的同类型命名空间。
与 clone 和 setns 的区别:
clone: 创建新进程时分配新命名空间。
setns: 加入一个已存在的命名空间。
unshare: 为当前进程创建并加入新的命名空间。
应用场景:
容器技术:容器运行时使用 unshare 来为容器进程提供隔离环境。
系统管理脚本:在执行可能影响全局环境的操作前,先 unshare 进入隔离环境,避免影响宿主机。
安全沙箱:为不受信任的程序创建隔离的运行环境。
权限:通常需要 root 权限,特别是涉及挂载、网络等操作时。
理解 unshare 有助于深入理解 Linux 容器和进程隔离的原理。对于 Linux 编程新手来说,它是掌握现代 Linux 系统编程和容器化技术的重要一环。