Annotation of embedaddon/mtr/net.c, revision 1.1.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>