Annotation of embedaddon/mtr/ui/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: 
1.1.1.2 ! misho      14:     You should have received a copy of the GNU General Public License along
        !            15:     with this program; if not, write to the Free Software Foundation, Inc.,
        !            16:     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
1.1       misho      17: */
                     18: 
                     19: #include "config.h"
                     20: 
                     21: #include <errno.h>
1.1.1.2 ! misho      22: #include <sys/types.h>
        !            23: #include <ifaddrs.h>
1.1       misho      24: #include <math.h>
                     25: #include <stdlib.h>
                     26: #include <string.h>
                     27: #include <sys/select.h>
                     28: #include <unistd.h>
                     29: 
                     30: #ifdef HAVE_ERROR_H
                     31: #include <error.h>
                     32: #else
                     33: #include "portability/error.h"
                     34: #endif
                     35: 
                     36: #include "mtr.h"
                     37: #include "cmdpipe.h"
                     38: #include "net.h"
                     39: #include "display.h"
                     40: #include "dns.h"
                     41: #include "utils.h"
1.1.1.2 ! misho      42: #include "packet/sockaddr.h"
1.1       misho      43: 
                     44: #define MinSequence 33000
                     45: #define MaxSequence 65536
                     46: 
                     47: static int packetsize;          /* packet size used by ping */
                     48: 
                     49: struct nethost {
1.1.1.2 ! misho      50:     ip_t addr;                  /* Latest host to respond */
        !            51:     ip_t addrs[MAX_PATH];        /* For Multi paths/Path Changes: List of all hosts that have responded */
        !            52:     int err;
1.1       misho      53:     int xmit;
                     54:     int returned;
                     55:     int sent;
                     56:     int up;
                     57:     long long ssd;              /* sum of squares of differences from the current average */
                     58:     int last;
                     59:     int best;
                     60:     int worst;
                     61:     int avg;                    /* average:  addByMin */
                     62:     int gmean;                  /* geometric mean: addByMin */
                     63:     int jitter;                 /* current jitter, defined as t1-t0 addByMin */
                     64:     int javg;                   /* avg jitter */
                     65:     int jworst;                 /* max jitter */
                     66:     int jinta;                  /* estimated variance,? rfc1889's "Interarrival Jitter" */
                     67:     int transit;
                     68:     int saved[SAVED_PINGS];
                     69:     int saved_seq_offset;
                     70:     struct mplslen mpls;
1.1.1.2 ! misho      71:     struct mplslen mplss[MAX_PATH];
1.1       misho      72: };
                     73: 
                     74: 
                     75: struct sequence {
                     76:     int index;
                     77:     int transit;
                     78:     int saved_seq;
                     79:     struct timeval time;
                     80: };
                     81: 
                     82: 
                     83: static struct nethost host[MaxHost];
                     84: static struct sequence sequence[MaxSequence];
                     85: static struct packet_command_pipe_t packet_command_pipe;
                     86: 
                     87: static struct sockaddr_storage sourcesockaddr_struct;
                     88: static struct sockaddr_storage remotesockaddr_struct;
                     89: 
                     90: static struct sockaddr *sourcesockaddr =
                     91:     (struct sockaddr *) &sourcesockaddr_struct;
                     92: static struct sockaddr *remotesockaddr =
                     93:     (struct sockaddr *) &remotesockaddr_struct;
                     94: 
                     95: static ip_t *sourceaddress;
                     96: static ip_t *remoteaddress;
                     97: 
                     98: #ifdef ENABLE_IPV6
                     99: static char localaddr[INET6_ADDRSTRLEN];
                    100: #else
                    101: #ifndef INET_ADDRSTRLEN
                    102: #define INET_ADDRSTRLEN 16
                    103: #endif
                    104: static char localaddr[INET_ADDRSTRLEN];
                    105: #endif
                    106: 
                    107: static int batch_at = 0;
                    108: static int numhosts = 10;
                    109: 
1.1.1.2 ! misho     110: 
        !           111: #define host_addr_cmp(index, other, af) \
        !           112:     addrcmp((void *) &(host[(index)].addr), (void *) (other), (af))
        !           113: 
        !           114: #define host_addrs_cmp(index, path, other, af) \
        !           115:     addrcmp((void *) &(host[(index)].addrs[path]), (void *) (other), (af))
        !           116: 
        !           117: 
1.1       misho     118: /* return the number of microseconds to wait before sending the next
                    119:    ping */
                    120: int calc_deltatime(
                    121:     float waittime)
                    122: {
                    123:     waittime /= numhosts;
                    124:     return 1000000 * waittime;
                    125: }
                    126: 
                    127: 
                    128: static void save_sequence(
                    129:     struct mtr_ctl *ctl,
                    130:     int index,
                    131:     int seq)
                    132: {
                    133:     display_rawxmit(ctl, index, seq);
                    134: 
                    135:     sequence[seq].index = index;
                    136:     sequence[seq].transit = 1;
                    137:     sequence[seq].saved_seq = ++host[index].xmit;
                    138:     memset(&sequence[seq].time, 0, sizeof(sequence[seq].time));
                    139: 
                    140:     host[index].transit = 1;
                    141: 
                    142:     if (host[index].sent) {
                    143:         host[index].up = 0;
                    144:     }
                    145: 
                    146:     host[index].sent = 1;
                    147:     net_save_xmit(index);
                    148: }
                    149: 
                    150: static int new_sequence(
                    151:     struct mtr_ctl *ctl,
                    152:     int index)
                    153: {
                    154:     static int next_sequence = MinSequence;
                    155:     int seq;
                    156: 
                    157:     seq = next_sequence++;
                    158:     if (next_sequence >= MaxSequence) {
                    159:         next_sequence = MinSequence;
                    160:     }
                    161: 
                    162:     save_sequence(ctl, index, seq);
                    163: 
                    164:     return seq;
                    165: }
                    166: 
                    167: 
                    168: /*  Attempt to find the host at a particular number of hops away  */
                    169: static void net_send_query(
                    170:     struct mtr_ctl *ctl,
                    171:     int index,
                    172:     int packet_size)
                    173: {
                    174:     int seq = new_sequence(ctl, index);
                    175:     int time_to_live = index + 1;
                    176: 
                    177:     send_probe_command(ctl, &packet_command_pipe, remoteaddress,
1.1.1.2 ! misho     178:                        sourceaddress, packet_size, seq, time_to_live);
1.1       misho     179: }
                    180: 
                    181: 
1.1.1.2 ! misho     182: /*
        !           183:     Mark a sequence entry as completed and return the host index
        !           184:     being probed.
        !           185: 
        !           186:     Returns -1 in the case of an invalid sequence number.
        !           187: */
        !           188: static int mark_sequence_complete(
        !           189:     int seq)
        !           190: {
        !           191:     if ((seq < 0) || (seq >= MaxSequence)) {
        !           192:         return -1;
        !           193:     }
        !           194: 
        !           195:     if (!sequence[seq].transit) {
        !           196:         return -1;
        !           197:     }
        !           198:     sequence[seq].transit = 0;
        !           199: 
        !           200:     return sequence[seq].index;
        !           201: }
        !           202: 
        !           203: 
        !           204: /*
        !           205:     A probe has successfully completed.
        !           206: 
        !           207:     Record the round trip time and address of the responding host.
        !           208: */
        !           209: 
1.1       misho     210: static void net_process_ping(
                    211:     struct mtr_ctl *ctl,
                    212:     int seq,
1.1.1.2 ! misho     213:     int err,
1.1       misho     214:     struct mplslen *mpls,
                    215:     ip_t * addr,
                    216:     int totusec)
                    217: {
                    218:     int index;
                    219:     int oldavg;                 /* usedByMin */
                    220:     int oldjavg;                /* usedByMin */
                    221:     int i;                      /* usedByMin */
1.1.1.2 ! misho     222:     int found = 0;
1.1       misho     223: #ifdef ENABLE_IPV6
                    224:     char addrcopy[sizeof(struct in6_addr)];
                    225: #else
                    226:     char addrcopy[sizeof(struct in_addr)];
                    227: #endif
1.1.1.2 ! misho     228:     struct nethost *nh = NULL;
1.1       misho     229: 
1.1.1.2 ! misho     230:     memcpy(&addrcopy, addr, sockaddr_addr_size(sourcesockaddr));
1.1       misho     231: 
1.1.1.2 ! misho     232:     index = mark_sequence_complete(seq);
        !           233:     if (index < 0) {
1.1       misho     234:         return;
                    235:     }
1.1.1.2 ! misho     236:     nh = &host[index];
        !           237:     nh->err = err;
1.1       misho     238: 
                    239: 
                    240: 
1.1.1.2 ! misho     241:     if (addrcmp(&nh->addr, &addrcopy, ctl->af) != 0) {
        !           242:         for (i = 0; i < MAX_PATH;) {
        !           243:             if (addrcmp(&nh->addrs[i], &nh->addr, ctl->af) == 0) {
        !           244:                 found = 1; /* This host is already in the list */
1.1       misho     245:                 break;
                    246:             }
1.1.1.2 ! misho     247:             if (addrcmp(&nh->addrs[i], &ctl->unspec_addr, ctl->af) == 0) {
        !           248:                 break; /* Found first vacant position */
        !           249:             }
1.1       misho     250:             i++;
                    251:         }
                    252: 
1.1.1.2 ! misho     253:         if (found == 0 && i < MAX_PATH) {
        !           254:             memcpy(&nh->addrs[i], &nh->addr, sockaddr_addr_size(sourcesockaddr));
        !           255: 
        !           256:             nh->mplss[i] = nh->mpls;
        !           257:             display_rawhost(ctl, index, (void *)&(nh->addrs[i]), (void *)&(nh->addrs[i]));
1.1       misho     258:         }
1.1.1.2 ! misho     259: 
        !           260:         /* Always save the latest host in nh->addr. This
        !           261:          * allows maxTTL to change whenever path changes.
        !           262:          */
        !           263:         memcpy(&nh->addr, addrcopy, sockaddr_addr_size(sourcesockaddr));
        !           264:         nh->mpls = *mpls;
        !           265:         display_rawhost(ctl, index, (void *)&(nh->addr), (void *)&(nh->mpls));
1.1       misho     266:     }
                    267: 
1.1.1.2 ! misho     268:     nh->jitter = totusec - nh->last;
        !           269:     if (nh->jitter < 0) {
        !           270:         nh->jitter = -nh->jitter;
1.1       misho     271:     }
                    272: 
1.1.1.2 ! misho     273:     nh->last = totusec;
1.1       misho     274: 
1.1.1.2 ! misho     275:     if (nh->returned < 1) {
        !           276:         nh->best = nh->worst = nh->gmean = totusec;
        !           277:         nh->avg = nh->ssd = 0;
1.1       misho     278: 
1.1.1.2 ! misho     279:         nh->jitter = nh->jworst = nh->jinta = 0;
1.1       misho     280:     }
                    281: 
1.1.1.2 ! misho     282:     if (totusec < nh->best) {
        !           283:         nh->best = totusec;
1.1       misho     284:     }
1.1.1.2 ! misho     285:     if (totusec > nh->worst) {
        !           286:         nh->worst = totusec;
1.1       misho     287:     }
                    288: 
1.1.1.2 ! misho     289:     if (nh->jitter > nh->jworst) {
        !           290:         nh->jworst = nh->jitter;
1.1       misho     291:     }
                    292: 
1.1.1.2 ! misho     293:     nh->returned++;
        !           294:     oldavg = nh->avg;
        !           295:     nh->avg += (totusec - oldavg + .0) / nh->returned;
        !           296:     nh->ssd +=
        !           297:         (totusec - oldavg + .0) * (totusec - nh->avg);
1.1       misho     298: 
1.1.1.2 ! misho     299:     oldjavg = nh->javg;
        !           300:     nh->javg +=
        !           301:         (nh->jitter - oldjavg) / nh->returned;
1.1       misho     302:     /* below algorithm is from rfc1889, A.8 */
1.1.1.2 ! misho     303:     nh->jinta +=
        !           304:         nh->jitter - ((nh->jinta + 8) >> 4);
1.1       misho     305: 
1.1.1.2 ! misho     306:     if (nh->returned > 1) {
        !           307:         nh->gmean =
        !           308:             pow((double) nh->gmean,
        !           309:                 (nh->returned - 1.0) / nh->returned)
        !           310:             * pow((double) totusec, 1.0 / nh->returned);
1.1       misho     311:     }
                    312: 
1.1.1.2 ! misho     313:     nh->sent = 0;
        !           314:     nh->up = 1;
        !           315:     nh->transit = 0;
1.1       misho     316: 
                    317:     net_save_return(index, sequence[seq].saved_seq, totusec);
                    318:     display_rawping(ctl, index, totusec, seq);
                    319: }
                    320: 
                    321: /*
                    322:     Invoked when the read pipe from the mtr-packet subprocess is readable.
                    323:     If we have received a complete reply, process it.
                    324: */
                    325: void net_process_return(
                    326:     struct mtr_ctl *ctl)
                    327: {
                    328:     handle_command_replies(ctl, &packet_command_pipe, net_process_ping);
                    329: }
                    330: 
                    331: 
                    332: ip_t *net_addr(
                    333:     int at)
                    334: {
                    335:     return (ip_t *) & (host[at].addr);
                    336: }
                    337: 
                    338: 
                    339: ip_t *net_addrs(
                    340:     int at,
                    341:     int i)
                    342: {
                    343:     return (ip_t *) & (host[at].addrs[i]);
                    344: }
                    345: 
1.1.1.2 ! misho     346: /*
        !           347:     Get the error code corresponding to a host entry.
        !           348: */
        !           349: int net_err(
        !           350:     int at)
        !           351: {
        !           352:     return host[at].err;
        !           353: }
        !           354: 
1.1       misho     355: void *net_mpls(
                    356:     int at)
                    357: {
                    358:     return (struct mplslen *) &(host[at].mplss);
                    359: }
                    360: 
                    361: void *net_mplss(
                    362:     int at,
                    363:     int i)
                    364: {
                    365:     return (struct mplslen *) &(host[at].mplss[i]);
                    366: }
                    367: 
                    368: int net_loss(
                    369:     int at)
                    370: {
                    371:     if ((host[at].xmit - host[at].transit) == 0) {
                    372:         return 0;
                    373:     }
                    374: 
                    375:     /* times extra 1000 */
                    376:     return 1000 * (100 -
                    377:                    (100.0 * host[at].returned /
                    378:                     (host[at].xmit - host[at].transit)));
                    379: }
                    380: 
                    381: 
                    382: int net_drop(
                    383:     int at)
                    384: {
                    385:     return (host[at].xmit - host[at].transit) - host[at].returned;
                    386: }
                    387: 
                    388: 
                    389: int net_last(
                    390:     int at)
                    391: {
                    392:     return (host[at].last);
                    393: }
                    394: 
                    395: 
                    396: int net_best(
                    397:     int at)
                    398: {
                    399:     return (host[at].best);
                    400: }
                    401: 
                    402: 
                    403: int net_worst(
                    404:     int at)
                    405: {
                    406:     return (host[at].worst);
                    407: }
                    408: 
                    409: 
                    410: int net_avg(
                    411:     int at)
                    412: {
                    413:     return (host[at].avg);
                    414: }
                    415: 
                    416: 
                    417: int net_gmean(
                    418:     int at)
                    419: {
                    420:     return (host[at].gmean);
                    421: }
                    422: 
                    423: 
                    424: int net_stdev(
                    425:     int at)
                    426: {
                    427:     if (host[at].returned > 1) {
                    428:         return (sqrt(host[at].ssd / (host[at].returned - 1.0)));
                    429:     } else {
                    430:         return (0);
                    431:     }
                    432: }
                    433: 
                    434: 
                    435: int net_jitter(
                    436:     int at)
                    437: {
                    438:     return (host[at].jitter);
                    439: }
                    440: 
                    441: 
                    442: int net_jworst(
                    443:     int at)
                    444: {
                    445:     return (host[at].jworst);
                    446: }
                    447: 
                    448: 
                    449: int net_javg(
                    450:     int at)
                    451: {
                    452:     return (host[at].javg);
                    453: }
                    454: 
                    455: 
                    456: int net_jinta(
                    457:     int at)
                    458: {
                    459:     return (host[at].jinta);
                    460: }
                    461: 
                    462: 
                    463: int net_max(
                    464:     struct mtr_ctl *ctl)
                    465: {
                    466:     int at;
                    467:     int max;
                    468: 
                    469:     max = 0;
1.1.1.2 ! misho     470:     for (at = 0; at < ctl->maxTTL; at++) {
        !           471:         if (host_addr_cmp(at , remoteaddress, ctl->af) == 0) {
1.1       misho     472:             return at + 1;
1.1.1.2 ! misho     473:         } else if (host[at].err != 0) {
        !           474:             /*
        !           475:                 If a hop has returned an ICMP error
        !           476:                 (such as "no route to host") then we'll consider that the
        !           477:                 final hop.
        !           478:             */
        !           479:             return at + 1;
        !           480:         } else if (host_addr_cmp(at, &ctl->unspec_addr, ctl->af) != 0) {
1.1       misho     481:             max = at + 2;
                    482:         }
                    483:     }
                    484: 
1.1.1.2 ! misho     485:     if (max > ctl->maxTTL)
        !           486:         max = ctl->maxTTL;
1.1       misho     487:     return max;
                    488: }
                    489: 
                    490: 
                    491: int net_min(
                    492:     struct mtr_ctl *ctl)
                    493: {
                    494:     return (ctl->fstTTL - 1);
                    495: }
                    496: 
                    497: 
                    498: int net_returned(
                    499:     int at)
                    500: {
                    501:     return host[at].returned;
                    502: }
                    503: 
                    504: 
                    505: int net_xmit(
                    506:     int at)
                    507: {
                    508:     return host[at].xmit;
                    509: }
                    510: 
                    511: 
                    512: int net_up(
                    513:     int at)
                    514: {
                    515:     return host[at].up;
                    516: }
                    517: 
                    518: 
                    519: char *net_localaddr(
                    520:     void)
                    521: {
                    522:     return localaddr;
                    523: }
                    524: 
                    525: 
                    526: void net_end_transit(
                    527:     void)
                    528: {
                    529:     int at;
                    530: 
                    531:     for (at = 0; at < MaxHost; at++) {
                    532:         host[at].transit = 0;
                    533:     }
                    534: }
                    535: 
                    536: int net_send_batch(
                    537:     struct mtr_ctl *ctl)
                    538: {
                    539:     int n_unknown = 0, i;
1.1.1.2 ! misho     540:     int restart = 0;
1.1       misho     541: 
                    542:     /* randomized packet size and/or bit pattern if packetsize<0 and/or 
                    543:        bitpattern<0.  abs(packetsize) and/or abs(bitpattern) will be used 
                    544:      */
                    545:     if (batch_at < ctl->fstTTL) {
                    546:         if (ctl->cpacketsize < 0) {
                    547:             /* Someone used a formula here that tried to correct for the 
                    548:                "end-error" in "rand()". By "end-error" I mean that if you 
                    549:                have a range for "rand()" that runs to 32768, and the 
                    550:                destination range is 10000, you end up with 4 out of 32768 
                    551:                0-2768's and only 3 out of 32768 for results 2769 .. 9999. 
1.1.1.2 ! misho     552:                As our destination range (in the example 10000) is much 
1.1       misho     553:                smaller (reasonable packet sizes), and our rand() range much 
                    554:                larger, this effect is insignificant. Oh! That other formula
                    555:                didn't work. */
                    556:             packetsize =
                    557:                 MINPACKET + rand() % (-ctl->cpacketsize - MINPACKET);
                    558:         } else {
                    559:             packetsize = ctl->cpacketsize;
                    560:         }
                    561:         if (ctl->bitpattern < 0) {
                    562:             ctl->bitpattern =
                    563:                 -(int) (256 + 255 * (rand() / (RAND_MAX + 0.1)));
                    564:         }
                    565:     }
                    566: 
                    567:     net_send_query(ctl, batch_at, abs(packetsize));
                    568: 
                    569:     for (i = ctl->fstTTL - 1; i < batch_at; i++) {
1.1.1.2 ! misho     570:         if (host_addr_cmp(i, &ctl->unspec_addr, ctl->af) == 0)
1.1       misho     571:             n_unknown++;
                    572: 
                    573:         /* The second condition in the next "if" statement was added in mtr-0.56, 
                    574:            but I don't remember why. It makes mtr stop skipping sections of unknown
                    575:            hosts. Removed in 0.65. 
                    576:            If the line proves necessary, it should at least NOT trigger that line
                    577:            when host[i].addr == 0 */
1.1.1.2 ! misho     578:         if (host_addr_cmp(i, remoteaddress, ctl->af) == 0) {
        !           579:             restart = 1;
        !           580:             numhosts = i + 1; /* Saves batch_at - index number of probes in the next round!*/
        !           581:             break;
        !           582:         }
1.1       misho     583:     }
                    584: 
                    585:     if (                        /* success in reaching target */
1.1.1.2 ! misho     586:            (host_addr_cmp(batch_at, remoteaddress, ctl->af) == 0) ||
1.1       misho     587:            /* fail in consecutive maxUnknown (firewall?) */
                    588:            (n_unknown > ctl->maxUnknown) ||
                    589:            /* or reach limit  */
                    590:            (batch_at >= ctl->maxTTL - 1)) {
1.1.1.2 ! misho     591:         restart = 1;
1.1       misho     592:         numhosts = batch_at + 1;
1.1.1.2 ! misho     593:     }
        !           594: 
        !           595:     if(restart) {
1.1       misho     596:         batch_at = ctl->fstTTL - 1;
                    597:         return 1;
                    598:     }
                    599: 
                    600:     batch_at++;
                    601:     return 0;
                    602: }
                    603: 
                    604: 
                    605: /*  Ensure the interface address a valid address for our use  */
                    606: static void net_validate_interface_address(
                    607:     int address_family,
                    608:     char *interface_address)
                    609: {
                    610:     if (inet_pton(address_family, interface_address, sourceaddress) != 1) {
                    611:         error(EXIT_FAILURE, errno, "invalid local address");
                    612:     }
                    613: 
                    614:     if (inet_ntop
                    615:         (address_family, sourceaddress, localaddr,
                    616:          sizeof(localaddr)) == NULL) {
                    617:         error(EXIT_FAILURE, errno, "invalid local address");
                    618:     }
                    619: }
                    620: 
                    621: 
                    622: /*
1.1.1.2 ! misho     623:     Given the name of a network interface and a preferred address
        !           624:     family (IPv4 or IPv6), find the source IP address for sending
        !           625:     probes from that interface.
        !           626: */
        !           627: static void net_find_interface_address_from_name(
        !           628:     struct sockaddr_storage *addr,
        !           629:     int address_family,
        !           630:     const char *interface_name)
        !           631: {
        !           632:     struct ifaddrs *ifaddrs;
        !           633:     struct ifaddrs *interface;
        !           634:     int found_interface_name = 0;
        !           635: 
        !           636:     if (getifaddrs(&ifaddrs) != 0) {
        !           637:         error(EXIT_FAILURE, errno, "getifaddrs failure");
        !           638:     }
        !           639: 
        !           640:     interface = ifaddrs;
        !           641:     while (interface != NULL) {
        !           642:         if (interface->ifa_addr != NULL && !strcmp(interface->ifa_name, interface_name)) {
        !           643:             found_interface_name = 1;
        !           644: 
        !           645:             if (interface->ifa_addr->sa_family == address_family) {
        !           646:                 if (address_family == AF_INET) {
        !           647:                     memcpy(addr,
        !           648:                         interface->ifa_addr, sizeof(struct sockaddr_in));
        !           649:                     freeifaddrs(ifaddrs);
        !           650: 
        !           651:                     return;
        !           652:                 } else if (address_family == AF_INET6) {
        !           653:                     memcpy(addr,
        !           654:                         interface->ifa_addr, sizeof(struct sockaddr_in6));
        !           655:                     freeifaddrs(ifaddrs);
        !           656: 
        !           657:                     return;
        !           658:                 }
        !           659:             }
        !           660:         }
        !           661: 
        !           662:         interface = interface->ifa_next;
        !           663:     }
        !           664: 
        !           665:     if (!found_interface_name) {
        !           666:         error(EXIT_FAILURE, 0, "no such interface");
        !           667:     } else if (address_family == AF_INET) {
        !           668:         error(EXIT_FAILURE, 0, "interface missing IPv4 address");
        !           669:     } else if (address_family == AF_INET6) {
        !           670:         error(EXIT_FAILURE, 0, "interface missing IPv6 address");
        !           671:     } else {
        !           672:         error(EXIT_FAILURE, 0, "interface missing address");
        !           673:     }
        !           674: }
        !           675: 
        !           676: 
        !           677: /*
1.1       misho     678:   Find the local address we will use to sent to the remote
                    679:   host by connecting a UDP socket and checking the address
                    680:   the socket is bound to.
                    681: */
                    682: static void net_find_local_address(
                    683:     void)
                    684: {
                    685:     int udp_socket;
                    686:     int addr_length;
                    687:     struct sockaddr_storage remote_sockaddr;
                    688: 
                    689:     udp_socket =
                    690:         socket(remotesockaddr->sa_family, SOCK_DGRAM, IPPROTO_UDP);
                    691:     if (udp_socket == -1) {
                    692:         error(EXIT_FAILURE, errno, "udp socket creation failed");
                    693:     }
                    694: 
                    695:     /*
                    696:        We need to set the port to a non-zero value for the connect
                    697:        to succeed.
                    698:      */
1.1.1.2 ! misho     699:     addr_length = sockaddr_size(&remotesockaddr_struct);
        !           700:     memcpy(&remote_sockaddr, &remotesockaddr_struct, addr_length);
        !           701:     *sockaddr_port_offset(&remote_sockaddr) = htons(1);
1.1       misho     702: 
                    703:     if (connect
1.1.1.2 ! misho     704:         (udp_socket, (struct sockaddr *) &remote_sockaddr, sockaddr_size(&remote_sockaddr))) {
        !           705: #ifdef __linux__
        !           706:         /* Linux doesn't require source address, so we can support
        !           707:          * a case when mtr is run against unreachable host (that can become
        !           708:          * reachable) */
        !           709:         if (errno == EHOSTUNREACH) {
        !           710:             close(udp_socket);
        !           711:             localaddr[0] = '\0';
        !           712:             return;
        !           713:         }
        !           714: #endif
1.1       misho     715:         error(EXIT_FAILURE, errno, "udp socket connect failed");
                    716:     }
                    717: 
                    718:     if (getsockname(udp_socket, sourcesockaddr, &addr_length)) {
                    719: 
                    720:         error(EXIT_FAILURE, errno, "local address determination failed");
                    721:     }
                    722: 
1.1.1.2 ! misho     723:     inet_ntop(sourcesockaddr->sa_family, sockaddr_addr_offset(sourcesockaddr), localaddr, sizeof(localaddr));
1.1       misho     724: 
                    725:     close(udp_socket);
                    726: }
                    727: 
                    728: 
                    729: int net_open(
                    730:     struct mtr_ctl *ctl,
                    731:     struct hostent *hostent)
                    732: {
                    733:     int err;
                    734: 
                    735:     /*  Spawn the mtr-packet child process  */
                    736:     err = open_command_pipe(ctl, &packet_command_pipe);
                    737:     if (err) {
                    738:         return err;
                    739:     }
                    740: 
                    741:     net_reset(ctl);
                    742: 
1.1.1.2 ! misho     743:     remotesockaddr->sa_family = sourcesockaddr->sa_family = hostent->h_addrtype;
        !           744:     memcpy(sockaddr_addr_offset(remotesockaddr), hostent->h_addr, sockaddr_addr_size(remotesockaddr));
1.1       misho     745: 
1.1.1.2 ! misho     746:     sourceaddress = sockaddr_addr_offset(sourcesockaddr);
        !           747:     remoteaddress = sockaddr_addr_offset(remotesockaddr);
1.1       misho     748: 
                    749:     if (ctl->InterfaceAddress) {
                    750:         net_validate_interface_address(ctl->af, ctl->InterfaceAddress);
1.1.1.2 ! misho     751:     } else if (ctl->InterfaceName) {
        !           752:         net_find_interface_address_from_name(
        !           753:             &sourcesockaddr_struct, ctl->af, ctl->InterfaceName);
        !           754:         inet_ntop(sourcesockaddr->sa_family, sockaddr_addr_offset(sourcesockaddr), localaddr, sizeof(localaddr));
1.1       misho     755:     } else {
                    756:         net_find_local_address();
                    757:     }
                    758: 
                    759:     return 0;
                    760: }
                    761: 
                    762: 
                    763: void net_reopen(
                    764:     struct mtr_ctl *ctl,
                    765:     struct hostent *addr)
                    766: {
                    767:     int at;
                    768: 
                    769:     for (at = 0; at < MaxHost; at++) {
                    770:         memset(&host[at], 0, sizeof(host[at]));
                    771:     }
                    772: 
                    773:     remotesockaddr->sa_family = addr->h_addrtype;
1.1.1.2 ! misho     774:     memcpy(remoteaddress, addr->h_addr, sockaddr_addr_size(remotesockaddr));
        !           775:     memcpy(sockaddr_addr_offset(remotesockaddr), addr->h_addr, sockaddr_addr_size(remotesockaddr));
1.1       misho     776:     net_reset(ctl);
                    777:     net_send_batch(ctl);
                    778: }
                    779: 
                    780: 
                    781: void net_reset(
                    782:     struct mtr_ctl *ctl)
                    783: {
                    784:     static struct nethost template = {
                    785:         .saved_seq_offset = 2 - SAVED_PINGS
                    786:     };
                    787: 
                    788:     int at, i;
                    789: 
                    790:     batch_at = ctl->fstTTL - 1; /* above replacedByMin */
                    791:     numhosts = 10;
                    792: 
                    793:     for (i = 0; i < SAVED_PINGS; i++)
                    794:         template.saved[i] = -2;
                    795: 
                    796:     for (at = 0; at < MaxHost; at++) {
                    797:         memcpy(&(host[at]), &template, sizeof(template));
                    798:     }
                    799: 
                    800:     for (at = 0; at < MaxSequence; at++) {
                    801:         sequence[at].transit = 0;
                    802:     }
                    803: 
                    804: }
                    805: 
                    806: 
                    807: /*  Close the pipe to the packet generator process, and kill the process  */
                    808: void net_close(
                    809:     void)
                    810: {
                    811:     close_command_pipe(&packet_command_pipe);
                    812: }
                    813: 
                    814: 
                    815: int net_waitfd(
                    816:     void)
                    817: {
                    818:     return packet_command_pipe.read_fd;
                    819: }
                    820: 
                    821: 
                    822: int *net_saved_pings(
                    823:     int at)
                    824: {
                    825:     return host[at].saved;
                    826: }
                    827: 
                    828: 
                    829: static void net_save_increment(
                    830:     void)
                    831: {
                    832:     int at;
                    833:     for (at = 0; at < MaxHost; at++) {
                    834:         memmove(host[at].saved, host[at].saved + 1,
                    835:                 (SAVED_PINGS - 1) * sizeof(int));
                    836:         host[at].saved[SAVED_PINGS - 1] = -2;
                    837:         host[at].saved_seq_offset += 1;
                    838:     }
                    839: }
                    840: 
                    841: 
                    842: void net_save_xmit(
                    843:     int at)
                    844: {
                    845:     if (host[at].saved[SAVED_PINGS - 1] != -2)
                    846:         net_save_increment();
                    847:     host[at].saved[SAVED_PINGS - 1] = -1;
                    848: }
                    849: 
                    850: 
                    851: void net_save_return(
                    852:     int at,
                    853:     int seq,
                    854:     int ms)
                    855: {
                    856:     int idx;
                    857:     idx = seq - host[at].saved_seq_offset;
                    858:     if ((idx < 0) || (idx >= SAVED_PINGS)) {
                    859:         return;
                    860:     }
                    861:     host[at].saved[idx] = ms;
                    862: }
                    863: 
                    864: /* Address comparison. */
                    865: int addrcmp(
1.1.1.2 ! misho     866:     void *a,
        !           867:     void *b,
1.1       misho     868:     int family)
                    869: {
                    870:     int rc = -1;
                    871: 
                    872:     switch (family) {
                    873:     case AF_INET:
                    874:         rc = memcmp(a, b, sizeof(struct in_addr));
                    875:         break;
                    876: #ifdef ENABLE_IPV6
                    877:     case AF_INET6:
                    878:         rc = memcmp(a, b, sizeof(struct in6_addr));
                    879:         break;
                    880: #endif
                    881:     }
                    882: 
                    883:     return rc;
                    884: }
                    885: 
                    886: /* for GTK frontend */
                    887: void net_harvest_fds(
                    888:     struct mtr_ctl *ctl)
                    889: {
                    890:     fd_set writefd;
                    891:     int maxfd = 0;
                    892:     struct timeval tv;
                    893: 
                    894:     FD_ZERO(&writefd);
                    895:     tv.tv_sec = 0;
                    896:     tv.tv_usec = 0;
                    897:     select(maxfd, NULL, &writefd, NULL, &tv);
                    898: }

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