26 void histogram(long *t, int n, int buckets, long lo, long hi);
32 "usage: %s [-n][-a tries][-h buckets][-t ttl][-x net] [protocol!]destination\n",
38 csquery(DS *ds, char *clone, char *dest)
41 char *p, buf[Maxstring];
44 * open connection server
46 snprint(buf, sizeof(buf), "%s/cs", ds->netdir);
47 fd = open(buf, ORDWR);
50 werrstr("can't translate");
54 /* no connection server, don't translate */
55 snprint(clone, sizeof(clone), "%s/%s/clone", ds->netdir, ds->proto);
56 strcpy(dest, ds->rem);
61 * ask connection server to translate
63 sprint(buf, "%s!%s", ds->proto, ds->rem);
64 if(write(fd, buf, strlen(buf)) < 0){
73 n = read(fd, buf, sizeof(buf) - 1);
76 werrstr("problem with cs");
83 werrstr("problem with cs");
94 * call the dns process and have it try to resolve the mx request
97 dodnsquery(DS *ds, char *ip, char *dom)
106 t = dnsquery(ds->netdir, ip, "ptr");
107 for(nt = t; nt != nil; nt = nt->entry)
108 if(strcmp(nt->attr, "dom") == 0){
109 strcpy(dom, nt->val);
117 /* for connection oriented protocols (il, tcp) we just need
118 * to try dialing. resending is up to it.
121 tcpilprobe(int cfd, int dfd, char *dest, int interval)
128 n = snprint(msg, sizeof msg, "connect %s", dest);
130 n = write(cfd, msg, n);
136 * for udp, we keep sending to an improbable port
137 * till we timeout or someone complains
140 udpprobe(int cfd, int dfd, char *dest, int interval)
147 n = snprint(msg, sizeof msg, "connect %s", dest);
148 if(write(cfd, msg, n)< 0)
152 for(i = 0; i < 3; i++){
154 if(write(dfd, "boo hoo ", 8) < 0)
157 * a hangup due to an error looks like 3 eofs followed
158 * by a real error. this is a qio.c qbread() strangeness
162 n = read(dfd, msg, sizeof(msg)-1);
169 errstr(err, sizeof err);
170 if(strstr(err, "alarm") == 0){
180 #define MSG "traceroute probe"
185 icmpprobe(int cfd, int dfd, char *dest, int interval)
187 int x, i, n, len, rv;
188 char buf[512], err[Maxstring], msg[Maxstring];
192 n = snprint(msg, sizeof msg, "connect %s", dest);
193 if(write(cfd, msg, n)< 0)
197 ip = (Icmphdr *)(buf + IPV4HDR_LEN);
198 for(i = 0; i < 3; i++){
200 ip->type = EchoRequest;
202 strcpy((char*)ip->data, MSG);
204 ip->seq[1] = MAGIC>>8;
205 len = IPV4HDR_LEN + ICMP_HDRSIZE + sizeof(MSG);
208 if(write(dfd, buf, len) < len)
212 n = read(dfd, buf, sizeof(buf));
215 errstr(err, sizeof err);
216 if(strstr(err, "alarm") == 0){
223 x = (ip->seq[1]<<8) | ip->seq[0];
224 if(n >= len && ip->type == EchoReply && x == MAGIC &&
225 strcmp((char*)ip->data, MSG) == 0){
235 catch(void *a, char *msg)
238 if(strstr(msg, "alarm"))
245 call(DS *ds, char *clone, char *dest, int ttl, long *interval)
249 char file[Maxstring];
258 cfd = open(clone, ORDWR);
260 werrstr("%s: %r", clone);
265 /* get conversation number */
266 n = read(cfd, msg, sizeof(msg)-1);
272 sprint(file, "%s/%s/%s/data", ds->netdir, ds->proto, msg);
273 dfd = open(file, ORDWR);
279 fprint(cfd, "ttl %d", ttl);
282 if(strcmp(ds->proto, "udp") == 0)
283 rv = udpprobe(cfd, dfd, dest, 3000);
284 else if(strcmp(ds->proto, "icmp") == 0)
285 rv = icmpprobe(cfd, dfd, dest, 3000);
286 else /* il and tcp */
287 rv = tcpilprobe(cfd, dfd, dest, 3000);
289 /* turn off alarms */
291 *interval = nsec()/1000 - start;
298 * parse a dial string. default netdir is /net.
299 * default proto is tcp.
302 dial_string_parse(char *str, DS *ds)
306 strncpy(ds->buf, str, Maxstring);
307 ds->buf[Maxstring-3] = 0;
309 p = strchr(ds->buf, '!');
319 for(p2 = p; *p2 != '/'; p2--)
322 ds->netdir = ds->buf;
328 if(strchr(ds->rem, '!') == 0)
329 strcat(ds->rem, "!32767");
333 main(int argc, char **argv)
335 int buckets, ttl, j, done, tries, notranslate;
339 char clone[Maxpath], dest[Maxstring], hop[Maxstring], dom[Maxstring];
350 tries = atoi(EARGF(usage()));
356 buckets = atoi(EARGF(usage()));
362 ttl = atoi(EARGF(usage()));
365 net = EARGF(usage());
374 t = malloc(tries*sizeof(ulong));
376 dial_string_parse(argv[0], &ds);
380 if(csquery(&ds, clone, dest) < 0){
381 fprint(2, "%s: %s: %r\n", argv0, argv[0]);
384 print("trying %s/%s!%s\n\n", ds.netdir, ds.proto, dest);
385 print(" round trip times in µs\n");
386 print(" low avg high\n");
387 print(" --------------------------\n");
390 for(; ttl < 32; ttl++){
391 for(j = 0; j < tries; j++){
392 if(call(&ds, clone, dest, ttl, &t[j]) >= 0){
394 print("%ld %s\n", t[j], dest);
399 errstr(err, sizeof err);
400 if(strstr(err, "refused")){
402 p = strchr(hop, '!');
406 } else if(strstr(err, "unreachable")){
407 snprint(hop, sizeof(hop), "%s", err);
408 p = strchr(hop, '!');
412 } else if(strncmp(err, "ttl exceeded at ", 16) == 0)
419 print("%ld %s\n", t[j], hop);
421 if(strcmp(hop, "*") == 0){
428 for(j = 0; j < tries; j++){
436 if(notranslate == 1 || dodnsquery(&ds, hop, dom) < 0)
438 /* don't truncate: ipv6 addresses can be quite long */
439 print("%-18s %8ld %8ld %8ld %s\n", hop, lo, sum/tries, hi, dom);
441 histogram(t, tries, buckets, lo, hi);
448 char *order = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
451 histogram(long *t, int n, int buckets, long lo, long hi)
462 print("+++++++++++++++++++++++\n");
463 span = (hi-lo)/buckets;
466 for(i = 0; i < buckets; i++){
468 for(j = 0; j < n; j++)
469 if(t[j] >= lo+i*span && t[j] <= lo+(i+1)*span)
473 snprint(x, sizeof x, "[%ld-%ld]", lo+i*span, lo+(i+1)*span);
474 print("%-16s %s\n", x, bar);
481 print("+++++++++++++++++++++++\n");