Blame ui/dns.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
/*
Packit b802ec
    Non-blocking DNS portion --
Packit b802ec
    Copyright (C) 1998 by Simon Kirby <sim@neato.org>
Packit b802ec
    Released under GPL, as above.
Packit b802ec
*/
Packit b802ec
Packit b802ec
#include "config.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
#include <errno.h>
Packit b802ec
#include <unistd.h>
Packit b802ec
#include <fcntl.h>
Packit b802ec
#include <string.h>
Packit b802ec
#include <stdio.h>
Packit b802ec
#include <stdlib.h>
Packit b802ec
#include <signal.h>
Packit b802ec
Packit b802ec
#include "mtr.h"
Packit b802ec
#include "dns.h"
Packit b802ec
#include "net.h"
Packit b802ec
#include "utils.h"
Packit b802ec
Packit b802ec
struct dns_results {
Packit b802ec
    ip_t ip;
Packit b802ec
    char *name;
Packit b802ec
    struct dns_results *next;
Packit b802ec
};
Packit b802ec
Packit b802ec
static struct dns_results *results;
Packit b802ec
Packit b802ec
char *strlongip(
Packit b802ec
    struct mtr_ctl *ctl,
Packit b802ec
    ip_t * ip)
Packit b802ec
{
Packit b802ec
#ifdef ENABLE_IPV6
Packit b802ec
    static char addrstr[INET6_ADDRSTRLEN];
Packit b802ec
Packit b802ec
    return (char *) inet_ntop(ctl->af, ip, addrstr, sizeof addrstr);
Packit b802ec
#else
Packit b802ec
    return inet_ntoa(*ip);
Packit b802ec
#endif
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
#ifdef ENABLE_IPV6
Packit b802ec
#define UNUSED_IF_NO_IPV6       /* empty */
Packit b802ec
#else
Packit b802ec
#define UNUSED_IF_NO_IPV6 ATTRIBUTE_UNUSED
Packit b802ec
#endif
Packit b802ec
Packit b802ec
static int todns[2], fromdns[2];
Packit b802ec
static FILE *fromdnsfp;
Packit b802ec
Packit b802ec
static int longipstr(
Packit b802ec
    char *s,
Packit b802ec
    ip_t * dst,
Packit b802ec
    int family UNUSED_IF_NO_IPV6)
Packit b802ec
{
Packit b802ec
#ifdef ENABLE_IPV6
Packit b802ec
    return inet_pton(family, s, dst);
Packit b802ec
#else
Packit b802ec
    return inet_aton(s, dst);
Packit b802ec
#endif
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
struct hostent *dns_forward(
Packit b802ec
    const char *name)
Packit b802ec
{
Packit b802ec
    struct hostent *host;
Packit b802ec
Packit b802ec
    if ((host = gethostbyname(name)))
Packit b802ec
        return host;
Packit b802ec
    else
Packit b802ec
        return NULL;
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
static struct dns_results *findip(
Packit b802ec
    struct mtr_ctl *ctl,
Packit b802ec
    ip_t * ip)
Packit b802ec
{
Packit b802ec
    struct dns_results *t;
Packit b802ec
Packit b802ec
    for (t = results; t; t = t->next) {
Packit b802ec
        if (addrcmp((void *) ip, (void *) &t->ip, ctl->af) == 0)
Packit b802ec
            return t;
Packit b802ec
    }
Packit b802ec
Packit b802ec
    return NULL;
Packit b802ec
}
Packit b802ec
Packit b802ec
static void set_sockaddr_ip(
Packit b802ec
    struct mtr_ctl *ctl,
Packit b802ec
    struct sockaddr_storage *sa,
Packit b802ec
    ip_t * ip)
Packit b802ec
{
Packit b802ec
    struct sockaddr_in *sa_in;
Packit b802ec
    struct sockaddr_in6 *sa_in6;
Packit b802ec
Packit b802ec
    memset(sa, 0, sizeof(struct sockaddr_storage));
Packit b802ec
    switch (ctl->af) {
Packit b802ec
    case AF_INET:
Packit b802ec
        sa_in = (struct sockaddr_in *) sa;
Packit b802ec
        sa_in->sin_family = ctl->af;
Packit b802ec
        addrcpy((void *) &sa_in->sin_addr, (void *) ip, ctl->af);
Packit b802ec
        break;
Packit b802ec
    case AF_INET6:
Packit b802ec
        sa_in6 = (struct sockaddr_in6 *) sa;
Packit b802ec
        sa_in6->sin6_family = ctl->af;
Packit b802ec
        addrcpy((void *) &sa_in6->sin6_addr, (void *) ip, ctl->af);
Packit b802ec
        break;
Packit b802ec
    }
Packit b802ec
}
Packit b802ec
Packit b802ec
void dns_open(
Packit b802ec
    struct mtr_ctl *ctl)
Packit b802ec
{
Packit b802ec
    int pid;
Packit b802ec
Packit b802ec
    if (pipe(todns) < 0) {
Packit b802ec
        error(EXIT_FAILURE, errno, "can't make a pipe for DNS process");
Packit b802ec
    }
Packit b802ec
Packit b802ec
    if (pipe(fromdns) < 0) {
Packit b802ec
        error(EXIT_FAILURE, errno, "can't make a pipe for DNS process");
Packit b802ec
    }
Packit b802ec
    fflush(stdout);
Packit b802ec
    pid = fork();
Packit b802ec
    if (pid < 0) {
Packit b802ec
        error(EXIT_FAILURE, errno, "can't fork for DNS process");
Packit b802ec
    }
Packit b802ec
    if (pid == 0) {
Packit b802ec
        char buf[2048];
Packit b802ec
        int i;
Packit b802ec
        FILE *infp;
Packit b802ec
Packit b802ec
        /* Automatically reap children. */
Packit b802ec
        if (signal(SIGCHLD, SIG_IGN) == SIG_ERR) {
Packit b802ec
            error(EXIT_FAILURE, errno, "signal");
Packit b802ec
        }
Packit b802ec
Packit b802ec
        /* Close all unneccessary FDs.
Packit b802ec
           for debugging and error reporting, keep std-in/out/err. */
Packit b802ec
        for (i = 3; i < fromdns[1]; i++) {
Packit b802ec
            if (i == todns[0])
Packit b802ec
                continue;
Packit b802ec
            if (i == fromdns[1])
Packit b802ec
                continue;
Packit b802ec
            close(i);
Packit b802ec
        }
Packit b802ec
        infp = fdopen(todns[0], "r");
Packit b802ec
Packit b802ec
        while (fgets(buf, sizeof(buf), infp)) {
Packit b802ec
            ip_t host;
Packit b802ec
            struct sockaddr_storage sa;
Packit b802ec
            socklen_t salen;
Packit b802ec
            char hostname[NI_MAXHOST];
Packit b802ec
            char result[INET6_ADDRSTRLEN + NI_MAXHOST + 2];
Packit b802ec
Packit b802ec
            if (!fork()) {
Packit b802ec
                int rv;
Packit b802ec
Packit b802ec
                buf[strlen(buf) - 1] = 0;       /* chomp newline. */
Packit b802ec
Packit b802ec
                longipstr(buf, &host, ctl->af);
Packit b802ec
                set_sockaddr_ip(ctl, &sa, &host);
Packit b802ec
                salen = (ctl->af == AF_INET) ? sizeof(struct sockaddr_in) :
Packit b802ec
                    sizeof(struct sockaddr_in6);
Packit b802ec
Packit b802ec
                rv = getnameinfo((struct sockaddr *) &sa, salen,
Packit b802ec
                                 hostname, sizeof(hostname), NULL, 0, 0);
Packit b802ec
                if (rv == 0) {
Packit b802ec
                    snprintf(result, sizeof(result),
Packit b802ec
                             "%s %s\n", strlongip(ctl, &host), hostname);
Packit b802ec
Packit b802ec
                    rv = write(fromdns[1], result, strlen(result));
Packit b802ec
                    if (rv < 0)
Packit b802ec
                        error(0, errno, "write DNS lookup result");
Packit b802ec
                }
Packit b802ec
Packit b802ec
                exit(EXIT_SUCCESS);
Packit b802ec
            }
Packit b802ec
        }
Packit b802ec
        exit(EXIT_SUCCESS);
Packit b802ec
    } else {
Packit b802ec
        int flags;
Packit b802ec
Packit b802ec
        /* the parent. */
Packit b802ec
        close(todns[0]);        /* close the pipe ends we don't need. */
Packit b802ec
        close(fromdns[1]);
Packit b802ec
        fromdnsfp = fdopen(fromdns[0], "r");
Packit b802ec
        flags = fcntl(fromdns[0], F_GETFL, 0);
Packit b802ec
        flags |= O_NONBLOCK;
Packit b802ec
        fcntl(fromdns[0], F_SETFL, flags);
Packit b802ec
    }
Packit b802ec
}
Packit b802ec
Packit b802ec
int dns_waitfd(
Packit b802ec
    void)
Packit b802ec
{
Packit b802ec
    return fromdns[0];
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
void dns_ack(
Packit b802ec
    struct mtr_ctl *ctl)
Packit b802ec
{
Packit b802ec
    char buf[2048], host[NI_MAXHOST], name[NI_MAXHOST];
Packit b802ec
    ip_t hostip;
Packit b802ec
    struct dns_results *r;
Packit b802ec
Packit b802ec
    while (fgets(buf, sizeof(buf), fromdnsfp)) {
Packit b802ec
        sscanf(buf, "%s %s", host, name);
Packit b802ec
Packit b802ec
        longipstr(host, &hostip, ctl->af);
Packit b802ec
        r = findip(ctl, &hostip);
Packit b802ec
        if (r)
Packit b802ec
            r->name = xstrdup(name);
Packit b802ec
        else
Packit b802ec
            error(0, 0, "dns_ack: Couldn't find host %s", host);
Packit b802ec
    }
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
Packit b802ec
#ifdef ENABLE_IPV6
Packit b802ec
Packit b802ec
int dns_waitfd6(
Packit b802ec
    void)
Packit b802ec
{
Packit b802ec
    return -1;
Packit b802ec
}
Packit b802ec
Packit b802ec
void dns_ack6(
Packit b802ec
    void)
Packit b802ec
{
Packit b802ec
    return;
Packit b802ec
}
Packit b802ec
Packit b802ec
#endif
Packit b802ec
Packit b802ec
Packit b802ec
char *dns_lookup2(
Packit b802ec
    struct mtr_ctl *ctl,
Packit b802ec
    ip_t * ip)
Packit b802ec
{
Packit b802ec
    struct dns_results *r;
Packit b802ec
    char buf[INET6_ADDRSTRLEN + 1];
Packit b802ec
    int rv;
Packit b802ec
Packit b802ec
    r = findip(ctl, ip);
Packit b802ec
    if (r) {
Packit b802ec
        /* we've got a result. */
Packit b802ec
        if (r->name)
Packit b802ec
            return r->name;
Packit b802ec
        else
Packit b802ec
            return strlongip(ctl, ip);
Packit b802ec
    } else {
Packit b802ec
        r = xmalloc(sizeof(struct dns_results));
Packit b802ec
        memcpy(&r->ip, ip, sizeof(r->ip));
Packit b802ec
        r->name = NULL;
Packit b802ec
        r->next = results;
Packit b802ec
        results = r;
Packit b802ec
        snprintf(buf, sizeof(buf), "%s\n", strlongip(ctl, ip));
Packit b802ec
        rv = write(todns[1], buf, strlen(buf));
Packit b802ec
        if (rv < 0)
Packit b802ec
            error(0, errno, "couldn't write to resolver process");
Packit b802ec
    }
Packit b802ec
    return strlongip(ctl, ip);
Packit b802ec
}
Packit b802ec
Packit b802ec
Packit b802ec
char *dns_lookup(
Packit b802ec
    struct mtr_ctl *ctl,
Packit b802ec
    ip_t * ip)
Packit b802ec
{
Packit b802ec
    char *t;
Packit b802ec
Packit b802ec
    if (!ctl->dns || !ctl->use_dns)
Packit b802ec
        return NULL;
Packit b802ec
    t = dns_lookup2(ctl, ip);
Packit b802ec
    return t;
Packit b802ec
}
Packit b802ec
Packit b802ec
/* XXX check if necessary/exported. */
Packit b802ec
Packit b802ec
/* Resolve an IP address to a hostname. */
Packit b802ec
struct hostent *addr2host(
Packit b802ec
    const char *addr,
Packit b802ec
    int family)
Packit b802ec
{
Packit b802ec
    int len = 0;
Packit b802ec
    switch (family) {
Packit b802ec
    case AF_INET:
Packit b802ec
        len = sizeof(struct in_addr);
Packit b802ec
        break;
Packit b802ec
#ifdef ENABLE_IPV6
Packit b802ec
    case AF_INET6:
Packit b802ec
        len = sizeof(struct in6_addr);
Packit b802ec
        break;
Packit b802ec
#endif
Packit b802ec
    }
Packit b802ec
    return gethostbyaddr(addr, len, family);
Packit b802ec
}