Signed-off-by: Paul Gofman pgofman@codeweavers.com --- Using SO_REUSEADDR is currently problematic when more than one UDP socket is bound to different interfaces. While that succeeds, it is unspecified which socket will receive a packet coming to INADDR_ANY. The filter being installed for each socket with SO_ATTACH_FILTER can only reject the packet coming for another interface but that rejected packed doesn't arrive to another socket.
SO_BINDTODEVICE seems to do exactly what we want without installing any socket filters and without requiring SO_REUSEADDR or SO_REUSEPORT. It originally considered for implementing broadcast listen on interface bound sockets but it wasn't much useful by that time as the SO_BINDTODEVICE required CAP_NET_RAW privilege which is normally not available for a non-root user. However, that changed since Linux 5.7 [2].
This patch uses SO_BINDTODEVICE but falls back to the previous way if that fails.
1. https://www.winehq.org/pipermail/wine-devel/2011-October/092681.html 2. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/patch/?id...
server/sock.c | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-)
diff --git a/server/sock.c b/server/sock.c index 03716cba90f..af08cd6be24 100644 --- a/server/sock.c +++ b/server/sock.c @@ -1756,12 +1756,14 @@ static int accept_into_socket( struct sock *sock, struct sock *acceptsock )
#ifdef IP_BOUND_IF
-static int bind_to_index( int fd, in_addr_t bind_addr, unsigned int index ) +static int bind_to_index( int fd, in_addr_t bind_addr, const char *name, unsigned int index, BOOL *need_reuse_addr ) { + *need_reuse_addr = TRUE; + return setsockopt( fd, IPPROTO_IP, IP_BOUND_IF, &index, sizeof(index) ); }
-#elif defined(IP_UNICAST_IF) && defined(SO_ATTACH_FILTER) +#elif defined(IP_UNICAST_IF) && defined(SO_ATTACH_FILTER) && defined(SO_BINDTODEVICE)
struct interface_filter { @@ -1794,13 +1796,26 @@ static struct interface_filter generic_interface_filter = BPF_STMT(BPF_RET+BPF_K, 0) /* dump packet */ };
-static int bind_to_index( int fd, in_addr_t bind_addr, unsigned int index ) +static int bind_to_index( int fd, in_addr_t bind_addr, const char *name, unsigned int index, BOOL *need_reuse_addr ) { in_addr_t ifindex = htonl( index ); struct interface_filter specific_interface_filter; struct sock_fprog filter_prog; int ret;
+ if (!setsockopt( fd, SOL_SOCKET, SO_BINDTODEVICE, name, strlen( name ) + 1 )) + { + *need_reuse_addr = FALSE; + return 0; + } + /* SO_BINDTODEVICE requires NET_CAP_RAW until Linux 5.7. */ + + if (debug_level) + fprintf( stderr, "setsockopt SO_BINDTODEVICE fd %d, name %s failed: %s, falling back to SO_REUSE_ADDR\n", + fd, name, strerror( errno )); + + *need_reuse_addr = TRUE; + if ((ret = setsockopt( fd, IPPROTO_IP, IP_UNICAST_IF, &ifindex, sizeof(ifindex) )) < 0) return ret;
@@ -1814,7 +1829,7 @@ static int bind_to_index( int fd, in_addr_t bind_addr, unsigned int index )
#else
-static int bind_to_index( int fd, in_addr_t bind_addr, unsigned int index ) +static int bind_to_index( int fd, in_addr_t bind_addr, const char *name, unsigned int index, BOOL *need_reuse_addr ) { errno = EOPNOTSUPP; return -1; @@ -1841,6 +1856,7 @@ static int bind_to_interface( struct sock *sock, const struct sockaddr_in *addr struct ifaddrs *ifaddrs, *ifaddr; int fd = get_unix_fd( sock->fd ); static const int enable = 1; + BOOL need_reuse_addr; unsigned int index;
if (bind_addr == htonl( INADDR_ANY ) || bind_addr == htonl( INADDR_LOOPBACK )) @@ -1866,14 +1882,14 @@ static int bind_to_interface( struct sock *sock, const struct sockaddr_in *addr
freeifaddrs( ifaddrs );
- if (bind_to_index( fd, bind_addr, index ) < 0) + if (bind_to_index( fd, bind_addr, ifaddr->ifa_name, index, &need_reuse_addr ) < 0) { if (debug_level) fprintf( stderr, "failed to bind to interface: %s\n", strerror( errno ) ); return 0; }
- if (setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable) ) < 0) + if (need_reuse_addr && setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable) ) < 0) { if (debug_level) fprintf( stderr, "failed to reuse address: %s\n", strerror( errno ) );
Does this qualify for Wine-bug: 50499 and 33008?
Am 12.10.2021 um 19:55 schrieb Paul Gofman pgofman@codeweavers.com:
Signed-off-by: Paul Gofman pgofman@codeweavers.com
Using SO_REUSEADDR is currently problematic when more than one UDP socket is bound to different interfaces. While that succeeds, it is unspecified which socket will receive a packet coming to INADDR_ANY. The filter being installed for each socket with SO_ATTACH_FILTER can only reject the packet coming for another interface but that rejected packed doesn't arrive to another socket.
SO_BINDTODEVICE seems to do exactly what we want without installing any socket filters and without requiring SO_REUSEADDR or SO_REUSEPORT. It originally considered for implementing broadcast listen on interface bound sockets but it wasn't much useful by that time as the SO_BINDTODEVICE required CAP_NET_RAW privilege which is normally not available for a non-root user. However, that changed since Linux 5.7 [2].
This patch uses SO_BINDTODEVICE but falls back to the previous way if that fails.
- https://www.winehq.org/pipermail/wine-devel/2011-October/092681.html
- https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/patch/?id...
server/sock.c | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-)
diff --git a/server/sock.c b/server/sock.c index 03716cba90f..af08cd6be24 100644 --- a/server/sock.c +++ b/server/sock.c @@ -1756,12 +1756,14 @@ static int accept_into_socket( struct sock *sock, struct sock *acceptsock )
#ifdef IP_BOUND_IF
-static int bind_to_index( int fd, in_addr_t bind_addr, unsigned int index ) +static int bind_to_index( int fd, in_addr_t bind_addr, const char *name, unsigned int index, BOOL *need_reuse_addr ) {
- *need_reuse_addr = TRUE;
- return setsockopt( fd, IPPROTO_IP, IP_BOUND_IF, &index, sizeof(index) );
}
-#elif defined(IP_UNICAST_IF) && defined(SO_ATTACH_FILTER) +#elif defined(IP_UNICAST_IF) && defined(SO_ATTACH_FILTER) && defined(SO_BINDTODEVICE)
struct interface_filter { @@ -1794,13 +1796,26 @@ static struct interface_filter generic_interface_filter = BPF_STMT(BPF_RET+BPF_K, 0) /* dump packet */ };
-static int bind_to_index( int fd, in_addr_t bind_addr, unsigned int index ) +static int bind_to_index( int fd, in_addr_t bind_addr, const char *name, unsigned int index, BOOL *need_reuse_addr ) { in_addr_t ifindex = htonl( index ); struct interface_filter specific_interface_filter; struct sock_fprog filter_prog; int ret;
- if (!setsockopt( fd, SOL_SOCKET, SO_BINDTODEVICE, name, strlen( name ) + 1 ))
- {
*need_reuse_addr = FALSE;
return 0;
- }
- /* SO_BINDTODEVICE requires NET_CAP_RAW until Linux 5.7. */
- if (debug_level)
fprintf( stderr, "setsockopt SO_BINDTODEVICE fd %d, name %s failed: %s, falling back to SO_REUSE_ADDR\n",
fd, name, strerror( errno ));
- *need_reuse_addr = TRUE;
- if ((ret = setsockopt( fd, IPPROTO_IP, IP_UNICAST_IF, &ifindex, sizeof(ifindex) )) < 0) return ret;
@@ -1814,7 +1829,7 @@ static int bind_to_index( int fd, in_addr_t bind_addr, unsigned int index )
#else
-static int bind_to_index( int fd, in_addr_t bind_addr, unsigned int index ) +static int bind_to_index( int fd, in_addr_t bind_addr, const char *name, unsigned int index, BOOL *need_reuse_addr ) { errno = EOPNOTSUPP; return -1; @@ -1841,6 +1856,7 @@ static int bind_to_interface( struct sock *sock, const struct sockaddr_in *addr struct ifaddrs *ifaddrs, *ifaddr; int fd = get_unix_fd( sock->fd ); static const int enable = 1;
BOOL need_reuse_addr; unsigned int index;
if (bind_addr == htonl( INADDR_ANY ) || bind_addr == htonl( INADDR_LOOPBACK ))
@@ -1866,14 +1882,14 @@ static int bind_to_interface( struct sock *sock, const struct sockaddr_in *addr
freeifaddrs( ifaddrs );
if (bind_to_index( fd, bind_addr, index ) < 0)
if (bind_to_index( fd, bind_addr, ifaddr->ifa_name, index, &need_reuse_addr ) < 0) { if (debug_level) fprintf( stderr, "failed to bind to interface: %s\n", strerror( errno ) ); return 0; }
if (setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable) ) < 0)
if (need_reuse_addr && setsockopt( fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable) ) < 0) { if (debug_level) fprintf( stderr, "failed to reuse address: %s\n", strerror( errno ) );
-- 2.31.1
Bug 33008 looks like about this. Bug 50499 is not related, that one is about SO_REUSEADDR explicitly used by an app (and not set by us to workaround broadcast issue) and behaving differently on Windows and Linux WRT which socket receives packets. I guess Bug 50499 can only be solved by using SO_ATTACH_REUSEPORT_CBPF as suggested there. But it is likely more complicated than just adding a filter as we probably need to track the 'reuse port' groups and adjust the filter accordingly on new binds and socket close. That should be easier now I guess when this all happens in wineserver than it would be before.
On 10/12/21 20:50, Stefan Dösinger wrote:
Does this qualify for Wine-bug: 50499 and 33008?
Am 12.10.2021 um 19:55 schrieb Paul Gofman pgofman@codeweavers.com:
Signed-off-by: Paul Gofman pgofman@codeweavers.com
Using SO_REUSEADDR is currently problematic when more than one UDP socket is bound to different interfaces. While that succeeds, it is unspecified which socket will receive a packet coming to INADDR_ANY. The filter being installed for each socket with SO_ATTACH_FILTER can only reject the packet coming for another interface but that rejected packed doesn't arrive to another socket. SO_BINDTODEVICE seems to do exactly what we want without installing any socket filters and without requiring SO_REUSEADDR or SO_REUSEPORT. It originally considered for implementing broadcast listen on interface bound sockets but it wasn't much useful by that time as the SO_BINDTODEVICE required CAP_NET_RAW privilege which is normally not available for a non-root user. However, that changed since Linux 5.7 [2]. This patch uses SO_BINDTODEVICE but falls back to the previous way if that fails. 1. https://www.winehq.org/pipermail/wine-devel/2011-October/092681.html 2. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/patch/?id=c427bfec18f2190b8f4718785ee8ed2db4f84ee6
server/sock.c | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-)
On 10/12/21 21:06, Paul Gofman wrote:
Bug 33008 looks like about this.
After a bit more careful consideration it looks to me 33008 is also different. That bug doesn't concern multiple sockets, as per description just one is created and the issue is the bind address substiution (something -> INADDR_ANY) which breaks some NAT rules setup on the machine. With this patche the address substitution still takes place, it is just it is not supposed to break multiple UDP sockets bound to different interface addresses with the same port. I am not currently aware if we can avoid INADDR_ANY substitution to receive broadcasts. I think there is no exception on this matter in Linux. So unless we want to do something completely different and much more complicated, like bringing in another "shadow" socket to listen to broadcasts and forward those, this bug will stay open.
On 10/12/21 21:06, Paul Gofman wrote:
Bug 33008 looks like about this.
This is correct, Bug 33008 is about two applications using the same port and binding to two different interfaces. This can be solved with a SO_ATTACH_REUSEPORT_CBPF rule, but it is complicated.
On 10/12/21 21:06, Paul Gofman wrote:
Bug 50499 is not related, that one is about SO_REUSEADDR explicitly used by an app (and not set by us to workaround broadcast issue) and behaving differently on Windows and Linux WRT which socket receives packets.
This is correct, though the solution is "the same". The SO_REUSEADDR behavior is easier to implement though, it just involves applying a SO_ATTACH_REUSEPORT_CBPF rule that always returns zero (zero is oldest).
Best, Erich
On Tue, Oct 12, 2021 at 12:50 PM Erich E. Hoover erich.e.hoover@gmail.com wrote:
On 10/12/21 21:06, Paul Gofman wrote:
Bug 33008 looks like about this.
This is correct, Bug 33008 is about two applications using the same port and binding to two different interfaces. This can be solved with a SO_ATTACH_REUSEPORT_CBPF rule, but it is complicated.
Ack, this is _incorrect_. Sorry about that.
Best, Erich
On Tue, Oct 12, 2021 at 12:51 PM Erich E. Hoover erich.e.hoover@gmail.com wrote:
On Tue, Oct 12, 2021 at 12:50 PM Erich E. Hoover erich.e.hoover@gmail.com wrote:
On 10/12/21 21:06, Paul Gofman wrote:
Bug 33008 looks like about this.
This is correct, Bug 33008 is about two applications using the same port and binding to two different interfaces. This can be solved with a SO_ATTACH_REUSEPORT_CBPF rule, but it is complicated.
Ack, this is _incorrect_. Sorry about that.
Wait, no - I had that right the first time. I really need more coffee today. Bug 33008 is about interface binding with two different applications using the same port on two interfaces (this issue). This can be solved with SO_ATTACH_REUSEPORT_CBPF rule, but it is complicated.
Best, Erich
On 10/12/21 21:58, Erich E. Hoover wrote:
On Tue, Oct 12, 2021 at 12:51 PM Erich E. Hoover erich.e.hoover@gmail.com wrote:
Wait, no - I had that right the first time. I really need more coffee today. Bug 33008 is about interface binding with two different applications using the same port on two interfaces (this issue). This can be solved with SO_ATTACH_REUSEPORT_CBPF rule, but it is complicated.
Hm... I am a bit unsure anymore what exactly is 33008, I read there that it is claimed incorrect to have some 1.2.3.4->0.0.0.0 per se as it breaks some NAT rules. But if it is strictly about two Wine processes binding UDP to different interfaces, same port, I think my patch should be fixing that.
On 10/12/21 21:50, Erich E. Hoover wrote:
On 10/12/21 21:06, Paul Gofman wrote:
Bug 50499 is not related, that one is about SO_REUSEADDR explicitly used by an app (and not set by us to workaround broadcast issue) and behaving differently on Windows and Linux WRT which socket receives packets.
This is correct, though the solution is "the same". The SO_REUSEADDR behavior is easier to implement though, it just involves applying a SO_ATTACH_REUSEPORT_CBPF rule that always returns zero (zero is oldest).
I am afraid it might be not that simple. If you close the oldest socket the last one will take its place which is probably not the one which should now start receiving all the packets.
On Tue, Oct 12, 2021 at 1:34 PM Paul Gofman pgofman@codeweavers.com wrote:
... Hm... I am a bit unsure anymore what exactly is 33008, I read there that it is claimed incorrect to have some 1.2.3.4->0.0.0.0 per se as it breaks some NAT rules. But if it is strictly about two Wine processes binding UDP to different interfaces, same port, I think my patch should be fixing that.
One process is a Wine process and the other is not, but the problem is that the Wine process is gobbling the packets meant for the other process (packets for the other process come to us since we bind second, and we're dropping all packets that are not part of our interface bind). Your patch will fix the issue for newer kernels, though it's also possible to fix it for older kernels with an incredibly complicated SO_ATTACH_REUSEPORT_CBPF rule (you can make a list of your sockets, match against that list, and return the ID that corresponds to the correct socket in the list or return -1 for the regular Linux behavior if it's not on the list).
On Tue, Oct 12, 2021 at 1:49 PM Paul Gofman pgofman@codeweavers.com wrote:
On 10/12/21 21:50, Erich E. Hoover wrote:
On 10/12/21 21:06, Paul Gofman wrote:
Bug 50499 is not related, that one is about SO_REUSEADDR explicitly used by an app (and not set by us to workaround broadcast issue) and behaving differently on Windows and Linux WRT which socket receives packets.
This is correct, though the solution is "the same". The SO_REUSEADDR behavior is easier to implement though, it just involves applying a SO_ATTACH_REUSEPORT_CBPF rule that always returns zero (zero is oldest).
I am afraid it might be not that simple. If you close the oldest socket the last one will take its place which is probably not the one which should now start receiving all the packets.
I suppose that's true, we probably would cover 99.99% of use cases with return 0 - but 100% proper implementation likely requires record keeping which socket is the oldest and returning the correct number.
Best, Erich
On 10/12/21 23:21, Erich E. Hoover wrote:
On Tue, Oct 12, 2021 at 1:34 PM Paul Gofman pgofman@codeweavers.com wrote:
... Hm... I am a bit unsure anymore what exactly is 33008, I read there that it is claimed incorrect to have some 1.2.3.4->0.0.0.0 per se as it breaks some NAT rules. But if it is strictly about two Wine processes binding UDP to different interfaces, same port, I think my patch should be fixing that.
One process is a Wine process and the other is not, but the problem is that the Wine process is gobbling the packets meant for the other process (packets for the other process come to us since we bind second, and we're dropping all packets that are not part of our interface bind). Your patch will fix the issue for newer kernels, though it's also possible to fix it for older kernels with an incredibly complicated SO_ATTACH_REUSEPORT_CBPF rule (you can make a list of your sockets, match against that list, and return the ID that corresponds to the correct socket in the list or return -1 for the regular Linux behavior if it's not on the list).
Yes, we would need to maintain the ordered 'reuse groups' in the wineserver and update the filters on sockets bind and close. That's for Wine only operation within a single prefix. As for another non-Wine (or other Wine prefix processes) I am not sure how we can track that at all, at least I could not find a way to query 'reuse group' information from the system. I don't see how returning -1 would make sense as falling back to the plain SO_REUSEPORT mechanism can still leave the other app without packets routed instead to our (wrongly bound) sockets. Even without the non-Wine processes part this seems rather complicated and given there seems to be a simple and sure way to do what we need since Linux 5.7 I don't see why would we need to implement a nontrivial intermediate step to be obsoleted anyway.
On Tue, Oct 12, 2021 at 2:32 PM Paul Gofman pgofman@codeweavers.com wrote:
On 10/12/21 23:21, Erich E. Hoover wrote:
On Tue, Oct 12, 2021 at 1:34 PM Paul Gofman pgofman@codeweavers.com wrote:
... Hm... I am a bit unsure anymore what exactly is 33008, I read there that it is claimed incorrect to have some 1.2.3.4->0.0.0.0 per se as it breaks some NAT rules. But if it is strictly about two Wine processes binding UDP to different interfaces, same port, I think my patch should be fixing that.
One process is a Wine process and the other is not, but the problem is that the Wine process is gobbling the packets meant for the other process (packets for the other process come to us since we bind second, and we're dropping all packets that are not part of our interface bind). Your patch will fix the issue for newer kernels, though it's also possible to fix it for older kernels with an incredibly complicated SO_ATTACH_REUSEPORT_CBPF rule (you can make a list of your sockets, match against that list, and return the ID that corresponds to the correct socket in the list or return -1 for the regular Linux behavior if it's not on the list).
Yes, we would need to maintain the ordered 'reuse groups' in the wineserver and update the filters on sockets bind and close. That's for Wine only operation within a single prefix. As for another non-Wine (or other Wine prefix processes) I am not sure how we can track that at all, at least I could not find a way to query 'reuse group' information from the system.
Yes, my understanding is that we would need to coordinate "amongst ourselves" and we would assume that nobody else tries to make a conflicting reuse group (probably a fair assumption).
I don't see how returning -1 would make sense as falling back to the plain SO_REUSEPORT mechanism can still leave the other app without packets routed instead to our (wrongly bound) sockets.
That's a fair point.
Even without the non-Wine processes part this seems rather complicated and given there seems to be a simple and sure way to do what we need since Linux 5.7 I don't see why would we need to implement a nontrivial intermediate step to be obsoleted anyway.
Agreed, "back in the day" this was the only way to solve the problem and the complexity kept me from proposing a proper fix. Fortunately things are much easier now and all the issues should be resolved on newer kernels with your patch.
Best, Erich
On 10/12/21 11:55, Paul Gofman wrote:
Signed-off-by: Paul Gofman pgofman@codeweavers.com
Using SO_REUSEADDR is currently problematic when more than one UDP socket is bound to different interfaces. While that succeeds, it is unspecified which socket will receive a packet coming to INADDR_ANY. The filter being installed for each socket with SO_ATTACH_FILTER can only reject the packet coming for another interface but that rejected packed doesn't arrive to another socket. SO_BINDTODEVICE seems to do exactly what we want without installing any socket filters and without requiring SO_REUSEADDR or SO_REUSEPORT. It originally considered for implementing broadcast listen on interface bound sockets but it wasn't much useful by that time as the SO_BINDTODEVICE required CAP_NET_RAW privilege which is normally not available for a non-root user. However, that changed since Linux 5.7 [2]. This patch uses SO_BINDTODEVICE but falls back to the previous way if that fails. 1. https://www.winehq.org/pipermail/wine-devel/2011-October/092681.html 2. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/patch/?id=c427bfec18f2190b8f4718785ee8ed2db4f84ee6
server/sock.c | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-)
diff --git a/server/sock.c b/server/sock.c index 03716cba90f..af08cd6be24 100644 --- a/server/sock.c +++ b/server/sock.c @@ -1756,12 +1756,14 @@ static int accept_into_socket( struct sock *sock, struct sock *acceptsock )
#ifdef IP_BOUND_IF
-static int bind_to_index( int fd, in_addr_t bind_addr, unsigned int index ) +static int bind_to_index( int fd, in_addr_t bind_addr, const char *name, unsigned int index, BOOL *need_reuse_addr )
Perhaps we should rename bind_to_index to bind_to_iface or something, then?
Actually, for that matter, should we just pass the name, and call if_nametoindex() only as needed?
Also, do we really need to return a bool? Can we just call SO_REUSEADDR in bind_to_index() instead? That strikes me as cleaner, despite duplicating the call.
On 10/12/21 20:58, Zebediah Figura (she/her) wrote:
On 10/12/21 11:55, Paul Gofman wrote:
Signed-off-by: Paul Gofman pgofman@codeweavers.com
Using SO_REUSEADDR is currently problematic when more than one UDP socket is bound to different interfaces. While that succeeds, it is unspecified which socket will receive a packet coming to INADDR_ANY. The filter being installed for each socket with SO_ATTACH_FILTER can only reject the packet coming for another interface but that rejected packed doesn't arrive to another socket.
SO_BINDTODEVICE seems to do exactly what we want without installing any socket filters and without requiring SO_REUSEADDR or SO_REUSEPORT. It originally considered for implementing broadcast listen on interface bound sockets but it wasn't much useful by that time as the SO_BINDTODEVICE required CAP_NET_RAW privilege which is normally not available for a non-root user. However, that changed since Linux 5.7 [2].
This patch uses SO_BINDTODEVICE but falls back to the previous way if that fails.
1. https://www.winehq.org/pipermail/wine-devel/2011-October/092681.html 2. https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/patch/?id...
server/sock.c | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-)
diff --git a/server/sock.c b/server/sock.c index 03716cba90f..af08cd6be24 100644 --- a/server/sock.c +++ b/server/sock.c @@ -1756,12 +1756,14 @@ static int accept_into_socket( struct sock *sock, struct sock *acceptsock ) #ifdef IP_BOUND_IF -static int bind_to_index( int fd, in_addr_t bind_addr, unsigned int index ) +static int bind_to_index( int fd, in_addr_t bind_addr, const char *name, unsigned int index, BOOL *need_reuse_addr )
Perhaps we should rename bind_to_index to bind_to_iface or something, then?
Actually, for that matter, should we just pass the name, and call if_nametoindex() only as needed?
Also, do we really need to return a bool? Can we just call SO_REUSEADDR in bind_to_index() instead? That strikes me as cleaner, despite duplicating the call.
I thought of that but was tempted to avoid duplication. I will resend this way.