on reading the man page, i found a small flaw in the implementation. according to the man page, -6 forces is of icmp6, even if the address is icmp4. i changed ping to do that.as a result, i added a -4 flag which forces the ping to use icmp4. obviously, there is no native 6-in-4, so this is an error. also, i corrected an indirection of a nil pointer when a name lookup fails. my pathetic excuse for unit testing, and a diff are below. my version (hacks and all) is attached. - erik ps. the hand-implementation of csquery seems to be a result of not trusting ndb/cs to be running. odd. does anyone have context on why this would be useful? --- ; ip/ping -6an1 bwc sending 1 64 byte messages 1000 ms apart to icmpv6!2402:6b00:22cd:bf80::9!1 2402:6b00:22cd:bf80::7 -> 2402:6b00:22cd:bf80::9 0: 2402:6b00:22cd:bf80::9 -> 2402:6b00:22cd:bf80::7 rtt 78 µs, avg rtt 78 µs, ttl = 255 ; ip/ping -4an1 bwc sending 1 64 byte messages 1000 ms apart to icmp!10.1.1.9!1 10.1.1.7 -> 10.1.1.9 0: 10.1.1.9 -> 10.1.1.7 rtt 70 µs, avg rtt 70 µs, ttl = 255 ; ip/ping -an1 bwc sending 1 64 byte messages 1000 ms apart to icmp!10.1.1.9!1 10.1.1.7 -> 10.1.1.9 0: 10.1.1.9 -> 10.1.1.7 rtt 72 µs, avg rtt 72 µs, ttl = 255 ; ip/ping -4an1 10.1.1.7 sending 1 64 byte messages 1000 ms apart to icmp!10.1.1.7!1 10.1.1.7 -> 10.1.1.7 0: 10.1.1.7 -> 10.1.1.7 rtt 15 µs, avg rtt 15 µs, ttl = 255 ; ip/ping -6an1 10.1.1.7 sending 1 64 byte messages 1000 ms apart to icmpv6!10.1.1.7!1 2402:6b00:22cd:bf80::7 -> 10.1.1.7 0: 10.1.1.7 -> 10.1.1.7 rtt 18 µs, avg rtt 18 µs, ttl = 255 ; ip/ping -4an1 2402:6b00:22cd:bf80::7 ip/ping: ip/ping: nametoip: address 2402:6b00:22cd:bf80::7 does not match proto 4 ; ip/ping -an1 missing ip/ping: cannot write tcp!missing!1 to/net/cs: cs: can't translate address: dns: resource does not exist; negrcode ; diffy -c ping.c /n/dump/2016/0101/sys/src/cmd/ip/ping.c:391,505 - ping.c:391,461 return colon; } - /* from /sys/src/libc/9sys/dial.c */ - - enum + char* + nametoip(char *cs, char *name, int *ipver) { - Maxstring = 128, - Maxpath = 256, - }; + int n,fd; + char buf[128], ip6[128], ip4[128], *p, *addr, *ip; - typedef struct DS DS; - struct DS { - /* dist string */ - char buf[Maxstring]; - char *netdir; - char *proto; - char *rem; - - /* other args */ - char *local; - char *dir; - int *cfdp; - }; - - /* - * parse a dial string - */ - static void - _dial_string_parse(char *str, DS *ds) - { - char *p, *p2; - - strncpy(ds->buf, str, Maxstring); - ds->buf[Maxstring-1] = 0; - - p = strchr(ds->buf, '!'); - if(p == 0) { - ds->netdir = 0; - ds->proto = "net"; - ds->rem = ds->buf; - } else { - if(*ds->buf != '/' && *ds->buf != '#'){ - ds->netdir = 0; - ds->proto = ds->buf; - } else { - for(p2 = p; *p2 != '/'; p2--) - ; - *p2++ = 0; - ds->netdir = ds->buf; - ds->proto = p2; - } - *p = 0; - ds->rem = p + 1; + ip6[0] = 0; + ip4[0] = 0; + if(isdottedquad(name)){ + snprint(ip4, sizeof ip4, "%s", name); + goto match; } - } + if(isv6lit(name)){ + snprint(ip6, sizeof ip6, "%s", name); + goto match; + } - /* end excerpt from /sys/src/libc/9sys/dial.c */ - - /* side effect: sets network & target */ - static int - isv4name(char *name) - { - int r = 1; - char *root, *ip, *pr; - DS ds; - - _dial_string_parse(name, &ds); - - /* cope with leading /net.alt/icmp! and the like */ - root = nil; - if (ds.netdir != nil) { - pr = strrchr(ds.netdir, '/'); - if (pr == nil) - pr = ds.netdir; - else { - *pr++ = '\0'; - root = ds.netdir; - network = strdup(root); + if(cs == nil) + cs = "/net/cs"; + fd = open(cs, ORDWR); + if(fd < 0) + sysfatal("cannot open %s: %r", cs); + addr = smprint("tcp!%s!1", name); + if(write(fd, addr, strlen(addr)) != strlen(addr)){ + close(fd); + sysfatal("cannot write %s to%s: %r", addr, cs); + } + free(addr); + seek(fd, 0, 0); + while((n = read(fd, buf, sizeof(buf)-1)) > 0){ + buf[n] = 0; + ip = strchr(buf,' '); + ip++; + p = strchr(ip,'!'); + *p = 0; + if(isdottedquad(ip)){ + if(ip4[0] == 0) + snprint(ip4, sizeof ip4, "%s", ip); + }else if(isv6lit(ip)){ + if(ip6[0] == 0) + snprint(ip6, sizeof ip6, "%s", ip); } - if (strcmp(pr, v4pr.net) == 0) - return 1; - if (strcmp(pr, v6pr.net) == 0) - return 0; } + close(fd); - /* if it's a literal, it's obvious from syntax which proto it is */ - free(target); - target = strdup(ds.rem); - if (isdottedquad(ds.rem)) - return 1; - else if (isv6lit(ds.rem)) - return 0; + match: + if((*ipver == 4 || *ipver == -1) && ip4[0] != 0){ + *ipver = 4; + return strdup(ip4); + }else if((*ipver == 6 || *ipver == -1) && ip6[0] != 0){ + *ipver = 6; + return strdup(ip6); + }else if(*ipver == 6 && ip4[0] != 0) + return strdup(ip4); + else if(ip4[0] != 0 || ip6[0] != 0) + werrstr("address %s does not match proto %d", ip4[0]? ip4: ip6, *ipver); - /* map name to ip and look at its syntax */ - ip = csgetvalue(root, "sys", ds.rem, "ip", nil); - if (ip == nil) - ip = csgetvalue(root, "dom", ds.rem, "ip", nil); - if (ip == nil) - ip = csgetvalue(root, "sys", ds.rem, "ipv6", nil); - if (ip == nil) - ip = csgetvalue(root, "dom", ds.rem, "ipv6", nil); - if (ip != nil) - r = isv4name(ip); - free(ip); - return r; + *ipver = -1; + return nil; } void main(int argc, char **argv) { - int fd, msglen, interval, nmsg; + int fd, msglen, interval, nmsg, ipver; char *ds; nsecfd = bintime(-1, nil, nil, nil); /n/dump/2016/0101/sys/src/cmd/ip/ping.c:509,517 - ping.c:465,475 msglen = interval = 0; nmsg = MAXMSG; + ipver = -1; ARGBEGIN { + case '4': case '6': - proto = &v6pr; + ipver = ARGC() - '0'; break; case 'a': addresses = 1; /n/dump/2016/0101/sys/src/cmd/ip/ping.c:568,576 - ping.c:526,537 notify(catch); - if (!isv4name(argv[0])) - proto = &v6pr; - ds = netmkaddr(argv[0], proto->net, "1"); + target = nametoip(nil, argv[0], &ipver); + if(target == nil) + sysfatal("%s: nametoip: %r", argv0); + proto = ipver==4? &v4pr: &v6pr; + + ds = netmkaddr(target, proto->net, "1"); fd = dial(ds, 0, 0, 0); if(fd < 0){ fprint(2, "%s: couldn't dial %s: %r\n", argv0, ds); /n/dump/2016/0101/sys/src/cmd/ip/ping.c:583,590 - ping.c:544,550 switch(rfork(RFPROC|RFMEM|RFFDG)){ case -1: - fprint(2, "%s: can't fork: %r\n", argv0); - /* fallthrough */ + sysfatal("%s: can't fork: %r\n", argv0); case 0: rcvr(fd, msglen, interval, nmsg); exits(0);