Annotation of embedaddon/mtr/net.c, revision 1.1

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

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