pathmtu/pathmtu.c: Support IPv6 in Linux probing method.
authorMark Wooding <mdw@distorted.org.uk>
Thu, 14 Sep 2017 09:14:59 +0000 (10:14 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Thu, 28 Jun 2018 23:26:39 +0000 (00:26 +0100)
pathmtu/pathmtu.c

index 8cf7d18..a352633 100644 (file)
@@ -664,7 +664,9 @@ static const struct probe_ops raw_ops = {
 #endif
 
 struct linux_state {
+  int sol, so_mtu_discover, so_mtu;
   int sk;
+  size_t hdrlen;
 };
 
 static int linux_setup(void *stv, int sk, const struct param *pp)
@@ -675,8 +677,21 @@ static int linux_setup(void *stv, int sk, const struct param *pp)
 
   /* Check that the address is OK. */
   switch (pp->a.sa.sa_family) {
-    case AF_INET: break;
-    default: errno = EPFNOSUPPORT; return (-1);
+    case AF_INET:
+      st->sol = IPPROTO_IP;
+      st->so_mtu_discover = IP_MTU_DISCOVER;
+      st->so_mtu = IP_MTU;
+      st->hdrlen = 28;
+      break;
+    case AF_INET6:
+      st->sol = IPPROTO_IPV6;
+      st->so_mtu_discover = IPV6_MTU_DISCOVER;
+      st->so_mtu = IPV6_MTU;
+      st->hdrlen = 48;
+      break;
+    default:
+      errno = EPFNOSUPPORT;
+      return (-1);
   }
 
   /* Snaffle the UDP socket. */
@@ -684,12 +699,12 @@ static int linux_setup(void *stv, int sk, const struct param *pp)
 
   /* Turn on kernel path-MTU discovery and force DF on. */
   i = IP_PMTUDISC_PROBE;
-  if (setsockopt(st->sk, IPPROTO_IP, IP_MTU_DISCOVER, &i, sizeof(i)))
+  if (setsockopt(st->sk, st->sol, st->so_mtu_discover, &i, sizeof(i)))
     return (-1);
 
   /* Read the initial MTU guess back and report it. */
   sz = sizeof(mtu);
-  if (getsockopt(st->sk, IPPROTO_IP, IP_MTU, &mtu, &sz))
+  if (getsockopt(st->sk, st->sol, st->so_mtu, &mtu, &sz))
     return (-1);
 
   /* Done. */
@@ -706,7 +721,7 @@ static int linux_xmit(void *stv, int mtu)
   struct linux_state *st = stv;
 
   /* Write the packet. */
-  if (write(st->sk, buf, mtu - 28) >= 0) return (RC_OK);
+  if (write(st->sk, buf, mtu - st->hdrlen) >= 0) return (RC_OK);
   else if (errno == EMSGSIZE) return (RC_LOWER);
   else return (RC_FAIL);
 }
@@ -733,7 +748,7 @@ static int linux_selproc(void *stv, fd_set *fd_in, struct probestate *ps)
        errno == ECONNREFUSED || errno == EHOSTUNREACH)
       return (RC_HIGHER);
     sz = sizeof(mtu);
-    if (getsockopt(st->sk, IPPROTO_IP, IP_MTU, &mtu, &sz))
+    if (getsockopt(st->sk, st->sol, st->so_mtu, &mtu, &sz))
       return (RC_FAIL);
     return (mtu);
   }