File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / mtr / net.c
Revision 1.1: download - view: text, annotated - select for diffs - revision graph
Sun Jul 21 23:43:42 2013 UTC (10 years, 11 months ago) by misho
CVS tags: MAIN, HEAD
Initial revision

    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>