Hi all,
there seems to be a regression which allows you to bind the same port
twice when the first bind call bound to all ip addresses (i. e. dual stack).
A second bind call for the same port will succeed if you try to bind to
a specific ipv4 (e. g. 127.0.0.1), binding to 0.0.0.0 or an ipv6 address
fails correctly with EADDRINUSE.
I included a small c program below to show the issue. Normally the
second bind call should fail, this was the case before v6.1.
I bisected the regression to commit 5456262d2baa ("net: Fix incorrect
address comparison when searching for a bind2 bucket").
I also checked that the issue is still present in v6.3-rc1.
Original report: https://github.com/containers/podman/issues/17719
#regzbot introduced: 5456262d2baa
```
#include <sys/socket.h>
#include <sys/un.h>
#include <stdlib.h>
#include <stdio.h>
#include <netinet/in.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int ret, sock1, sock2;
struct sockaddr_in6 addr;
struct sockaddr_in addr2;
sock1 = socket(AF_INET6, SOCK_STREAM, 0);
if (sock1 == -1)
{
perror("socket1");
exit(1);
}
sock2 = socket(AF_INET, SOCK_STREAM, 0);
if (sock2 == -1)
{
perror("socket2");
exit(1);
}
memset(&addr, 0, sizeof(addr));
addr.sin6_family = AF_INET6;
addr.sin6_addr = in6addr_any;
addr.sin6_port = htons(8080);
memset(&addr2, 0, sizeof(addr2));
addr2.sin_family = AF_INET;
addr2.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
addr2.sin_port = htons(8080);
ret = bind(sock1, (struct sockaddr *)&addr, sizeof(addr));
if (ret == -1)
{
perror("bind1");
exit(1);
}
printf("bind1 ret: %d\n", ret);
if ((listen(sock1, 5)) != 0)
{
perror("listen1");
exit(1);
}
ret = bind(sock2, (struct sockaddr *)&addr2, sizeof(addr2));
if (ret == -1)
{
perror("bind2");
exit(1);
}
printf("bind2 ret: %d\n", ret);
if ((listen(sock2, 5)) != 0)
{
perror("listen2");
exit(1);
}
// uncomment pause() to see with ss -tlpn the bound ports
// pause();
return 0;
}
```
Best regards,
Paul