tunctl1.5.1源代码分析
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 会逐个返回 d、u、g,然后你可以通过 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 设备进行通信,执行相应的配置和控制操作。





浙公网安备 33010602011771号