gpt4 book ai didi

linux - 为什么 CAP_NET_RAW 不能与 SO_BINDTODEVICE 一起使用?

转载 作者:太空狗 更新时间:2023-10-29 11:42:51 26 4
gpt4 key购买 nike

我有以下简单的测试程序来创建一个 UDP 套接字并使用 SO_BINDTODEVICE 将它绑定(bind)到一个特定的接口(interface),这样我就可以 bind() 它所以 INADDR_ANY 专门在该接口(interface)上接收 UDP 广播。

//filename: bindtest.c
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>

#define MY_PORT (333)
#define MY_DEVICE "enp0s3"

#define BUFFERSIZE (1000)

/* global variables */
int sock;
struct sockaddr_in sa;
struct sockaddr_in my_addr;
char buffer[BUFFERSIZE];

int main(int argc, char *argv[])
{
unsigned int echolen, clientlen;
int rc, n;
char opt_buffer[1000];
struct protoent *udp_protoent;
struct timeval receive_timeout;
int optval;
socklen_t opt_length;
sleep(1);
/* Create the UDP socket */
if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
{
printf ("%s: failed to create UDP socket (%s) \n",
argv[0], strerror(errno));
exit (EXIT_FAILURE);
}
printf ("UDP socket created\n");

/* set the recvfrom timeout value */
receive_timeout.tv_sec = 5;
receive_timeout.tv_usec = 0;
rc=setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &receive_timeout, sizeof(receive_timeout));
if (rc != 0)
{
printf ("%s: could not set SO_RCVTIMEO (%s)\n",
argv[0], strerror(errno));
exit (EXIT_FAILURE);
}
printf ("set timeout to time [s]: %d time [ms]: %d\n", receive_timeout.tv_sec, receive_timeout.tv_usec);
/* allow broadcast messages for the socket */
int true = 1;
rc=setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &true, sizeof(true));
if (rc != 0)
{
printf ("%s: could not set SO_BROADCAST (%s)\n",
argv[0], strerror(errno));
exit (EXIT_FAILURE);
}
printf ("set SO_BROADCAST worked\n");
/* bind to a specific interface */
char device[] = MY_DEVICE;
rc=setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, device, sizeof(device));
if (rc != 0)
{
printf ("%s: could not set SO_BINDTODEVICE (%s)\n",
argv[0], strerror(errno));
exit (EXIT_FAILURE);
}
printf ("SO_BINDTODEVICE worked\n");

/* bind my own Port */
my_addr.sin_family = AF_INET;
my_addr.sin_addr.s_addr = INADDR_ANY;
my_addr.sin_port = htons(MY_PORT);
rc = bind (sock, (struct sockaddr *) &my_addr, sizeof(my_addr));
if (rc < 0)
{
printf ("%s: could not bind port (%s)\n",
argv[0], strerror(errno));
exit (EXIT_FAILURE);
}
printf ("bind() worked\n");
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = INADDR_BROADCAST;
sa.sin_port = htons(MY_PORT);

char data[20];
sprintf(data,"FOOBAR");
int res = sendto(sock, &data, strlen(data), 0, (struct sockaddr*)&sa, sizeof(sa));
if(res < 0){
printf("could not send\n");
} else {
printf("data sent\n");
}


close(sock);
printf ("socket closed\n");

exit(0);
}

当我以非 root 用户身份运行该程序时,我得到以下输出:

$ ./bindtest 
UDP socket created
set timeout to time [s]: 5 time [ms]: 0
set SO_BROADCAST worked
./bindtest: could not set SO_BINDTODEVICE (Operation not permitted)

这是非常合乎逻辑的,因为我不是 rootSO_BINDTODEVICE 是一个特权操作。但据我所知,它包含在功能 CAP_NET_RAWthis snippet of code from the Linux kernel :

static int sock_setbindtodevice(struct sock *sk, char __user *optval,
int optlen)
{
int ret = -ENOPROTOOPT;
#ifdef CONFIG_NETDEVICES
struct net *net = sock_net(sk);
char devname[IFNAMSIZ];
int index;

/* Sorry... */
ret = -EPERM;
if (!ns_capable(net->user_ns, CAP_NET_RAW))
goto out;

我做的时候还好:

$ getcap bindtest
$ sudo setcap cap_net_raw+ep bindtest
$ getcap bindtest
bindtest = cap_net_raw+ep

我得到相同的错误输出:

$ ./bindtest 
UDP socket created
set timeout to time [s]: 5 time [ms]: 0
set SO_BROADCAST worked
./bindtest: could not set SO_BINDTODEVICE (Operation not permitted)

当然,它作为 root 运行:

$ sudo ./bindtest
UDP socket created
set timeout to time [s]: 5 time [ms]: 0
set SO_BROADCAST worked
SO_BINDTODEVICE worked
bind() worked
data sent
socket closed

那么为什么它们没有按预期工作呢?

最佳答案

代码是正确的,getcap/setcap 的用法是正确的,所以一定是其他东西阻止了它的工作。

事实上,这是因为所有这些都是在 /home/user 中完成的,在这个系统上,它是使用 nosuid 选项等挂载的。

所以只需将二进制文件移动到例如/usr/bin/ 或任何其他未安装的部分 nosuid 将首先按预期工作。

(尽管您还需要 CAP_NET_BIND_SERVICE 才能使 bind() 使用端口 333,如示例中所示)

关于linux - 为什么 CAP_NET_RAW 不能与 SO_BINDTODEVICE 一起使用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35229902/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com