如何绑定到仅一个网络接口(Linux)的所有地址? [英] How to bind to all addresses of only one network interface (Linux)?
问题描述
我要实现的目标是将IPv6套接字绑定到仅一个特定设备的任何地址 ,而不是整个系统.我的直觉是我可以将setsockopt()
与SO_BINDTODEVICE
绑定到::
.它主要完成了我期望的操作.行为在v4中是相同的.
What I am trying to achieve is binding an IPv6 socket to any address of just one particular device, not system-wide. My intuition is that I could setsockopt()
with SO_BINDTODEVICE
followed by a bind to ::
. It mostly does what I expect it to do. The behaviour is the same in v4.
使用SO_BINDTODEVICE
绑定到接口的套接字将仅接受对该接口上地址的连接.期望如此之高.
The sockets bound to an interface with SO_BINDTODEVICE
will only accept connections made to addresses on that interface. That much is expected.
但是,如果在接口A上存在使用相同端口 but 的套接字时,如果我试图绑定到接口B上的源端口,则会遇到errno地址已在使用中"
However, I run into errno "Address already in use", if I'm trying to bind to a source port on interface B when there is a socket using the same port but on interface A.
例如:
- nic A具有IPv6 fd00:aaaa :: a/64
- nic B具有IPv6 fd00:bbbb :: b/64
- 他们不共享网络.
立即输入(伪代码):
- 进程1调用
socket(...)
并绑定bind(fd00:aaaa::a/64, 9000)
. - 进程2调用
socket(...)
和setsockopt(SO_BINDTODEVICE, "B")
- 进程2(续)调用
bind(::, 9000)
并获取EADDRINUSE
.为什么?
- process 1 calls
socket(...)
and bindsbind(fd00:aaaa::a/64, 9000)
. - process 2 calls
socket(...)
andsetsockopt(SO_BINDTODEVICE, "B")
- process 2 (continued) calls
bind(::, 9000)
and getsEADDRINUSE
. Why?
SO_BINDTODEVICE
如何真正起作用?保守地说,使用中的地址"的确定是否会忽略接口套接字绑定到的地址?是网络堆栈分层问题吗?
How does SO_BINDTODEVICE
really work? Does the determination for "addresses in use" ignore, conservatively, the interface sockets are bound to? Is it a networking stack layering issue?
示例跟踪:
- 我在特定地址
nc -l fd00:aaaa::a 9000
上启动侦听套接字(服务器).其踪迹如下:
- I start a listening socket (server) on a specific address:
nc -l fd00:aaaa::a 9000
. Its trace is as follows:
socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP) = 3
setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
bind(3, {
sa_family=AF_INET6,
sin6_port=htons(9000),
inet_pton(AF_INET6, "fd00:aaaa::a", &sin6_addr),
sin6_flowinfo=0, sin6_scope_id=0
}, 28) = 0
listen(3, 1) = 0
accept(3, ...
- 即使我已经绑定到另一个接口,如果我绑定到另一个接口正在使用的端口,则连接到它(客户端)也会失败:
socket(PF_INET6, SOCK_STREAM, IPPROTO_IP) = 3
setsockopt(3, SOL_SOCKET, SO_BINDTODEVICE, "nicB\0", 5) = 0
bind(3, {sa_family=AF_INET6,
sin6_port=htons(9000),
inet_pton(AF_INET6, "::", &sin6_addr),
sin6_flowinfo=0,
sin6_scope_id=0
}, 28) = -1 //EADDRINUSE (Address already in use)
- 但是,如果我未指定端口,则绑定到
::
时一切正常(侦听器仍在运行):
- However, if I don't specify the port, then all is good when binding to
::
(while the listener still runs):
socket(PF_INET6, SOCK_STREAM, IPPROTO_IP) = 3
setsockopt(3, SOL_SOCKET, SO_BINDTODEVICE, "nicB\0", 5) = 0
bind(3, {
sa_family=AF_INET6,
sin6_port=htons(0),
inet_pton(AF_INET6, "::", &sin6_addr),
sin6_flowinfo=0, sin6_scope_id=0
}, 28) = 0
connect(3, {
sa_family=AF_INET6,
sin6_port=htons(9000),
inet_pton(AF_INET6, "fd00:aaaa::a", &sin6_addr),
sin6_flowinfo=0, sin6_scope_id=0
}, 28) = ...
注意:这是在3.19.0-68通用x86_64上. Ubuntu 14.04.如果有所不同,在我的测试中,nicB是桥接模式下的macvlan,其父级为nicA.
推荐答案
如果已经有一个套接字绑定到特定的IP地址和端口,则只有提供了另一个特定的IP地址,您才能再次绑定到该端口.在这种情况下,您不能使用INADDR_ANY.
If there is a socket already bound to a specific IP address and port, you can only bind to that port again if you provide another specific IP address. You cannot use INADDR_ANY in this circumstance.
这篇关于如何绑定到仅一个网络接口(Linux)的所有地址?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!