在macOS上,我有一个我创建的
我的问题是,尽管我的Macbook上的sys/sockio.h定义了值SIOCSIFNETMASK,但是struct ifreq似乎没有任何netmask字段。net/if.h向我展示了这一点。
在Linux上,它看起来像这样
现在,我突然想到这只是一个联合体,而且在 macOS 上没有定义
我是不是漏掉了什么显而易见的东西?
这是我的最小可复现示例(MRE):
utun
接口。我想用C语言为它分配一个IPv4地址和子网掩码。前者我可以通过SIOCSIFADDR
ioctl
命令来实现。然而,我在设置子网掩码方面遇到了一些问题。在Linux上,我会这样做。struct sockaddr_in addr = {.sin_family = AF_INET};
struct ifreq ifr = {.ifr_name = "utun5"};
inet_pton(AF_INET, "255.255.255.0", &addr.sin_addr);
memcpy(&ifr.ifr_netmask, &addr, sizeof(addr));
if ( ioctl(sock, SIOCSIFNETMASK, &ifr) == -1 ) {
// handle the error
}
我的问题是,尽管我的Macbook上的sys/sockio.h定义了值SIOCSIFNETMASK,但是struct ifreq似乎没有任何netmask字段。net/if.h向我展示了这一点。
struct ifreq {
char ifr_name[IFNAMESIZ];
union {
struct sockaddr ifru_addr;
struct sockaddr ifru_dstaddr;
struct sockaddr ifru_broadaddr;
short ifru_flags;
...
在Linux上,它看起来像这样
struct ifreq {
union {
char ifrn_name[IFNAMSIZ];
} ifr_ifrn;
union {
struct sockaddr ifru_addr;
struct sockaddr ifru_dstaddr;
struct sockaddr ifru_broadaddr;
struct sockaddr ifru_netmask;
struct sockaddr ifru_hwaddr;
...
现在,我突然想到这只是一个联合体,而且在 macOS 上没有定义
ifru_netmask
也无关紧要。我可以在 ifru_addr
中设置子网掩码的值。我尝试过了,虽然 SIOCSIFNETMASK
命令成功执行,但是 ifconfig
显示设备仍然具有默认的子网掩码 0xff000000
。utun5: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> mtu 1500
inet 1.2.3.4 --> 0.0.0.0 netmask 0xff000000
我是不是漏掉了什么显而易见的东西?
这是我的最小可复现示例(MRE):
#include <arpa/inet.h>
#include <net/if.h>
#include <net/if_utun.h>
#include <netinet/in.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/kern_control.h>
#include <sys/kern_event.h>
#include <sys/socket.h>
#include <unistd.h>
int
tun_device_create(char *if_name)
{
int fd;
struct ctl_info info = {0};
struct sockaddr_ctl addr = {
.sc_family = AF_SYSTEM, .sc_len = sizeof(struct sockaddr_ctl), .ss_sysaddr = AF_SYS_CONTROL};
fd = socket(AF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);
if (fd < 0) {
perror("socket (AF_SYSTEM)");
return -1;
}
snprintf(info.ctl_name, sizeof(info.ctl_name), "%s", UTUN_CONTROL_NAME);
if (ioctl(fd, CTLIOCGINFO, &info) == -1) {
perror("ioctl (CTLIOCGINFO)");
goto error;
}
addr.sc_id = info.ctl_id;
if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) != 0) {
perror("connect (AF_SYSTEM)");
goto error;
}
if (getsockopt(fd, SYSPROTO_CONTROL, UTUN_OPT_IFNAME, if_name, &(socklen_t){IFNAMSIZ}) != 0) {
perror("getsockopt (SYSPROTO_CONTROL)");
goto error;
}
return fd;
error:
close(fd);
return -1;
}
int
set_addr_and_bring_up(const char *if_name, const char *ipv4_address, const char *ipv4_netmask)
{
int sock, ret = -1;
struct ifreq ifr = {0};
struct sockaddr_in *addr = (struct sockaddr_in *)&ifr.ifr_addr;
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
perror("socket");
return -1;
}
snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", if_name);
addr->sin_family = AF_INET;
inet_pton(AF_INET, ipv4_address, &addr->sin_addr);
if (ioctl(sock, SIOCSIFADDR, &ifr) == -1) {
perror("ioctl (SIOCSIFADDR)");
goto done;
}
inet_pton(AF_INET, ipv4_netmask, &addr->sin_addr);
if (ioctl(sock, SIOCSIFNETMASK, &ifr) == -1) {
perror("ioctl (SIOCSIFNETMASK)");
goto done;
}
ifr.ifr_flags = IFF_UP;
if (ioctl(sock, SIOCSIFFLAGS, &ifr) == -1) {
perror("ioctl (SIOCSIFFLAGS)");
goto done;
}
ret = 0;
done:
close(sock);
return ret;
}
int
main()
{
int fd;
char if_name[IFNAMSIZ];
fd = tun_device_create(if_name);
if (fd < 0) {
return 1;
}
if (set_addr_and_bring_up(if_name, "1.2.3.4", "255.255.255.0") != 0) {
close(fd);
return 1;
}
printf("Tun device created: %s\n", if_name);
pause();
close(fd);
return 0;
}
254.0.0.0
、252.0.0.0
等等。 - undefined