将套接字绑定到网络接口

30

如何将套接字绑定到特定的网络接口?我尝试在服务器端使用setsockopt,但客户端仍然可以通过eth0和lo接口访问服务。

我可以通过使用serv_addr.sin_addr.s_addr设置特定的IP地址来实现这一点。

但我怀疑我们可以仅使用setsockopt(不提及IP地址)将其绑定到接口。

3个回答

43
你可以通过设置SO_BINDTODEVICE套接字选项来绑定到特定的接口。
struct ifreq ifr;

memset(&ifr, 0, sizeof(ifr));
snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "eth0");
if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr)) < 0) {
    ... error handling ...
}

警告:您必须是root用户或具有CAP_NET_RAW权限才能使用此选项。
第二种方法是您可以使用getifaddrs()来解析与接口绑定的IP地址。
请点击后面的链接查看一个详细的示例。

1
我有一个新问题,使用您的方法,eth0和eth1具有相同的IP地址是否会有影响? - Splash
我非常确定它应该说“您必须是root 或者 具有CAP_NET_RAW功能”,您不需要两者都具备。 - dreua
1
你好,https://linux.die.net/man/3/setsockopt 上没有列出SO_BINDTODEVICE,这意味着它不再受支持了吗? - AAB

3

你所说的唯一方法就是通过设置特定的IP地址,使用serv_addr.sin_addr.s_addr

如果不知道要绑定到哪个地址,你就无法完成它。

如果需要,你可以使用ioctl来确定当前的IP地址,尽管这些天可能有更聪明的方法来做到这一点 - 我最近没有在现代Linux发行版上做过太多的工作。


1
谢谢Joe。我可以了解一下使用setsockopt和SO_BINDTODEVICE的方法吗? - user2003595

2

也许有人会觉得这很有用,所以我分享一下对我有效的解决方案(Linux,C++):

uint32_t interfaceIndex = if_nametoindex(interfaceName);

其中"interfaceName"是我们要绑定到的接口的名称,例如"eth0"(参见:https://linux.die.net/man/3/if_nametoindex)。 现在我们可以通过"sin6_scope_id"(如果我们使用IPv6)来在套接字地址结构中指定这个接口:

struct sockaddr_in6 socketAddress;
socketAddress.sin6_scope_id = interfaceIndex;

现在我们可以像往常一样通过“bind”把套接字绑定到接口。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接