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

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

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