编辑
2023-10-25
linux
00
请注意,本文编写于 563 天前,最后修改于 563 天前,其中某些信息可能已经过时。

接下来讲解一下用unshareclone来创建NetWor kNameSpace,先讲解一下这两个API:

unshare unshare用于将当前进程分离(unshare)出指定的命名空间(namespace)。它允许进程创建独立于父进程的命名空间,从而实现进程在不同命名空间中运行的隔离。

c
#include <sched.h> int unshare(int flags);
  • flags:指定要分离的命名空间类型,可以使用以下标志的按位或运算进行组合:
    • CLONE_NEWNS:分离挂载命名空间(Mount Namespace)。
    • CLONE_NEWUTS:分离UTS命名空间。
    • CLONE_NEWIPC:分离IPC命名空间。
    • CLONE_NEWPID:分离PID命名空间。
    • CLONE_NEWNET:分离网络命名空间。
    • CLONE_NEWUSER:分离用户命名空间。
    • CLONE_NEWCGROUP:分离控制组命名空间。
    • CLONE_NEWTIME:分离时间命名空间(自Linux 5.6起可用)。

成功调用unshare函数会将当前进程分离出指定的命名空间,并创建一个新的独立命名空间。在新的命名空间中,进程可以执行与父进程隔离的操作,例如挂载文件系统、更改主机名、配置网络接口等。

unshare函数只分离命名空间,具体的命名空间配置需要在调用unshare之后进行,例如使用mount函数挂载文件系统、sethostname函数设置主机名等。

clone

clone用于创建一个新的进程,并可以选择性地与父进程共享或分离多个资源,包括进程空间、文件系统、信号处理等。

c
#include <sched.h> int clone(int (*fn)(void *), void *child_stack, int flags, void *arg, ...);
  • fn:指向子进程要执行的函数的指针。该函数应该具有 int 类型的返回值,接受一个 void* 类型的参数。
  • child_stack:指向子进程栈的指针。子进程会在一个新的栈空间中执行,child_stack 指向该栈的顶部。栈应该是独立分配的,并且具有足够的空间来容纳子进程执行所需的栈帧。
  • flags:用于指定创建子进程时的行为和资源共享方式的标志位,可以使用以下标志的按位或运算进行组合:
    • CLONE_CHILD_CLEARTID:子进程在调用exec函数或退出时,会将tid置为0。
    • CLONE_CHILD_SETTID:子进程在调用exec函数或退出时,会将tid置为子进程ID。
    • CLONE_FILES:子进程与父进程共享文件描述符表。
    • CLONE_FS:子进程与父进程共享文件系统信息。
    • CLONE_IO:子进程与父进程共享I/O上下文。
    • CLONE_NEWIPC:子进程创建一个新的IPC命名空间。
    • CLONE_NEWNET:子进程创建一个新的网络命名空间。
    • CLONE_NEWNS:子进程创建一个新的挂载命名空间。
    • CLONE_NEWPID:子进程创建一个新的PID命名空间。
    • CLONE_NEWUTS:子进程创建一个新的UTS命名空间。
    • CLONE_NEWUSER:子进程创建一个新的用户命名空间。
    • CLONE_NEWCGROUP:子进程创建一个新的控制组命名空间。
    • CLONE_PARENT:子进程的父进程为调用clone的进程。
    • CLONE_PARENT_SETTID:子进程的父进程ID会存储在ptid中。
    • CLONE_PTRACE:子进程与父进程共享ptrace
    • CLONE_SETTLS:子进程的线程局部存储与父进程相同。
    • CLONE_SIGHAND:子进程与父进程共享信号处理程序。
    • CLONE_SYSVSEM:子进程与父进程共享System V信号量。
    • CLONE_THREAD:子进程创建为与父进程共享线程组的线程。
    • CLONE_UNTRACED:子进程创建后不会受到ptrace跟踪。
    • CLONE_VFORK:子进程使用父进程的页表直到调用exec或者调用_exit退出。
    • CLONE_VM:子进程与父进程共享内存空间。
  • arg:传递给子进程函数的参数。

clone 函数创建一个新的进程,并在子进程中执行指定的函数。子进程的执行流程会从 fn 指向的函数开始。child_stack 参数指定子进程的栈空间,flags 参数用于指定资源的共享方式。子进程创建成功后,clone 函数会返回子进程的进程ID。

接下来是调用示例:

c
#define _GNU_SOURCE #include <stdio.h> #include <sched.h> #include <stdlib.h> #include <unistd.h> #include <sys/wait.h> #define STACK_SIZE 65536 static int child_func(void *arg) { // 在子进程中,进行需要在独立网络命名空间中运行的操作 printf("Child process: PID=%ld\n", (long) getpid()); // 在子进程中,可以进行网络相关的操作,例如配置网络接口、设置IP地址等 sleep(10); // 模拟子进程在网络命名空间中的操作 printf("Child process: Exiting\n"); return 0; } int main() { printf("Parent process: PID=%ld\n", (long) getpid()); // 为子进程分配栈空间 char *stack = malloc(STACK_SIZE); if (stack == NULL) { perror("malloc"); exit(EXIT_FAILURE); } // 使用clone创建子进程,并指定CLONE_NEWNET标志来创建独立网络命名空间 pid_t child_pid = clone(child_func, stack + STACK_SIZE, CLONE_NEWNET | SIGCHLD, NULL); if (child_pid == -1) { perror("clone"); exit(EXIT_FAILURE); } // 在父进程中,可以继续进行其他操作 sleep(5); // 模拟父进程的操作 printf("Parent process: Waiting for child process to exit...\n"); waitpid(child_pid, NULL, 0); // 等待子进程退出 printf("Parent process: Exiting\n"); return 0; }
c
#define _GNU_SOURCE #include <stdio.h> #include <sched.h> #include <stdlib.h> #include <unistd.h> int main() { printf("Parent process: PID=%ld\n", (long) getpid()); printf("Parent process: Creating a new network namespace...\n"); // 创建独立的网络命名空间 if (unshare(CLONE_NEWNET) == -1) { perror("unshare"); exit(EXIT_FAILURE); } printf("Parent process: In the new network namespace\n"); // 在新的网络命名空间中,可以进行网络相关的操作,例如配置网络接口、设置IP地址等 sleep(10); // 模拟在网络命名空间中的操作 printf("Parent process: Exiting\n"); return 0; }

以上程序经过运行测试,必须要用root权限才能创建namespace

本文作者:yowayimono

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!