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