tunctl1.5.1源代码分析

发布时间 2023-11-10 23:24:49作者: huh&uh

file address: https://files.cnblogs.com/files/blogs/773707/tunctl.zip?t=1699629591&download=true
strtol 是 C 语言标准库中的一个函数,用于将字符串转换为长整型数(long)。

long strtol(const char *str, char **endptr, int base);
  • str:要转换的字符串。
  • endptr:指向字符指针的指针,用于存储转换结束后剩余的字符串的地址。如果这个参数为 NULL,则忽略这个信息。
  • base:表示数字的进制,可以是 2 到 36 之间的任何值,或者是 0。如果为 0,则根据字符串的前缀来确定进制(0x 或 0X 表示十六进制,0 表示八进制,其它为十进制)。

strtol 返回转换后的长整型数。如果发生错误,返回 0 并设置 errno

下面是一个简单的示例,演示如何使用 strtol

#include <stdio.h>
#include <stdlib.h>

int main() {
    char str[] = "12345";
    char *endptr;
    long num = strtol(str, &endptr, 10);

    if (*endptr != '\0') {
        printf("Conversion failed. Remaining string: %s\n", endptr);
    } else {
        printf("Converted number: %ld\n", num);
    }

    return 0;
}

此示例将字符串 "12345" 转换为长整型数 12345,并打印转换结果。如果转换失败,它会打印剩余的字符串。

getgrnam 是 C 语言标准库中的一个函数,用于通过组名获取对应的组结构。该函数的声明如下:

#include <grp.h>

struct group *getgrnam(const char *name);
  • name:要查找的组名。

getgrnam 函数返回一个指向 group 结构体的指针,该结构体包含了有关组的信息,包括组名、组 ID、组的用户列表等。如果未找到对应的组,返回 NULL

下面是一个简单的示例,演示如何使用 getgrnam 函数:

#include <stdio.h>
#include <grp.h>

int main() {
    const char *group_name = "users";
    struct group *grp = getgrnam(group_name);

    if (grp != NULL) {
        printf("Group information for %s:\n", group_name);
        printf("Group name: %s\n", grp->gr_name);
        printf("Group ID: %d\n", grp->gr_gid);

        // Print user list
        printf("Group members:\n");
        for (int i = 0; grp->gr_mem[i] != NULL; i++) {
            printf("  %s\n", grp->gr_mem[i]);
        }
    } else {
        printf("Group %s not found.\n", group_name);
    }

    return 0;
}

此示例通过组名 "users" 获取组的信息,并打印组名、组 ID 以及组成员的列表。如果未找到组,它会打印相应的消息。
这里的 "bd:f:npt:u:g:h"getopt 函数的第三个参数,即期望的选项字符串。它定义了你的程序可以接受的命令行选项,并指明哪些选项需要参数。

解释一下这个字符串:

  • b:表示一个短选项 -b,没有参数。
  • d::表示一个短选项 -d,后面需要一个参数。
  • f::表示一个短选项 -f,后面需要一个参数。
  • n:表示一个短选项 -n,没有参数。
  • p:表示一个短选项 -p,没有参数。
  • t::表示一个短选项 -t,后面需要一个参数。
  • u::表示一个短选项 -u,后面需要一个参数。
  • g::表示一个短选项 -g,后面需要一个参数。
  • h:表示一个短选项 -h,没有参数。

这个字符串告诉 getopt 函数你的程序支持哪些短选项,以及这些选项是否需要参数。在代码中,getopt 会根据这个字符串解析命令行参数,并将下一个选项字符返回给 opt 变量。

例如,如果你的命令行参数是 -d some_device -u some_user -g some_group,那么在 while 循环中,getopt 会逐个返回 dug,然后你可以通过 optarg 获取相应的参数值。
getpwnam 函数是用于通过用户名获取用户信息的函数。该函数的声明如下:

#include <sys/types.h>
#include <pwd.h>

struct passwd *getpwnam(const char *name);

函数接受一个用户名作为参数,返回一个指向 struct passwd 结构的指针。struct passwd 结构包含了有关用户的信息,例如用户名、用户 ID、组 ID、用户的主目录等。

下面是一个简单的例子,演示如何使用 getpwnam 函数:

#include <stdio.h>
#include <pwd.h>

int main() {
    const char *username = "your_username";
    struct passwd *pwd = getpwnam(username);

    if (pwd != NULL) {
        printf("User Information:\n");
        printf("Username: %s\n", pwd->pw_name);
        printf("User ID: %d\n", (int)pwd->pw_uid);
        printf("Group ID: %d\n", (int)pwd->pw_gid);
        printf("Home Directory: %s\n", pwd->pw_dir);
    } else {
        printf("User not found.\n");
    }

    return 0;
}

请将 "your_username" 替换为你想要查询的实际用户名。在实际应用中,你可能需要检查返回的指针是否为 NULL,以确定用户是否存在。
argv += optind;
argc -= optind;
这两行代码用于更新命令行参数,以便忽略已经被处理的选项。optind 是 getopt 函数的全局变量,表示下一个要处理的参数的索引。argv 是一个指向命令行参数数组的指针,而 argc 是命令行参数的个数。

在处理命令行参数时,getopt 会逐个获取选项,并将 optind 更新为下一个要处理的参数的索引。optind 的初值通常为 1。optind 之前的参数是程序名,通常不包含选项。

argv += optind; 将 argv 向后移动,指向下一个要处理的参数。argc -= optind; 则减去已经处理的参数个数,以保持 argc 的正确值。这两行代码的目的是调整 argv 和 argc,以便后续的代码只处理用户输入的实际参数,而不包括程序名和已经处理过的选项。
ioctl 是一个用于设备 I/O 控制的系统调用,它可以在不同类型的设备上执行各种操作。在C语言中,ioctl 函数的原型如下:

int ioctl(int fd, unsigned long request, ...);
  • fd 是指向打开设备的文件描述符。
  • request 是控制命令的整数,用于指定要执行的操作。
  • ... 是一个可选的参数列表,用于传递命令所需的任何参数。

ioctl 的使用通常涉及到与具体设备相关的命令和参数。在你提供的代码中,ioctl 主要用于配置 TUN/TAP 设备的属性,例如设置设备的所有者、组、持久性等。

在你的代码中的一些 ioctl 使用示例:

ioctl(tap_fd, TUNSETIFF, (void *) &ifr); // 设置 TUN/TAP 设备的接口
ioctl(tap_fd, TUNSETOWNER, owner); // 设置 TUN/TAP 设备的所有者
ioctl(tap_fd, TUNSETGROUP, group); // 设置 TUN/TAP 设备的组
ioctl(tap_fd, TUNSETPERSIST, 1); // 设置 TUN/TAP 设备为持久性

这些调用通过 ioctl 来与 TUN/TAP 设备进行通信,执行相应的配置和控制操作。