Annotation of embedaddon/mtr/net.c, revision 1.1.1.2
1.1 misho 1: /*
2: mtr -- a network diagnostic tool
3: Copyright (C) 1997,1998 Matt Kimball
4:
5: This program is free software; you can redistribute it and/or modify
6: it under the terms of the GNU General Public License version 2 as
7: published by the Free Software Foundation.
8:
9: This program is distributed in the hope that it will be useful,
10: but WITHOUT ANY WARRANTY; without even the implied warranty of
11: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12: GNU General Public License for more details.
13:
14: You should have received a copy of the GNU General Public License
15: along with this program; if not, write to the Free Software
16: Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17: */
18:
1.1.1.2 ! misho 19: #include "config.h"
1.1 misho 20:
21: #if defined(HAVE_SYS_XTI_H)
22: #include <sys/xti.h>
23: #endif
24:
25: #include <sys/types.h>
26: #include <sys/time.h>
27: #include <sys/socket.h>
28: #include <sys/ioctl.h>
29: #include <sys/select.h>
30: #include <netinet/in.h>
31: #include <memory.h>
32: #include <unistd.h>
33: #ifdef HAVE_FCNTL_H
34: #include <fcntl.h>
35: #endif
36: #include <stdio.h>
37: #include <stdlib.h>
38: #include <math.h>
39: #include <errno.h>
40: #include <string.h>
41:
42: #include "mtr.h"
43: #include "net.h"
44: #include "display.h"
45: #include "dns.h"
46:
47: /* We can't rely on header files to provide this information, because
48: the fields have different names between, for instance, Linux and
49: Solaris */
50: struct ICMPHeader {
51: uint8 type;
52: uint8 code;
53: uint16 checksum;
54: uint16 id;
55: uint16 sequence;
56: };
57:
58: /* Structure of an UDP header. */
59: struct UDPHeader {
60: uint16 srcport;
61: uint16 dstport;
62: uint16 length;
63: uint16 checksum;
64: };
65:
66: /* Structure of an TCP header, as far as we need it. */
67: struct TCPHeader {
68: uint16 srcport;
69: uint16 dstport;
70: uint32 seq;
71: };
72:
73: /* Structure of an IPv4 UDP pseudoheader. */
74: struct UDPv4PHeader {
75: uint32 saddr;
76: uint32 daddr;
77: uint8 zero;
78: uint8 protocol;
79: uint16 len;
80: };
81:
82: /* Structure of an IP header. */
83: struct IPHeader {
84: uint8 version;
85: uint8 tos;
86: uint16 len;
87: uint16 id;
88: uint16 frag;
89: uint8 ttl;
90: uint8 protocol;
91: uint16 check;
92: uint32 saddr;
93: uint32 daddr;
94: };
95:
96:
97: #define ICMP_ECHO 8
98: #define ICMP_ECHOREPLY 0
99:
100: #define ICMP_TSTAMP 13
101: #define ICMP_TSTAMPREPLY 14
102:
103: #define ICMP_TIME_EXCEEDED 11
104: #define ICMP_UNREACHABLE 3
105:
106: #ifndef SOL_IP
107: #define SOL_IP 0
108: #endif
109:
110: struct nethost {
111: ip_t addr;
112: ip_t addrs[MAXPATH]; /* for multi paths byMin */
113: int xmit;
114: int returned;
115: int sent;
116: int up;
117: long long var;/* variance, could be overflowed */
118: int last;
119: int best;
120: int worst;
121: int avg; /* average: addByMin */
122: int gmean; /* geometirc mean: addByMin */
123: int jitter; /* current jitter, defined as t1-t0 addByMin */
124: /*int jbest;*/ /* min jitter, of cause it is 0, not needed */
125: int javg; /* avg jitter */
126: int jworst; /* max jitter */
127: int jinta; /* estimated variance,? rfc1889's "Interarrival Jitter" */
128: int transit;
129: int saved[SAVED_PINGS];
130: int saved_seq_offset;
131: struct mplslen mpls;
132: struct mplslen mplss[MAXPATH];
133: };
134:
135:
136: struct sequence {
137: int index;
138: int transit;
139: int saved_seq;
140: struct timeval time;
141: int socket;
142: };
143:
144:
145: /* Configuration parameter: How many queries to unknown hosts do we
146: send? (This limits the amount of traffic generated if a host is not
147: reachable) */
148: #define MAX_UNKNOWN_HOSTS 5
149:
150:
151: /* BSD-derived kernels use host byte order for the IP length and
152: offset fields when using raw sockets. We detect this automatically at
153: run-time and do the right thing. */
154: static int BSDfix = 0;
155:
156: static struct nethost host[MaxHost];
157: static struct sequence sequence[MaxSequence];
158: static struct timeval reset = { 0, 0 };
159:
160: int timestamp;
161: int sendsock4;
162: int sendsock4_icmp;
163: int sendsock4_udp;
164: int recvsock4;
165: int sendsock6;
166: int sendsock6_icmp;
167: int sendsock6_udp;
168: int recvsock6;
169: int sendsock;
170: int recvsock;
171:
172: #ifdef ENABLE_IPV6
173: struct sockaddr_storage sourcesockaddr_struct;
174: struct sockaddr_storage remotesockaddr_struct;
175: struct sockaddr_in6 * ssa6 = (struct sockaddr_in6 *) &sourcesockaddr_struct;
176: struct sockaddr_in6 * rsa6 = (struct sockaddr_in6 *) &remotesockaddr_struct;
177: #else
178: struct sockaddr_in sourcesockaddr_struct;
179: struct sockaddr_in remotesockaddr_struct;
180: #endif
181:
182: struct sockaddr * sourcesockaddr = (struct sockaddr *) &sourcesockaddr_struct;
183: struct sockaddr * remotesockaddr = (struct sockaddr *) &remotesockaddr_struct;
184: struct sockaddr_in * ssa4 = (struct sockaddr_in *) &sourcesockaddr_struct;
185: struct sockaddr_in * rsa4 = (struct sockaddr_in *) &remotesockaddr_struct;
186:
187: ip_t * sourceaddress;
188: ip_t * remoteaddress;
189:
190: /* XXX How do I code this to be IPV6 compatible??? */
191: #ifdef ENABLE_IPV6
192: char localaddr[INET6_ADDRSTRLEN];
193: #else
194: #ifndef INET_ADDRSTRLEN
195: #define INET_ADDRSTRLEN 16
196: #endif
197: char localaddr[INET_ADDRSTRLEN];
198: #endif
199:
200: static int batch_at = 0;
201: static int numhosts = 10;
202:
203: extern int fstTTL; /* initial hub(ttl) to ping byMin */
204: extern int maxTTL; /* last hub to ping byMin*/
205: extern int cpacketsize; /* packet size used by ping */
206: static int packetsize; /* packet size used by ping */
207: extern int bitpattern; /* packet bit pattern used by ping */
208: extern int tos; /* type of service set in ping packet*/
209: extern int af; /* address family of remote target */
210: extern int mtrtype; /* type of query packet used */
211: extern int remoteport; /* target port for TCP tracing */
212: extern int timeout; /* timeout for TCP connections */
1.1.1.2 ! misho 213: #ifdef SO_MARK
! 214: extern int mark; /* SO_MARK to set for ping packet*/
! 215: #endif
1.1 misho 216:
217: /* return the number of microseconds to wait before sending the next
218: ping */
219: int calc_deltatime (float waittime)
220: {
221: waittime /= numhosts;
222: return 1000000 * waittime;
223: }
224:
225:
226: /* This doesn't work for odd sz. I don't know enough about this to say
227: that this is wrong. It doesn't seem to cripple mtr though. -- REW */
228: int checksum(void *data, int sz)
229: {
230: unsigned short *ch;
231: unsigned int sum;
232:
233: sum = 0;
234: ch = data;
235: sz = sz / 2;
236: while (sz--) {
237: sum += *(ch++);
238: }
239:
240: sum = (sum >> 16) + (sum & 0xffff);
241:
242: return (~sum & 0xffff);
243: }
244:
245:
246: /* Prepend pseudoheader to the udp datagram and calculate checksum */
247: int udp_checksum(void *pheader, void *udata, int psize, int dsize)
248: {
249: unsigned int tsize = psize + dsize;
250: char csumpacket[tsize];
251: memset(csumpacket, (unsigned char) abs(bitpattern), abs(tsize));
252:
253: struct UDPv4PHeader *prepend = (struct UDPv4PHeader *) csumpacket;
254: struct UDPv4PHeader *udppheader = (struct UDPv4PHeader *) pheader;
255: prepend->saddr = udppheader->saddr;
256: prepend->daddr = udppheader->daddr;
257: prepend->zero = 0;
258: prepend->protocol = udppheader->protocol;
259: prepend->len = udppheader->len;
260:
261: struct UDPHeader *content = (struct UDPHeader *)(csumpacket + psize);
262: struct UDPHeader *udpdata = (struct UDPHeader *) udata;
263: content->srcport = udpdata->srcport;
264: content->dstport = udpdata->dstport;
265: content->length = udpdata->length;
266: content->checksum = udpdata->checksum;
267:
268: return checksum(csumpacket,tsize);
269: }
270:
271:
272: void save_sequence(int index, int seq)
273: {
274: sequence[seq].index = index;
275: sequence[seq].transit = 1;
276: sequence[seq].saved_seq = ++host[index].xmit;
277: memset(&sequence[seq].time, 0, sizeof(sequence[seq].time));
278:
279: host[index].transit = 1;
280: if (host[index].sent)
281: host[index].up = 0;
282: host[index].sent = 1;
283: net_save_xmit(index);
284: }
285:
286: int new_sequence(int index)
287: {
288: static int next_sequence = MinSequence;
289: int seq;
290:
291: seq = next_sequence++;
292: if (next_sequence >= MaxSequence)
293: next_sequence = MinSequence;
294:
295: save_sequence(index, seq);
296:
297: return seq;
298: }
299:
300: /* Attempt to connect to a TCP port with a TTL */
301: void net_send_tcp(int index)
302: {
303: int ttl, s;
304: int opt = 1;
305: int port;
306: struct sockaddr_storage local;
307: struct sockaddr_storage remote;
308: struct sockaddr_in *local4 = (struct sockaddr_in *) &local;
309: struct sockaddr_in6 *local6 = (struct sockaddr_in6 *) &local;
310: struct sockaddr_in *remote4 = (struct sockaddr_in *) &remote;
311: struct sockaddr_in6 *remote6 = (struct sockaddr_in6 *) &remote;
312: socklen_t len;
313:
314: ttl = index + 1;
315:
316: s = socket(af, SOCK_STREAM, 0);
317: if (s < 0) {
318: display_clear();
319: perror("socket()");
320: exit(EXIT_FAILURE);
321: }
322:
323: memset(&local, 0, sizeof (local));
324: memset(&remote, 0, sizeof (remote));
325: local.ss_family = af;
326: remote.ss_family = af;
327:
328: switch (af) {
329: case AF_INET:
330: addrcpy((void *) &local4->sin_addr, (void *) &ssa4->sin_addr, af);
331: addrcpy((void *) &remote4->sin_addr, (void *) remoteaddress, af);
332: remote4->sin_port = htons(remoteport);
1.1.1.2 ! misho 333: len = sizeof (struct sockaddr_in);
1.1 misho 334: break;
335: #ifdef ENABLE_IPV6
336: case AF_INET6:
337: addrcpy((void *) &local6->sin6_addr, (void *) &ssa6->sin6_addr, af);
338: addrcpy((void *) &remote6->sin6_addr, (void *) remoteaddress, af);
339: remote6->sin6_port = htons(remoteport);
1.1.1.2 ! misho 340: len = sizeof (struct sockaddr_in6);
1.1 misho 341: break;
342: #endif
343: }
344:
1.1.1.2 ! misho 345: if (bind(s, (struct sockaddr *) &local, len)) {
1.1 misho 346: display_clear();
347: perror("bind()");
348: exit(EXIT_FAILURE);
349: }
350:
351: if (getsockname(s, (struct sockaddr *) &local, &len)) {
352: display_clear();
353: perror("getsockname()");
354: exit(EXIT_FAILURE);
355: }
356:
357: opt = 1;
358: if (ioctl(s, FIONBIO, &opt)) {
359: display_clear();
360: perror("ioctl FIONBIO");
361: exit(EXIT_FAILURE);
362: }
363:
364: switch (af) {
365: case AF_INET:
366: if (setsockopt(s, IPPROTO_IP, IP_TTL, &ttl, sizeof (ttl))) {
367: display_clear();
368: perror("setsockopt IP_TTL");
369: exit(EXIT_FAILURE);
370: }
371: if (setsockopt(s, IPPROTO_IP, IP_TOS, &tos, sizeof (tos))) {
372: display_clear();
373: perror("setsockopt IP_TOS");
374: exit(EXIT_FAILURE);
375: }
376: break;
377: #ifdef ENABLE_IPV6
378: case AF_INET6:
379: if (setsockopt(s, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof (ttl))) {
380: display_clear();
381: perror("setsockopt IP_TTL");
382: exit(EXIT_FAILURE);
383: }
384: break;
385: #endif
386: }
387:
1.1.1.2 ! misho 388: #ifdef SO_MARK
! 389: if (mark >= 0 && setsockopt( s, SOL_SOCKET, SO_MARK, &mark, sizeof mark ) ) {
! 390: perror( "setsockopt SO_MARK" );
! 391: exit( EXIT_FAILURE );
! 392: }
! 393: #endif
! 394:
1.1 misho 395: switch (local.ss_family) {
396: case AF_INET:
397: port = ntohs(local4->sin_port);
398: break;
399: #ifdef ENABLE_IPV6
400: case AF_INET6:
401: port = ntohs(local6->sin6_port);
402: break;
403: #endif
404: default:
405: display_clear();
406: perror("unknown AF?");
407: exit(EXIT_FAILURE);
408: }
409:
410: save_sequence(index, port);
411: gettimeofday(&sequence[port].time, NULL);
412: sequence[port].socket = s;
413:
1.1.1.2 ! misho 414: connect(s, (struct sockaddr *) &remote, len);
1.1 misho 415: }
416:
417: /* Attempt to find the host at a particular number of hops away */
418: void net_send_query(int index)
419: {
420: if (mtrtype == IPPROTO_TCP) {
421: net_send_tcp(index);
422: return;
423: }
424:
425: /*ok char packet[sizeof(struct IPHeader) + sizeof(struct ICMPHeader)];*/
426: char packet[MAXPACKET];
427: struct IPHeader *ip = (struct IPHeader *) packet;
428: struct ICMPHeader *icmp = NULL;
429: struct UDPHeader *udp = NULL;
430: struct UDPv4PHeader *udpp = NULL;
431: uint16 mypid;
432:
433: /*ok int packetsize = sizeof(struct IPHeader) + sizeof(struct ICMPHeader) + datasize;*/
434: int rv;
435: static int first=1;
436: int ttl, iphsize = 0, echotype = 0, salen = 0;
437:
438: ttl = index + 1;
439:
440: #ifdef ENABLE_IPV6
441: /* offset for ipv6 checksum calculation */
442: int offset = 6;
443: #endif
444:
445: if ( packetsize < MINPACKET ) packetsize = MINPACKET;
446: if ( packetsize > MAXPACKET ) packetsize = MAXPACKET;
447:
448: memset(packet, (unsigned char) abs(bitpattern), abs(packetsize));
449:
450: switch ( af ) {
451: case AF_INET:
452: #if !defined(IP_HDRINCL) && defined(IP_TOS) && defined(IP_TTL)
453: iphsize = 0;
454: if ( setsockopt( sendsock, IPPROTO_IP, IP_TOS, &tos, sizeof tos ) ) {
455: perror( "setsockopt IP_TOS" );
456: exit( EXIT_FAILURE );
457: }
458: if ( setsockopt( sendsock, IPPROTO_IP, IP_TTL, &ttl, sizeof ttl ) ) {
459: perror( "setsockopt IP_TTL" );
460: exit( EXIT_FAILURE );
461: }
462: #else
463: iphsize = sizeof (struct IPHeader);
464:
465: ip->version = 0x45;
466: ip->tos = tos;
467: ip->len = BSDfix ? abs(packetsize): htons (abs(packetsize));
468: ip->id = 0;
469: ip->frag = 0; /* 1, if want to find mtu size? Min */
470: ip->ttl = ttl;
471: ip->protocol = mtrtype;
472: ip->check = 0;
473:
474: /* BSD needs the source address here, Linux & others do not... */
475: addrcpy( (void *) &(ip->saddr), (void *) &(ssa4->sin_addr), AF_INET );
476: addrcpy( (void *) &(ip->daddr), (void *) remoteaddress, AF_INET );
477: #endif
478: echotype = ICMP_ECHO;
479: salen = sizeof (struct sockaddr_in);
480: break;
481: #ifdef ENABLE_IPV6
482: case AF_INET6:
483: iphsize = 0;
484: if ( setsockopt( sendsock, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
485: &ttl, sizeof ttl ) ) {
486: perror( "setsockopt IPV6_UNICAST_HOPS" );
487: exit( EXIT_FAILURE);
488: }
489: echotype = ICMP6_ECHO_REQUEST;
490: salen = sizeof (struct sockaddr_in6);
491: break;
492: #endif
493: }
494:
1.1.1.2 ! misho 495: #ifdef SO_MARK
! 496: if (mark >= 0 && setsockopt( sendsock, SOL_SOCKET, SO_MARK, &mark, sizeof mark ) ) {
! 497: perror( "setsockopt SO_MARK" );
! 498: exit( EXIT_FAILURE );
! 499: }
! 500: #endif
! 501:
1.1 misho 502: switch ( mtrtype ) {
503: case IPPROTO_ICMP:
504: icmp = (struct ICMPHeader *)(packet + iphsize);
505: icmp->type = echotype;
506: icmp->code = 0;
507: icmp->checksum = 0;
508: icmp->id = getpid();
509: icmp->sequence = new_sequence(index);
510: icmp->checksum = checksum(icmp, abs(packetsize) - iphsize);
511:
512: gettimeofday(&sequence[icmp->sequence].time, NULL);
513: break;
514:
515: case IPPROTO_UDP:
516: udp = (struct UDPHeader *)(packet + iphsize);
517: udp->checksum = 0;
518: mypid = (uint16)getpid();
519: if (mypid < MinPort)
520: mypid += MinPort;
521:
522: udp->srcport = htons(mypid);
523: udp->length = abs(packetsize) - iphsize;
524: if(!BSDfix)
525: udp->length = htons(udp->length);
526:
527: udp->dstport = new_sequence(index);
528: gettimeofday(&sequence[udp->dstport].time, NULL);
529: udp->dstport = htons(udp->dstport);
530: break;
531: }
532:
533: switch ( af ) {
534: case AF_INET:
535: switch ( mtrtype ) {
536: case IPPROTO_UDP:
537: /* checksum is not mandatory. only calculate if we know ip->saddr */
538: if (ip->saddr) {
539: udpp = (struct UDPv4PHeader *)(malloc(sizeof(struct UDPv4PHeader)));
540: udpp->saddr = ip->saddr;
541: udpp->daddr = ip->daddr;
542: udpp->protocol = ip->protocol;
543: udpp->len = udp->length;
544: udp->checksum = udp_checksum(udpp, udp, sizeof(struct UDPv4PHeader), abs(packetsize) - iphsize);
545: }
546: break;
547: }
548:
549: ip->check = checksum(packet, abs(packetsize));
550: break;
551: #ifdef ENABLE_IPV6
552: case AF_INET6:
553: switch ( mtrtype ) {
554: case IPPROTO_UDP:
555: /* kernel checksum calculation */
556: if ( setsockopt(sendsock, IPPROTO_IPV6, IPV6_CHECKSUM, &offset, sizeof(offset)) ) {
557: perror( "setsockopt IPV6_CHECKSUM" );
558: exit( EXIT_FAILURE);
559: }
560: break;
561: }
562: break;
563: #endif
564: }
565:
566: rv = sendto(sendsock, packet, abs(packetsize), 0,
567: remotesockaddr, salen);
568: if (first && (rv < 0) && ((errno == EINVAL) || (errno == EMSGSIZE))) {
569: /* Try the first packet again using host byte order. */
570: ip->len = abs (packetsize);
571: rv = sendto(sendsock, packet, abs(packetsize), 0,
572: remotesockaddr, salen);
573: if (rv >= 0) {
574: BSDfix = 1;
575: }
576: }
577: first = 0;
578: }
579:
580:
581: /* We got a return on something we sent out. Record the address and
582: time. */
583: void net_process_ping(int seq, struct mplslen mpls, void * addr, struct timeval now)
584: {
585: int index;
586: int totusec;
587: int oldavg; /* usedByMin */
588: int oldjavg; /* usedByMin */
589: int i; /* usedByMin */
590: #ifdef ENABLE_IPV6
591: char addrcopy[sizeof(struct in6_addr)];
592: #else
593: char addrcopy[sizeof(struct in_addr)];
594: #endif
595:
596: /* Copy the from address ASAP because it can be overwritten */
597: addrcpy( (void *) &addrcopy, addr, af );
598:
599: if (seq < 0 || seq >= MaxSequence)
600: return;
601:
602: if (!sequence[seq].transit)
603: return;
604: sequence[seq].transit = 0;
605:
606: if (sequence[seq].socket > 0) {
607: close(sequence[seq].socket);
608: sequence[seq].socket = 0;
609: }
610:
611: index = sequence[seq].index;
612:
613: totusec = (now.tv_sec - sequence[seq].time.tv_sec ) * 1000000 +
614: (now.tv_usec - sequence[seq].time.tv_usec);
615: /* impossible? if( totusec < 0 ) totusec = 0 */;
616:
617: if ( addrcmp( (void *) &(host[index].addr),
618: (void *) &unspec_addr, af ) == 0 ) {
619: /* should be out of if as addr can change */
620: addrcpy( (void *) &(host[index].addr), addrcopy, af );
621: host[index].mpls = mpls;
622: display_rawhost(index, (void *) &(host[index].addr));
623:
624: /* multi paths */
625: addrcpy( (void *) &(host[index].addrs[0]), addrcopy, af );
626: host[index].mplss[0] = mpls;
627: } else {
628: for( i=0; i<MAXPATH; ) {
629: if( addrcmp( (void *) &(host[index].addrs[i]), (void *) &addrcopy,
630: af ) == 0 ||
631: addrcmp( (void *) &(host[index].addrs[i]),
632: (void *) &unspec_addr, af ) == 0 ) break;
633: i++;
634: }
635: if( addrcmp( (void *) &(host[index].addrs[i]), addrcopy, af ) != 0 &&
636: i<MAXPATH ) {
637: addrcpy( (void *) &(host[index].addrs[i]), addrcopy, af );
638: host[index].mplss[i] = mpls;
639: display_rawhost(index, (void *) &(host[index].addrs[i]));
640: }
641: }
642:
643: host[index].jitter = totusec - host[index].last;
644: if (host[index].jitter < 0 ) host[index].jitter = - host[index].jitter;
645: host[index].last = totusec;
646:
647: if (host[index].returned < 1) {
648: host[index].best = host[index].worst = host[index].gmean = totusec;
649: host[index].avg = host[index].var = 0;
650:
651: host[index].jitter = host[index].jworst = host[index].jinta= 0;
652: }
653:
654: /* some time best can be too good to be true, experienced
655: * at least in linux 2.4.x.
656: * safe guard 1) best[index]>=best[index-1] if index>0
657: * 2) best >= average-20,000 usec (good number?)
658: if (index > 0) {
659: if (totusec < host[index].best &&
660: totusec>= host[index-1].best) host[index].best = totusec;
661: } else {
662: if(totusec < host[index].best) host[index].best = totusec;
663: }
664: */
665: if (totusec < host[index].best ) host[index].best = totusec;
666: if (totusec > host[index].worst) host[index].worst = totusec;
667:
668: if (host[index].jitter > host[index].jworst)
669: host[index].jworst = host[index].jitter;
670:
671: host[index].returned++;
672: oldavg = host[index].avg;
673: host[index].avg += (totusec - oldavg +.0) / host[index].returned;
674: host[index].var += (totusec - oldavg +.0) * (totusec - host[index].avg) / 1000000;
675:
676: oldjavg = host[index].javg;
677: host[index].javg += (host[index].jitter - oldjavg) / host[index].returned;
678: /* below algorithm is from rfc1889, A.8 */
679: host[index].jinta += host[index].jitter - ((host[index].jinta + 8) >> 4);
680:
681: if ( host[index].returned > 1 )
682: host[index].gmean = pow( (double) host[index].gmean, (host[index].returned-1.0)/host[index].returned )
683: * pow( (double) totusec, 1.0/host[index].returned );
684: host[index].sent = 0;
685: host[index].up = 1;
686: host[index].transit = 0;
687:
688: net_save_return(index, sequence[seq].saved_seq, totusec);
689: display_rawping(index, totusec);
690: }
691:
692:
693: /* We know a packet has come in, because the main select loop has called us,
694: now we just need to read it, see if it is for us, and if it is a reply
695: to something we sent, then call net_process_ping() */
696: void net_process_return(void)
697: {
698: char packet[MAXPACKET];
699: #ifdef ENABLE_IPV6
700: struct sockaddr_storage fromsockaddr_struct;
701: struct sockaddr_in6 * fsa6 = (struct sockaddr_in6 *) &fromsockaddr_struct;
702: #else
703: struct sockaddr_in fromsockaddr_struct;
704: #endif
705: struct sockaddr * fromsockaddr = (struct sockaddr *) &fromsockaddr_struct;
706: struct sockaddr_in * fsa4 = (struct sockaddr_in *) &fromsockaddr_struct;
707: socklen_t fromsockaddrsize;
708: int num;
709: struct ICMPHeader *header = NULL;
710: struct UDPHeader *udpheader = NULL;
711: struct TCPHeader *tcpheader = NULL;
712: struct timeval now;
713: ip_t * fromaddress = NULL;
714: int echoreplytype = 0, timeexceededtype = 0, unreachabletype = 0;
715: int sequence = 0;
716:
717: /* MPLS decoding */
718: struct mplslen mpls;
719: mpls.labels = 0;
720:
721: gettimeofday(&now, NULL);
722: switch ( af ) {
723: case AF_INET:
724: fromsockaddrsize = sizeof (struct sockaddr_in);
725: fromaddress = (ip_t *) &(fsa4->sin_addr);
726: echoreplytype = ICMP_ECHOREPLY;
727: timeexceededtype = ICMP_TIME_EXCEEDED;
728: unreachabletype = ICMP_UNREACHABLE;
729: break;
730: #ifdef ENABLE_IPV6
731: case AF_INET6:
732: fromsockaddrsize = sizeof (struct sockaddr_in6);
733: fromaddress = (ip_t *) &(fsa6->sin6_addr);
734: echoreplytype = ICMP6_ECHO_REPLY;
735: timeexceededtype = ICMP6_TIME_EXCEEDED;
736: unreachabletype = ICMP6_DST_UNREACH;
737: break;
738: #endif
739: }
740:
741: num = recvfrom(recvsock, packet, MAXPACKET, 0,
742: fromsockaddr, &fromsockaddrsize);
743:
744: switch ( af ) {
745: case AF_INET:
746: if((size_t) num < sizeof(struct IPHeader) + sizeof(struct ICMPHeader))
747: return;
748: header = (struct ICMPHeader *)(packet + sizeof(struct IPHeader));
749: break;
750: #ifdef ENABLE_IPV6
751: case AF_INET6:
752: if(num < sizeof(struct ICMPHeader))
753: return;
754:
755: header = (struct ICMPHeader *) packet;
756: break;
757: #endif
758: }
759:
760: switch ( mtrtype ) {
761: case IPPROTO_ICMP:
762: if (header->type == echoreplytype) {
763: if(header->id != (uint16)getpid())
764: return;
765:
766: sequence = header->sequence;
767: } else if (header->type == timeexceededtype) {
768: switch ( af ) {
769: case AF_INET:
770:
771: if ((size_t) num < sizeof(struct IPHeader) +
772: sizeof(struct ICMPHeader) +
773: sizeof (struct IPHeader) +
774: sizeof (struct ICMPHeader))
775: return;
776: header = (struct ICMPHeader *)(packet + sizeof (struct IPHeader) +
777: sizeof (struct ICMPHeader) +
778: sizeof (struct IPHeader));
779:
780: if(num > 160)
781: decodempls(num, packet, &mpls, 156);
782:
783: break;
784: #ifdef ENABLE_IPV6
785: case AF_INET6:
786: if ( num < sizeof (struct ICMPHeader) +
787: sizeof (struct ip6_hdr) + sizeof (struct ICMPHeader) )
788: return;
789: header = (struct ICMPHeader *) ( packet +
790: sizeof (struct ICMPHeader) +
791: sizeof (struct ip6_hdr) );
792:
793: if(num > 140)
794: decodempls(num, packet, &mpls, 136);
795:
796: break;
797: #endif
798: }
799:
800: if (header->id != (uint16)getpid())
801: return;
802:
803: sequence = header->sequence;
804: }
805: break;
806:
807: case IPPROTO_UDP:
808: if (header->type == timeexceededtype || header->type == unreachabletype) {
809: switch ( af ) {
810: case AF_INET:
811:
812: if ((size_t) num < sizeof(struct IPHeader) +
813: sizeof(struct ICMPHeader) +
814: sizeof (struct IPHeader) +
815: sizeof (struct UDPHeader))
816: return;
817: udpheader = (struct UDPHeader *)(packet + sizeof (struct IPHeader) +
818: sizeof (struct ICMPHeader) +
819: sizeof (struct IPHeader));
820:
821: if(num > 160)
822: decodempls(num, packet, &mpls, 156);
823:
824: break;
825: #ifdef ENABLE_IPV6
826: case AF_INET6:
827: if ( num < sizeof (struct ICMPHeader) +
828: sizeof (struct ip6_hdr) + sizeof (struct UDPHeader) )
829: return;
830: udpheader = (struct UDPHeader *) ( packet +
831: sizeof (struct ICMPHeader) +
832: sizeof (struct ip6_hdr) );
833:
834: if(num > 140)
835: decodempls(num, packet, &mpls, 136);
836:
837: break;
838: #endif
839: }
840: sequence = ntohs(udpheader->dstport);
841: }
842: break;
843:
844: case IPPROTO_TCP:
845: if (header->type == timeexceededtype || header->type == unreachabletype) {
846: switch ( af ) {
847: case AF_INET:
848:
849: if ((size_t) num < sizeof(struct IPHeader) +
850: sizeof(struct ICMPHeader) +
851: sizeof (struct IPHeader) +
852: sizeof (struct TCPHeader))
853: return;
854: tcpheader = (struct TCPHeader *)(packet + sizeof (struct IPHeader) +
855: sizeof (struct ICMPHeader) +
856: sizeof (struct IPHeader));
857:
858: if(num > 160)
859: decodempls(num, packet, &mpls, 156);
860:
861: break;
862: #ifdef ENABLE_IPV6
863: case AF_INET6:
864: if ( num < sizeof (struct ICMPHeader) +
865: sizeof (struct ip6_hdr) + sizeof (struct TCPHeader) )
866: return;
867: tcpheader = (struct TCPHeader *) ( packet +
868: sizeof (struct ICMPHeader) +
869: sizeof (struct ip6_hdr) );
870:
871: if(num > 140)
872: decodempls(num, packet, &mpls, 136);
873:
874: break;
875: #endif
876: }
877: sequence = ntohs(tcpheader->srcport);
878: }
879: break;
880: }
881:
882: if (sequence)
883: net_process_ping (sequence, mpls, (void *) fromaddress, now);
884: }
885:
886:
887: ip_t *net_addr(int at)
888: {
889: return (ip_t *)&(host[at].addr);
890: }
891:
892:
893: ip_t *net_addrs(int at, int i)
894: {
895: return (ip_t *)&(host[at].addrs[i]);
896: }
897:
898: void *net_mpls(int at)
899: {
900: return (struct mplslen *)&(host[at].mplss);
901: }
902:
903: void *net_mplss(int at, int i)
904: {
905: return (struct mplslen *)&(host[at].mplss[i]);
906: }
907:
908: int net_loss(int at)
909: {
910: if ((host[at].xmit - host[at].transit) == 0)
911: return 0;
912: /* times extra 1000 */
913: return 1000*(100 - (100.0 * host[at].returned / (host[at].xmit - host[at].transit)) );
914: }
915:
916:
917: int net_drop(int at)
918: {
919: return (host[at].xmit - host[at].transit) - host[at].returned;
920: }
921:
922:
923: int net_last(int at)
924: {
925: return (host[at].last);
926: }
927:
928:
929: int net_best(int at)
930: {
931: return (host[at].best);
932: }
933:
934:
935: int net_worst(int at)
936: {
937: return (host[at].worst);
938: }
939:
940:
941: int net_avg(int at)
942: {
943: return (host[at].avg);
944: }
945:
946:
947: int net_gmean(int at)
948: {
949: return (host[at].gmean);
950: }
951:
952:
953: int net_stdev(int at)
954: {
955: if( host[at].returned > 1 ) {
956: return ( 1000.0 * sqrt( host[at].var/(host[at].returned -1.0) ) );
957: } else {
958: return( 0 );
959: }
960: }
961:
962:
963: int net_jitter(int at)
964: {
965: return (host[at].jitter);
966: }
967:
968:
969: int net_jworst(int at)
970: {
971: return (host[at].jworst);
972: }
973:
974:
975: int net_javg(int at)
976: {
977: return (host[at].javg);
978: }
979:
980:
981: int net_jinta(int at)
982: {
983: return (host[at].jinta);
984: }
985:
986:
987: int net_max(void)
988: {
989: int at;
990: int max;
991:
992: max = 0;
993: /* for(at = 0; at < MaxHost-2; at++) { */
994: for(at = 0; at < maxTTL-1; at++) {
995: if ( addrcmp( (void *) &(host[at].addr),
996: (void *) remoteaddress, af ) == 0 ) {
997: return at + 1;
998: } else if ( addrcmp( (void *) &(host[at].addr),
999: (void *) &unspec_addr, af ) != 0 ) {
1000: max = at + 2;
1001: }
1002: }
1003:
1004: return max;
1005: }
1006:
1007:
1008: int net_min (void)
1009: {
1010: return ( fstTTL - 1 );
1011: }
1012:
1013:
1014: int net_returned(int at)
1015: {
1016: return host[at].returned;
1017: }
1018:
1019:
1020: int net_xmit(int at)
1021: {
1022: return host[at].xmit;
1023: }
1024:
1025:
1026: int net_transit(int at)
1027: {
1028: return host[at].transit;
1029: }
1030:
1031:
1032: int net_up(int at)
1033: {
1034: return host[at].up;
1035: }
1036:
1037:
1038: char * net_localaddr (void)
1039: {
1040: return localaddr;
1041: }
1042:
1043:
1044: void net_end_transit(void)
1045: {
1046: int at;
1047:
1048: for(at = 0; at < MaxHost; at++) {
1049: host[at].transit = 0;
1050: }
1051: }
1052:
1053: int net_send_batch(void)
1054: {
1055: int n_unknown=0, i;
1056:
1057: /* randomized packet size and/or bit pattern if packetsize<0 and/or
1058: bitpattern<0. abs(packetsize) and/or abs(bitpattern) will be used
1059: */
1060: if( batch_at < fstTTL ) {
1061: if( cpacketsize < 0 ) {
1062: /* Someone used a formula here that tried to correct for the
1063: "end-error" in "rand()". By "end-error" I mean that if you
1064: have a range for "rand()" that runs to 32768, and the
1065: destination range is 10000, you end up with 4 out of 32768
1066: 0-2768's and only 3 out of 32768 for results 2769 .. 9999.
1067: As our detination range (in the example 10000) is much
1068: smaller (reasonable packet sizes), and our rand() range much
1069: larger, this effect is insignificant. Oh! That other formula
1070: didn't work. */
1071: packetsize = MINPACKET + rand () % (-cpacketsize - MINPACKET);
1072: } else {
1073: packetsize = cpacketsize;
1074: }
1075: if( bitpattern < 0 ) {
1076: bitpattern = - (int)(256 + 255*(rand()/(RAND_MAX+0.1)));
1077: }
1078: }
1079:
1080: /* printf ("cpacketsize = %d, packetsize = %d\n", cpacketsize, packetsize); */
1081:
1082: net_send_query(batch_at);
1083:
1084: for (i=fstTTL-1;i<batch_at;i++) {
1085: if ( addrcmp( (void *) &(host[i].addr), (void *) &unspec_addr, af ) == 0 )
1086: n_unknown++;
1087:
1088: /* The second condition in the next "if" statement was added in mtr-0.56,
1089: but I don't remember why. It makes mtr stop skipping sections of unknown
1090: hosts. Removed in 0.65.
1091: If the line proves neccesary, it should at least NOT trigger that line
1092: when host[i].addr == 0 */
1093: if ( ( addrcmp( (void *) &(host[i].addr),
1094: (void *) remoteaddress, af ) == 0 )
1095: /* || (host[i].addr == host[batch_at].addr) */)
1096: n_unknown = MaxHost; /* Make sure we drop into "we should restart" */
1097: }
1098:
1099: if ( /* success in reaching target */
1100: ( addrcmp( (void *) &(host[batch_at].addr),
1101: (void *) remoteaddress, af ) == 0 ) ||
1102: /* fail in consecuitive MAX_UNKNOWN_HOSTS (firewall?) */
1103: (n_unknown > MAX_UNKNOWN_HOSTS) ||
1104: /* or reach limit */
1105: (batch_at >= maxTTL-1)) {
1106: numhosts = batch_at+1;
1107: batch_at = fstTTL - 1;
1108: return 1;
1109: }
1110:
1111: batch_at++;
1112: return 0;
1113: }
1114:
1115:
1116: static void set_fd_flags(int fd)
1117: {
1118: #if defined(HAVE_FCNTL) && defined(FD_CLOEXEC)
1119: int oldflags;
1120:
1121: if (fd < 0) return;
1122:
1123: oldflags = fcntl(fd, F_GETFD);
1124: if (oldflags == -1) {
1125: perror("Couldn't get fd's flags");
1126: return;
1127: }
1128: if (fcntl(fd, F_SETFD, oldflags | FD_CLOEXEC))
1129: perror("Couldn't set fd's flags");
1130: #endif
1131: }
1132:
1133: int net_preopen(void)
1134: {
1135: int trueopt = 1;
1136:
1137: #if !defined(IP_HDRINCL) && defined(IP_TOS) && defined(IP_TTL)
1138: sendsock4_icmp = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
1139: sendsock4_udp = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
1140: #else
1141: sendsock4 = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
1142: #endif
1143: if (sendsock4 < 0)
1144: return -1;
1145: #ifdef ENABLE_IPV6
1146: sendsock6_icmp = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
1147: sendsock6_udp = socket(AF_INET6, SOCK_RAW, IPPROTO_UDP);
1148: #endif
1149:
1150: #ifdef IP_HDRINCL
1151: /* FreeBSD wants this to avoid sending out packets with protocol type RAW
1152: to the network. */
1153: if (setsockopt(sendsock4, SOL_IP, IP_HDRINCL, &trueopt, sizeof(trueopt))) {
1154: perror("setsockopt(IP_HDRINCL,1)");
1155: return -1;
1156: }
1157: #endif /* IP_HDRINCL */
1158:
1159: recvsock4 = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
1160: if (recvsock4 < 0)
1161: return -1;
1162: set_fd_flags(recvsock4);
1163: #ifdef ENABLE_IPV6
1164: recvsock6 = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
1165: if (recvsock6 >= 0)
1166: set_fd_flags(recvsock6);
1167: #endif
1168:
1169: return 0;
1170: }
1171:
1172:
1173: int net_selectsocket(void)
1174: {
1175: #if !defined(IP_HDRINCL) && defined(IP_TOS) && defined(IP_TTL)
1176: switch ( mtrtype ) {
1177: case IPPROTO_ICMP:
1178: sendsock4 = sendsock4_icmp;
1179: break;
1180: case IPPROTO_UDP:
1181: sendsock4 = sendsock4_udp;
1182: break;
1183: }
1184: #endif
1185: if (sendsock4 < 0)
1186: return -1;
1187: #ifdef ENABLE_IPV6
1188: switch ( mtrtype ) {
1189: case IPPROTO_ICMP:
1190: sendsock6 = sendsock6_icmp;
1191: break;
1192: case IPPROTO_UDP:
1193: sendsock6 = sendsock6_udp;
1194: break;
1195: }
1196: if ((sendsock6 < 0) && (sendsock4 < 0))
1197: return -1;
1198: #endif
1199:
1200: return 0;
1201: }
1202:
1203:
1204: int net_open(struct hostent * host)
1205: {
1206: #ifdef ENABLE_IPV6
1207: struct sockaddr_storage name_struct;
1208: #else
1209: struct sockaddr_in name_struct;
1210: #endif
1211: struct sockaddr * name = (struct sockaddr *) &name_struct;
1212: socklen_t len;
1213:
1214: net_reset();
1215:
1216: remotesockaddr->sa_family = host->h_addrtype;
1217:
1218: switch ( host->h_addrtype ) {
1219: case AF_INET:
1220: sendsock = sendsock4;
1221: recvsock = recvsock4;
1222: addrcpy( (void *) &(rsa4->sin_addr), host->h_addr, AF_INET );
1223: sourceaddress = (ip_t *) &(ssa4->sin_addr);
1224: remoteaddress = (ip_t *) &(rsa4->sin_addr);
1225: break;
1226: #ifdef ENABLE_IPV6
1227: case AF_INET6:
1228: if (sendsock6 < 0 || recvsock6 < 0) {
1229: fprintf( stderr, "Could not open IPv6 socket\n" );
1230: exit( EXIT_FAILURE );
1231: }
1232: sendsock = sendsock6;
1233: recvsock = recvsock6;
1234: addrcpy( (void *) &(rsa6->sin6_addr), host->h_addr, AF_INET6 );
1235: sourceaddress = (ip_t *) &(ssa6->sin6_addr);
1236: remoteaddress = (ip_t *) &(rsa6->sin6_addr);
1237: break;
1238: #endif
1239: default:
1240: fprintf( stderr, "net_open bad address type\n" );
1241: exit( EXIT_FAILURE );
1242: }
1243:
1244: len = sizeof name_struct;
1245: getsockname (recvsock, name, &len);
1246: sockaddrtop( name, localaddr, sizeof localaddr );
1247: #if 0
1248: printf ("got localaddr: %s\n", localaddr);
1249: #endif
1250:
1251: return 0;
1252: }
1253:
1254:
1255: void net_reopen(struct hostent * addr)
1256: {
1257: int at;
1258:
1259: for(at = 0; at < MaxHost; at++) {
1260: memset(&host[at], 0, sizeof(host[at]));
1261: }
1262:
1263: remotesockaddr->sa_family = addr->h_addrtype;
1264: addrcpy( (void *) remoteaddress, addr->h_addr, addr->h_addrtype );
1265:
1266: switch ( addr->h_addrtype ) {
1267: case AF_INET:
1268: addrcpy( (void *) &(rsa4->sin_addr), addr->h_addr, AF_INET );
1269: break;
1270: #ifdef ENABLE_IPV6
1271: case AF_INET6:
1272: addrcpy( (void *) &(rsa6->sin6_addr), addr->h_addr, AF_INET6 );
1273: break;
1274: #endif
1275: default:
1276: fprintf( stderr, "net_reopen bad address type\n" );
1277: exit( EXIT_FAILURE );
1278: }
1279:
1280: net_reset ();
1281: net_send_batch();
1282: }
1283:
1284:
1285: void net_reset(void)
1286: {
1287: int at;
1288: int i;
1289:
1290: batch_at = fstTTL - 1; /* above replacedByMin */
1291: numhosts = 10;
1292:
1293: for (at = 0; at < MaxHost; at++) {
1294: host[at].xmit = 0;
1295: host[at].transit = 0;
1296: host[at].returned = 0;
1297: host[at].sent = 0;
1298: host[at].up = 0;
1299: host[at].last = 0;
1300: host[at].avg = 0;
1301: host[at].best = 0;
1302: host[at].worst = 0;
1303: host[at].gmean = 0;
1304: host[at].var = 0;
1305: host[at].jitter = 0;
1306: host[at].javg = 0;
1307: host[at].jworst = 0;
1308: host[at].jinta = 0;
1309: for (i=0; i<SAVED_PINGS; i++) {
1310: host[at].saved[i] = -2; /* unsent */
1311: }
1312: host[at].saved_seq_offset = -SAVED_PINGS+2;
1313: }
1314:
1315: for (at = 0; at < MaxSequence; at++) {
1316: sequence[at].transit = 0;
1317: if (sequence[at].socket > 0) {
1318: close(sequence[at].socket);
1319: sequence[at].socket = 0;
1320: }
1321: }
1322:
1323: gettimeofday(&reset, NULL);
1324: }
1325:
1326:
1327: int net_set_interfaceaddress (char *InterfaceAddress)
1328: {
1329: int len = 0;
1330:
1331: if (!InterfaceAddress) return 0;
1332:
1333: sourcesockaddr->sa_family = af;
1334: switch ( af ) {
1335: case AF_INET:
1336: ssa4->sin_port = 0;
1337: if ( inet_aton( InterfaceAddress, &(ssa4->sin_addr) ) < 1 ) {
1338: fprintf( stderr, "mtr: bad interface address: %s\n", InterfaceAddress );
1339: return( 1 );
1340: }
1341: len = sizeof (struct sockaddr);
1342: break;
1343: #ifdef ENABLE_IPV6
1344: case AF_INET6:
1345: ssa6->sin6_port = 0;
1346: if ( inet_pton( af, InterfaceAddress, &(ssa6->sin6_addr) ) < 1 ) {
1347: fprintf( stderr, "mtr: bad interface address: %s\n", InterfaceAddress );
1348: return( 1 );
1349: }
1350: len = sizeof (struct sockaddr_in6);
1351: break;
1352: #endif
1353: }
1354:
1355: if ( bind( sendsock, sourcesockaddr, len ) == -1 ) {
1356: perror("mtr: failed to bind to interface");
1357: return( 1 );
1358: }
1359: return 0;
1360: }
1361:
1362:
1363:
1364: void net_close(void)
1365: {
1366: if (sendsock4 >= 0) {
1367: close(sendsock4_icmp);
1368: close(sendsock4_udp);
1369: }
1370: if (recvsock4 >= 0) close(recvsock4);
1371: if (sendsock6 >= 0) {
1372: close(sendsock6_icmp);
1373: close(sendsock6_udp);
1374: }
1375: if (recvsock6 >= 0) close(recvsock6);
1376: }
1377:
1378:
1379: int net_waitfd(void)
1380: {
1381: return recvsock;
1382: }
1383:
1384:
1385: int* net_saved_pings(int at)
1386: {
1387: return host[at].saved;
1388: }
1389:
1390:
1391: void net_save_increment(void)
1392: {
1393: int at;
1394: for (at = 0; at < MaxHost; at++) {
1395: memmove(host[at].saved, host[at].saved+1, (SAVED_PINGS-1)*sizeof(int));
1396: host[at].saved[SAVED_PINGS-1] = -2;
1397: host[at].saved_seq_offset += 1;
1398: }
1399: }
1400:
1401:
1402: void net_save_xmit(int at)
1403: {
1404: if (host[at].saved[SAVED_PINGS-1] != -2)
1405: net_save_increment();
1406: host[at].saved[SAVED_PINGS-1] = -1;
1407: }
1408:
1409:
1410: void net_save_return(int at, int seq, int ms)
1411: {
1412: int idx;
1413: idx = seq - host[at].saved_seq_offset;
1.1.1.2 ! misho 1414: if (idx < 0 || idx >= SAVED_PINGS) {
1.1 misho 1415: return;
1416: }
1417: host[at].saved[idx] = ms;
1418: }
1419:
1420: /* Similar to inet_ntop but uses a sockaddr as it's argument. */
1421: void sockaddrtop( struct sockaddr * saddr, char * strptr, size_t len ) {
1422: struct sockaddr_in * sa4;
1423: #ifdef ENABLE_IPV6
1424: struct sockaddr_in6 * sa6;
1425: #endif
1426:
1427: switch ( saddr->sa_family ) {
1428: case AF_INET:
1429: sa4 = (struct sockaddr_in *) saddr;
1430: strncpy( strptr, inet_ntoa( sa4->sin_addr ), len - 1 );
1431: strptr[ len - 1 ] = '\0';
1432: return;
1433: #ifdef ENABLE_IPV6
1434: case AF_INET6:
1435: sa6 = (struct sockaddr_in6 *) saddr;
1436: inet_ntop( sa6->sin6_family, &(sa6->sin6_addr), strptr, len );
1437: return;
1438: #endif
1439: default:
1440: fprintf( stderr, "sockaddrtop unknown address type\n" );
1441: strptr[0] = '\0';
1442: return;
1443: }
1444: }
1445:
1446: /* Address comparison. */
1447: int addrcmp( char * a, char * b, int af ) {
1448: int rc = -1;
1449:
1450: switch ( af ) {
1451: case AF_INET:
1452: rc = memcmp( a, b, sizeof (struct in_addr) );
1453: break;
1454: #ifdef ENABLE_IPV6
1455: case AF_INET6:
1456: rc = memcmp( a, b, sizeof (struct in6_addr) );
1457: break;
1458: #endif
1459: }
1460:
1461: return rc;
1462: }
1463:
1464: /* Address copy. */
1465: void addrcpy( char * a, char * b, int af ) {
1466:
1467: switch ( af ) {
1468: case AF_INET:
1469: memcpy( a, b, sizeof (struct in_addr) );
1470: break;
1471: #ifdef ENABLE_IPV6
1472: case AF_INET6:
1473: memcpy( a, b, sizeof (struct in6_addr) );
1474: break;
1475: #endif
1476: }
1477: }
1478:
1479: /* Decode MPLS */
1480: void decodempls(int num, char *packet, struct mplslen *mpls, int offset) {
1481:
1482: int i;
1483: unsigned int ext_ver, ext_res, ext_chk, obj_hdr_len;
1484: u_char obj_hdr_class, obj_hdr_type;
1485:
1486: /* loosely derived from the traceroute-nanog.c
1487: * decoding by Jorge Boncompte */
1488: ext_ver = packet[offset]>>4;
1489: ext_res = (packet[offset]&15)+ packet[offset+1];
1490: ext_chk = ((unsigned int)packet[offset+2]<<8)+packet[offset+3];
1491:
1492: /* Check for ICMP extension header */
1493: if (ext_ver == 2 && ext_res == 0 && ext_chk != 0 && num >= (offset+6)) {
1494: obj_hdr_len = ((int)packet[offset+4]<<8)+packet[offset+5];
1495: obj_hdr_class = packet[offset+6];
1496: obj_hdr_type = packet[offset+7];
1497:
1498: /* make sure we have an MPLS extension */
1499: if (obj_hdr_len >= 8 && obj_hdr_class == 1 && obj_hdr_type == 1) {
1500: /* how many labels do we have? will be at least 1 */
1501: mpls->labels = (obj_hdr_len-4)/4;
1502:
1503: /* save all label objects */
1504: for(i=0; (i<mpls->labels) && (i < MAXLABELS) && (num >= (offset+8)+(i*4)); i++) {
1505:
1506: /* piece together the 20 byte label value */
1507: mpls->label[i] = ((unsigned long) (packet[(offset+8)+(i*4)] << 12 & 0xff000) +
1508: (unsigned int) (packet[(offset+9)+(i*4)] << 4 & 0xff0) +
1509: (packet[(offset+10)+(i*4)] >> 4 & 0xf));
1510: mpls->exp[i] = (packet[(offset+10)+(i*4)] >> 1) & 0x7;
1511: mpls->s[i] = (packet[(offset+10)+(i*4)] & 0x1); /* should be 1 if only one label */
1512: mpls->ttl[i] = packet[(offset+11)+(i*4)];
1513: }
1514: }
1515: }
1516: }
1517:
1518: /* Add open sockets to select() */
1519: void net_add_fds(fd_set *writefd, int *maxfd)
1520: {
1521: int at, fd;
1522: for (at = 0; at < MaxSequence; at++) {
1523: fd = sequence[at].socket;
1524: if (fd > 0) {
1525: FD_SET(fd, writefd);
1526: if (fd >= *maxfd)
1527: *maxfd = fd + 1;
1528: }
1529: }
1530: }
1531:
1532: /* check if we got connection or error on any fds */
1533: void net_process_fds(fd_set *writefd)
1534: {
1535: int at, fd, r;
1536: struct timeval now;
1537: uint64_t unow, utime;
1538:
1539: /* Can't do MPLS decoding */
1540: struct mplslen mpls;
1541: mpls.labels = 0;
1542:
1543: gettimeofday(&now, NULL);
1544: unow = now.tv_sec * 1000000L + now.tv_usec;
1545:
1546: for (at = 0; at < MaxSequence; at++) {
1547: fd = sequence[at].socket;
1548: if (fd > 0 && FD_ISSET(fd, writefd)) {
1549: r = write(fd, "G", 1);
1550: /* if write was successful, or connection refused we have
1551: * (probably) reached the remote address. Anything else happens to the
1552: * connection, we write it off to avoid leaking sockets */
1553: if (r == 1 || errno == ECONNREFUSED)
1554: net_process_ping(at, mpls, remoteaddress, now);
1555: else if (errno != EAGAIN) {
1556: close(fd);
1557: sequence[at].socket = 0;
1558: }
1559: }
1560: if (fd > 0) {
1561: utime = sequence[at].time.tv_sec * 1000000L + sequence[at].time.tv_usec;
1562: if (unow - utime > timeout) {
1563: close(fd);
1564: sequence[at].socket = 0;
1565: }
1566: }
1567: }
1568: }
1569:
1570: /* for GTK frontend */
1571: void net_harvest_fds(void)
1572: {
1573: fd_set writefd;
1574: int maxfd = 0;
1575: struct timeval tv;
1576:
1577: FD_ZERO(&writefd);
1578: tv.tv_sec = 0;
1579: tv.tv_usec = 0;
1580: net_add_fds(&writefd, &maxfd);
1581: select(maxfd, NULL, &writefd, NULL, &tv);
1582: net_process_fds(&writefd);
1.1.1.2 ! misho 1583: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>