|
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 |
}
|