union addr {
struct sockaddr sa;
struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
};
+/* Check whether an address family is even slightly supported. */
+static int addrfamok(int af)
+{
+ switch (af) {
+ case AF_INET: case AF_INET6: return (1);
+ default: return (0);
+ }
+}
+
/* Return the size of a socket address. */
static size_t addrsz(const union addr *a)
{
switch (a->sa.sa_family) {
case AF_INET: return (sizeof(a->sin));
+ case AF_INET6: return (sizeof(a->sin6));
default: abort();
}
}
case AF_INET:
return (a->sin.sin_addr.s_addr == b->sin.sin_addr.s_addr &&
(!(f&AEF_PORT) || a->sin.sin_port == b->sin.sin_port));
+ case AF_INET6:
+ return (!memcmp(a->sin6.sin6_addr.s6_addr,
+ b->sin6.sin6_addr.s6_addr, 16) &&
+ (!(f&AEF_PORT) || a->sin6.sin6_port == b->sin6.sin6_port));
default:
abort();
}
st = xmalloc(pp->pops->statesz);
if ((mtu = pp->pops->setup(st, sk, pp)) < 0) goto fail_2;
ps.pp = pp; ps.q = rand() & 0xffff;
- lo = 576; hi = mtu;
+ switch (pp->a.sa.sa_family) {
+ case AF_INET: lo = 576; break;
+ case AF_INET6: lo = 1280; break;
+ default: abort();
+ }
+ hi = mtu;
+ if (hi < lo) { errno = EMSGSIZE; return (-1); }
/* And now we do a thing which is sort of like a binary search, except that
* we also take explicit clues as establishing a new upper bound, and we
static void usage(FILE *fp)
{
- pquis(fp, "Usage: $ [-v] [-H HEADER] [-m METHOD]\n\
+ pquis(fp, "Usage: $ [-46v] [-H HEADER] [-m METHOD]\n\
[-r SECS] [-g FACTOR] [-t SECS] HOST [PORT]\n");
}
-V, --version Show version number.\n\
-u, --usage Show brief usage message.\n\
\n\
+-4, --ipv4 Restrict to IPv4 only.\n\
+-6, --ipv6 Restrict to IPv6 only.\n\
-g, --growth=FACTOR Growth factor for retransmit interval.\n\
-m, --method=METHOD Use METHOD to probe for MTU.\n\
-r, --retransmit=SECS Retransmit if no reply after SEC.\n\
hex_ctx hc;
dstr d = DSTR_INIT;
size_t sz;
- int i;
- unsigned long u;
- char *q;
- struct hostent *h;
- struct servent *s;
+ int i, err;
+ struct addrinfo aihint = { 0 }, *ailist, *ai;
+ const char *host, *svc = "7";
unsigned f = 0;
#define f_bogus 1u
ego(argv[0]);
fillbuffer(buf, sizeof(buf));
- pp.a.sin.sin_port = htons(7);
+
+ aihint.ai_family = AF_UNSPEC;
+ aihint.ai_protocol = IPPROTO_UDP;
+ aihint.ai_socktype = SOCK_DGRAM;
+ aihint.ai_flags = AI_ADDRCONFIG;
for (;;) {
static const struct option opts[] = {
{ "help", 0, 0, 'h' },
{ "version", 0, 0, 'V' },
{ "usage", 0, 0, 'u' },
+ { "ipv4", 0, 0, '4' },
+ { "ipv6", 0, 0, '6' },
{ "header", OPTF_ARGREQ, 0, 'H' },
{ "growth", OPTF_ARGREQ, 0, 'g' },
{ "method", OPTF_ARGREQ, 0, 'm' },
{ 0, 0, 0, 0 }
};
- i = mdwopt(argc, argv, "hVu" "H:g:m:r:t:v", opts, 0, 0, 0);
+ i = mdwopt(argc, argv, "hVu" "46H:g:m:r:t:v", opts, 0, 0, 0);
if (i < 0) break;
switch (i) {
case 'h': help(stdout); exit(0);
pp.seqoff = sz;
break;
+ case '4': aihint.ai_family = AF_INET; break;
+ case '6': aihint.ai_family = AF_INET6; break;
case 'g': pp.regr = s2f(optarg, "retransmit growth factor"); break;
case 'r': pp.retx = s2f(optarg, "retransmit interval"); break;
case 't': pp.timeout = s2f(optarg, "timeout"); break;
exit(EXIT_FAILURE);
}
- if ((h = gethostbyname(*argv)) == 0)
- die(EXIT_FAILURE, "unknown host `%s': %s", *argv, hstrerror(h_errno));
- if (h->h_addrtype != AF_INET)
- die(EXIT_FAILURE, "unsupported address family for host `%s'", *argv);
- memcpy(&pp.a.sin.sin_addr, h->h_addr, sizeof(struct in_addr));
- argv++; argc--;
-
- if (*argv) {
- errno = 0;
- u = strtoul(*argv, &q, 0);
- if (!errno && !*q)
- pp.a.sin.sin_port = htons(u);
- else if ((s = getservbyname(*argv, "udp")) == 0)
- die(EXIT_FAILURE, "unknown UDP service `%s'", *argv);
- else
- pp.a.sin.sin_port = s->s_port;
+ host = argv[0];
+ if (argv[1]) svc = argv[1];
+ if ((err = getaddrinfo(host, svc, &aihint, &ailist)) != 0) {
+ die(EXIT_FAILURE, "unknown host `%s' or service `%s': %s",
+ host, svc, gai_strerror(err));
}
+ for (ai = ailist; ai && !addrfamok(ai->ai_family); ai = ai->ai_next);
+ if (!ai) die(EXIT_FAILURE, "no supported address families for `%s'", host);
+ assert(ai->ai_addrlen <= sizeof(pp.a));
+ memcpy(&pp.a, ai->ai_addr, ai->ai_addrlen);
- pp.a.sin.sin_family = AF_INET;
i = pathmtu(&pp);
if (i < 0)
die(EXIT_FAILURE, "failed to discover MTU: %s", strerror(errno));