chiark / gitweb /
pkstream/pkstream.c: Be more careful about handling address families.
authorMark Wooding <mdw@distorted.org.uk>
Thu, 28 Sep 2017 00:52:03 +0000 (01:52 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Thu, 28 Jun 2018 23:24:00 +0000 (00:24 +0100)
  * Introduce a concept of `known' address families.  Currently, only
    `AF_INET' is known.

  * Filter `struct addrinfo' chains for known address families.  If we
    come up short, complain.

  * Tweak `aihints' to arrange that addresses which are supposed to
    match up actually will do: so server peer and bind addresses should
    match; client bind and connect addresses should match; and UDP local
    and remote addresses should match.

  * Initialize address structures using the `ai_family' slot from the
    appropriate `struct addrinfo' structure.

pkstream/pkstream.c

index dd4658e4f6d7b5cb3b28f1ee1270925057582864..cf66b3e419518c5b40d1908e6ca17876a926081f 100644 (file)
@@ -111,6 +111,14 @@ static socklen_t addrsz(const addr *a)
   }
 }
 
+static int knownafp(int af)
+{
+  switch (af) {
+    case AF_INET: return (1);
+    default: return (0);
+  }
+}
+
 static int initsock(int fd, int af)
 {
   switch (af) {
@@ -141,11 +149,17 @@ static int addreq(const addr *a, const addr *b)
   }
 }
 
-static void initaddr(addr *a)
+static void initaddr(addr *a, int af)
 {
-  a->sin.sin_family = AF_INET;
-  a->sin.sin_addr.s_addr = INADDR_ANY;
-  a->sin.sin_port = 0;
+  a->sa.sa_family = af;
+  switch (af) {
+    case AF_INET:
+      a->sin.sin_addr.s_addr = INADDR_ANY;
+      a->sin.sin_port = 0;
+      break;
+    default:
+      abort();
+  }
 }
 
 #define caf_addr 1u
@@ -343,10 +357,12 @@ static void pushaddrs(addr_v *av, const struct addrinfo *ailist)
   const struct addrinfo *ai;
   size_t i, n;
 
-  for (ai = ailist, n = 0; ai; ai = ai->ai_next) n++;
+  for (ai = ailist, n = 0; ai; ai = ai->ai_next)
+    if (knownafp(ai->ai_family)) n++;
   DA_ENSURE(av, n);
   for (i = DA_LEN(av), ai = ailist; ai; ai = ai->ai_next) {
-    initaddr(&DA(av)[i]);
+    if (!knownafp(ai->ai_family)) continue;
+    initaddr(&DA(av)[i], ai->ai_family);
     copyaddr(&DA(av)[i++], ai->ai_addr, caf_addr | caf_port);
   }
   DA_EXTEND(av, n);
@@ -481,9 +497,13 @@ int main(int argc, char *argv[])
       freeaddrinfo(ailist);
     } else if (!bindsvc) {
       if (n != 1) die(1, "can only bind to one address as client");
-      parseaddr(&aihint, DA(&bindhosts)[0], 0, 0, &ailist); ai = ailist;
-      initaddr(&bindaddr);
+      parseaddr(&aihint, DA(&bindhosts)[0], 0, 0, &ailist);
+      for (ai = ailist; ai && !knownafp(ai->ai_family); ai = ai->ai_next);
+      if (!ai)
+       die(1, "no usable addresses returned for `%s'", DA(&bindhosts)[0]);
+      initaddr(&bindaddr, ai->ai_family);
       copyaddr(&bindaddr, ai->ai_addr, caf_addr);
+      aihint.ai_family = ai->ai_family;
       freeaddrinfo(ailist);
     } else for (i = 0; i < n; i++) {
       parseaddr(&aihint, DA(&bindhosts)[i], bindsvc, 0, &ailist);
@@ -507,6 +527,7 @@ int main(int argc, char *argv[])
       pushaddrs(&cw.peer, ailist);
       freeaddrinfo(ailist);
     }
+    if (!DA_LEN(&cw.peer)) die(1, "no usable peer addresses");
   }
 
   if (connhost) {
@@ -530,10 +551,13 @@ int main(int argc, char *argv[])
       die(1, "couldn't connect to TCP server: %s", strerror(errno));
   }
 
+  aihint.ai_family = AF_INET;
   aihint.ai_socktype = SOCK_DGRAM;
   aihint.ai_protocol = IPPROTO_UDP;
   aihint.ai_flags = AI_ADDRCONFIG | AI_PASSIVE;
-  parseaddr(&aihint, argv[optind], 0, paf_parse, &ailist); ai = ailist;
+  parseaddr(&aihint, argv[optind], 0, paf_parse, &ailist);
+  for (ai = ailist; ai && !knownafp(ai->ai_family); ai = ai->ai_next);
+  if (!ai) die(1, "no usable addresses returned for `%s'", argv[optind]);
   if ((fd_udp = socket(ai->ai_family, SOCK_DGRAM, IPPROTO_UDP)) < 0 ||
       initsock(fd_udp, ai->ai_family) ||
       nonblockify(fd_udp) || cloexec(fd_udp) ||
@@ -542,6 +566,7 @@ int main(int argc, char *argv[])
       bind(fd_udp, ai->ai_addr, ai->ai_addrlen))
     die(1, "couldn't set up UDP socket: %s", strerror(errno));
   freeaddrinfo(ailist);
+  aihint.ai_family = ai->ai_family;
   aihint.ai_flags = AI_ADDRCONFIG;
   parseaddr(&aihint, argv[optind + 1], 0, paf_parse, &ailist);
   for (ai = ailist; ai; ai = ai->ai_next)