chmod u+s $(DESTDIR)$(sbindir)/mtr
mtr_SOURCES = mtr.c \
- asn.c asn.h \
net.c net.h \
dns.c dns.h \
raw.c raw.h \
select.c select.h \
mtr-curses.h \
mtr-gtk.h
+
+if IPINFO
+mtr_SOURCES += asn.c asn.h
+endif
+
nodist_mtr_SOURCES = version.h
EXTRA_mtr_SOURCES = curses.c \
gtk.c
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include "asn.h"
-
#include <unistd.h>
+#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <resolv.h>
#include <string.h>
#include <sys/socket.h>
+#include <search.h>
+#include "config.h"
+#include "mtr.h"
+#include "asn.h"
-int PrintAS = 0;
-#ifndef NO_GLIB
-GHashTable * ashash = NULL;
+/*
+#ifndef IIDEBUG
+#define IIDEBUG
+#include <syslog.h>
#endif
+*/
+
+#define IIHASH_HI 128
+#define ITEMSMAX 15
+#define ITEMSEP '|'
+#define NAMELEN 127
+#define UNKN "???"
+
+int ipinfo_no = -1;
+int ipinfo_max = -1;
+int iihash = 0;
+char fmtinfo[32];
+extern int af; /* address family of remote target */
+
+// items width: ASN, Route, Country, Registry, Allocated
+int iiwidth[] = { 6, 19, 4, 8, 11}; // item len + space
+int iiwidth_len = sizeof(iiwidth)/sizeof((iiwidth)[0]);
-char *asn_lookup(const char *domain)
-{
+typedef char* items_t[ITEMSMAX + 1];
+items_t items_a; // without hash: items
+char txtrec[NAMELEN + 1]; // without hash: txtrec
+items_t* items = &items_a;
+
+
+char *ipinfo_lookup(const char *domain) {
unsigned char answer[PACKETSZ], *pt;
char host[128];
char *txt;
memset(answer, 0, PACKETSZ);
if((len = res_query(domain, C_IN, T_TXT, answer, PACKETSZ)) < 0) {
- return "-1";
+#ifdef IIDEBUG
+ if (iihash)
+ syslog(LOG_INFO, "Malloc-txt: %s", UNKN);
+#endif
+ return (iihash)?strdup(UNKN):UNKN;
}
pt = answer + sizeof(HEADER);
}
pt += INT16SZ; /* class */
+ pt += INT32SZ; /* ttl */
GETSHORT(size, pt);
txtlen = *pt;
printf("@Broken TXT record (txtlen = %d, size = %d)\n", txtlen, size); return NULL;
}
- if(!(txt = malloc(txtlen + 1)))
- return NULL;
+ if (txtlen > NAMELEN)
+ txtlen = NAMELEN;
+
+ if (iihash) {
+ if (!(txt = malloc(txtlen + 1)))
+ return NULL;
+ } else
+ txt = (char*)txtrec;
pt++;
strncpy(txt, (char*) pt, txtlen);
txt[txtlen] = 0;
+#ifdef IIDEBUG
+ if (iihash)
+ syslog(LOG_INFO, "Malloc-txt(%p): %s", txt, txt);
+#endif
+
return txt;
}
+char* trimsep(char *s) {
+ int l;
+ char *p = s;
+ while (*p == ' ' || *p == ITEMSEP)
+ *p++ = '\0';
+ for (l = strlen(p)-1; p[l] == ' ' || p[l] == ITEMSEP; l--)
+ p[l] = '\0';
+ return p;
+}
+
+// originX.asn.cymru.com txtrec: ASN | Route | Country | Registry | Allocated
+char* split_txtrec(char *txtrec) {
+ if (!txtrec)
+ return NULL;
+ if (iihash) {
+#ifdef IIDEBUG
+ syslog(LOG_INFO, "Malloc-tbl: %s", txtrec);
+#endif
+ if (!(items = malloc(sizeof(*items)))) {
+#ifdef IIDEBUG
+ syslog(LOG_INFO, "Free-txt(%p)", txtrec);
+#endif
+ free(txtrec);
+ return NULL;
+ }
+ }
+
+ char* prev = (*items)[0] = trimsep(txtrec);
+ char* next;
+ int i = 0, j;
+
+ while ((next = strchr(prev, ITEMSEP)) && (i < ITEMSMAX)) {
+ *next++ = '\0';
+ (*items)[i++] = trimsep(prev);
+ (*items)[i] = prev = trimsep(next);
+ }
+ if (i < ITEMSMAX)
+ i++;
+ for (j = i; j <= ITEMSMAX; j++)
+ (*items)[j] = NULL;
+
+ if (i > ipinfo_max)
+ ipinfo_max = i;
+ if (ipinfo_no >= i) {
+ if (ipinfo_no >= ipinfo_max)
+ ipinfo_no = 0;
+ return (*items)[0];
+ } else
+ return (*items)[ipinfo_no];
+}
+
+#ifdef ENABLE_IPV6
+// from dns.c:addr2ip6arpa()
+void reverse_host6(struct in6_addr *addr, char *buff) {
+ int i;
+ char *b = buff;
+ for (i=(sizeof(*addr)/2-1); i>=0; i--, b+=4) // 64b portion
+ sprintf(b, "%x.%x.", addr->s6_addr[i] & 0xf, addr->s6_addr[i] >> 4);
+ buff[strlen(buff) - 1] = '\0';
+}
+#endif
+
+char *get_ipinfo(ip_t *addr) {
+ if (!addr)
+ return NULL;
+
+ char key[NAMELEN];
+ char lookup_key[NAMELEN];
+
+ if (af == AF_INET6) {
+#ifdef ENABLE_IPV6
+ reverse_host6(addr, key);
+ if (snprintf(lookup_key, NAMELEN, "%s.origin6.asn.cymru.com", key) >= NAMELEN)
+ return NULL;
+#else
+ return NULL;
+#endif
+ } else {
+ unsigned char buff[4];
+ memcpy(buff, addr, 4);
+ if (snprintf(key, NAMELEN, "%d.%d.%d.%d", buff[3], buff[2], buff[1], buff[0]) >= NAMELEN)
+ return NULL;
+ if (snprintf(lookup_key, NAMELEN, "%s.origin.asn.cymru.com", key) >= NAMELEN)
+ return NULL;
+ }
+
+ char *val = NULL;
+ ENTRY item;
+
+ if (iihash) {
+#ifdef IIDEBUG
+ syslog(LOG_INFO, ">> Search: %s", key);
+#endif
+ item.key = key;;
+ ENTRY *found_item;
+ if ((found_item = hsearch(item, FIND))) {
+ if (!(val = (*((items_t*)found_item->data))[ipinfo_no]))
+ val = (*((items_t*)found_item->data))[0];
+#ifdef IIDEBUG
+ syslog(LOG_INFO, "Found (hashed): %s", val);
+#endif
+ }
+ }
+
+ if (!val) {
+#ifdef IIDEBUG
+ syslog(LOG_INFO, "Lookup: %s", key);
+#endif
+ if ((val = split_txtrec(ipinfo_lookup(lookup_key)))) {
+#ifdef IIDEBUG
+ syslog(LOG_INFO, "Looked up: %s", key);
+#endif
+ if (iihash)
+ if ((item.key = strdup(key))) {
+ item.data = items;
+ hsearch(item, ENTER);
+#ifdef IIDEBUG
+ syslog(LOG_INFO, "Insert into hash: %s", key);
+#endif
+ }
+ }
+ }
+
+ return val;
+}
+
+int get_iiwidth(void) {
+ return (ipinfo_no < iiwidth_len) ? iiwidth[ipinfo_no] : iiwidth[ipinfo_no % iiwidth_len];
+}
+
+char *fmt_ipinfo(ip_t *addr) {
+ char *ipinfo = get_ipinfo(addr);
+ char fmt[8];
+ snprintf(fmt, sizeof(fmt), "%s%%-%ds", ipinfo_no?"":"AS", get_iiwidth());
+ snprintf(fmtinfo, sizeof(fmtinfo), fmt, ipinfo?ipinfo:UNKN);
+ return fmtinfo;
+}
+
+int is_printii(void) {
+ return ((ipinfo_no >= 0) && (ipinfo_no != ipinfo_max));
+}
+void asn_open(void) {
+ if (ipinfo_no >= 0) {
+#ifdef IIDEBUG
+ syslog(LOG_INFO, "hcreate(%d)", IIHASH_HI);
+#endif
+ if (!(iihash = hcreate(IIHASH_HI)))
+ perror("ipinfo hash");
+ }
+}
+void asn_close(void) {
+ if (iihash) {
+#ifdef IIDEBUG
+ syslog(LOG_INFO, "hdestroy()");
+#endif
+ hdestroy();
+ iihash = 0;
+ }
+}
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <config.h>
-#ifndef NO_GLIB
-#include <glib.h>
-#endif
-
-/* Prototypes for asn.c */
-
-extern int PrintAS;
-#ifndef NO_GLIB
-extern GHashTable * ashash;
-#endif
-char *asn_lookup(const char *domain);
+extern int ipinfo_no;
+extern int ipinfo_max;
+extern int iiwidth_len;
+extern int iihash;
+void asn_open();
+void asn_close();
+char *fmt_ipinfo(ip_t *addr);
+int get_iiwidth(void);
+int is_printii(void);
[ --without-glib Do not try to use glib at all],
WANTS_GLIB=$withval, WANTS_GLIB=yes)
+AC_ARG_WITH([ipinfo],
+[ --without-ipinfo Do not try to use ipinfo lookup at all],
+[case "${withval}" in
+ yes) ipinfo=true ;;
+ no) ipinfo=false ;;
+ *) AC_MSG_ERROR([bad value ${withval} for --with-ipinfo]) ;;
+esac],[ipinfo=true])
+AM_CONDITIONAL([IPINFO], [test x$ipinfo = xtrue])
+if test "x$ipinfo" = "xfalse"; then
+ AC_DEFINE([NO_IPINFO], [1], [Define to disable ipinfo lookup])
+fi
+
AC_ARG_ENABLE(ipv6,
[ --disable-ipv6 Do not enable IPv6],
WANTS_IPV6=$enableval, WANTS_IPV6=yes)
#include "display.h"
#include "net.h"
#include "dns.h"
+#ifndef NO_IPINFO
#include "asn.h"
-#include "version.h"
-#ifndef NO_GLIB
-#include <glib.h>
#endif
+#include "version.h"
#endif
#include <time.h>
return ActionMPLS;
if (tolower(c) == 'n')
return ActionDNS;
+#ifndef NO_IPINFO
+ if (tolower(c) == 'y')
+ return ActionII;
+ if (tolower(c) == 'z')
+ return ActionAS;
+#endif
if (c == '+')
return ActionScrollDown;
if (c == '-')
}
/* reserve to display help message */
if (tolower(c) == '?'|| tolower(c) == 'h') {
+ int pressanykey_row = 20;
mvprintw(2, 0, "Command:\n" );
printw(" ?|h help\n" );
printw(" p pause (SPACE to resume)\n" );
printw(" s <n> set the packet size to n or random(n<0)\n" );
printw(" b <c> set ping bit pattern to c(0..255) or random(c<0)\n" );
printw(" Q <t> set ping packet's TOS to t\n" );
- printw(" u switch between ICMP ECHO and UDP datagrams\n\n" );
- mvprintw(16, 0, " press any key to go back..." );
+ printw(" u switch between ICMP ECHO and UDP datagrams\n" );
+#ifndef NO_IPINFO
+ printw(" y switching IP info\n");
+ printw(" z toggle ASN info on/off\n");
+ pressanykey_row += 2;
+#endif
+ printw("\n");
+ mvprintw(pressanykey_row, 0, " press any key to go back..." );
getch(); /* get any key */
return ActionNone;
mpls = net_mpls(at);
if( addrcmp( (void *) addr, (void *) &unspec_addr, af ) != 0 ) {
-#ifndef NO_GLIB
-#ifdef ENABLE_IPV6
- struct in6_addr addr6 = *addr;
-#else
- unsigned char *addr4 = (unsigned char *)addr;
-#endif
-
- if (PrintAS) {
- u_char ipv4[4];
-#ifdef ENABLE_IPV6
- ipv4[0] = addr6.s6_addr[0];
- ipv4[1] = addr6.s6_addr[1];
- ipv4[2] = addr6.s6_addr[2];
- ipv4[3] = addr6.s6_addr[3];
-#else
- ipv4[0] = addr4[0];
- ipv4[1] = addr4[1];
- ipv4[2] = addr4[2];
- ipv4[3] = addr4[3];
-#endif
-
-#define NAMELEN 127
- char ipv4_buf[NAMELEN];
- char* chip = (char*) &ipv4_buf;
- char* chas = NULL;
- char** key_ptr = &chip;
- char** value_ptr = &chas;
-
-
- if (snprintf(ipv4_buf, NAMELEN, "%d.%d.%d.%d.asn.routeviews.org", ipv4[3],
- ipv4[2], ipv4[1], ipv4[0]) >= NAMELEN) {
- return;
- }
-
-
-
- gboolean result =
- g_hash_table_lookup_extended
- (ashash, ipv4_buf, (gpointer*)key_ptr, (gpointer*)value_ptr);
- if (!result) {
- char* as = asn_lookup(ipv4_buf);
- chip = (char*) strdup(ipv4_buf);
- chas = (char*) as;
- g_hash_table_insert(ashash, chip, chas);
- }
- //g_hash_table_destroy(hash);
-
-
- printw("[AS%s] ", chas);
- }
-#endif /* NO_GLIB */
name = dns_lookup(addr);
if (! net_up(at))
attron(A_BOLD);
+#ifndef NO_IPINFO
+ if (is_printii())
+ printw(fmt_ipinfo(addr));
+#endif
if(name != NULL) {
if (show_ips) printw("%s (%s)", name, strlongip(addr));
else printw("%s", name);
name = dns_lookup(addrs);
if (! net_up(at)) attron(A_BOLD);
+ printw("\n ");
+#ifndef NO_IPINFO
+ if (is_printii())
+ printw(fmt_ipinfo(addrs));
+#endif
if (name != NULL) {
- if (show_ips) printw("\n %s (%s)", name, strlongip(addrs));
- else printw("\n %s", name);
+ if (show_ips) printw("%s (%s)", name, strlongip(addrs));
+ else printw("%s", name);
} else {
- printw("\n %s", strlongip( addrs ) );
+ printw("%s", strlongip( addrs ) );
}
for (k=0; k < mplss->labels && enablempls; k++) {
printw("\n [MPLS: Lbl %lu Exp %u S %u TTL %u]", mplss->label[k], mplss->exp[k], mplss->s[k], mplss->ttl[k]);
if (! net_up(at))
attron(A_BOLD);
- name = dns_lookup(addr);
- if (name) {
- printw("%s", name);
- } else {
- printw("%s", strlongip( addr ) );
- }
+ if (addrcmp((void *) addr, (void *) &unspec_addr, af)) {
+#ifndef NO_IPINFO
+ if (is_printii())
+ printw(fmt_ipinfo(addr));
+#endif
+ name = dns_lookup(addr);
+ printw("%s", name?name:strlongip(addr));
+ } else
+ printw("???");
attroff(A_BOLD);
getyx(stdscr, y, __unused_int);
} else {
char msg[80];
- int max_cols = maxx<=SAVED_PINGS+30 ? maxx-30 : SAVED_PINGS;
- startstat = 28;
+ int padding = 30;
+#ifndef NO_IPINFO
+ if (is_printii())
+ padding += get_iiwidth();
+#endif
+ int max_cols = maxx<=SAVED_PINGS+padding ? maxx-padding : SAVED_PINGS;
+ startstat = padding - 2;
sprintf(msg, " Last %3d pings", max_cols);
mvprintw(rowstat - 1, startstat, msg);
void mtr_curses_open(void)
{
-#ifndef NO_GLIB
- ashash = g_hash_table_new(g_str_hash, g_str_equal);
-#endif
initscr();
raw();
noecho();
#include "select.h"
#include "raw.h"
#include "dns.h"
+#ifndef NO_IPINFO
+#include <asn.h>
+#endif
extern int DisplayMode;
break;
case DisplayCurses:
mtr_curses_open();
+#ifndef NO_IPINFO
+ if (ipinfo_no >= 0)
+ asn_open();
+#endif
break;
case DisplaySplit:
split_open();
csv_close();
break;
case DisplayCurses:
+#ifndef NO_IPINFO
+ if (ipinfo_no >= 0)
+ asn_close();
+#endif
mtr_curses_close();
break;
case DisplaySplit:
(notably the one on Irix 5.2) do not like that. */
enum { ActionNone, ActionQuit, ActionReset, ActionDisplay,
ActionClear, ActionPause, ActionResume, ActionMPLS, ActionDNS,
+#ifndef NO_IPINFO
+ ActionII, ActionAS,
+#endif
ActionScrollDown, ActionScrollUp };
enum { DisplayReport, DisplayCurses, DisplayGTK, DisplaySplit,
DisplayRaw, DisplayXML, DisplayCSV, DisplayTXT};
#include "dns.h"
#include "report.h"
#include "net.h"
+#ifndef NO_IPINFO
#include "asn.h"
+#endif
#include "version.h"
{ "udp", 0, 0, 'u' }, /* UDP (default is ICMP) */
{ "inet", 0, 0, '4' }, /* IPv4 only */
{ "inet6", 0, 0, '6' }, /* IPv6 only */
- { "aslookup", 0, 0, 'z' }, /* Do AS lookup */
+#ifndef NO_IPINFO
+ { "ipinfo", 1, 0, 'y' }, /* IP info lookup */
+ { "aslookup", 0, 0, 'z' }, /* Do AS lookup (--ipinfo 0) */
+#endif
{ 0, 0, 0, 0 }
};
while(1) {
/* added f:m:o: byMin */
opt = getopt_long(argc, argv,
- "vhrwxtglpo:B:i:c:s:Q:ena:f:m:ubz46", long_options, NULL);
+ "vhrwxtglpo:B:i:c:s:Q:ena:f:m:uby:z46", long_options, NULL);
if(opt == -1)
break;
fprintf( stderr, "IPv6 not enabled.\n" );
break;
#endif
+#ifndef NO_IPINFO
+ case 'y':
+ ipinfo_no = atoi (optarg);
+ if (ipinfo_no < 0)
+ ipinfo_no = 0;
+ break;
case 'z':
- PrintAS = 1;
+ ipinfo_no = 0;
break;
+#endif
}
}
printf("usage: %s [-hvrwctglspniu46] [--help] [--version] [--report]\n"
"\t\t[--report-wide] [--report-cycles=COUNT] [--curses] [--gtk]\n"
"\t\t[--raw] [--split] [--mpls] [--no-dns] [--show-ips]\n"
- "\t\t[--address interface] [--aslookup]\n" /* BL */
+ "\t\t[--address interface]\n" /* BL */
+#ifndef NO_IPINFO
+ "\t\t[--ipinfo=item_no|-y item_no]\n"
+ "\t\t[--aslookup|-z]\n"
+#endif
"\t\t[--psize=bytes/-s bytes]\n" /* ok */
"\t\t[--report-wide|-w] [-u]\n" /* rew */
"\t\t[--interval=SECONDS] HOSTNAME [PACKETSIZE]\n", argv[0]);
#include "report.h"
#include "net.h"
#include "dns.h"
+#ifndef NO_IPINFO
+#include "asn.h"
+#endif
#define MAXLOADBAL 5
}
+#ifndef NO_IPINFO
+void print_mpls(struct mplslen *mpls) {
+ int k;
+ for (k=0; k < mpls->labels; k++)
+ printf(" [MPLS: Lbl %lu Exp %u S %u TTL %u]\n", mpls->label[k], mpls->exp[k], mpls->s[k], mpls->ttl[k]);
+}
+#endif
+
void report_close(void)
{
- int i, j, k, at, max, z, w;
+ int i, j, at, max, z, w;
struct mplslen *mpls, *mplss;
ip_t *addr;
ip_t *addr2 = NULL;
}
}
+#ifndef NO_IPINFO
+ int len_tmp = len_hosts;
+ if (ipinfo_no >= 0) {
+ ipinfo_no %= iiwidth_len;
+ if (reportwide) {
+ len_hosts++; // space
+ len_tmp += get_iiwidth();
+ if (!ipinfo_no)
+ len_tmp += 2; // align header: AS
+ }
+ }
+ snprintf( fmt, sizeof(fmt), "HOST: %%-%ds", len_tmp);
+#else
snprintf( fmt, sizeof(fmt), "HOST: %%-%ds", len_hosts);
+#endif
snprintf(buf, sizeof(buf), fmt, LocalHostname);
len = reportwide ? strlen(buf) : len_hosts;
for( i=0; i<MAXFLD; i++ ) {
mpls = net_mpls(at);
snprint_addr(name, sizeof(name), addr);
+#ifndef NO_IPINFO
+ if (is_printii()) {
+ snprintf(fmt, sizeof(fmt), " %%2d. %%s%%-%ds", len_hosts);
+ snprintf(buf, sizeof(buf), fmt, at+1, fmt_ipinfo(addr), name);
+ } else {
+#endif
snprintf( fmt, sizeof(fmt), " %%2d.|-- %%-%ds", len_hosts);
snprintf(buf, sizeof(buf), fmt, at+1, name);
+#ifndef NO_IPINFO
+ }
+#endif
len = reportwide ? strlen(buf) : len_hosts;
for( i=0; i<MAXFLD; i++ ) {
j = fld_index[fld_active [i]];
if (!found) {
+#ifndef NO_IPINFO
+ if (is_printii()) {
+ if (mpls->labels && z == 1 && enablempls)
+ print_mpls(mpls);
+ snprint_addr(name, sizeof(name), addr2);
+ printf(" %s%s\n", fmt_ipinfo(addr2), name);
+ if (enablempls)
+ print_mpls(mplss);
+ } else {
+#else
+ int k;
if (mpls->labels && z == 1 && enablempls) {
for (k=0; k < mpls->labels; k++) {
printf(" | |+-- [MPLS: Lbl %lu Exp %u S %u TTL %u]\n", mpls->label[k], mpls->exp[k], mpls->s[k], mpls->ttl[k]);
printf(" | +-- [MPLS: Lbl %lu Exp %u S %u TTL %u]\n", mplss->label[k], mplss->exp[k], mplss->s[k], mplss->ttl[k]);
}
}
+#endif
+#ifndef NO_IPINFO
+ }
+#endif
}
}
/* No multipath */
+#ifndef NO_IPINFO
+ if (is_printii()) {
+ if (mpls->labels && z == 1 && enablempls)
+ print_mpls(mpls);
+ } else {
+#else
if(mpls->labels && z == 1 && enablempls) {
+ int k;
for (k=0; k < mpls->labels; k++) {
printf(" | +-- [MPLS: Lbl %lu Exp %u S %u TTL %u]\n", mpls->label[k], mpls->exp[k], mpls->s[k], mpls->ttl[k]);
}
}
+#endif
+#ifndef NO_IPINFO
+ }
+#endif
}
}
#include "display.h"
#include "dns.h"
#include "net.h"
+#ifndef NO_IPINFO
+#include "asn.h"
+#endif
extern int Interactive;
extern int MaxPing;
display_clear();
}
break;
+#ifndef NO_IPINFO
+ case ActionII:
+ if (ipinfo_no >= 0) {
+ ipinfo_no++;
+ if (ipinfo_no > ipinfo_max)
+ ipinfo_no = 0;
+ }
+ break;
+ case ActionAS:
+ if (ipinfo_no >= 0)
+ ipinfo_no = ipinfo_no?0:ipinfo_max;
+ break;
+#endif
case ActionScrollDown:
display_offset += 5;