如何绑定到仅一个网络接口(Linux)的所有地址? [英] How to bind to all addresses of only one network interface (Linux)?

查看:125
本文介绍了如何绑定到仅一个网络接口(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 binds bind(fd00:aaaa::a/64, 9000).
  • process 2 calls socket(...) and setsockopt(SO_BINDTODEVICE, "B")
  • process 2 (continued) calls bind(::, 9000) and gets EADDRINUSE. 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?

示例跟踪:

  1. 我在特定地址nc -l fd00:aaaa::a 9000上启动侦听套接字(服务器).其踪迹如下:
  1. 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, ...

  1. 即使我已经绑定到另一个接口,如果我绑定到另一个接口正在使用的端口,则连接到它(客户端)也会失败:

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)

  1. 但是,如果我未指定端口,则绑定到::时一切正常(侦听器仍在运行):
  1. 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆