File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / mtr / net.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Nov 1 09:33:48 2016 UTC (7 years, 7 months ago) by misho
Branches: mtr, elwix, MAIN
CVS tags: v0_86, HEAD
mtr 0.86

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>