Blame ui/net.c

Packit b802ec
/*
Packit b802ec
    mtr  --  a network diagnostic tool
Packit b802ec
    Copyright (C) 1997,1998  Matt Kimball
Packit b802ec
Packit b802ec
    This program is free software; you can redistribute it and/or modify
Packit b802ec
    it under the terms of the GNU General Public License version 2 as 
Packit b802ec
    published by the Free Software Foundation.
Packit b802ec
Packit b802ec
    This program is distributed in the hope that it will be useful,
Packit b802ec
    but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit b802ec
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit b802ec
    GNU General Public License for more details.
Packit b802ec
Packit b802ec
    You should have received a copy of the GNU General Public License
Packit b802ec
    along with this program; if not, write to the Free Software
Packit b802ec
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Packit b802ec
*/
Packit b802ec
Packit b802ec
#include "config.h"
Packit b802ec
Packit b802ec
#include <errno.h>
Packit b802ec
#include <math.h>
Packit b802ec
#include <stdlib.h>
Packit b802ec
#include <string.h>
Packit b802ec
#include <sys/select.h>
Packit b802ec
#include <unistd.h>
Packit b802ec
Packit b802ec
#ifdef HAVE_ERROR_H
Packit b802ec
#include <error.h>
Packit b802ec
#else
Packit b802ec
#include "portability/error.h"
Packit b802ec
#endif
Packit b802ec
Packit b802ec
#include "mtr.h"
Packit b802ec
#include "cmdpipe.h"
Packit b802ec
#include "net.h"
Packit b802ec
#include "display.h"
Packit b802ec
#include "dns.h"
Packit b802ec
#include "utils.h"
Packit b802ec
Packit b802ec
#define MinSequence 33000
Packit b802ec
#define MaxSequence 65536
Packit b802ec
Packit b802ec
static int packetsize;          /* packet size used by ping */
Packit b802ec
Packit b802ec
static void sockaddrtop(
Packit b802ec
    struct sockaddr *saddr,
Packit b802ec
    char *strptr,
Packit b802ec
    size_t len);
Packit b802ec
Packit b802ec
struct nethost {
Packit b802ec
    ip_t addr;
Packit b802ec
    ip_t addrs[MAXPATH];        /* for multi paths byMin */
Packit b802ec
    int xmit;
Packit b802ec
    int returned;
Packit b802ec
    int sent;
Packit b802ec
    int up;
Packit b802ec
    long long ssd;              /* sum of squares of differences from the current average */
Packit b802ec
    int last;
Packit b802ec
    int best;
Packit b802ec
    int worst;
Packit b802ec
    int avg;                    /* average:  addByMin */
Packit b802ec
    int gmean;                  /* geometric mean: addByMin */
Packit b802ec
    int jitter;                 /* current jitter, defined as t1-t0 addByMin */
Packit b802ec
    int javg;                   /* avg jitter */
Packit b802ec
    int jworst;                 /* max jitter */
Packit b802ec
    int jinta;                  /* estimated variance,? rfc1889's "Interarrival Jitter" */
Packit b802ec
    int transit;
Packit b802ec
    int saved[SAVED_PINGS];
Packit b802ec
    int saved_seq_offset;
Packit b802ec
    struct mplslen mpls;
Packit b802ec
    struct mplslen mplss[MAXPATH];
Packit b802ec
};
Packit b802ec
Packit b802ec
Packit b802ec
struct sequence {
Packit b802ec
    int index;
Packit b802ec
    int transit;
Packit b802ec
    int saved_seq;
Packit b802ec
    struct timeval time;
Packit b802ec
};
Packit b802ec
Packit b802ec
Packit b802ec
static struct nethost host[MaxHost];
Packit b802ec
static struct sequence sequence[MaxSequence];
Packit b802ec
static struct packet_command_pipe_t packet_command_pipe;
Packit b802ec
Packit b802ec
#ifdef ENABLE_IPV6
Packit b802ec
static struct sockaddr_storage sourcesockaddr_struct;
Packit b802ec
static struct sockaddr_storage remotesockaddr_struct;
Packit b802ec
static struct sockaddr_in6 *ssa6 =
Packit b802ec
    (struct sockaddr_in6 *) &sourcesockaddr_struct;
Packit b802ec
static struct sockaddr_in6 *rsa6 =
Packit b802ec
    (struct sockaddr_in6 *) &remotesockaddr_struct;
Packit b802ec
#else
Packit b802ec
static struct sockaddr_in sourcesockaddr_struct;
Packit b802ec
static struct sockaddr_in remotesockaddr_struct;
Packit b802ec
#endif
Packit b802ec
Packit b802ec
static struct sockaddr *sourcesockaddr =
Packit b802ec
    (struct sockaddr *) &sourcesockaddr_struct;
Packit b802ec
static struct sockaddr *remotesockaddr =
Packit b802ec
    (struct sockaddr *) &remotesockaddr_struct;
Packit b802ec
static struct sockaddr_in *ssa4 =
Packit b802ec
    (struct sockaddr_in *) &sourcesockaddr_struct;
Packit b802ec
static struct sockaddr_in *rsa4 =
Packit b802ec
    (struct sockaddr_in *) &remotesockaddr_struct;
Packit b802ec
Packit b802ec
static ip_t *sourceaddress;
Packit b802ec
static ip_t *remoteaddress;
Packit b802ec
Packit b802ec
#ifdef ENABLE_IPV6
Packit b802ec
static char localaddr[INET6_ADDRSTRLEN];
Packit b802ec
#else
Packit b802ec
#ifndef INET_ADDRSTRLEN
Packit b802ec
#define INET_ADDRSTRLEN 16
Packit b802ec
#endif
Packit b802ec
static char localaddr[INET_ADDRSTRLEN];
Packit b802ec
#endif
Packit b802ec
Packit b802ec
static int batch_at = 0;
Packit b802ec
static int numhosts = 10;
Packit b802ec
Packit b802ec
/* return the number of microseconds to wait before sending the next
Packit b802ec
   ping */
Packit b802ec
int calc_deltatime(
Packit b802ec
    float waittime)
Packit b802ec
{
Packit b802ec
    waittime /= numhosts;
Packit b802ec
    return 1000000 * waittime;
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
static void save_sequence(
Packit b802ec
    struct mtr_ctl *ctl,
Packit b802ec
    int index,
Packit b802ec
    int seq)
Packit b802ec
{
Packit b802ec
    display_rawxmit(ctl, index, seq);
Packit b802ec
Packit b802ec
    sequence[seq].index = index;
Packit b802ec
    sequence[seq].transit = 1;
Packit b802ec
    sequence[seq].saved_seq = ++host[index].xmit;
Packit b802ec
    memset(&sequence[seq].time, 0, sizeof(sequence[seq].time));
Packit b802ec
Packit b802ec
    host[index].transit = 1;
Packit b802ec
Packit b802ec
    if (host[index].sent) {
Packit b802ec
        host[index].up = 0;
Packit b802ec
    }
Packit b802ec
Packit b802ec
    host[index].sent = 1;
Packit b802ec
    net_save_xmit(index);
Packit b802ec
}
Packit b802ec
Packit b802ec
static int new_sequence(
Packit b802ec
    struct mtr_ctl *ctl,
Packit b802ec
    int index)
Packit b802ec
{
Packit b802ec
    static int next_sequence = MinSequence;
Packit b802ec
    int seq;
Packit b802ec
Packit b802ec
    seq = next_sequence++;
Packit b802ec
    if (next_sequence >= MaxSequence) {
Packit b802ec
        next_sequence = MinSequence;
Packit b802ec
    }
Packit b802ec
Packit b802ec
    save_sequence(ctl, index, seq);
Packit b802ec
Packit b802ec
    return seq;
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
/*  Attempt to find the host at a particular number of hops away  */
Packit b802ec
static void net_send_query(
Packit b802ec
    struct mtr_ctl *ctl,
Packit b802ec
    int index,
Packit b802ec
    int packet_size)
Packit b802ec
{
Packit b802ec
    int seq = new_sequence(ctl, index);
Packit b802ec
    int time_to_live = index + 1;
Packit b802ec
Packit b802ec
    send_probe_command(ctl, &packet_command_pipe, remoteaddress,
Packit b802ec
                       sourceaddress, packetsize, seq, time_to_live);
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
/* We got a return on something we sent out.  Record the address and
Packit b802ec
   time.  */
Packit b802ec
static void net_process_ping(
Packit b802ec
    struct mtr_ctl *ctl,
Packit b802ec
    int seq,
Packit b802ec
    struct mplslen *mpls,
Packit b802ec
    ip_t * addr,
Packit b802ec
    int totusec)
Packit b802ec
{
Packit b802ec
    int index;
Packit b802ec
    int oldavg;                 /* usedByMin */
Packit b802ec
    int oldjavg;                /* usedByMin */
Packit b802ec
    int i;                      /* usedByMin */
Packit b802ec
#ifdef ENABLE_IPV6
Packit b802ec
    char addrcopy[sizeof(struct in6_addr)];
Packit b802ec
#else
Packit b802ec
    char addrcopy[sizeof(struct in_addr)];
Packit b802ec
#endif
Packit b802ec
Packit b802ec
    addrcpy((void *) &addrcopy, (char *) addr, ctl->af);
Packit b802ec
Packit b802ec
    if ((seq < 0) || (seq >= MaxSequence)) {
Packit b802ec
        return;
Packit b802ec
    }
Packit b802ec
Packit b802ec
    if (!sequence[seq].transit) {
Packit b802ec
        return;
Packit b802ec
    }
Packit b802ec
    sequence[seq].transit = 0;
Packit b802ec
Packit b802ec
    index = sequence[seq].index;
Packit b802ec
Packit b802ec
    if (addrcmp((void *) &(host[index].addr),
Packit b802ec
                (void *) &ctl->unspec_addr, ctl->af) == 0) {
Packit b802ec
        /* should be out of if as addr can change */
Packit b802ec
        addrcpy((void *) &(host[index].addr), addrcopy, ctl->af);
Packit b802ec
        host[index].mpls = *mpls;
Packit b802ec
        display_rawhost(ctl, index, (void *) &(host[index].addr));
Packit b802ec
Packit b802ec
        /* multi paths */
Packit b802ec
        addrcpy((void *) &(host[index].addrs[0]), addrcopy, ctl->af);
Packit b802ec
        host[index].mplss[0] = *mpls;
Packit b802ec
    } else {
Packit b802ec
        for (i = 0; i < MAXPATH;) {
Packit b802ec
            if (addrcmp
Packit b802ec
                ((void *) &(host[index].addrs[i]), (void *) &addrcopy,
Packit b802ec
                 ctl->af) == 0
Packit b802ec
                || addrcmp((void *) &(host[index].addrs[i]),
Packit b802ec
                           (void *) &ctl->unspec_addr, ctl->af) == 0) {
Packit b802ec
                break;
Packit b802ec
            }
Packit b802ec
            i++;
Packit b802ec
        }
Packit b802ec
Packit b802ec
        if (addrcmp((void *) &(host[index].addrs[i]), addrcopy, ctl->af) !=
Packit b802ec
            0 && i < MAXPATH) {
Packit b802ec
            addrcpy((void *) &(host[index].addrs[i]), addrcopy, ctl->af);
Packit b802ec
            host[index].mplss[i] = *mpls;
Packit b802ec
            display_rawhost(ctl, index, (void *) &(host[index].addrs[i]));
Packit b802ec
        }
Packit b802ec
    }
Packit b802ec
Packit b802ec
    host[index].jitter = totusec - host[index].last;
Packit b802ec
    if (host[index].jitter < 0) {
Packit b802ec
        host[index].jitter = -host[index].jitter;
Packit b802ec
    }
Packit b802ec
Packit b802ec
    host[index].last = totusec;
Packit b802ec
Packit b802ec
    if (host[index].returned < 1) {
Packit b802ec
        host[index].best = host[index].worst = host[index].gmean = totusec;
Packit b802ec
        host[index].avg = host[index].ssd = 0;
Packit b802ec
Packit b802ec
        host[index].jitter = host[index].jworst = host[index].jinta = 0;
Packit b802ec
    }
Packit b802ec
Packit b802ec
    if (totusec < host[index].best) {
Packit b802ec
        host[index].best = totusec;
Packit b802ec
    }
Packit b802ec
    if (totusec > host[index].worst) {
Packit b802ec
        host[index].worst = totusec;
Packit b802ec
    }
Packit b802ec
Packit b802ec
    if (host[index].jitter > host[index].jworst) {
Packit b802ec
        host[index].jworst = host[index].jitter;
Packit b802ec
    }
Packit b802ec
Packit b802ec
    host[index].returned++;
Packit b802ec
    oldavg = host[index].avg;
Packit b802ec
    host[index].avg += (totusec - oldavg + .0) / host[index].returned;
Packit b802ec
    host[index].ssd +=
Packit b802ec
        (totusec - oldavg + .0) * (totusec - host[index].avg);
Packit b802ec
Packit b802ec
    oldjavg = host[index].javg;
Packit b802ec
    host[index].javg +=
Packit b802ec
        (host[index].jitter - oldjavg) / host[index].returned;
Packit b802ec
    /* below algorithm is from rfc1889, A.8 */
Packit b802ec
    host[index].jinta +=
Packit b802ec
        host[index].jitter - ((host[index].jinta + 8) >> 4);
Packit b802ec
Packit b802ec
    if (host[index].returned > 1) {
Packit b802ec
        host[index].gmean =
Packit b802ec
            pow((double) host[index].gmean,
Packit b802ec
                (host[index].returned - 1.0) / host[index].returned)
Packit b802ec
            * pow((double) totusec, 1.0 / host[index].returned);
Packit b802ec
    }
Packit b802ec
Packit b802ec
    host[index].sent = 0;
Packit b802ec
    host[index].up = 1;
Packit b802ec
    host[index].transit = 0;
Packit b802ec
Packit b802ec
    net_save_return(index, sequence[seq].saved_seq, totusec);
Packit b802ec
    display_rawping(ctl, index, totusec, seq);
Packit b802ec
}
Packit b802ec
Packit b802ec
/*
Packit b802ec
    Invoked when the read pipe from the mtr-packet subprocess is readable.
Packit b802ec
    If we have received a complete reply, process it.
Packit b802ec
*/
Packit b802ec
void net_process_return(
Packit b802ec
    struct mtr_ctl *ctl)
Packit b802ec
{
Packit b802ec
    handle_command_replies(ctl, &packet_command_pipe, net_process_ping);
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
ip_t *net_addr(
Packit b802ec
    int at)
Packit b802ec
{
Packit b802ec
    return (ip_t *) & (host[at].addr);
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
ip_t *net_addrs(
Packit b802ec
    int at,
Packit b802ec
    int i)
Packit b802ec
{
Packit b802ec
    return (ip_t *) & (host[at].addrs[i]);
Packit b802ec
}
Packit b802ec
Packit b802ec
void *net_mpls(
Packit b802ec
    int at)
Packit b802ec
{
Packit b802ec
    return (struct mplslen *) &(host[at].mplss);
Packit b802ec
}
Packit b802ec
Packit b802ec
void *net_mplss(
Packit b802ec
    int at,
Packit b802ec
    int i)
Packit b802ec
{
Packit b802ec
    return (struct mplslen *) &(host[at].mplss[i]);
Packit b802ec
}
Packit b802ec
Packit b802ec
int net_loss(
Packit b802ec
    int at)
Packit b802ec
{
Packit b802ec
    if ((host[at].xmit - host[at].transit) == 0) {
Packit b802ec
        return 0;
Packit b802ec
    }
Packit b802ec
Packit b802ec
    /* times extra 1000 */
Packit b802ec
    return 1000 * (100 -
Packit b802ec
                   (100.0 * host[at].returned /
Packit b802ec
                    (host[at].xmit - host[at].transit)));
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
int net_drop(
Packit b802ec
    int at)
Packit b802ec
{
Packit b802ec
    return (host[at].xmit - host[at].transit) - host[at].returned;
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
int net_last(
Packit b802ec
    int at)
Packit b802ec
{
Packit b802ec
    return (host[at].last);
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
int net_best(
Packit b802ec
    int at)
Packit b802ec
{
Packit b802ec
    return (host[at].best);
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
int net_worst(
Packit b802ec
    int at)
Packit b802ec
{
Packit b802ec
    return (host[at].worst);
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
int net_avg(
Packit b802ec
    int at)
Packit b802ec
{
Packit b802ec
    return (host[at].avg);
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
int net_gmean(
Packit b802ec
    int at)
Packit b802ec
{
Packit b802ec
    return (host[at].gmean);
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
int net_stdev(
Packit b802ec
    int at)
Packit b802ec
{
Packit b802ec
    if (host[at].returned > 1) {
Packit b802ec
        return (sqrt(host[at].ssd / (host[at].returned - 1.0)));
Packit b802ec
    } else {
Packit b802ec
        return (0);
Packit b802ec
    }
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
int net_jitter(
Packit b802ec
    int at)
Packit b802ec
{
Packit b802ec
    return (host[at].jitter);
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
int net_jworst(
Packit b802ec
    int at)
Packit b802ec
{
Packit b802ec
    return (host[at].jworst);
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
int net_javg(
Packit b802ec
    int at)
Packit b802ec
{
Packit b802ec
    return (host[at].javg);
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
int net_jinta(
Packit b802ec
    int at)
Packit b802ec
{
Packit b802ec
    return (host[at].jinta);
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
int net_max(
Packit b802ec
    struct mtr_ctl *ctl)
Packit b802ec
{
Packit b802ec
    int at;
Packit b802ec
    int max;
Packit b802ec
Packit b802ec
    max = 0;
Packit b802ec
    for (at = 0; at < ctl->maxTTL - 1; at++) {
Packit b802ec
        if (addrcmp((void *) &(host[at].addr),
Packit b802ec
                    (void *) remoteaddress, ctl->af) == 0) {
Packit b802ec
            return at + 1;
Packit b802ec
        } else if (addrcmp((void *) &(host[at].addr),
Packit b802ec
                           (void *) &ctl->unspec_addr, ctl->af) != 0) {
Packit b802ec
            max = at + 2;
Packit b802ec
        }
Packit b802ec
    }
Packit b802ec
Packit b802ec
    return max;
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
int net_min(
Packit b802ec
    struct mtr_ctl *ctl)
Packit b802ec
{
Packit b802ec
    return (ctl->fstTTL - 1);
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
int net_returned(
Packit b802ec
    int at)
Packit b802ec
{
Packit b802ec
    return host[at].returned;
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
int net_xmit(
Packit b802ec
    int at)
Packit b802ec
{
Packit b802ec
    return host[at].xmit;
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
int net_up(
Packit b802ec
    int at)
Packit b802ec
{
Packit b802ec
    return host[at].up;
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
char *net_localaddr(
Packit b802ec
    void)
Packit b802ec
{
Packit b802ec
    return localaddr;
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
void net_end_transit(
Packit b802ec
    void)
Packit b802ec
{
Packit b802ec
    int at;
Packit b802ec
Packit b802ec
    for (at = 0; at < MaxHost; at++) {
Packit b802ec
        host[at].transit = 0;
Packit b802ec
    }
Packit b802ec
}
Packit b802ec
Packit b802ec
int net_send_batch(
Packit b802ec
    struct mtr_ctl *ctl)
Packit b802ec
{
Packit b802ec
    int n_unknown = 0, i;
Packit b802ec
Packit b802ec
    /* randomized packet size and/or bit pattern if packetsize<0 and/or 
Packit b802ec
       bitpattern<0.  abs(packetsize) and/or abs(bitpattern) will be used 
Packit b802ec
     */
Packit b802ec
    if (batch_at < ctl->fstTTL) {
Packit b802ec
        if (ctl->cpacketsize < 0) {
Packit b802ec
            /* Someone used a formula here that tried to correct for the 
Packit b802ec
               "end-error" in "rand()". By "end-error" I mean that if you 
Packit b802ec
               have a range for "rand()" that runs to 32768, and the 
Packit b802ec
               destination range is 10000, you end up with 4 out of 32768 
Packit b802ec
               0-2768's and only 3 out of 32768 for results 2769 .. 9999. 
Packit b802ec
               As our detination range (in the example 10000) is much 
Packit b802ec
               smaller (reasonable packet sizes), and our rand() range much 
Packit b802ec
               larger, this effect is insignificant. Oh! That other formula
Packit b802ec
               didn't work. */
Packit b802ec
            packetsize =
Packit b802ec
                MINPACKET + rand() % (-ctl->cpacketsize - MINPACKET);
Packit b802ec
        } else {
Packit b802ec
            packetsize = ctl->cpacketsize;
Packit b802ec
        }
Packit b802ec
        if (ctl->bitpattern < 0) {
Packit b802ec
            ctl->bitpattern =
Packit b802ec
                -(int) (256 + 255 * (rand() / (RAND_MAX + 0.1)));
Packit b802ec
        }
Packit b802ec
    }
Packit b802ec
Packit b802ec
    net_send_query(ctl, batch_at, abs(packetsize));
Packit b802ec
Packit b802ec
    for (i = ctl->fstTTL - 1; i < batch_at; i++) {
Packit b802ec
        if (addrcmp
Packit b802ec
            ((void *) &(host[i].addr), (void *) &ctl->unspec_addr,
Packit b802ec
             ctl->af) == 0)
Packit b802ec
            n_unknown++;
Packit b802ec
Packit b802ec
        /* The second condition in the next "if" statement was added in mtr-0.56, 
Packit b802ec
           but I don't remember why. It makes mtr stop skipping sections of unknown
Packit b802ec
           hosts. Removed in 0.65. 
Packit b802ec
           If the line proves necessary, it should at least NOT trigger that line
Packit b802ec
           when host[i].addr == 0 */
Packit b802ec
        if ((addrcmp((void *) &(host[i].addr),
Packit b802ec
                     (void *) remoteaddress, ctl->af) == 0))
Packit b802ec
            n_unknown = MaxHost;        /* Make sure we drop into "we should restart" */
Packit b802ec
    }
Packit b802ec
Packit b802ec
    if (                        /* success in reaching target */
Packit b802ec
           (addrcmp((void *) &(host[batch_at].addr),
Packit b802ec
                    (void *) remoteaddress, ctl->af) == 0) ||
Packit b802ec
           /* fail in consecutive maxUnknown (firewall?) */
Packit b802ec
           (n_unknown > ctl->maxUnknown) ||
Packit b802ec
           /* or reach limit  */
Packit b802ec
           (batch_at >= ctl->maxTTL - 1)) {
Packit b802ec
        numhosts = batch_at + 1;
Packit b802ec
        batch_at = ctl->fstTTL - 1;
Packit b802ec
        return 1;
Packit b802ec
    }
Packit b802ec
Packit b802ec
    batch_at++;
Packit b802ec
    return 0;
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
/*  Ensure the interface address a valid address for our use  */
Packit b802ec
static void net_validate_interface_address(
Packit b802ec
    int address_family,
Packit b802ec
    char *interface_address)
Packit b802ec
{
Packit b802ec
    if (inet_pton(address_family, interface_address, sourceaddress) != 1) {
Packit b802ec
        error(EXIT_FAILURE, errno, "invalid local address");
Packit b802ec
    }
Packit b802ec
Packit b802ec
    if (inet_ntop
Packit b802ec
        (address_family, sourceaddress, localaddr,
Packit b802ec
         sizeof(localaddr)) == NULL) {
Packit b802ec
        error(EXIT_FAILURE, errno, "invalid local address");
Packit b802ec
    }
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
/*
Packit b802ec
  Find the local address we will use to sent to the remote
Packit b802ec
  host by connecting a UDP socket and checking the address
Packit b802ec
  the socket is bound to.
Packit b802ec
*/
Packit b802ec
static void net_find_local_address(
Packit b802ec
    void)
Packit b802ec
{
Packit b802ec
    int udp_socket;
Packit b802ec
    int addr_length;
Packit b802ec
    struct sockaddr_storage remote_sockaddr;
Packit b802ec
    struct sockaddr_in *remote4;
Packit b802ec
    struct sockaddr_in6 *remote6;
Packit b802ec
Packit b802ec
    udp_socket =
Packit b802ec
        socket(remotesockaddr->sa_family, SOCK_DGRAM, IPPROTO_UDP);
Packit b802ec
    if (udp_socket == -1) {
Packit b802ec
        error(EXIT_FAILURE, errno, "udp socket creation failed");
Packit b802ec
    }
Packit b802ec
Packit b802ec
    /*
Packit b802ec
       We need to set the port to a non-zero value for the connect
Packit b802ec
       to succeed.
Packit b802ec
     */
Packit b802ec
    if (remotesockaddr->sa_family == AF_INET6) {
Packit b802ec
#ifdef ENABLE_IPV6
Packit b802ec
        addr_length = sizeof(struct sockaddr_in6);
Packit b802ec
Packit b802ec
        memcpy(&remote_sockaddr, rsa6, addr_length);
Packit b802ec
        remote6 = (struct sockaddr_in6 *) &remote_sockaddr;
Packit b802ec
        remote6->sin6_port = htons(1);
Packit b802ec
#endif
Packit b802ec
    } else {
Packit b802ec
        addr_length = sizeof(struct sockaddr_in);
Packit b802ec
Packit b802ec
        memcpy(&remote_sockaddr, rsa4, addr_length);
Packit b802ec
        remote4 = (struct sockaddr_in *) &remote_sockaddr;
Packit b802ec
        remote4->sin_port = htons(1);
Packit b802ec
    }
Packit b802ec
Packit b802ec
    if (connect
Packit b802ec
        (udp_socket, (struct sockaddr *) &remote_sockaddr, addr_length)) {
Packit b802ec
        error(EXIT_FAILURE, errno, "udp socket connect failed");
Packit b802ec
    }
Packit b802ec
Packit b802ec
    if (getsockname(udp_socket, sourcesockaddr, &addr_length)) {
Packit b802ec
Packit b802ec
        error(EXIT_FAILURE, errno, "local address determination failed");
Packit b802ec
    }
Packit b802ec
Packit b802ec
    sockaddrtop(sourcesockaddr, localaddr, sizeof(localaddr));
Packit b802ec
Packit b802ec
    close(udp_socket);
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
int net_open(
Packit b802ec
    struct mtr_ctl *ctl,
Packit b802ec
    struct hostent *hostent)
Packit b802ec
{
Packit b802ec
    int err;
Packit b802ec
Packit b802ec
    /*  Spawn the mtr-packet child process  */
Packit b802ec
    err = open_command_pipe(ctl, &packet_command_pipe);
Packit b802ec
    if (err) {
Packit b802ec
        return err;
Packit b802ec
    }
Packit b802ec
Packit b802ec
    net_reset(ctl);
Packit b802ec
Packit b802ec
    remotesockaddr->sa_family = hostent->h_addrtype;
Packit b802ec
Packit b802ec
    switch (hostent->h_addrtype) {
Packit b802ec
    case AF_INET:
Packit b802ec
        addrcpy((void *) &(rsa4->sin_addr), hostent->h_addr, AF_INET);
Packit b802ec
        sourceaddress = (ip_t *) & (ssa4->sin_addr);
Packit b802ec
        remoteaddress = (ip_t *) & (rsa4->sin_addr);
Packit b802ec
        break;
Packit b802ec
#ifdef ENABLE_IPV6
Packit b802ec
    case AF_INET6:
Packit b802ec
        addrcpy((void *) &(rsa6->sin6_addr), hostent->h_addr, AF_INET6);
Packit b802ec
        sourceaddress = (ip_t *) & (ssa6->sin6_addr);
Packit b802ec
        remoteaddress = (ip_t *) & (rsa6->sin6_addr);
Packit b802ec
        break;
Packit b802ec
#endif
Packit b802ec
    default:
Packit b802ec
        error(EXIT_FAILURE, 0, "net_open bad address type");
Packit b802ec
    }
Packit b802ec
Packit b802ec
    if (ctl->InterfaceAddress) {
Packit b802ec
        net_validate_interface_address(ctl->af, ctl->InterfaceAddress);
Packit b802ec
    } else {
Packit b802ec
        net_find_local_address();
Packit b802ec
    }
Packit b802ec
Packit b802ec
    return 0;
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
void net_reopen(
Packit b802ec
    struct mtr_ctl *ctl,
Packit b802ec
    struct hostent *addr)
Packit b802ec
{
Packit b802ec
    int at;
Packit b802ec
Packit b802ec
    for (at = 0; at < MaxHost; at++) {
Packit b802ec
        memset(&host[at], 0, sizeof(host[at]));
Packit b802ec
    }
Packit b802ec
Packit b802ec
    remotesockaddr->sa_family = addr->h_addrtype;
Packit b802ec
    addrcpy((void *) remoteaddress, addr->h_addr, addr->h_addrtype);
Packit b802ec
Packit b802ec
    switch (addr->h_addrtype) {
Packit b802ec
    case AF_INET:
Packit b802ec
        addrcpy((void *) &(rsa4->sin_addr), addr->h_addr, AF_INET);
Packit b802ec
        break;
Packit b802ec
#ifdef ENABLE_IPV6
Packit b802ec
    case AF_INET6:
Packit b802ec
        addrcpy((void *) &(rsa6->sin6_addr), addr->h_addr, AF_INET6);
Packit b802ec
        break;
Packit b802ec
#endif
Packit b802ec
    default:
Packit b802ec
        error(EXIT_FAILURE, 0, "net_reopen bad address type");
Packit b802ec
    }
Packit b802ec
Packit b802ec
    net_reset(ctl);
Packit b802ec
    net_send_batch(ctl);
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
void net_reset(
Packit b802ec
    struct mtr_ctl *ctl)
Packit b802ec
{
Packit b802ec
    static struct nethost template = {
Packit b802ec
        .saved_seq_offset = 2 - SAVED_PINGS
Packit b802ec
    };
Packit b802ec
Packit b802ec
    int at, i;
Packit b802ec
Packit b802ec
    batch_at = ctl->fstTTL - 1; /* above replacedByMin */
Packit b802ec
    numhosts = 10;
Packit b802ec
Packit b802ec
    for (i = 0; i < SAVED_PINGS; i++)
Packit b802ec
        template.saved[i] = -2;
Packit b802ec
Packit b802ec
    for (at = 0; at < MaxHost; at++) {
Packit b802ec
        memcpy(&(host[at]), &template, sizeof(template));
Packit b802ec
    }
Packit b802ec
Packit b802ec
    for (at = 0; at < MaxSequence; at++) {
Packit b802ec
        sequence[at].transit = 0;
Packit b802ec
    }
Packit b802ec
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
/*  Close the pipe to the packet generator process, and kill the process  */
Packit b802ec
void net_close(
Packit b802ec
    void)
Packit b802ec
{
Packit b802ec
    close_command_pipe(&packet_command_pipe);
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
int net_waitfd(
Packit b802ec
    void)
Packit b802ec
{
Packit b802ec
    return packet_command_pipe.read_fd;
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
int *net_saved_pings(
Packit b802ec
    int at)
Packit b802ec
{
Packit b802ec
    return host[at].saved;
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
static void net_save_increment(
Packit b802ec
    void)
Packit b802ec
{
Packit b802ec
    int at;
Packit b802ec
    for (at = 0; at < MaxHost; at++) {
Packit b802ec
        memmove(host[at].saved, host[at].saved + 1,
Packit b802ec
                (SAVED_PINGS - 1) * sizeof(int));
Packit b802ec
        host[at].saved[SAVED_PINGS - 1] = -2;
Packit b802ec
        host[at].saved_seq_offset += 1;
Packit b802ec
    }
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
void net_save_xmit(
Packit b802ec
    int at)
Packit b802ec
{
Packit b802ec
    if (host[at].saved[SAVED_PINGS - 1] != -2)
Packit b802ec
        net_save_increment();
Packit b802ec
    host[at].saved[SAVED_PINGS - 1] = -1;
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
void net_save_return(
Packit b802ec
    int at,
Packit b802ec
    int seq,
Packit b802ec
    int ms)
Packit b802ec
{
Packit b802ec
    int idx;
Packit b802ec
    idx = seq - host[at].saved_seq_offset;
Packit b802ec
    if ((idx < 0) || (idx >= SAVED_PINGS)) {
Packit b802ec
        return;
Packit b802ec
    }
Packit b802ec
    host[at].saved[idx] = ms;
Packit b802ec
}
Packit b802ec
Packit b802ec
/* Similar to inet_ntop but uses a sockaddr as it's argument. */
Packit b802ec
static void sockaddrtop(
Packit b802ec
    struct sockaddr *saddr,
Packit b802ec
    char *strptr,
Packit b802ec
    size_t len)
Packit b802ec
{
Packit b802ec
    struct sockaddr_in *sa4;
Packit b802ec
#ifdef ENABLE_IPV6
Packit b802ec
    struct sockaddr_in6 *sa6;
Packit b802ec
#endif
Packit b802ec
Packit b802ec
    switch (saddr->sa_family) {
Packit b802ec
    case AF_INET:
Packit b802ec
        sa4 = (struct sockaddr_in *) saddr;
Packit b802ec
        xstrncpy(strptr, inet_ntoa(sa4->sin_addr), len - 1);
Packit b802ec
        strptr[len - 1] = '\0';
Packit b802ec
        return;
Packit b802ec
#ifdef ENABLE_IPV6
Packit b802ec
    case AF_INET6:
Packit b802ec
        sa6 = (struct sockaddr_in6 *) saddr;
Packit b802ec
        inet_ntop(sa6->sin6_family, &(sa6->sin6_addr), strptr, len);
Packit b802ec
        return;
Packit b802ec
#endif
Packit b802ec
    default:
Packit b802ec
        error(0, 0, "sockaddrtop unknown address type");
Packit b802ec
        strptr[0] = '\0';
Packit b802ec
        return;
Packit b802ec
    }
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
/* Address comparison. */
Packit b802ec
int addrcmp(
Packit b802ec
    char *a,
Packit b802ec
    char *b,
Packit b802ec
    int family)
Packit b802ec
{
Packit b802ec
    int rc = -1;
Packit b802ec
Packit b802ec
    switch (family) {
Packit b802ec
    case AF_INET:
Packit b802ec
        rc = memcmp(a, b, sizeof(struct in_addr));
Packit b802ec
        break;
Packit b802ec
#ifdef ENABLE_IPV6
Packit b802ec
    case AF_INET6:
Packit b802ec
        rc = memcmp(a, b, sizeof(struct in6_addr));
Packit b802ec
        break;
Packit b802ec
#endif
Packit b802ec
    }
Packit b802ec
Packit b802ec
    return rc;
Packit b802ec
}
Packit b802ec
Packit b802ec
/* Address copy. */
Packit b802ec
void addrcpy(
Packit b802ec
    char *a,
Packit b802ec
    char *b,
Packit b802ec
    int family)
Packit b802ec
{
Packit b802ec
Packit b802ec
    switch (family) {
Packit b802ec
    case AF_INET:
Packit b802ec
        memcpy(a, b, sizeof(struct in_addr));
Packit b802ec
        break;
Packit b802ec
#ifdef ENABLE_IPV6
Packit b802ec
    case AF_INET6:
Packit b802ec
        memcpy(a, b, sizeof(struct in6_addr));
Packit b802ec
        break;
Packit b802ec
#endif
Packit b802ec
    }
Packit b802ec
}
Packit b802ec
Packit b802ec
/* for GTK frontend */
Packit b802ec
void net_harvest_fds(
Packit b802ec
    struct mtr_ctl *ctl)
Packit b802ec
{
Packit b802ec
    fd_set writefd;
Packit b802ec
    int maxfd = 0;
Packit b802ec
    struct timeval tv;
Packit b802ec
Packit b802ec
    FD_ZERO(&writefd);
Packit b802ec
    tv.tv_sec = 0;
Packit b802ec
    tv.tv_usec = 0;
Packit b802ec
    select(maxfd, NULL, &writefd, NULL, &tv;;
Packit b802ec
}