Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 10 Aug 2020 16:55:30 +0000
From:      bugzilla-noreply@freebsd.org
To:        bugs@FreeBSD.org
Subject:   [Bug 248579] PRoblem with accept(2) and dual IPv4/IPv6 TCP servers
Message-ID:  <bug-248579-227@https.bugs.freebsd.org/bugzilla/>

next in thread | raw e-mail | index | archive | help
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=3D248579

            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@FreeBSD.org
          Reporter: rec@rcousins.com

While writing a TCP server designed to accept both IPv4 and IPv6 connection=
s,
I've found that the recommended way fails, but the same code runs under Lin=
ux
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 =3D NULL;

  memset(&hints, 0, sizeof(hints));
  //  hints.ai_family =3D PF_UNSPEC;
  hints.ai_family =3D AF_INET6;=20=20
  hints.ai_socktype =3D SOCK_STREAM;
  hints.ai_protocol =3D IPPROTO_TCP;
  hints.ai_flags =3D AI_PASSIVE;

  if ((error =3D getaddrinfo(NULL, port, &hints, &res0)))
    errx(1, "%s", gai_strerror(error));

  for (res =3D res0; res; res =3D res->ai_next) {
    printf("Trying Family=3D%d, Socktype=3D%d, Protocol=3D%d\n",
           res->ai_family,=20
           res->ai_socktype,
           res->ai_protocol);
    if ((s =3D socket(res->ai_family,=20
                    res->ai_socktype,
                    res->ai_protocol)) < 0) {
      cause =3D "socket";
      continue;
    }
    int yes =3D 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 =3D "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 =3D make_listen("5000");

  while (1) {
    char addr[80];
    struct sockaddr_storage client_addr;
    socklen_t client_addr_len =3D sizeof(client_addr);

    int fc =3D accept(listen_fd,
                    (struct sockaddr *)&client_addr,
                    &client_addr_len);
    if (fc < 0) {
      warn("Accept()");
      continue;
    }

    if (client_addr.ss_family =3D=3D AF_INET) {
      struct sockaddr_in *p =3D (struct sockaddr_in *)&client_addr;
      inet_ntop(p->sin_family, &p->sin_addr,
              addr,sizeof(addr));
    } else {
      struct sockaddr_in6 *p =3D (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);
  }
}

--=20
You are receiving this mail because:
You are the assignee for the bug.=



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?bug-248579-227>