(This patch is similar to nbdkit commit 9eec2335d630, "server/sockets: get
rid of AI_ADDRCONFIG", 2022-01-19).
Consider the following call tree:
  start_conversion()                [conversion.c]
    start_nbd_server()              [nbd.c]
      open_listening_socket()       [nbd.c]
        bind_tcpip_socket()         [nbd.c]
          getaddrinfo()
          socket()
          bind()
    wait_for_nbd_server_to_start()  [nbd.c]
      connect_to_nbdkit()           [nbd.c]
        getaddrinfo()
        socket()
        connect()
    open_data_connection()          [ssh.c]
      /* "-R 0:localhost:<port>" */
- For each of IPv4 and IPv6, if the network config on the host running
  virt-p2v supports that protocol, then bind_tcpip_socket() intends to
  bind the port for that protocol.
- connect_to_nbdkit() connects to the port using *one* of IPv4 and IPv6;
  it just wants to see NBDMAGIC, regardless of IP version.
- The ssh "-R 0:localhost:<port>" option, formatted by
  open_data_connection(), instructs ssh to create a reverse forwarding
  channel (a listening socket) per IP version (this can be verified with
  "netstat" on the conversion server). In case the reverse NBD connection
  on the conversion server were made to sshd over IPv6, then ssh on the
  p2v server would presumably want to connect to nbdkit over IPv6 too.
The (theoretical) problem with using AI_ADDRCONFIG in bind_tcpip_socket()
is that, in case the p2v server has no publicly routable IPv6 address
assigned, then bind_tcpip_socket() will not bind ::1 from "localhost". And
then the IPv6 reverse forwarding attempt, set up by
open_data_connection(), *might* fail.
Remove AI_ADDRCONFIG anyway. While at it, spell out AF_UNSPEC as well (in
practice, this makes no difference, as Linux defines AF_UNSPEC as
PF_UNSPEC as 0).
While running the local test suite ("make -j10 check") on a host without a
publicly routable IPv6 address, the "netstat -anp" output changes, due to
this patch. Before:
 Active Internet connections (servers and established)
 Proto Recv-Q Send-Q Local Address           Foreign Address         State      
PID/Program name
 tcp        0      0 127.0.0.1:58273         0.0.0.0:*               LISTEN     
51057/nbdkit
 tcp        0      0 127.0.0.1:58272         0.0.0.0:*               LISTEN     
51050/nbdkit
 tcp        0      0 127.0.0.1:58272         127.0.0.1:35332         ESTABLISHED
51050/nbdkit
 tcp        0      0 127.0.0.1:35332         127.0.0.1:58272         ESTABLISHED
51204/nbdkit 
We have two nbdkit processes (PIDs 51057 and 51050) listening over TCPv4,
and a third one (PID 51204) connected to PID 51050 over TCPv4.
After:
 Active Internet connections (servers and established)
 Proto Recv-Q Send-Q Local Address           Foreign Address         State      
PID/Program name
 tcp        0      0 127.0.0.1:54146         0.0.0.0:*               LISTEN     
49310/nbdkit
 tcp        0      0 127.0.0.1:54145         0.0.0.0:*               LISTEN     
49303/nbdkit
 tcp6       0      0 ::1:54145               :::*                    LISTEN     
49303/nbdkit
 tcp6       0      0 ::1:54146               :::*                    LISTEN     
49310/nbdkit
 tcp6       0      0 ::1:57432               ::1:54145               ESTABLISHED
49457/nbdkit
 tcp6       0      0 ::1:54145               ::1:57432               ESTABLISHED
49303/nbdkit 
The two listening nbdkit processes (PIDs 49310 and 49303) are now doing so
over both TCPv4 and TCPv6, and the third one (PID 49457) actually connects
to PID 49303 over TCPv6!
Ref: 
https://listman.redhat.com/archives/libguestfs/2022-March/028475.html
Suggested-by: Richard W.M. Jones <rjones(a)redhat.com>
Signed-off-by: Laszlo Ersek <lersek(a)redhat.com>
Reviewed-by: Richard W.M. Jones <rjones(a)redhat.com>
---
Notes:
    v2:
    - pick up Rich's R-b
 nbd.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/nbd.c b/nbd.c
index b836e50aa03d..cd1b9ab6197b 100644
--- a/nbd.c
+++ b/nbd.c
@@ -279,90 +279,91 @@ static int
 bind_tcpip_socket (const char *port, int **fds_rtn, size_t *nr_fds_rtn)
 {
   struct addrinfo *ai = NULL;
   struct addrinfo hints;
   struct addrinfo *a;
   int err;
   int *fds = NULL;
   size_t nr_fds;
   int addr_in_use = 0;
 
   memset (&hints, 0, sizeof hints);
-  hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
+  hints.ai_family = AF_UNSPEC;
+  hints.ai_flags = AI_PASSIVE;
   hints.ai_socktype = SOCK_STREAM;
 
   err = getaddrinfo ("localhost", port, &hints, &ai);
   if (err != 0) {
 #if DEBUG_STDERR
     fprintf (stderr, "%s: getaddrinfo: localhost: %s: %s", g_get_prgname (),
              port, gai_strerror (err));
 #endif
     return -1;
   }
 
   nr_fds = 0;
 
   for (a = ai; a != NULL; a = a->ai_next) {
     int sock, opt;
 
     sock = socket (a->ai_family, a->ai_socktype, a->ai_protocol);
     if (sock == -1)
       error (EXIT_FAILURE, errno, "socket");
 
     opt = 1;
     if (setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof opt) == -1)
       perror ("setsockopt: SO_REUSEADDR");
 
 #ifdef IPV6_V6ONLY
     if (a->ai_family == PF_INET6) {
       if (setsockopt (sock, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof opt) == -1)
         perror ("setsockopt: IPv6 only");
     }
 #endif
 
     if (bind (sock, a->ai_addr, a->ai_addrlen) == -1) {
       if (errno == EADDRINUSE) {
         addr_in_use = 1;
         close (sock);
         continue;
       }
       perror ("bind");
       close (sock);
       continue;
     }
 
     if (listen (sock, SOMAXCONN) == -1) {
       perror ("listen");
       close (sock);
       continue;
     }
 
     nr_fds++;
     fds = realloc (fds, sizeof (int) * nr_fds);
     if (!fds)
       error (EXIT_FAILURE, errno, "realloc");
     fds[nr_fds-1] = sock;
   }
 
   freeaddrinfo (ai);
 
   if (nr_fds == 0 && addr_in_use) {
 #if DEBUG_STDERR
     fprintf (stderr, "%s: unable to bind to localhost:%s: %s\n",
              g_get_prgname (), port, strerror (EADDRINUSE));
 #endif
     return -1;
   }
 
 #if DEBUG_STDERR
   fprintf (stderr, "%s: bound to localhost:%s (%zu socket(s))\n",
            g_get_prgname (), port, nr_fds);
 #endif
 
   *fds_rtn = fds;
   *nr_fds_rtn = nr_fds;
   return 0;
 }
 
 /**
  * Wait for nbdkit to start and be listening for connections.
  */
-- 
2.19.1.3.g30247aa5d201