Annotation of embedaddon/mtr/ui/net.c, revision 1.1.1.3

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

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