|
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 <unistd.h>
|
|
Packit |
b802ec |
#include <stdio.h>
|
|
Packit |
b802ec |
#include <stdlib.h>
|
|
Packit |
b802ec |
#include <sys/types.h>
|
|
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 |
|
|
Packit |
b802ec |
#ifdef __APPLE__
|
|
Packit |
b802ec |
#define BIND_8_COMPAT
|
|
Packit |
b802ec |
#endif
|
|
Packit |
b802ec |
#include <arpa/nameser.h>
|
|
Packit |
b802ec |
#ifdef HAVE_ARPA_NAMESER_COMPAT_H
|
|
Packit |
b802ec |
#include <arpa/nameser_compat.h>
|
|
Packit |
b802ec |
#endif
|
|
Packit |
b802ec |
#include <netdb.h>
|
|
Packit |
b802ec |
#include <netinet/in.h>
|
|
Packit |
b802ec |
#include <resolv.h>
|
|
Packit |
b802ec |
#include <string.h>
|
|
Packit |
b802ec |
#include <sys/socket.h>
|
|
Packit |
b802ec |
#include <search.h>
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
#include "mtr.h"
|
|
Packit |
b802ec |
#include "asn.h"
|
|
Packit |
b802ec |
#include "utils.h"
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
/* #define IIDEBUG */
|
|
Packit |
b802ec |
#ifdef IIDEBUG
|
|
Packit |
b802ec |
#include <syslog.h>
|
|
Packit |
b802ec |
#define DEB_syslog syslog
|
|
Packit |
b802ec |
#else
|
|
Packit |
b802ec |
#define DEB_syslog(...) do {} while (0)
|
|
Packit |
b802ec |
#endif
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
#define IIHASH_HI 128
|
|
Packit |
b802ec |
#define ITEMSMAX 15
|
|
Packit |
b802ec |
#define ITEMSEP '|'
|
|
Packit |
b802ec |
#define NAMELEN 127
|
|
Packit |
b802ec |
#define UNKN "???"
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
static int iihash = 0;
|
|
Packit |
b802ec |
static char fmtinfo[32];
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
/* items width: ASN, Route, Country, Registry, Allocated */
|
|
Packit |
b802ec |
static const int iiwidth[] = { 7, 19, 4, 8, 11 }; /* item len + space */
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
typedef char *items_t[ITEMSMAX + 1];
|
|
Packit |
b802ec |
static items_t items_a; /* without hash: items */
|
|
Packit |
b802ec |
static char txtrec[NAMELEN + 1]; /* without hash: txtrec */
|
|
Packit |
b802ec |
static items_t *items = &items_a;
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
static char *ipinfo_lookup(
|
|
Packit |
b802ec |
const char *domain)
|
|
Packit |
b802ec |
{
|
|
Packit |
b802ec |
unsigned char answer[PACKETSZ], *pt;
|
|
Packit |
b802ec |
char host[128];
|
|
Packit |
b802ec |
char *txt;
|
|
Packit |
b802ec |
int len, exp, size, txtlen, type;
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
if (res_init() < 0) {
|
|
Packit |
b802ec |
error(0, 0, "@res_init failed");
|
|
Packit |
b802ec |
return NULL;
|
|
Packit |
b802ec |
}
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
memset(answer, 0, PACKETSZ);
|
|
Packit |
b802ec |
if ((len = res_query(domain, C_IN, T_TXT, answer, PACKETSZ)) < 0) {
|
|
Packit |
b802ec |
if (iihash)
|
|
Packit |
b802ec |
DEB_syslog(LOG_INFO, "Malloc-txt: %s", UNKN);
|
|
Packit |
b802ec |
return xstrdup(UNKN);
|
|
Packit |
b802ec |
}
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
pt = answer + sizeof(HEADER);
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
if ((exp =
|
|
Packit |
b802ec |
dn_expand(answer, answer + len, pt, host, sizeof(host))) < 0) {
|
|
Packit |
b802ec |
printf("@dn_expand failed\n");
|
|
Packit |
b802ec |
return NULL;
|
|
Packit |
b802ec |
}
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
pt += exp;
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
GETSHORT(type, pt);
|
|
Packit |
b802ec |
if (type != T_TXT) {
|
|
Packit |
b802ec |
printf("@Broken DNS reply.\n");
|
|
Packit |
b802ec |
return NULL;
|
|
Packit |
b802ec |
}
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
pt += INT16SZ; /* class */
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
if ((exp =
|
|
Packit |
b802ec |
dn_expand(answer, answer + len, pt, host, sizeof(host))) < 0) {
|
|
Packit |
b802ec |
printf("@second dn_expand failed\n");
|
|
Packit |
b802ec |
return NULL;
|
|
Packit |
b802ec |
}
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
pt += exp;
|
|
Packit |
b802ec |
GETSHORT(type, pt);
|
|
Packit |
b802ec |
if (type != T_TXT) {
|
|
Packit |
b802ec |
printf("@Not a TXT record\n");
|
|
Packit |
b802ec |
return NULL;
|
|
Packit |
b802ec |
}
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
pt += INT16SZ; /* class */
|
|
Packit |
b802ec |
pt += INT32SZ; /* ttl */
|
|
Packit |
b802ec |
GETSHORT(size, pt);
|
|
Packit |
b802ec |
txtlen = *pt;
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
if (txtlen >= size || !txtlen) {
|
|
Packit |
b802ec |
printf("@Broken TXT record (txtlen = %d, size = %d)\n", txtlen,
|
|
Packit |
b802ec |
size);
|
|
Packit |
b802ec |
return NULL;
|
|
Packit |
b802ec |
}
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
if (txtlen > NAMELEN)
|
|
Packit |
b802ec |
txtlen = NAMELEN;
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
if (iihash) {
|
|
Packit |
b802ec |
txt = xmalloc(txtlen + 1);
|
|
Packit |
b802ec |
} else
|
|
Packit |
b802ec |
txt = (char *) txtrec;
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
pt++;
|
|
Packit |
b802ec |
xstrncpy(txt, (char *) pt, txtlen + 1);
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
if (iihash)
|
|
Packit |
b802ec |
DEB_syslog(LOG_INFO, "Malloc-txt(%p): %s", txt, txt);
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
return txt;
|
|
Packit |
b802ec |
}
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
/* originX.asn.cymru.com txtrec: ASN | Route | Country | Registry | Allocated */
|
|
Packit |
b802ec |
static char *split_txtrec(
|
|
Packit |
b802ec |
struct mtr_ctl *ctl,
|
|
Packit |
b802ec |
char *txt_rec)
|
|
Packit |
b802ec |
{
|
|
Packit |
b802ec |
char *prev;
|
|
Packit |
b802ec |
char *next;
|
|
Packit |
b802ec |
int i = 0, j;
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
if (!txt_rec)
|
|
Packit |
b802ec |
return NULL;
|
|
Packit |
b802ec |
if (iihash) {
|
|
Packit |
b802ec |
DEB_syslog(LOG_INFO, "Malloc-tbl: %s", txt_rec);
|
|
Packit |
b802ec |
if (!(items = malloc(sizeof(*items)))) {
|
|
Packit |
b802ec |
DEB_syslog(LOG_INFO, "Free-txt(%p)", txt_rec);
|
|
Packit |
b802ec |
free(txt_rec);
|
|
Packit |
b802ec |
return NULL;
|
|
Packit |
b802ec |
}
|
|
Packit |
b802ec |
}
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
prev = txt_rec;
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
while ((next = strchr(prev, ITEMSEP)) && (i < ITEMSMAX)) {
|
|
Packit |
b802ec |
*next = '\0';
|
|
Packit |
b802ec |
next++;
|
|
Packit |
b802ec |
(*items)[i] = trim(prev, ITEMSEP);
|
|
Packit |
b802ec |
prev = next;
|
|
Packit |
b802ec |
i++;
|
|
Packit |
b802ec |
}
|
|
Packit |
b802ec |
(*items)[i] = trim(prev, ITEMSEP);
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
if (i < ITEMSMAX)
|
|
Packit |
b802ec |
i++;
|
|
Packit |
b802ec |
for (j = i; j <= ITEMSMAX; j++)
|
|
Packit |
b802ec |
(*items)[j] = NULL;
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
if (i > ctl->ipinfo_max)
|
|
Packit |
b802ec |
ctl->ipinfo_max = i;
|
|
Packit |
b802ec |
if (ctl->ipinfo_no >= i) {
|
|
Packit |
b802ec |
if (ctl->ipinfo_no >= ctl->ipinfo_max)
|
|
Packit |
b802ec |
ctl->ipinfo_no = 0;
|
|
Packit |
b802ec |
return (*items)[0];
|
|
Packit |
b802ec |
} else
|
|
Packit |
b802ec |
return (*items)[ctl->ipinfo_no];
|
|
Packit |
b802ec |
}
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
#ifdef ENABLE_IPV6
|
|
Packit |
b802ec |
/* from dns.c:addr2ip6arpa() */
|
|
Packit |
b802ec |
static void reverse_host6(
|
|
Packit |
b802ec |
struct in6_addr *addr,
|
|
Packit |
b802ec |
char *buff,
|
|
Packit |
b802ec |
int buff_length)
|
|
Packit |
b802ec |
{
|
|
Packit |
b802ec |
int i;
|
|
Packit |
b802ec |
char *b = buff;
|
|
Packit |
b802ec |
for (i = (sizeof(*addr) / 2 - 1); i >= 0; i--, b += 4) /* 64b portion */
|
|
Packit |
b802ec |
snprintf(b, buff_length,
|
|
Packit |
b802ec |
"%x.%x.", addr->s6_addr[i] & 0xf, addr->s6_addr[i] >> 4);
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
buff[strlen(buff) - 1] = '\0';
|
|
Packit |
b802ec |
}
|
|
Packit |
b802ec |
#endif
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
static char *get_ipinfo(
|
|
Packit |
b802ec |
struct mtr_ctl *ctl,
|
|
Packit |
b802ec |
ip_t * addr)
|
|
Packit |
b802ec |
{
|
|
Packit |
b802ec |
char key[NAMELEN];
|
|
Packit |
b802ec |
char lookup_key[NAMELEN];
|
|
Packit |
b802ec |
char *val = NULL;
|
|
Packit |
b802ec |
ENTRY item;
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
if (!addr)
|
|
Packit |
b802ec |
return NULL;
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
if (ctl->af == AF_INET6) {
|
|
Packit |
b802ec |
#ifdef ENABLE_IPV6
|
|
Packit |
b802ec |
reverse_host6(addr, key, NAMELEN);
|
|
Packit |
b802ec |
if (snprintf(lookup_key, NAMELEN, "%s.origin6.asn.cymru.com", key)
|
|
Packit |
b802ec |
>= NAMELEN)
|
|
Packit |
b802ec |
return NULL;
|
|
Packit |
b802ec |
#else
|
|
Packit |
b802ec |
return NULL;
|
|
Packit |
b802ec |
#endif
|
|
Packit |
b802ec |
} else {
|
|
Packit |
b802ec |
unsigned char buff[4];
|
|
Packit |
b802ec |
memcpy(buff, addr, 4);
|
|
Packit |
b802ec |
if (snprintf
|
|
Packit |
b802ec |
(key, NAMELEN, "%d.%d.%d.%d", buff[3], buff[2], buff[1],
|
|
Packit |
b802ec |
buff[0]) >= NAMELEN)
|
|
Packit |
b802ec |
return NULL;
|
|
Packit |
b802ec |
if (snprintf(lookup_key, NAMELEN, "%s.origin.asn.cymru.com", key)
|
|
Packit |
b802ec |
>= NAMELEN)
|
|
Packit |
b802ec |
return NULL;
|
|
Packit |
b802ec |
}
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
if (iihash) {
|
|
Packit |
b802ec |
ENTRY *found_item;
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
DEB_syslog(LOG_INFO, ">> Search: %s", key);
|
|
Packit |
b802ec |
item.key = key;;
|
|
Packit |
b802ec |
if ((found_item = hsearch(item, FIND))) {
|
|
Packit |
b802ec |
if (!(val = (*((items_t *) found_item->data))[ctl->ipinfo_no]))
|
|
Packit |
b802ec |
val = (*((items_t *) found_item->data))[0];
|
|
Packit |
b802ec |
DEB_syslog(LOG_INFO, "Found (hashed): %s", val);
|
|
Packit |
b802ec |
}
|
|
Packit |
b802ec |
}
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
if (!val) {
|
|
Packit |
b802ec |
DEB_syslog(LOG_INFO, "Lookup: %s", key);
|
|
Packit |
b802ec |
if ((val = split_txtrec(ctl, ipinfo_lookup(lookup_key)))) {
|
|
Packit |
b802ec |
DEB_syslog(LOG_INFO, "Looked up: %s", key);
|
|
Packit |
b802ec |
if (iihash)
|
|
Packit |
b802ec |
if ((item.key = xstrdup(key))) {
|
|
Packit |
b802ec |
item.data = (void *) items;
|
|
Packit |
b802ec |
hsearch(item, ENTER);
|
|
Packit |
b802ec |
DEB_syslog(LOG_INFO, "Insert into hash: %s", key);
|
|
Packit |
b802ec |
}
|
|
Packit |
b802ec |
}
|
|
Packit |
b802ec |
}
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
return val;
|
|
Packit |
b802ec |
}
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
ATTRIBUTE_CONST size_t get_iiwidth_len(
|
|
Packit |
b802ec |
void)
|
|
Packit |
b802ec |
{
|
|
Packit |
b802ec |
return (sizeof(iiwidth) / sizeof((iiwidth)[0]));
|
|
Packit |
b802ec |
}
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
ATTRIBUTE_CONST int get_iiwidth(
|
|
Packit |
b802ec |
int ipinfo_no)
|
|
Packit |
b802ec |
{
|
|
Packit |
b802ec |
static const int len = (sizeof(iiwidth) / sizeof((iiwidth)[0]));
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
if (ipinfo_no < len)
|
|
Packit |
b802ec |
return iiwidth[ipinfo_no];
|
|
Packit |
b802ec |
return iiwidth[ipinfo_no % len];
|
|
Packit |
b802ec |
}
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
char *fmt_ipinfo(
|
|
Packit |
b802ec |
struct mtr_ctl *ctl,
|
|
Packit |
b802ec |
ip_t * addr)
|
|
Packit |
b802ec |
{
|
|
Packit |
b802ec |
char *ipinfo = get_ipinfo(ctl, addr);
|
|
Packit |
b802ec |
char fmt[8];
|
|
Packit |
b802ec |
snprintf(fmt, sizeof(fmt), "%s%%-%ds", ctl->ipinfo_no ? "" : "AS",
|
|
Packit |
b802ec |
get_iiwidth(ctl->ipinfo_no));
|
|
Packit |
b802ec |
snprintf(fmtinfo, sizeof(fmtinfo), fmt, ipinfo ? ipinfo : UNKN);
|
|
Packit |
b802ec |
return fmtinfo;
|
|
Packit |
b802ec |
}
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
int is_printii(
|
|
Packit |
b802ec |
struct mtr_ctl *ctl)
|
|
Packit |
b802ec |
{
|
|
Packit |
b802ec |
return ((ctl->ipinfo_no >= 0) && (ctl->ipinfo_no != ctl->ipinfo_max));
|
|
Packit |
b802ec |
}
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
void asn_open(
|
|
Packit |
b802ec |
struct mtr_ctl *ctl)
|
|
Packit |
b802ec |
{
|
|
Packit |
b802ec |
if (ctl->ipinfo_no >= 0) {
|
|
Packit |
b802ec |
DEB_syslog(LOG_INFO, "hcreate(%d)", IIHASH_HI);
|
|
Packit |
b802ec |
if (!(iihash = hcreate(IIHASH_HI)))
|
|
Packit |
b802ec |
error(0, errno, "ipinfo hash");
|
|
Packit |
b802ec |
}
|
|
Packit |
b802ec |
}
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
void asn_close(
|
|
Packit |
b802ec |
struct mtr_ctl *ctl)
|
|
Packit |
b802ec |
{
|
|
Packit |
b802ec |
if ((ctl->ipinfo_no >= 0) && iihash) {
|
|
Packit |
b802ec |
DEB_syslog(LOG_INFO, "hdestroy()");
|
|
Packit |
b802ec |
hdestroy();
|
|
Packit |
b802ec |
iihash = 0;
|
|
Packit |
b802ec |
}
|
|
Packit |
b802ec |
}
|