DatagramChannel::disconnect appears to rebind socket to the wildcard address
Kurt Miller
kurt at intricatesoftware.com
Wed Sep 25 18:50:47 UTC 2019
On Wed, 2019-09-25 at 18:38 +0100, Alan Bateman wrote:
> Is this project this active? Are there folks here that work on the
> xxxBSD ports?
>
> JDK-8231259 [1] is a bug submitted against the
> java.nio.channels.DatagramChannel implementation on macOS a few days
> ago. It looks like a macOS bug, rather than a JDK bug.
>
> The scenario is a UDP socket is bound to a specific local address,
> connected, and then disconnected (to dissolve the association). It seems
> that the disconnect changes the local address (as reported by
> getsocketname) to the wildcard address (INADDR_ANY or the IPv6
> equivalent). There are several ways to disconnect (disconnectx, connect
> with an invalid address, or connect with a family of AF_UNSPEC) and the
> unexplained behavior arises with all.
>
> If there are still people here then I'm wondering if the same behavior
> is observed on other BSD operating systems. That is, does UDP disconnect
> deliberately change the local address to INADDR_ANY?
>
> Thanks,
>
> -Alan
>
> [1] https://bugs.openjdk.java.net/browse/JDK-8231259
>
Hi Alan,
The project is active but currently we are using github forks of
AdoptOpenJDK.
Yes, I have observed that bug on OpenBSD as well. It is indeed
a kernel bug on OpenBSD. I have kernel patches to correct it
but haven't pushed them forward through the review process there.
I just did a quick test on FreeBSD 11 on amd64 and it also
doesn't retain the bound address.
Regards,
-Kurt
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/param.h>
#include <arpa/inet.h>
#include <netinet/in.h>
int main()
{
char hostname[MAXHOSTNAMELEN];
struct hostent *he;
int fd;
struct sockaddr addr;
struct sockaddr addr1;
socklen_t socklen;
char ip6str[INET6_ADDRSTRLEN];
if (gethostname(hostname, sizeof(hostname)) != 0) {
perror("gethostname failed");
exit(1);
}
if ((he = gethostbyname(hostname)) == NULL) {
perror("gethostbyname failed");
exit(1);
}
memset(&addr, 0, sizeof(addr));
addr.sa_family = he->h_addrtype;
if (addr.sa_family == AF_INET6) {
memcpy(&((struct sockaddr_in6 *)&addr)->sin6_addr, he->h_addr, he->h_length);
} else if (addr.sa_family == AF_INET) {
memcpy(&((struct sockaddr_in *)&addr)->sin_addr.s_addr, he->h_addr, he->h_length);
} else {
perror("unknown address family");
exit(1);
}
if ((fd = socket(addr.sa_family, SOCK_DGRAM, 0)) < 0) {
perror("socket failed");
exit(1);
}
if (bind(fd, &addr, sizeof(addr)) != 0) {
perror("bind failed");
exit(1);
}
/* retrive bound address info into addr and print results */
memset(&addr, 0, sizeof(addr));
socklen = sizeof(addr);
if (getsockname(fd, &addr, &socklen) != 0) {
perror("getsockname failed");
exit(1);
}
if (addr.sa_family == AF_INET6) {
inet_ntop(AF_INET6, &((struct sockaddr_in6 *)&addr)->sin6_addr, ip6str, sizeof(ip6str));
printf("Bind IP: %s\n", ip6str);
printf("Bind Port: %d\n", ((struct sockaddr_in6 *)&addr)->sin6_port);
} else if (addr.sa_family == AF_INET) {
printf("Bind IP: %s\n", inet_ntoa(((struct sockaddr_in *)&addr)->sin_addr));
printf("Bind Port: %d\n", ((struct sockaddr_in *)&addr)->sin_port);
}
/* setup addr1 for connect on port 16000 */
memset(&addr1, 0, sizeof(addr1));
addr1.sa_family = he->h_addrtype;
if (addr1.sa_family == AF_INET6) {
memcpy(&((struct sockaddr_in6 *)&addr1)->sin6_addr, he->h_addr, he->h_length);
((struct sockaddr_in6 *)&addr1)->sin6_port = 16000;
} else {
memcpy(&((struct sockaddr_in *)&addr1)->sin_addr.s_addr, he->h_addr, he->h_length);
((struct sockaddr_in *)&addr1)->sin_port = 16000;
}
if (connect(fd, &addr1, sizeof(addr1)) != 0) {
perror("connect failed");
exit(1);
}
/* disconnect dgram socket */
memset(&addr1, 0, sizeof(addr1));
addr1.sa_family = AF_UNSPEC;
/* disconnecting always returns EAFNOSUPPORT */
connect(fd, &addr1, sizeof(addr1));
/* re-retrive bound address info into addr1 */
memset(&addr1, 0, sizeof(addr1));
if (getsockname(fd, &addr1, &socklen) != 0) {
perror("getsockname failed");
exit(1);
}
if (addr1.sa_family == AF_INET6) {
inet_ntop(AF_INET6, &((struct sockaddr_in6 *)&addr1)->sin6_addr, ip6str, sizeof(ip6str));
printf("Bind IP: %s\n", ip6str);
printf("Bind Port: %d\n", ((struct sockaddr_in6 *)&addr1)->sin6_port);
} else if (addr1.sa_family == AF_INET) {
printf("Bind IP: %s\n", inet_ntoa(((struct sockaddr_in *)&addr1)->sin_addr));
printf("Bind Port: %d\n", ((struct sockaddr_in *)&addr1)->sin_port);
}
int ret = memcmp(&addr, &addr1, sizeof(addr1));
if (ret == 0)
printf("socket bind was not lost\n");
else
printf("socket bind changed\n");
return ret;
}
More information about the bsd-port-dev
mailing list