Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/feature-vt/sys/src/cmd/ip/traceroute.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include <u.h>
2
#include <libc.h>
3
#include <ctype.h>
4
#include <bio.h>
5
#include <ndb.h>
6
#include <ip.h>
7
#include "icmp.h"
8
 
9
enum{
10
	Maxstring=	128,
11
	Maxpath=	256,
12
};
13
 
14
typedef struct DS DS;
15
struct DS {
16
	/* dial string */
17
	char	buf[Maxstring];
18
	char	*netdir;
19
	char	*proto;
20
	char	*rem;
21
};
22
 
23
char *argv0;
24
int debug;
25
 
26
void	histogram(long *t, int n, int buckets, long lo, long hi);
27
 
28
void
29
usage(void)
30
{
31
	fprint(2,
32
"usage: %s [-n][-a tries][-h buckets][-t ttl][-x net] [protocol!]destination\n",
33
		argv0);
34
	exits("usage");
35
}
36
 
37
static int
38
csquery(DS *ds, char *clone, char *dest)
39
{
40
	int n, fd;
41
	char *p, buf[Maxstring];
42
 
43
	/*
44
	 *  open connection server
45
	 */
46
	snprint(buf, sizeof(buf), "%s/cs", ds->netdir);
47
	fd = open(buf, ORDWR);
48
	if(fd < 0){
49
		if(!isdigit(*dest)){
50
			werrstr("can't translate");
51
			return -1;
52
		}
53
 
54
		/* no connection server, don't translate */
55
		snprint(clone, sizeof(clone), "%s/%s/clone", ds->netdir, ds->proto);
56
		strcpy(dest, ds->rem);
57
		return 0;
58
	}
59
 
60
	/*
61
	 *  ask connection server to translate
62
	 */
63
	sprint(buf, "%s!%s", ds->proto, ds->rem);
64
	if(write(fd, buf, strlen(buf)) < 0){
65
		close(fd);
66
		return -1;
67
	}
68
 
69
	/*
70
	 *  get an address.
71
	 */
72
	seek(fd, 0, 0);
73
	n = read(fd, buf, sizeof(buf) - 1);
74
	close(fd);
75
	if(n <= 0){
76
		werrstr("problem with cs");
77
		return -1;
78
	}
79
 
80
	buf[n] = 0;
81
	p = strchr(buf, ' ');
82
	if(p == 0){
83
		werrstr("problem with cs");
84
		return -1;
85
	}
86
 
87
	*p++ = 0;
88
	strcpy(clone, buf);
89
	strcpy(dest, p);
90
	return 0;
91
}
92
 
93
/*
94
 *  call the dns process and have it try to resolve the mx request
95
 */
96
static int
97
dodnsquery(DS *ds, char *ip, char *dom)
98
{
99
	char *p;
100
	Ndbtuple *t, *nt;
101
 
102
	p = strchr(ip, '!');
103
	if(p)
104
		*p = 0;
105
 
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);
110
			ndbfree(t);
111
			return 0;
112
		}
113
	ndbfree(t);
114
	return -1;
115
}
116
 
117
/*  for connection oriented protocols (il, tcp) we just need
118
 *  to try dialing.  resending is up to it.
119
 */
120
static int
121
tcpilprobe(int cfd, int dfd, char *dest, int interval)
122
{
123
	int n;
124
	char msg[Maxstring];
125
 
126
	USED(dfd);
127
 
128
	n = snprint(msg, sizeof msg, "connect %s", dest);
129
	alarm(interval);
130
	n = write(cfd, msg, n);
131
	alarm(0);
132
	return n;
133
}
134
 
135
/*
136
 *  for udp, we keep sending to an improbable port
137
 *  till we timeout or someone complains
138
 */
139
static int
140
udpprobe(int cfd, int dfd, char *dest, int interval)
141
{
142
	int n, i, rv;
143
	char msg[Maxstring];
144
	char err[Maxstring];
145
 
146
	seek(cfd, 0, 0);
147
	n = snprint(msg, sizeof msg, "connect %s", dest);
148
	if(write(cfd, msg, n)< 0)
149
		return -1;
150
 
151
	rv = -1;
152
	for(i = 0; i < 3; i++){
153
		alarm(interval/3);
154
		if(write(dfd, "boo hoo ", 8) < 0)
155
			break;
156
		/*
157
		 *  a hangup due to an error looks like 3 eofs followed
158
		 *  by a real error.  this is a qio.c qbread() strangeness
159
		 *  done for pipes.
160
		 */
161
		do {
162
			n = read(dfd, msg, sizeof(msg)-1);
163
		} while(n == 0);
164
		alarm(0);
165
		if(n > 0){
166
			rv = 0;
167
			break;
168
		}
169
		errstr(err, sizeof err);
170
		if(strstr(err, "alarm") == 0){
171
			werrstr(err);
172
			break;
173
		}
174
		werrstr(err);
175
	}
176
	alarm(0);
177
	return rv;
178
}
179
 
180
#define MSG "traceroute probe"
181
#define MAGIC 0xdead
182
 
183
/* ICMPv4 only */
184
static int
185
icmpprobe(int cfd, int dfd, char *dest, int interval)
186
{
187
	int x, i, n, len, rv;
188
	char buf[512], err[Maxstring], msg[Maxstring];
189
	Icmphdr *ip;
190
 
191
	seek(cfd, 0, 0);
192
	n = snprint(msg, sizeof msg, "connect %s", dest);
193
	if(write(cfd, msg, n)< 0)
194
		return -1;
195
 
196
	rv = -1;
197
	ip = (Icmphdr *)(buf + IPV4HDR_LEN);
198
	for(i = 0; i < 3; i++){
199
		alarm(interval/3);
200
		ip->type = EchoRequest;
201
		ip->code = 0;
202
		strcpy((char*)ip->data, MSG);
203
		ip->seq[0] = MAGIC;
204
		ip->seq[1] = MAGIC>>8;
205
		len = IPV4HDR_LEN + ICMP_HDRSIZE + sizeof(MSG);
206
 
207
		/* send a request */
208
		if(write(dfd, buf, len) < len)
209
			break;
210
 
211
		/* wait for reply */
212
		n = read(dfd, buf, sizeof(buf));
213
		alarm(0);
214
		if(n < 0){
215
			errstr(err, sizeof err);
216
			if(strstr(err, "alarm") == 0){
217
				werrstr(err);
218
				break;
219
			}
220
			werrstr(err);
221
			continue;
222
		}
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){
226
			rv = 0;
227
			break;
228
		}
229
	}
230
	alarm(0);
231
	return rv;
232
}
233
 
234
static void
235
catch(void *a, char *msg)
236
{
237
	USED(a);
238
	if(strstr(msg, "alarm"))
239
		noted(NCONT);
240
	else
241
		noted(NDFLT);
242
}
243
 
244
static int
245
call(DS *ds, char *clone, char *dest, int ttl, long *interval)
246
{
247
	int cfd, dfd, rv, n;
248
	char msg[Maxstring];
249
	char file[Maxstring];
250
	vlong start;
251
 
252
	notify(catch);
253
 
254
	/* start timing */
255
	start = nsec()/1000;
256
	rv = -1;
257
 
258
	cfd = open(clone, ORDWR);
259
	if(cfd < 0){
260
		werrstr("%s: %r", clone);
261
		return -1;
262
	}
263
	dfd = -1;
264
 
265
	/* get conversation number */
266
	n = read(cfd, msg, sizeof(msg)-1);
267
	if(n <= 0)
268
		goto out;
269
	msg[n] = 0;
270
 
271
	/* open data file */
272
	sprint(file, "%s/%s/%s/data", ds->netdir, ds->proto, msg);
273
	dfd = open(file, ORDWR);
274
	if(dfd < 0)
275
		goto out;
276
 
277
	/* set ttl */
278
	if(ttl)
279
		fprint(cfd, "ttl %d", ttl);
280
 
281
	/* probe */
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);
288
out:
289
	/* turn off alarms */
290
	alarm(0);
291
	*interval = nsec()/1000 - start;
292
	close(cfd);
293
	close(dfd);
294
	return rv;
295
}
296
 
297
/*
298
 *  parse a dial string.  default netdir is /net.
299
 *  default proto is tcp.
300
 */
301
static void
302
dial_string_parse(char *str, DS *ds)
303
{
304
	char *p, *p2;
305
 
306
	strncpy(ds->buf, str, Maxstring);
307
	ds->buf[Maxstring-3] = 0;
308
 
309
	p = strchr(ds->buf, '!');
310
	if(p == 0) {
311
		ds->netdir = 0;
312
		ds->proto = "tcp";
313
		ds->rem = ds->buf;
314
	} else {
315
		if(*ds->buf != '/'){
316
			ds->netdir = 0;
317
			ds->proto = ds->buf;
318
		} else {
319
			for(p2 = p; *p2 != '/'; p2--)
320
				;
321
			*p2++ = 0;
322
			ds->netdir = ds->buf;
323
			ds->proto = p2;
324
		}
325
		*p = 0;
326
		ds->rem = p + 1;
327
	}
328
	if(strchr(ds->rem, '!') == 0)
329
		strcat(ds->rem, "!32767");
330
}
331
 
332
void
333
main(int argc, char **argv)
334
{
335
	int buckets, ttl, j, done, tries, notranslate;
336
	long lo, hi, sum, x;
337
	long *t;
338
	char *net, *p;
339
	char clone[Maxpath], dest[Maxstring], hop[Maxstring], dom[Maxstring];
340
	char err[Maxstring];
341
	DS ds;
342
 
343
	buckets = 0;
344
	tries = 3;
345
	notranslate = 0;
346
	net = "/net";
347
	ttl = 1;
348
	ARGBEGIN{
349
	case 'a':
350
		tries = atoi(EARGF(usage()));
351
		break;
352
	case 'd':
353
		debug++;
354
		break;
355
	case 'h':
356
		buckets = atoi(EARGF(usage()));
357
		break;
358
	case 'n':
359
		notranslate++;
360
		break;
361
	case 't':
362
		ttl = atoi(EARGF(usage()));
363
		break;
364
	case 'x':
365
		net = EARGF(usage());
366
		break;
367
	default:
368
		usage();
369
	}ARGEND;
370
 
371
	if(argc < 1)
372
		usage();
373
 
374
	t = malloc(tries*sizeof(ulong));
375
 
376
	dial_string_parse(argv[0], &ds);
377
 
378
	if(ds.netdir == 0)
379
		ds.netdir = net;
380
	if(csquery(&ds, clone, dest) < 0){
381
		fprint(2, "%s: %s: %r\n", argv0, argv[0]);
382
		exits(0);
383
	}
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");
388
 
389
	done = 0;
390
	for(; ttl < 32; ttl++){
391
		for(j = 0; j < tries; j++){
392
			if(call(&ds, clone, dest, ttl, &t[j]) >= 0){
393
				if(debug)
394
					print("%ld %s\n", t[j], dest);
395
				strcpy(hop, dest);
396
				done = 1;
397
				continue;
398
			}
399
			errstr(err, sizeof err);
400
			if(strstr(err, "refused")){
401
				strcpy(hop, dest);
402
				p = strchr(hop, '!');
403
				if(p)
404
					*p = 0;
405
				done = 1;
406
			} else if(strstr(err, "unreachable")){
407
				snprint(hop, sizeof(hop), "%s", err);
408
				p = strchr(hop, '!');
409
				if(p)
410
					*p = 0;
411
				done = 1;
412
			} else if(strncmp(err, "ttl exceeded at ", 16) == 0)
413
				strcpy(hop, err+16);
414
			else {
415
				strcpy(hop, "*");
416
				break;
417
			}
418
			if(debug)
419
				print("%ld %s\n", t[j], hop);
420
		}
421
		if(strcmp(hop, "*") == 0){
422
			print("*\n");
423
			continue;
424
		}
425
		lo = 10000000;
426
		hi = 0;
427
		sum = 0;
428
		for(j = 0; j < tries; j++){
429
			x = t[j];
430
			sum += x;
431
			if(x < lo)
432
				lo = x;
433
			if(x > hi)
434
				hi = x;
435
		}
436
		if(notranslate == 1 || dodnsquery(&ds, hop, dom) < 0)
437
			dom[0] = 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);
440
		if(buckets)
441
			histogram(t, tries, buckets, lo, hi);
442
		if(done)
443
			break;
444
	}
445
	exits(0);
446
}
447
 
448
char *order = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
449
 
450
void
451
histogram(long *t, int n, int buckets, long lo, long hi)
452
{
453
	int i, j, empty;
454
	long span;
455
	static char *bar;
456
	char *p;
457
	char x[64];
458
 
459
	if(bar == nil)
460
		bar = malloc(n+1);
461
 
462
	print("+++++++++++++++++++++++\n");
463
	span = (hi-lo)/buckets;
464
	span++;
465
	empty = 0;
466
	for(i = 0; i < buckets; i++){
467
		p = bar;
468
		for(j = 0; j < n; j++)
469
			if(t[j] >= lo+i*span && t[j] <= lo+(i+1)*span)
470
				*p++ = order[j];
471
		*p = 0;
472
		if(p != bar){
473
			snprint(x, sizeof x, "[%ld-%ld]", lo+i*span, lo+(i+1)*span);
474
			print("%-16s %s\n", x, bar);
475
			empty = 0;
476
		} else if(!empty){
477
			print("...\n");
478
			empty = 1;
479
		}
480
	}
481
	print("+++++++++++++++++++++++\n");
482
}