"Cannot assign requested address" 尝试设置 TUN 接口网络掩码时
"Cannot assign requested address" when trying to set TUN interface netmask
我正在尝试编写一个 Linux 用户空间程序,它打开一个 TUN 接口并为其分配一个 IPv4 地址和一个网络掩码。分配 IP 地址工作正常,但设置网络掩码会导致标题中出现错误(如果 perror
之后立即调用)。这是展示问题的代码片段:
int tun_open(char *tun_name)
{
int tun_fd;
if ((tun_fd = open("/dev/net/tun", O_RDWR)) == -1) {
return -1;
}
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
if (ioctl(tun_fd, TUNSETIFF, &ifr) == -1) {
close(tun_fd);
return -1;
}
strncpy(tun_name, ifr.ifr_name, IFNAMSIZ);
return tun_fd;
}
int tun_assign_addr(int tun_fd,
char const *tun_name,
char const *tun_addr,
char const *tun_netmask)
{
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, tun_name, IFNAMSIZ);
ifr.ifr_addr = *(struct sockaddr *)&addr;
int s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0);
if (inet_pton(addr.sin_family, tun_addr, &addr.sin_addr) != 1)
return -1;
if (ioctl(s, SIOCSIFADDR, &ifr) == -1)
return -1;
if (inet_pton(addr.sin_family, tun_netmask, &addr.sin_addr) != 1)
return -1;
if (ioctl(s, SIOCSIFNETMASK, &ifr) == -1) {
perror(">>> ERROR HERE <<<")
return -1;
}
return 0;
}
int main()
{
int tun_fd;
char tun_name[IFNAMSIZ];
assert(tun_open(tun_name) != -1);
assert(tun_assign_addr(tun_fd, tun_name, "10.0.0.0", "255.255.255.0") != -1);
}
在深入研究了内核代码之后(我在 5.14.14
)看来这一定是因为 bad_mask
签入了 net/ipv4/devinet.c:1214
。但是,如果我在我的网络掩码上从 include/linux/inetdevice.h
手动 运行 bad_mask
它 returns false
正如预期的那样。
这里到底发生了什么?
在设置地址之前,您将addr
的“内容”分配给ifr_addr
,对于像网络掩码这样的ip。因此,您将向 ioctl 发送 NULL 以获得 IP,然后向 MASK 发送 NULL。 inet_pton
仅触摸 addr
,然后不会更改 ifr.ifr_addr
。
这是更正后的代码:
int tun_assign_addr(int tun_fd,
char const *tun_name,
char const *tun_addr,
char const *tun_netmask)
{
struct sockaddr_in addr,mask;
memset(&addr, 0, sizeof(addr));
memset(&mask, 0, sizeof(mask));
addr.sin_family = AF_INET;
mask.sin_family = AF_INET;
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, tun_name, IFNAMSIZ);
int s = socket(addr.sin_family, SOCK_DGRAM, 0);
if (inet_pton(addr.sin_family, tun_addr, &addr.sin_addr) != 1)
return -1;
ifr.ifr_addr = *(struct sockaddr *)&addr;
if (ioctl(s, SIOCSIFADDR, &ifr) == -1) {
perror(">>> ERROR HERE ADD <<<");
return -1;
}
if (inet_pton(mask.sin_family, tun_netmask, &mask.sin_addr) != 1)
return -1;
ifr.ifr_netmask = *(struct sockaddr *)&mask;
if (ioctl(s, SIOCSIFNETMASK, &ifr) == -1) {
perror(">>> ERROR HERE MSK <<<");
return -1;
}
return 0;
}
我正在尝试编写一个 Linux 用户空间程序,它打开一个 TUN 接口并为其分配一个 IPv4 地址和一个网络掩码。分配 IP 地址工作正常,但设置网络掩码会导致标题中出现错误(如果 perror
之后立即调用)。这是展示问题的代码片段:
int tun_open(char *tun_name)
{
int tun_fd;
if ((tun_fd = open("/dev/net/tun", O_RDWR)) == -1) {
return -1;
}
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
if (ioctl(tun_fd, TUNSETIFF, &ifr) == -1) {
close(tun_fd);
return -1;
}
strncpy(tun_name, ifr.ifr_name, IFNAMSIZ);
return tun_fd;
}
int tun_assign_addr(int tun_fd,
char const *tun_name,
char const *tun_addr,
char const *tun_netmask)
{
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, tun_name, IFNAMSIZ);
ifr.ifr_addr = *(struct sockaddr *)&addr;
int s = socket(ifr.ifr_addr.sa_family, SOCK_DGRAM, 0);
if (inet_pton(addr.sin_family, tun_addr, &addr.sin_addr) != 1)
return -1;
if (ioctl(s, SIOCSIFADDR, &ifr) == -1)
return -1;
if (inet_pton(addr.sin_family, tun_netmask, &addr.sin_addr) != 1)
return -1;
if (ioctl(s, SIOCSIFNETMASK, &ifr) == -1) {
perror(">>> ERROR HERE <<<")
return -1;
}
return 0;
}
int main()
{
int tun_fd;
char tun_name[IFNAMSIZ];
assert(tun_open(tun_name) != -1);
assert(tun_assign_addr(tun_fd, tun_name, "10.0.0.0", "255.255.255.0") != -1);
}
在深入研究了内核代码之后(我在 5.14.14
)看来这一定是因为 bad_mask
签入了 net/ipv4/devinet.c:1214
。但是,如果我在我的网络掩码上从 include/linux/inetdevice.h
手动 运行 bad_mask
它 returns false
正如预期的那样。
这里到底发生了什么?
在设置地址之前,您将addr
的“内容”分配给ifr_addr
,对于像网络掩码这样的ip。因此,您将向 ioctl 发送 NULL 以获得 IP,然后向 MASK 发送 NULL。 inet_pton
仅触摸 addr
,然后不会更改 ifr.ifr_addr
。
这是更正后的代码:
int tun_assign_addr(int tun_fd,
char const *tun_name,
char const *tun_addr,
char const *tun_netmask)
{
struct sockaddr_in addr,mask;
memset(&addr, 0, sizeof(addr));
memset(&mask, 0, sizeof(mask));
addr.sin_family = AF_INET;
mask.sin_family = AF_INET;
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, tun_name, IFNAMSIZ);
int s = socket(addr.sin_family, SOCK_DGRAM, 0);
if (inet_pton(addr.sin_family, tun_addr, &addr.sin_addr) != 1)
return -1;
ifr.ifr_addr = *(struct sockaddr *)&addr;
if (ioctl(s, SIOCSIFADDR, &ifr) == -1) {
perror(">>> ERROR HERE ADD <<<");
return -1;
}
if (inet_pton(mask.sin_family, tun_netmask, &mask.sin_addr) != 1)
return -1;
ifr.ifr_netmask = *(struct sockaddr *)&mask;
if (ioctl(s, SIOCSIFNETMASK, &ifr) == -1) {
perror(">>> ERROR HERE MSK <<<");
return -1;
}
return 0;
}