[Bug 248579] PRoblem with accept(2) and dual IPv4/IPv6 TCP servers
bugzilla-noreply at freebsd.org
bugzilla-noreply at freebsd.org
Mon Aug 10 16:55:31 UTC 2020
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=248579
Bug ID: 248579
Summary: PRoblem with accept(2) and dual IPv4/IPv6 TCP servers
Product: Base System
Version: 12.1-RELEASE
Hardware: Any
OS: Any
Status: New
Severity: Affects Some People
Priority: ---
Component: kern
Assignee: bugs at FreeBSD.org
Reporter: rec at rcousins.com
While writing a TCP server designed to accept both IPv4 and IPv6 connections,
I've found that the recommended way fails, but the same code runs under Linux
perfectly. The failure is that IPv6 connections succeed and IPv4 connections
always fail.
Way to exercise bug:
- Compile code below (cc -o foo foo.c will work)
- run command ("./foo") in one window
- In another window try to connect to port 5000
for example: telnet ::1 5000 <-- should work
telnet 127.0.0.1 5000 <-- should work but fails 100% of the
time.
Repeating this test under modern Linux results in both telnet sessions
connecting.
Code to exercise bug:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <err.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int
make_listen(char *port)
{
struct addrinfo hints, *res, *res0;
int error;
int s;
const char *cause = NULL;
memset(&hints, 0, sizeof(hints));
// hints.ai_family = PF_UNSPEC;
hints.ai_family = AF_INET6;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
if ((error = getaddrinfo(NULL, port, &hints, &res0)))
errx(1, "%s", gai_strerror(error));
for (res = res0; res; res = res->ai_next) {
printf("Trying Family=%d, Socktype=%d, Protocol=%d\n",
res->ai_family,
res->ai_socktype,
res->ai_protocol);
if ((s = socket(res->ai_family,
res->ai_socktype,
res->ai_protocol)) < 0) {
cause = "socket";
continue;
}
int yes = 1;
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0)
errx(1,"Setsockopt(SO_REUSEADDR) failed.");
if (bind(s,
res->ai_addr,
res->ai_addrlen) < 0) {
cause = "bind";
close(s);
continue;
}
listen(s, 5);
freeaddrinfo(res0);
return s;
}
err(1, "%s", cause);
freeaddrinfo(res0);
return -1;
}
int
main(int argc, char *argv[])
{
int listen_fd = make_listen("5000");
while (1) {
char addr[80];
struct sockaddr_storage client_addr;
socklen_t client_addr_len = sizeof(client_addr);
int fc = accept(listen_fd,
(struct sockaddr *)&client_addr,
&client_addr_len);
if (fc < 0) {
warn("Accept()");
continue;
}
if (client_addr.ss_family == AF_INET) {
struct sockaddr_in *p = (struct sockaddr_in *)&client_addr;
inet_ntop(p->sin_family, &p->sin_addr,
addr,sizeof(addr));
} else {
struct sockaddr_in6 *p = (struct sockaddr_in6 *)&client_addr;
inet_ntop(p->sin6_family, &p->sin6_addr,
addr,sizeof(addr));
}
printf("Connection from (%d) %s\n",
client_addr_len,
addr);
(void)write(fc,"Hello\n",6);
close(fc);
}
}
--
You are receiving this mail because:
You are the assignee for the bug.
More information about the freebsd-bugs
mailing list