- included some old patches.
- included patch from Antonio Querubin for better IPV6 support
restructured some more whitespace.
- added mtr.h where "global" things should go. Not finished moving
things around, but now that the infrastructure is there, it should
be easy.
source: ftp://ftp.bitwizard.nl/mtr/mtr-0.68.tar.gz
Mike Simons (msimons@moria.simons-clan.com)
Aaron Scarisbrick,
Craig Milo Rogers (Rogers@ISI.EDU)
+ Antonio Querubin <tony@aloha.net>
Russell Nelson (rn-mtr@crynwr.com)
Davin Milun (milun@acm.org)
Josh Martin (jmartin@columbiaservices.net)
sbin_PROGRAMS = mtr
man_MANS = mtr.8
-install-exec-am:
+install-exec-hook:
chmod u+s $(DESTDIR)$(sbindir)/mtr
mtr_SOURCES = mtr.c \
WHAT'S NEW?
+ v0.68 included some old patches.
+ included patch from Antonio Querubin for better IPV6 support
+ restructured some more whitespace.
+ added mtr.h where "global" things should go. Not finished
+ moving things around, but now that the infrastructure is there,
+ it should be easy.
v0.67 Bad keyboarding by REW caused this one out the door. Sorry.
No changes.
v0.66 Through the Debian bugtracking system a bug report and
AC_INIT(mtr.c)
-AM_INIT_AUTOMAKE(mtr, 0.67)
+AM_INIT_AUTOMAKE(mtr, 0.68)
AC_SUBST(GTK_OBJ)
[ --enable-gtk2 Compile against GTK2 instead of GTK+],
WANTS_GTK2=$enableval, WANTS_GTK2=no)
+AC_ARG_ENABLE(ipv6,
+[ --disable-ipv6 Do not enable IPv6],
+WANTS_IPV6=$enableval, WANTS_IPV6=yes)
+
if test "x$WANTS_GTK" = "xyes"; then
if test "x$WANTS_GTK2" = "xyes"; then
AM_PATH_GTK_2_0(2.0.0, CFLAGS="$CFLAGS $GTK_CFLAGS"
AC_CHECK_FUNC(herror, , AC_DEFINE(NO_HERROR))
AC_CHECK_FUNC(strerror, , AC_DEFINE(NO_STRERROR))
+AC_CHECK_FUNC(getaddrinfo,
+[if test "$WANTS_IPV6" = "yes"; then
+ AC_DEFINE([ENABLE_IPV6], [], [Define to enable IPv6])
+fi])
dnl Add C flags to display more warnings
AC_MSG_CHECKING(for C flags to get more warnings)
*/
#include <config.h>
+#include <strings.h>
#ifndef NO_CURSES
#include <ctype.h>
# define getmaxyx(win,y,x) ((y) = (win)->_maxy + 1, (x) = (win)->_maxx + 1)
#endif
+#include "mtr.h"
#include "mtr-curses.h"
#include "display.h"
#include "net.h"
extern int bitpattern;
extern int tos;
extern float WaitTime;
-
+extern int af;
void pwcenter(char *str)
{
printw(str);
}
-int mtr_curses_keyaction()
+
+int mtr_curses_keyaction(void)
{
int c = getch();
int i=0;
mvprintw(3, 0, "Size Range: %d-%d, <0 random.\n", MINPACKET, MAXPACKET);
move(2,20);
refresh();
- while ( (c=getch ()) != '\n' && i<MAXFLD ) {
+ while ( (c=getch ()) != '\n' && i < MAXFLD ) {
attron(A_BOLD); printw("%c", c); attroff(A_BOLD); refresh ();
buf[i++] = c; /* need more checking on 'c' */
}
mvprintw(3, 0, "Pattern Range: 0(0x00)-255(0xff), <0 random.\n");
move(2,18);
refresh();
- while ( (c=getch ()) != '\n' && i<MAXFLD ) {
+ while ( (c=getch ()) != '\n' && i < MAXFLD ) {
attron(A_BOLD); printw("%c", c); attroff(A_BOLD); refresh ();
buf[i++] = c; /* need more checking on 'c' */
}
mvprintw(3, 0, "default 0x00, min cost 0x02, rel 0x04,, thr 0x08, low del 0x10...\n");
move(2,22);
refresh();
- while ( (c=getch ()) != '\n' && i<MAXFLD ) {
+ while ( (c=getch ()) != '\n' && i < MAXFLD ) {
attron(A_BOLD); printw("%c", c); attroff(A_BOLD); refresh();
buf[i++] = c; /* need more checking on 'c' */
}
mvprintw(2, 0, "Interval : %0.0f\n\n", WaitTime );
move(2,11);
refresh();
- while ( (c=getch ()) != '\n' && i<MAXFLD ) {
+ while ( (c=getch ()) != '\n' && i < MAXFLD ) {
attron(A_BOLD); printw("%c", c); attroff(A_BOLD); refresh();
buf[i++] = c; /* need more checking on 'c' */
}
mvprintw(2, 0, "First TTL: %d\n\n", fstTTL );
move(2,11);
refresh();
- while ( (c=getch ()) != '\n' && i<MAXFLD ) {
+ while ( (c=getch ()) != '\n' && i < MAXFLD ) {
attron(A_BOLD); printw("%c", c); attroff(A_BOLD); refresh();
buf[i++] = c; /* need more checking on 'c' */
}
mvprintw(2, 0, "Max TTL: %d\n\n", maxTTL );
move(2,9);
refresh();
- while ( (c=getch ()) != '\n' && i<MAXFLD ) {
+ while ( (c=getch ()) != '\n' && i < MAXFLD ) {
attron(A_BOLD); printw("%c", c); attroff(A_BOLD); refresh();
buf[i++] = c; /* need more checking on 'c' */
}
return ActionNone; /* ignore unknown input */
}
+
void mtr_curses_hosts(int startstat)
{
int max;
int at;
- int addr, addrs;
+ ip_t *addr, *addrs;
int y, x;
char *name;
printw("%2d. ", at + 1);
addr = net_addr(at);
- if(addr != 0) {
+ if( addrcmp( (void *) addr, (void *) &unspec_addr, af ) != 0 ) {
name = dns_lookup(addr);
if (! net_up(at))
attron(A_BOLD);
if(name != NULL) {
printw("%s", name);
} else {
- printw("%d.%d.%d.%d", (addr >> 24) & 0xff, (addr >> 16) & 0xff,
- (addr >> 8) & 0xff, addr & 0xff);
+ printw("%s", strlongip( addr ) );
}
attroff(A_BOLD);
/* Multi path by Min */
for (i=0; i < MAXPATH; i++ ) {
addrs = net_addrs(at, i);
- if (addrs == addr) continue;
- if (addrs == 0) break;
+ if ( addrcmp( (void *) addrs, (void *) addr, af ) == 0 ) continue;
+ if ( addrcmp( (void *) addrs, (void *) &unspec_addr, af ) == 0 ) break;
name = dns_lookup(addrs);
if (! net_up(at)) attron(A_BOLD);
if (name != NULL) {
printw("\n %s", name);
} else {
- printw("\n %d.%d.%d.%d",
- (addrs >> 24) & 0xff, (addrs >> 16) & 0xff,
- (addrs >> 8) & 0xff, addrs & 0xff);
+ printw("\n %s", strlongip( addrs ) );
}
attroff(A_BOLD);
}
move(2, 0);
}
+
static double factors[] = { 0.02, 0.05, 0.08, 0.15, 0.33, 0.50, 0.80, 1.00 };
static int scale[8];
static int low_ms, high_ms;
}
}
+
static const char* block_map = ".123abc>";
void mtr_print_scaled(int ms)
printw(">");
}
+
void mtr_fill_graph(int at, int cols)
{
int* saved;
}
}
+
void mtr_curses_graph(int startstat, int cols)
{
- int max, at, addr, y, x;
+ int max, at, y, x;
+ ip_t * addr;
char* name;
max = net_max();
if (name) {
printw("%s", name);
} else {
- printw("%d.%d.%d.%d", (addr >> 24) & 0xff, (addr >> 16) && 0xff, (addr >> 8) & 0xff, addr & 0xff);
+ printw("%s", strlongip( addr ) );
}
attroff(A_BOLD);
}
}
-void mtr_curses_redraw()
+
+void mtr_curses_redraw(void)
{
int maxx, maxy;
int startstat;
pwcenter("My traceroute [v" VERSION "]");
attroff(A_BOLD);
- mvprintw(1, 0, "%s (%s)", LocalHostname, inet_ntoa(*net_localaddr()));
+ mvprintw(1, 0, "%s (%s)", LocalHostname, net_localaddr());
printw("(tos=0x%X ", tos);
printw("psize=%d ", abs(packetsize) );
printw("bitpattern=0x%02X)", (unsigned char)(abs(bitpattern)));
}
-void mtr_curses_open()
+void mtr_curses_open(void)
{
initscr();
raw();
}
-void mtr_curses_close()
+void mtr_curses_close(void)
{
printw("\n");
endwin();
}
-void mtr_curses_clear()
+void mtr_curses_clear(void)
{
mtr_curses_close();
mtr_curses_open();
#include <config.h>
#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+#include "mtr.h"
#include "display.h"
#include "mtr-curses.h"
#include "mtr-gtk.h"
#include "report.h"
#include "select.h"
#include "raw.h"
+#include "dns.h"
extern int DisplayMode;
#endif
}
-void display_open() {
+
+void display_open(void)
+{
switch(DisplayMode) {
case DisplayReport:
}
}
-void display_close() {
+
+void display_close(void)
+{
switch(DisplayMode) {
case DisplayReport:
report_close();
}
}
-void display_redraw() {
+
+void display_redraw(void)
+{
switch(DisplayMode) {
case DisplayCurses:
}
}
-int display_keyaction() {
+
+int display_keyaction(void)
+{
switch(DisplayMode) {
case DisplayCurses:
return mtr_curses_keyaction();
}
-void display_rawping(int host, int msec) {
+void display_rawping(int host, int msec)
+{
switch(DisplayMode) {
case DisplayReport:
case DisplayTXT:
}
-void display_rawhost(int host, int ip_addr) {
+void display_rawhost(int host, ip_t *ip_addr)
+{
switch(DisplayMode) {
case DisplayReport:
case DisplayTXT:
}
-void display_loop() {
+void display_loop(void)
+{
switch(DisplayMode) {
case DisplayReport:
case DisplayTXT:
}
-void display_clear() {
+void display_clear(void)
+{
switch(DisplayMode) {
case DisplayCurses:
mtr_curses_clear();
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include <netinet/in.h>
+
enum { ActionNone, ActionQuit, ActionReset, ActionDisplay,
ActionClear, ActionPause, ActionResume, ActionDNS,
ActionScrollDown, ActionScrollUp, };
/* Prototypes for display.c */
void display_detect(int *argc, char ***argv);
-void display_open();
-void display_close();
-void display_redraw();
+void display_open(void);
+void display_close(void);
+void display_redraw(void);
void display_rawping(int hostnum, int msec);
-void display_rawhost(int hostnum, int ip_addr);
-int display_keyaction();
-void display_loop();
-void display_clear();
+void display_rawhost(int hostnum, ip_t *ip_addr);
+int display_keyaction(void);
+void display_loop(void);
+void display_clear(void);
extern int display_mode;
-extern int use_dns;
-extern int dns;
extern int display_offset; /* only used in text mode */
#include <errno.h>
#include <time.h>
+#include "mtr.h"
#include "dns.h"
+#include "net.h"
#ifdef NO_STRERROR
extern int sys_nerr;
/* Hmm, it seems Irix requires this */
extern int errno;
+extern int af;
+
/* Defines */
#undef Debug
long idseed = 0xdeadbeef;
long aseed;
-struct sockaddr_in from;
+#ifdef ENABLE_IPV6
+struct sockaddr_storage from_sastruct;
+struct sockaddr_in6 * from6 = (struct sockaddr_in6 *) &from_sastruct;
+#else
+struct sockaddr_in from_sastruct;
+#endif
+
+struct sockaddr_in * from4 = (struct sockaddr_in *) &from_sastruct;
+struct sockaddr * from = (struct sockaddr *) &from_sastruct;
int resfd;
-int fromlen = sizeof(struct sockaddr_in);
+int fromlen = sizeof from_sastruct;
char tempstring[16384+1+1];
char sendstring[1024+1];
}
-char *strlongip(ip_t ip)
+char *strlongip(ip_t * ip)
{
- struct in_addr a;
- a.s_addr = htonl(ip);
- return inet_ntoa(a);
+#ifdef ENABLE_IPV6
+ static char buf[INET6_ADDRSTRLEN];
+
+ return (char *) inet_ntop( af, ip, buf, sizeof buf );
+#else
+ return inet_ntoa( *ip );
+#endif
}
-ip_t longipstr(char *s)
+int longipstr(char *s, ip_t *dst)
{
- return inet_addr(s);
+#ifdef ENABLE_IPV6
+ return inet_pton( af, s, dst );
+#else
+ return inet_aton( s, dst );
+#endif
}
-int dns_forward(char *name)
+struct hostent * dns_forward(char *name)
{
struct hostent *host;
if ((host = gethostbyname(name)))
- return *(int *)host->h_addr;
+ return host;
else
- return 0;
+ return NULL;
}
strerror(errno));
exit(-1);
}
- localhost = longipstr("127.0.0.1");
+ longipstr( "127.0.0.1", &localhost );
aseed = time(NULL) ^ (time(NULL) << 3) ^ (dword)getpid();
for (i = 0;i < BashSize;i++) {
idbash[i] = NULL;
}
-dword getipbash(ip_t ip)
+dword getipbash(ip_t * ip)
{
- return (dword)BashModulo(ip);
+ char *p = (char *) ip;
+ int i, len = 0;
+ dword bashvalue = 0;
+
+ switch ( af ) {
+ case AF_INET:
+ len = sizeof (struct in_addr);
+ break;
+#ifdef ENABLE_IPV6
+ case AF_INET6:
+ len = sizeof (struct in6_addr);
+ break;
+#endif
+ }
+ for (i = 0; i < len; i++, p++) {
+ bashvalue^= *p;
+ bashvalue+= (*p >> 1) + (bashvalue >> 1);
+ }
+ return BashModulo(bashvalue);
}
struct resolve *rp;
dword bashnum;
- bashnum = getipbash(addrp->ip);
+ bashnum = getipbash( &(addrp->ip) );
rp = ipbash[bashnum];
if (rp) {
- while ((rp->nextip) && (addrp->ip > rp->nextip->ip))
+ while ((rp->nextip) &&
+ ( addrcmp( (void *) &(addrp->ip),
+ (void *) &(rp->nextip->ip), af ) > 0 ))
rp = rp->nextip;
- while ((rp->previousip) && (addrp->ip < rp->previousip->ip))
+ while ((rp->previousip) &&
+ ( addrcmp( (void *) &(addrp->ip),
+ (void *) &(rp->previousip->ip), af ) < 0 ))
rp = rp->previousip;
- if (rp->ip < addrp->ip) {
+ if ( addrcmp( (void *) &(rp->ip), (void *) &(addrp->ip), af ) < 0 ) {
addrp->previousip = rp;
addrp->nextip = rp->nextip;
if (rp->nextip)
{
dword bashnum;
- bashnum = getipbash(rp->ip);
+ bashnum = getipbash( &(rp->ip) );
if (ipbash[bashnum] == rp)
ipbash[bashnum] = (rp->previousip)? rp->previousip : rp->nextip;
if (rp->nextip)
}
-struct resolve *findip(ip_t ip)
+struct resolve *findip(ip_t * ip)
{
struct resolve *rp;
dword bashnum;
bashnum = getipbash(ip);
rp = ipbash[bashnum];
if (rp) {
- while ((rp->nextip) && (ip >= rp->nextip->ip))
+ while ((rp->nextip) &&
+ ( addrcmp( (void *) ip, (void *) &(rp->nextip->ip), af ) >= 0 ))
rp = rp->nextip;
- while ((rp->previousip) && (ip <= rp->previousip->ip))
+ while ((rp->previousip) &&
+ ( addrcmp( (void *) ip, (void *) &(rp->previousip->ip), af ) <= 0 ))
rp = rp->previousip;
- if (ip == rp->ip) {
+ if ( addrcmp( (void *) ip, (void *) &(rp->ip), af ) == 0 ) {
ipbash[bashnum] = rp;
return rp;
} else
restell(tempstring);
}
} else if (type == T_PTR) {
+ switch ( af ) {
+ case AF_INET:
sprintf(tempstring,"%u.%u.%u.%u.in-addr.arpa",
((byte *)&rp->ip)[3],
((byte *)&rp->ip)[2],
((byte *)&rp->ip)[1],
((byte *)&rp->ip)[0]);
+ break;
+#ifdef ENABLE_IPV6
+ case AF_INET6:
+ addr2ip6arpa( &(rp->ip), tempstring );
+ break;
+#endif
+ }
dorequest(tempstring,type,rp->id);
if (debug) {
sprintf(tempstring,"Resolver: Sent domain lookup request for \"%s\".",
- strlongip(rp->ip));
+ strlongip( &(rp->ip) ));
restell(tempstring);
}
}
}
-void parserespacket(byte *s,int l)
+void parserespacket(byte *s, int l)
{
struct resolve *rp;
packetheader *hp;
word rr,datatype,class,qdatatype,qclass;
byte rdatalength;
- if (l < sizeof(packetheader)) {
+ if (l < (int) sizeof(packetheader)) {
restell("Resolver error: Packet smaller than standard header size.");
return;
}
- if (l == sizeof(packetheader)) {
+ if (l == (int) sizeof(packetheader)) {
restell("Resolver error: Packet has empty body.");
return;
}
case STATE_PTRREQ1:
case STATE_PTRREQ2:
case STATE_PTRREQ3:
+ switch ( af ) {
+ case AF_INET:
sprintf(stackstring,"%u.%u.%u.%u.in-addr.arpa",
((byte *)&rp->ip)[3],
((byte *)&rp->ip)[2],
((byte *)&rp->ip)[1],
((byte *)&rp->ip)[0]);
break;
+#ifdef ENABLE_IPV6
+ case AF_INET6:
+ addr2ip6arpa( &(rp->ip), stackstring );
+ break;
+#endif
+ }
}
*namestring = '\0';
r = dn_expand(s,s + l,c,namestring,MAXDNAME);
restell(tempstring);
return;
}
- if (memcmp(&rp->ip,(ip_t *)c,sizeof(ip_t))) {
+ if ( addrcmp( (void *) &(rp->ip), (void *) c, af ) == 0 ) {
sprintf(tempstring,"Resolver: Reverse authentication failed: %s != ",
- strlongip(rp->ip));
- memcpy(&alignedip,(ip_t *)c,sizeof(ip_t));
- strcat(tempstring,strlongip(alignedip));
+ strlongip( &(rp->ip) ));
+ addrcpy( (void *) &alignedip, (void *) c, af );
+ strcat(tempstring,strlongip( &alignedip ));
restell(tempstring);
res_hostipmismatch++;
failrp(rp);
} else {
sprintf(tempstring,"Resolver: Reverse authentication complete: %s == \"%s\".",
- strlongip(rp->ip),nonull(rp->hostname));
+ strlongip( &(rp->ip) ),nonull(rp->hostname));
restell(tempstring);
res_reversesuccess++;
passrp(rp,ttl);
{
int r,i;
- r = recvfrom(resfd,(byte *)resrecvbuf,MaxPacketsize,0,(struct sockaddr *)&from,&fromlen);
+ r = recvfrom(resfd,(byte *)resrecvbuf,MaxPacketsize,0,
+ from, &fromlen);
if (r > 0) {
/* Check to see if this server is actually one we sent to */
- if (from.sin_addr.s_addr == localhost) {
+ if ( addrcmp( (void *) &(from4->sin_addr), (void *) &localhost,
+ (int) AF_INET ) == 0 ) {
for (i = 0;i < _res.nscount;i++)
- if ((_res.nsaddr_list[i].sin_addr.s_addr == from.sin_addr.s_addr) ||
- (!_res.nsaddr_list[i].sin_addr.s_addr)) /* 0.0.0.0 replies as 127.0.0.1 */
+ if ( addrcmp( (void *) &(_res.nsaddr_list[i].sin_addr),
+ (void *) &(from4->sin_addr), (int) AF_INET ) == 0 ||
+ addrcmp( (void *) &(_res.nsaddr_list[i].sin_addr),
+ (void *) &unspec_addr, (int) AF_INET ) != 0 ) /* 0.0.0.0 replies as 127.0.0.1 */
break;
} else
for (i = 0;i < _res.nscount;i++)
- if (_res.nsaddr_list[i].sin_addr.s_addr == from.sin_addr.s_addr)
+ if ( addrcmp( (void *) &(_res.nsaddr_list[i].sin_addr),
+ (void *) &(from4->sin_addr), AF_INET ) == 0 )
break;
if (i == _res.nscount) {
sprintf(tempstring,"Resolver error: Received reply from unknown source: %s",
- inet_ntoa(from.sin_addr));
+ inet_ntoa(from4->sin_addr ));
restell(tempstring);
} else
parserespacket((byte *)resrecvbuf,r);
case STATE_FAILED: /* Fake TTL has expired */
if (debug) {
sprintf(tempstring,"Resolver: Cache record for \"%s\" (%s) has expired. (state: %u) Marked for expire at: %g, time: %g.",
- nonull(rp->hostname),strlongip(rp->ip),rp->state,rp->expiretime,sweeptime);
+ nonull(rp->hostname), strlongip( &(rp->ip) ),
+ rp->state, rp->expiretime, sweeptime);
restell(tempstring);
}
unlinkresolve(rp);
}
-char *dns_lookup2(ip_t ip)
+char *dns_lookup2(ip_t * ip)
{
struct resolve *rp;
- ip = htonl(ip);
if ((rp = findip(ip))) {
if ((rp->state == STATE_FINISHED) || (rp->state == STATE_FAILED)) {
if ((rp->state == STATE_FINISHED) && (rp->hostname)) {
rp = allocresolve();
rp->state = STATE_PTRREQ1;
rp->expiretime = sweeptime + ResRetryDelay1;
- rp->ip = ip;
+ addrcpy( (void *) &(rp->ip), (void *) ip, af );
linkresolve(rp);
- rp->ip = ip;
+ addrcpy( (void *) &(rp->ip), (void *) ip, af );
linkresolveip(rp);
sendrequest(rp,T_PTR);
return NULL;
}
-char *dns_lookup(ip_t ip)
+char *dns_lookup(ip_t * ip)
{
char *t;
t = dns_lookup2 (ip);
return (t&&use_dns)?t:strlongip(ip);
}
+
+#ifdef ENABLE_IPV6
+/* Returns an ip6.arpa character string. */
+void addr2ip6arpa( ip_t * ip, char * buf ) {
+ unsigned char * p = (char *) ip;
+ unsigned char * b = buf;
+ int i;
+
+ for ( i = sizeof (struct in6_addr) - 1; i >= 0; i-- ) {
+ sprintf( b, "%x.%x.", p[i] % 16, p[i] >> 4 );
+ b += 4;
+ }
+ sprintf( b, "ip6.arpa" );
+ return;
+}
+#endif
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-/* Typedefs */
-
-typedef unsigned char byte;
-typedef unsigned short word;
-typedef unsigned long dword;
-
-typedef unsigned int ip_t;
-
+#include <netinet/in.h>
/* Prototypes for dns.c */
-void dns_open();
-int dns_waitfd();
-void dns_ack();
+void dns_open(void);
+int dns_waitfd(void);
+void dns_ack(void);
void dns_events(double *sinterval);
-char *dns_lookup(ip_t address);
-char *dns_lookup2(ip_t address);
-int dns_forward(char *name);
-char *strlongip(ip_t ip);
+char *dns_lookup(ip_t * address);
+char *dns_lookup2(ip_t * address);
+struct hostent * dns_forward(char *name);
+char *strlongip(ip_t * ip);
+
+void addr2ip6arpa( ip_t * ip, char * buf );
-extern int dns;
errors, only prototype getopt for the GNU C library. */
extern int getopt (int argc, char *const *argv, const char *shortopts);
#else /* not __GNU_LIBRARY__ */
-extern int getopt ();
+extern int getopt (void);
#endif /* __GNU_LIBRARY__ */
extern int getopt_long (int argc, char *const *argv, const char *shortopts,
const struct option *longopts, int *longind);
const struct option *longopts, int *longind,
int long_only);
#else /* not __STDC__ */
-extern int getopt ();
-extern int getopt_long ();
-extern int getopt_long_only ();
+extern int getopt (void);
+extern int getopt_long (void);
+extern int getopt_long_only (void);
-extern int _getopt_internal ();
+extern int _getopt_internal (void);
#endif /* __STDC__ */
#ifdef __cplusplus
#include <sys/types.h>
#ifndef NO_GTK
+#include <stdio.h>
#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
#include <gtk/gtk.h>
+#include "mtr.h"
#include "net.h"
#include "dns.h"
#include "mtr-gtk.h"
#include "img/mtr_icon.xpm"
#endif
-
gint gtk_ping(gpointer data);
extern char *Hostname;
extern float WaitTime;
+extern int af;
static int tag;
static GtkWidget *Pause_Button;
}
}
-int gtk_detect(int *argc, char ***argv)
+
+int gtk_detect(UNUSED int *argc, UNUSED char ***argv)
{
if(getenv("DISPLAY") != NULL) {
/* If we do this here, gtk_init exits on an error. This happens
}
}
-gint Window_destroy(GtkWidget *Window, gpointer data)
+
+gint Window_destroy(UNUSED GtkWidget *Window, UNUSED gpointer data)
{
gtk_main_quit();
return FALSE;
}
-gint Restart_clicked(GtkWidget *Button, gpointer data)
+
+gint Restart_clicked(UNUSED GtkWidget *Button, UNUSED gpointer data)
{
net_reset();
gtk_redraw();
}
-gint Pause_clicked(GtkWidget *Button, gpointer data)
+gint Pause_clicked(UNUSED GtkWidget *Button, UNUSED gpointer data)
{
static int paused = 0;
return FALSE;
}
+
/*
* There is a small problem with the following code:
* The timeout is canceled and removed in order to ensure that
* What's the problem with this? (-> "I don't think so) -- REW
*/
-gint WaitTime_changed(GtkAdjustment *Adj, GtkWidget *Button)
+gint WaitTime_changed(UNUSED GtkAdjustment *Adj, UNUSED GtkWidget *Button)
{
WaitTime = gtk_spin_button_get_value_as_float(GTK_SPIN_BUTTON(Button));
gtk_timeout_remove (tag);
return FALSE;
}
-gint Host_activate(GtkWidget *Entry, gpointer data)
+
+gint Host_activate(GtkWidget *Entry, UNUSED gpointer data)
{
- int addr;
+ struct hostent * addr;
addr = dns_forward(gtk_entry_get_text(GTK_ENTRY(Entry)));
if(addr) {
return FALSE;
}
+
GdkPixmap *gtk_load_pixmap(char **pixmap)
{
return gdk_pixmap_colormap_create_from_xpm_d(NULL,
NULL, NULL, pixmap);
}
+
void Toolbar_fill(GtkWidget *Toolbar)
{
GtkWidget *Button;
gtk_widget_show(Entry);
}
+
char *Report_Text[] = { "Hostname", "Loss", "Rcv", "Snt", "Last", "Best", "Avg", "Worst", "StDev", NULL };
int Report_Positions[] = { 10, 200, 240, 280, 320, 360, 400, 440, 480, 0 };
GtkWidget *Report;
GtkWidget *GetRow(int index)
{
- int addr;
+ ip_t * addr;
char *name;
GtkWidget *Row, *Label;
addr = net_addr(index);
name = "???";
- if(addr != 0) {
+ if ( addrcmp( (void *) addr, (void *) &unspec_addr, af ) != 0 ) {
name = dns_lookup(addr);
if(!name) {
/* Actually this is not neccesary:
return Row;
}
-GtkWidget *Scrollarea_create()
+
+GtkWidget *Scrollarea_create(void)
{
GtkWidget *List;
GtkWidget *scroll;
return scroll;
}
+
void gtk_add_row(GtkWidget *List)
{
int at;
gtk_widget_show(Row);
}
+
void gtk_set_field(GtkCList *List, int row, int ix, char *str) {
gtk_clist_set_text(List, row, ix, str);
}
+
//void gtk_set_field_num(GtkCList *List, int row, int ix, char *format, int num) {
// changed int to dobule byMin
void gtk_set_field_num(GtkCList *List, int row, int ix, char *format, double num)
gtk_set_field(List, row, ix, str);
}
+
void gtk_update_row(GtkCList *List, int row)
{
- int addr;
+ ip_t *addr;
char str[256], *name;
GdkColor color;
GdkColormap *cmap;
addr = net_addr(row);
name = "???";
- if(addr != 0) {
+ if ( addrcmp( (void *) addr, (void *) &unspec_addr, af ) != 0 ) {
name = dns_lookup(addr);
if(!name) {
- sprintf(str, "%d.%d.%d.%d", (addr >> 24) & 0xff, (addr >> 16) & 0xff,
- (addr >> 8) & 0xff, addr & 0xff);
+ sprintf(str, "%s", strlongip( addr ));
name = str;
}
}
/* the row - net_min() is kind of not clean, need some more work */
gtk_set_field(List, row - net_min(), 0, name);
- gtk_set_field_num(List, row - net_min(), 1, "%.0f%%", net_loss(row)/1000.0);
+ gtk_set_field_num(List, row - net_min(), 1, "%.1f%%", net_loss(row)/1000.0);
gtk_set_field_num(List, row - net_min(), 2, "%.0f", net_returned(row));
gtk_set_field_num(List, row - net_min(), 3, "%.0f", net_xmit(row));
gtk_set_field_num(List, row - net_min(), 6, "%.0f", net_avg(row)/1000.0);
gtk_set_field_num(List, row - net_min(), 7, "%.0f", net_worst(row)/1000.0);
gtk_set_field_num(List, row - net_min(), 8, "%.2f", net_stdev(row)/1000.0);
-
}
-void gtk_redraw()
+
+void gtk_redraw(void)
{
int at = net_min(); // changed from 0 to net_min for TTL stuff byMin
int max = net_max();
gtk_clist_thaw(GTK_CLIST(ReportBody));
}
+
void Window_fill(GtkWidget *Window)
{
GtkWidget *VBox;
gtk_widget_show(VBox);
}
-void gtk_open()
+
+void gtk_open(void)
{
GtkWidget *Window;
GdkPixmap *icon;
gdk_window_set_icon_name(Window->window, "mtr");
}
-void gtk_close()
+
+void gtk_close(void)
{
}
-int gtk_keyaction()
+
+int gtk_keyaction(void)
{
return 0;
}
-gint gtk_ping(gpointer data)
+
+gint gtk_ping(UNUSED gpointer data)
{
gtk_redraw();
net_send_batch();
return TRUE;
}
-void gtk_net_data(gpointer data, gint fd, GdkInputCondition cond)
+
+void gtk_net_data(UNUSED gpointer data, UNUSED gint fd, UNUSED GdkInputCondition cond)
{
net_process_return();
}
-void gtk_dns_data(gpointer data, gint fd, GdkInputCondition cond)
+
+void gtk_dns_data(UNUSED gpointer data, UNUSED gint fd, UNUSED GdkInputCondition cond)
{
dns_ack();
-
gtk_redraw();
}
-void gtk_loop()
+void gtk_loop(void)
{
gtk_add_ping_timeout ();
gdk_input_add(net_waitfd(), GDK_INPUT_READ, gtk_net_data, NULL);
gtk_main();
}
+
+
*/
/* Prototypes for curses.c */
-void mtr_curses_open();
-void mtr_curses_close();
-void mtr_curses_redraw();
-int mtr_curses_keyaction();
-void mtr_curses_clear();
+void mtr_curses_open(void);
+void mtr_curses_close(void);
+void mtr_curses_redraw(void);
+int mtr_curses_keyaction(void);
+void mtr_curses_clear(void);
/* Prototypes for gtk.c */
int gtk_detect(int *argc, char ***argv);
-void gtk_open();
-void gtk_close();
-void gtk_redraw();
-int gtk_keyaction();
-void gtk_loop();
+void gtk_open(void);
+void gtk_close(void);
+void gtk_redraw(void);
+int gtk_keyaction(void);
+void gtk_loop(void);
.SH SYNOPSIS
.B mtr
[\c
-.B \-hvrctglsni\c
+.B \-hvrctglsni46\c
]
[\c
.B \-\-help\c
Use this option to specify the positive number of seconds between ICMP
ECHO requests. The default value for this parameter is one second.
+.TP
+.B \-4
+.br
+Use IPv4 only.
+
+.TP
+.B \-6
+.br
+Use IPv6 only.
+
.SH BUGS
Some modern routers give a lower priority to ICMP ECHO packets than
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
+#include <strings.h>
+#include "mtr.h"
#include "mtr-curses.h"
#include "getopt.h"
#include "display.h"
{ "address", 1, 0, 'a' },
{ "first-ttl", 1, 0, 'f' }, /* -f & -m are borrowed from traceroute */
{ "max-ttl", 1, 0, 'm' },
+ { "inet", 0, 0, '4' }, /* IPv4 only */
+ { "inet6", 0, 0, '6' }, /* IPv6 only */
{ 0, 0, 0, 0 }
};
while(1) {
/* added f:m:o: byMin */
opt = getopt_long(argc, argv,
- "vhrxtglpo:i:c:s:b:Q:na:f:m:", long_options, NULL);
+ "vhrxtglpo:i:c:s:b:Q:na:f:m:46", long_options, NULL);
if(opt == -1)
break;
tos = 0;
}
break;
+ case '4':
+ af = AF_INET;
+ break;
+ case '6':
+#ifdef ENABLE_IPV6
+ af = AF_INET6;
+ break;
+#else
+ fprintf( stderr, "IPv6 not enabled.\n" );
+ break;
+#endif
}
}
argv[0] = "mtr";
argc = 1;
p = strtok (string, " \t");
- while (p && (argc < (sizeof(argv)/sizeof(argv[0])))) {
+ while (p != NULL && ((size_t) argc < (sizeof(argv)/sizeof(argv[0])))) {
argv[argc++] = p;
p = strtok (NULL, " \t");
}
- if (p) {
+ if (p != NULL) {
fprintf (stderr, "Warning: extra arguments ignored: %s", p);
}
int main(int argc, char **argv)
{
- int traddr;
+ ip_t * traddr;
struct hostent * host = NULL;
int net_preopen_result;
+#ifdef ENABLE_IPV6
+ struct addrinfo hints, *res;
+ int error;
+ struct hostent trhost;
+ char * alptr[2];
+ struct sockaddr_in * sa4;
+ struct sockaddr_in6 * sa6;
+#endif
/* Get the raw sockets first thing, so we can drop to user euid immediately */
- net_preopen_result = net_preopen ();
+ if ( ( net_preopen_result = net_preopen () ) ) {
+ fprintf( stderr, "mtr: unable to get raw sockets.\n" );
+ exit( EXIT_FAILURE );
+ }
/* Now drop to user permissions */
if (setuid(getuid())) {
}
if (PrintHelp) {
- printf("usage: %s [-hvrctglsni] [--help] [--version] [--report]\n"
+ printf("usage: %s [-hvrctglsni46] [--help] [--version] [--report]\n"
"\t\t[--report-cycles=COUNT] [--curses] [--gtk]\n"
"\t\t[--raw] [--split] [--no-dns] [--address interface]\n" /* BL */
"\t\t[--psize=bytes/-p=bytes]\n" /* ok */
}
#ifdef ENABLE_IPV6
- if (af == AF_UNSPEC) {
- af = AF_INET6;
- host = gethostbyname2(Hostname, af);
- if (host == NULL) af = AF_INET;
+ /* gethostbyname2() is deprecated so we'll use getaddrinfo() instead. */
+ bzero( &hints, sizeof hints );
+ hints.ai_family = af;
+ hints.ai_socktype = SOCK_DGRAM;
+ error = getaddrinfo( Hostname, "0", &hints, &res );
+ if ( error ) {
+ perror( gai_strerror(error) );
+ exit( EXIT_FAILURE );
}
-#endif
-
- if (host == NULL) {
- host = gethostbyname(Hostname);
+ /* Convert the first addrinfo into a hostent. */
+ host = &trhost;
+ bzero( host, sizeof trhost );
+ host->h_name = res->ai_canonname;
+ host->h_aliases = NULL;
+ host->h_addrtype = res->ai_family;
+ af = res->ai_family;
+ host->h_length = res->ai_addrlen;
+ host->h_addr_list = alptr;
+ switch ( af ) {
+ case AF_INET:
+ sa4 = (struct sockaddr_in *) res->ai_addr;
+ alptr[0] = (void *) &(sa4->sin_addr);
+ break;
+ case AF_INET6:
+ sa6 = (struct sockaddr_in6 *) res->ai_addr;
+ alptr[0] = (void *) &(sa6->sin6_addr);
+ break;
+ default:
+ fprintf( stderr, "mtr unknown address type\n" );
+ exit( EXIT_FAILURE );
}
-
+ alptr[1] = NULL;
+#else
+ host = gethostbyname(Hostname);
if (host == NULL) {
- herror("mtr");
+ herror("mtr gethostbyname");
exit(1);
}
+ af = host->h_addrtype;
+#endif
- switch (af) {
- case AF_INET:
- traddr = *(int *)host->h_addr;
+ traddr = (ip_t *) host->h_addr;
- if (net_open(traddr) != 0) {
+ if (net_open(host) != 0) {
fprintf(stderr, "mtr: Unable to start net module.\n");
exit(1);
}
- break;
-#ifdef ENABLE_IPV6
- case AF_INET6:
- if(net6_open((struct in6_addr *)host->h_addr) != 0) {
- printf("mtr: Unable to get raw socket. (Executable not suid?)\n");
- exit(1);
- }
- break;
-#endif
- }
display_open();
dns_open();
--- /dev/null
+/*
+ mtr -- a network diagnostic tool
+ Copyright (C) 1997,1998 Matt Kimball
+ Copyright (C) 2005 R.E.Wolff@BitWizard.nl
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* Typedefs */
+
+typedef unsigned char byte;
+typedef unsigned short word;
+typedef unsigned long dword;
+
+#ifdef ENABLE_IPV6
+typedef struct in6_addr ip_t;
+#else
+typedef struct in_addr ip_t;
+#endif
+
+extern int dns;
+extern int use_dns;
+
+#ifdef __GNUC__
+#define UNUSED __attribute__((__unused__))
+#else
+#define UNUSED
+#endif
+
#include <stdlib.h>
#include <math.h>
#include <errno.h>
+#include <string.h>
+#include "mtr.h"
#include "net.h"
#include "display.h"
-
+#include "dns.h"
/* We can't rely on header files to provide this information, because
the fields have different names between, for instance, Linux and
#endif
struct nethost {
- uint32 addr;
- uint32 addrs[MAXPATH]; /* for multi paths byMin */
+ ip_t addr;
+ ip_t addrs[MAXPATH]; /* for multi paths byMin */
int xmit;
int returned;
int sent;
static struct timeval reset = { 0, 0 };
int timestamp;
+int sendsock4;
+int recvsock4;
+int sendsock6;
+int recvsock6;
int sendsock;
int recvsock;
-struct sockaddr_in sourceaddress;
-struct sockaddr_in remoteaddress;
+
+#ifdef ENABLE_IPV6
+struct sockaddr_storage sourcesockaddr_struct;
+struct sockaddr_storage remotesockaddr_struct;
+struct sockaddr_in6 * ssa6 = (struct sockaddr_in6 *) &sourcesockaddr_struct;
+struct sockaddr_in6 * rsa6 = (struct sockaddr_in6 *) &remotesockaddr_struct;
+#else
+struct sockaddr_in sourcesockaddr_struct;
+struct sockaddr_in remotesockaddr_struct;
+#endif
+
+struct sockaddr * sourcesockaddr = (struct sockaddr *) &sourcesockaddr_struct;
+struct sockaddr * remotesockaddr = (struct sockaddr *) &remotesockaddr_struct;
+struct sockaddr_in * ssa4 = (struct sockaddr_in *) &sourcesockaddr_struct;
+struct sockaddr_in * rsa4 = (struct sockaddr_in *) &remotesockaddr_struct;
+
+ip_t * sourceaddress;
+ip_t * remoteaddress;
/* XXX How do I code this to be IPV6 compatible??? -- REW */
-struct in_addr localaddr;
+#ifdef ENABLE_IPV6
+char localaddr[INET6_ADDRSTRLEN];
+#else
+#ifndef INET_ADDRSTRLEN
+#define INET_ADDRSTRLEN 16
+#endif
+char localaddr[INET_ADDRSTRLEN];
+#endif
static int batch_at = 0;
static int numhosts = 10;
extern int packetsize; /* packet size used by ping */
extern int bitpattern; /* packet bit pattern used by ping */
extern int tos; /* type of service set in ping packet*/
-
+extern int af; /* address family of remote target */
/* return the number of microseconds to wait before sending the next
{
/*ok char packet[sizeof(struct IPHeader) + sizeof(struct ICMPHeader)];*/
char packet[MAXPACKET];
- struct IPHeader *ip;
+ struct IPHeader *ip = (struct IPHeader *) packet;
struct ICMPHeader *icmp;
/*ok int packetsize = sizeof(struct IPHeader) + sizeof(struct ICMPHeader) + datasize;*/
int rv;
static int first=1;
+ int ttl, iphsize = 0, echotype = 0, salen = 0;
+
+ ttl = index + 1;
if ( packetsize < MINPACKET ) packetsize = MINPACKET;
if ( packetsize > MAXPACKET ) packetsize = MAXPACKET;
memset(packet, (unsigned char) abs(bitpattern), abs(packetsize));
- ip = (struct IPHeader *)packet;
- icmp = (struct ICMPHeader *)(packet + sizeof(struct IPHeader));
+ switch ( af ) {
+ case AF_INET:
+ iphsize = sizeof (struct IPHeader);
ip->version = 0x45;
ip->tos = tos;
ip->len = BSDfix ? abs(packetsize): htons (abs(packetsize));
ip->id = 0;
ip->frag = 0; /* 1, if want to find mtu size? Min */
- ip->ttl = index + 1;
+ ip->ttl = ttl;
ip->protocol = IPPROTO_ICMP;
ip->check = 0;
/* BSD needs the source address here, Linux & others do not... */
- ip->saddr = saddr_correction(sourceaddress.sin_addr.s_addr);
- ip->daddr = remoteaddress.sin_addr.s_addr;
+ addrcpy( (void *) &(ip->saddr), (void *) &(ssa4->sin_addr), AF_INET );
+ addrcpy( (void *) &(ip->daddr), (void *) remoteaddress, AF_INET );
+
+ echotype = ICMP_ECHO;
+ salen = sizeof (struct sockaddr_in);
+ break;
+#ifdef ENABLE_IPV6
+ case AF_INET6:
+ iphsize = 0;
+ if ( setsockopt( sendsock, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
+ &ttl, sizeof ttl ) ) {
+ perror( "setsockopt IPV6_UNICAST_HOPS" );
+ exit( EXIT_FAILURE);
+ }
+ echotype = ICMP6_ECHO_REQUEST;
+ salen = sizeof (struct sockaddr_storage);
+ break;
+#endif
+ }
- icmp->type = ICMP_ECHO;
+ icmp = (struct ICMPHeader *)(packet + iphsize);
+ icmp->type = echotype;
icmp->code = 0;
icmp->checksum = 0;
icmp->id = getpid();
icmp->sequence = new_sequence(index);
+ icmp->checksum = checksum(icmp, abs(packetsize) - iphsize);
- icmp->checksum = checksum(icmp, abs(packetsize) - sizeof(struct IPHeader));
- ip->check = checksum(ip, abs(packetsize));
+ switch ( af ) {
+ case AF_INET:
+ ip->check = checksum(packet, abs(packetsize));
+ break;
+ }
gettimeofday(&sequence[icmp->sequence].time, NULL);
+
rv = sendto(sendsock, packet, abs(packetsize), 0,
- (struct sockaddr *)&remoteaddress, sizeof(remoteaddress));
+ remotesockaddr, salen);
if (first && (rv < 0) && (errno == EINVAL)) {
ip->len = abs (packetsize);
rv = sendto(sendsock, packet, abs(packetsize), 0,
- (struct sockaddr *)&remoteaddress, sizeof(remoteaddress));
+ remotesockaddr, salen);
if (rv >= 0) {
fprintf (stderr, "You've got a broken (FreeBSD?) system\n");
BSDfix = 1;
/* We got a return on something we sent out. Record the address and
time. */
-void net_process_ping(int seq, uint32 addr, struct timeval now)
+void net_process_ping(int seq, void * addr, struct timeval now)
{
int index;
int totusec;
(now.tv_usec - sequence[seq].time.tv_usec);
/* impossible? if( totusec < 0 ) totusec = 0 */;
- if (host[index].addr == 0) {
- host[index].addr = addr; // should be out of if as addr can change
- display_rawhost(index, host[index].addr);
+ if ( addrcmp( (void *) &(host[index].addr),
+ (void *) &unspec_addr, af ) == 0 ) {
+ // should be out of if as addr can change
+ addrcpy( (void *) &(host[index].addr), addr, af );
+ display_rawhost(index, (void *) &(host[index].addr));
/* multi paths by Min */
- host[index].addrs[0] = addr;
+ addrcpy( (void *) &(host[index].addrs[0]), addr, af );
} else {
for( i=0; i<MAXPATH; ) {
- if( host[index].addrs[i] == addr || host[index].addrs[i] == 0 ) break;
+ if( addrcmp( (void *) &(host[index].addrs[i]), (void *) &addr,
+ af ) == 0 ||
+ addrcmp( (void *) &(host[index].addrs[i]),
+ (void *) &unspec_addr, af ) == 0 ) break;
i++;
}
- if( host[index].addrs[i] != addr && i<MAXPATH ) {
- host[index].addrs[i] = addr;
+ if( addrcmp( (void *) &(host[index].addrs[i]), addr, af ) != 0 &&
+ i<MAXPATH ) {
+ addrcpy( (void *) &(host[index].addrs[i]), addr, af );
}
/* end multi paths */
}
/* We know a packet has come in, because the main select loop has called us,
now we just need to read it, see if it is for us, and if it is a reply
to something we sent, then call net_process_ping() */
-void net_process_return()
+void net_process_return(void)
{
char packet[MAXPACKET];
- struct sockaddr_in fromaddr;
- int fromaddrsize;
+#ifdef ENABLE_IPV6
+ struct sockaddr_storage fromsockaddr_struct;
+ struct sockaddr_in6 * fsa6 = (struct sockaddr_in6 *) &fromsockaddr_struct;
+#else
+ struct sockaddr_in fromsockaddr_struct;
+#endif
+ struct sockaddr * fromsockaddr = (struct sockaddr *) &fromsockaddr_struct;
+ struct sockaddr_in * fsa4 = (struct sockaddr_in *) &fromsockaddr_struct;
+ int fromsockaddrsize;
int num;
- struct ICMPHeader *header;
+ struct ICMPHeader *header = NULL;
struct timeval now;
+ ip_t * fromaddress = NULL;
+ int echoreplytype = 0, timeexceededtype = 0;
gettimeofday(&now, NULL);
+ switch ( af ) {
+ case AF_INET:
+ fromsockaddrsize = sizeof (struct sockaddr_in);
+ fromaddress = (ip_t *) &(fsa4->sin_addr);
+ echoreplytype = ICMP_ECHOREPLY;
+ timeexceededtype = ICMP_TIME_EXCEEDED;
+ break;
+#ifdef ENABLE_IPV6
+ case AF_INET6:
+ fromsockaddrsize = sizeof (struct sockaddr_storage);
+ fromaddress = (ip_t *) &(fsa6->sin6_addr);
+ echoreplytype = ICMP6_ECHO_REPLY;
+ timeexceededtype = ICMP6_TIME_EXCEEDED;
+ break;
+#endif
+ }
- fromaddrsize = sizeof(fromaddr);
num = recvfrom(recvsock, packet, MAXPACKET, 0,
- (struct sockaddr *)&fromaddr, &fromaddrsize);
+ fromsockaddr, &fromsockaddrsize);
- if(num < sizeof(struct IPHeader) + sizeof(struct ICMPHeader))
- return;
+ switch ( af ) {
+ case AF_INET:
+ if((size_t) num < sizeof(struct IPHeader) + sizeof(struct ICMPHeader))
+ return;
+ header = (struct ICMPHeader *)(packet + sizeof(struct IPHeader));
+ break;
+#ifdef ENABLE_IPV6
+ case AF_INET6:
+ if(num < sizeof(struct ICMPHeader))
+ return;
- header = (struct ICMPHeader *)(packet + sizeof(struct IPHeader));
- if(header->type == ICMP_ECHOREPLY) {
+ header = (struct ICMPHeader *) packet;
+ break;
+#endif
+ }
+ if (header->type == echoreplytype) {
if(header->id != (uint16)getpid())
return;
- net_process_ping(header->sequence, fromaddr.sin_addr.s_addr, now);
- } else if(header->type == ICMP_TIME_EXCEEDED) {
- if(num < sizeof(struct IPHeader) + sizeof(struct ICMPHeader) +
- sizeof(struct IPHeader) + sizeof(struct ICMPHeader))
- return;
-
- header = (struct ICMPHeader *)(packet + sizeof(struct IPHeader) +
- sizeof(struct ICMPHeader) + sizeof(struct IPHeader));
- if(header->id != (uint16)getpid())
+ net_process_ping (header->sequence, (void *) fromaddress, now);
+ } else if (header->type == timeexceededtype) {
+ switch ( af ) {
+ case AF_INET:
+
+ if ((size_t) num < sizeof(struct IPHeader) +
+ sizeof(struct ICMPHeader) +
+ sizeof (struct IPHeader) +
+ sizeof (struct ICMPHeader))
+ return;
+ header = (struct ICMPHeader *)(packet + sizeof (struct IPHeader) +
+ sizeof (struct ICMPHeader) +
+ sizeof (struct IPHeader));
+ break;
+#ifdef ENABLE_IPV6
+ case AF_INET6:
+ if ( num < sizeof (struct ICMPHeader) +
+ sizeof (struct ip6_hdr) + sizeof (struct ICMPHeader) )
+ return;
+ header = (struct ICMPHeader *) ( packet +
+ sizeof (struct ICMPHeader) +
+ sizeof (struct ip6_hdr) );
+ break;
+#endif
+ }
+
+ if (header->id != (uint16)getpid())
return;
- net_process_ping(header->sequence, fromaddr.sin_addr.s_addr, now);
+ net_process_ping(header->sequence, (void *)fromaddress, now);
}
}
-int net_addr(int at) {
- return ntohl(host[at].addr);
+ip_t *net_addr(int at)
+{
+ return (ip_t *)&(host[at].addr);
}
-int net_addrs(int at, int i) {
- return ntohl(host[at].addrs[i]);
+ip_t *net_addrs(int at, int i)
+{
+ return (ip_t *)&(host[at].addrs[i]);
}
-
int net_loss(int at)
{
if ((host[at].xmit - host[at].transit) == 0)
/* end jitter */
-int net_max()
+int net_max(void)
{
int at;
int max;
// replacedByMin
// for(at = 0; at < MaxHost-2; at++) {
for(at = 0; at < maxTTL-1; at++) {
- if(host[at].addr == remoteaddress.sin_addr.s_addr) {
+ if ( addrcmp( (void *) &(host[at].addr),
+ (void *) remoteaddress, af ) == 0 ) {
return at + 1;
- } else if(host[at].addr != 0) {
+ } else if ( addrcmp( (void *) &(host[at].addr),
+ (void *) &unspec_addr, af ) != 0 ) {
max = at + 2;
}
}
/* add by Min (wonder its named net_min;-)) because of ttl stuff */
-int net_min ()
+int net_min (void)
{
return ( fstTTL - 1 );
}
}
-struct in_addr *net_localaddr (void)
+char * net_localaddr (void)
{
- return &localaddr;
+ return localaddr;
}
-void net_end_transit()
+void net_end_transit(void)
{
int at;
}
}
-int net_send_batch()
+int net_send_batch(void)
{
int n_unknown=0, i;
net_send_query(batch_at);
for (i=fstTTL-1;i<batch_at;i++) {
- if (host[i].addr == 0)
+ if ( addrcmp( (void *) &(host[i].addr), (void *) &unspec_addr, af ) == 0 )
n_unknown++;
/* The second condition in the next "if" statement was added in mtr-0.56,
hosts. Removed in 0.65.
If the line proves neccesary, it should at least NOT trigger that line
when host[i].addr == 0 -- REW */
- if ((host[i].addr == remoteaddress.sin_addr.s_addr)
+ if ( ( addrcmp( (void *) &(host[i].addr),
+ (void *) remoteaddress, af ) == 0 )
/* || (host[i].addr == host[batch_at].addr) */)
n_unknown = MaxHost; /* Make sure we drop into "we should restart" */
}
if ( // success in reaching target
- (host[batch_at].addr == remoteaddress.sin_addr.s_addr) ||
+ ( addrcmp( (void *) &(host[batch_at].addr),
+ (void *) remoteaddress, af ) == 0 ) ||
// fail in consecuitive MAX_UNKNOWN_HOSTS (firewall?)
(n_unknown > MAX_UNKNOWN_HOSTS) ||
// or reach limit
}
-int net_preopen()
+int net_preopen(void)
{
int trueopt = 1;
- sendsock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
- if (sendsock < 0)
+ sendsock4 = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
+ if (sendsock4 < 0)
+ return -1;
+#ifdef ENABLE_IPV6
+ sendsock6 = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
+ if (sendsock6 < 0)
return -1;
+#endif
#ifdef IP_HDRINCL
/* FreeBSD wants this to avoid sending out packets with protocol type RAW
to the network. */
- if (setsockopt(sendsock, SOL_IP, IP_HDRINCL, &trueopt, sizeof(trueopt))) {
+ if (setsockopt(sendsock4, SOL_IP, IP_HDRINCL, &trueopt, sizeof(trueopt))) {
perror("setsockopt(IP_HDRINCL,1)");
return -1;
}
-#endif
+#endif /* IP_HDRINCL */
- recvsock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
- if (recvsock < 0)
+ recvsock4 = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
+ if (recvsock4 < 0)
return -1;
+#ifdef ENABLE_IPV6
+ recvsock6 = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
+ if (recvsock6 < 0)
+ return -1;
+#endif
return 0;
}
-int net_open(int addr)
+int net_open(struct hostent * host)
{
- struct sockaddr_in name;
+#ifdef ENABLE_IPV6
+ struct sockaddr_storage name_struct;
+#else
+ struct sockaddr_in name_struct;
+#endif
+ struct sockaddr * name = (struct sockaddr *) &name_struct;
int len;
net_reset();
- remoteaddress.sin_family = AF_INET;
- remoteaddress.sin_addr.s_addr = addr;
+ remotesockaddr->sa_family = host->h_addrtype;
+
+ switch ( host->h_addrtype ) {
+ case AF_INET:
+ sendsock = sendsock4;
+ recvsock = recvsock4;
+ addrcpy( (void *) &(rsa4->sin_addr), host->h_addr, AF_INET );
+ sourceaddress = (ip_t *) &(ssa4->sin_addr);
+ remoteaddress = (ip_t *) &(rsa4->sin_addr);
+ break;
+#ifdef ENABLE_IPV6
+ case AF_INET6:
+ sendsock = sendsock6;
+ recvsock = recvsock6;
+ addrcpy( (void *) &(rsa6->sin6_addr), host->h_addr, AF_INET6 );
+ sourceaddress = (ip_t *) &(ssa6->sin6_addr);
+ remoteaddress = (ip_t *) &(rsa6->sin6_addr);
+ break;
+#endif
+ default:
+ fprintf( stderr, "net_open bad address type\n" );
+ exit( EXIT_FAILURE );
+ }
- len = sizeof (name);
- getsockname (recvsock, (struct sockaddr *)&name, &len);
- localaddr = name.sin_addr;
+ len = sizeof name_struct;
+ getsockname (recvsock, name, &len);
+ sockaddrtop( name, localaddr, sizeof localaddr );
#if 0
- printf ("got localaddr: %x\n", *(int *)&localaddr);
+ printf ("got localaddr: %s\n", localaddr);
#endif
return 0;
}
-void net_reopen(int addr)
+void net_reopen(struct hostent * addr)
{
int at;
memset(&host[at], 0, sizeof(host[at]));
}
- remoteaddress.sin_family = AF_INET;
- remoteaddress.sin_addr.s_addr = addr;
+ remotesockaddr->sa_family = addr->h_addrtype;
+
+ switch ( addr->h_addrtype ) {
+ case AF_INET:
+ addrcpy( (void *) remoteaddress, addr->h_addr, AF_INET );
+ break;
+#ifdef ENABLE_IPV6
+ case AF_INET6:
+ addrcpy( (void *) &(rsa6->sin6_addr), addr->h_addr, AF_INET6 );
+ break;
+#endif
+ default:
+ fprintf( stderr, "net_reopen bad address type\n" );
+ exit( EXIT_FAILURE );
+ }
net_reset ();
net_send_batch();
}
-void net_reset()
+void net_reset(void)
{
int at;
int i;
if (!InterfaceAddress) return 0;
- sourceaddress.sin_family = AF_INET;
- sourceaddress.sin_port = 0;
- sourceaddress.sin_addr.s_addr = 0;
+ sourcesockaddr->sa_family = af;
+ switch ( af ) {
+ case AF_INET:
+ ssa4->sin_port = 0;
+ ssa4->sin_addr.s_addr = 0;
if(sscanf(InterfaceAddress, "%u.%u.%u.%u%c", &i1, &i2, &i3, &i4, &dummy) != 4) {
printf("mtr: bad interface address: %s\n", InterfaceAddress);
exit(1);
}
- ((unsigned char*)&sourceaddress.sin_addr)[0] = i1;
- ((unsigned char*)&sourceaddress.sin_addr)[1] = i2;
- ((unsigned char*)&sourceaddress.sin_addr)[2] = i3;
- ((unsigned char*)&sourceaddress.sin_addr)[3] = i4;
+ ((unsigned char*)&ssa4->sin_addr)[0] = i1;
+ ((unsigned char*)&ssa4->sin_addr)[1] = i2;
+ ((unsigned char*)&ssa4->sin_addr)[2] = i3;
+ ((unsigned char*)&ssa4->sin_addr)[3] = i4;
+ break;
+#ifdef ENABLE_IPV6
+ case AF_INET6:
+ ssa6->sin6_port = 0;
+ inet_pton( af, InterfaceAddress, &(ssa6->sin6_addr) );
+ break;
+#endif
+ }
- if(bind(sendsock, (struct sockaddr*)&sourceaddress, sizeof(sourceaddress)) == -1) {
+ if (bind(sendsock, sourcesockaddr, sizeof sourcesockaddr_struct) == -1) {
perror("mtr: failed to bind to interface");
exit(1);
}
-void net_close()
+void net_close(void)
{
close(sendsock);
close(recvsock);
}
-int net_waitfd()
+int net_waitfd(void)
{
return recvsock;
}
-int* net_saved_pings(int at)
+int* net_saved_pings(int at)
{
return host[at].saved;
}
-void net_save_increment()
+void net_save_increment(void)
{
int at;
for (at = 0; at < MaxHost; at++) {
}
-void net_save_xmit(int at)
+void net_save_xmit(int at)
{
if (host[at].saved[SAVED_PINGS-1] != -2)
net_save_increment();
}
-void net_save_return(int at, int seq, int ms)
+void net_save_return(int at, int seq, int ms)
{
int idx;
idx = seq - host[at].saved_seq_offset;
}
host[at].saved[idx] = ms;
}
+
+/* Similar to inet_ntop but uses a sockaddr as it's argument. */
+void sockaddrtop( struct sockaddr * saddr, char * strptr, size_t len ) {
+ struct sockaddr_in * sa4;
+#ifdef ENABLE_IPV6
+ struct sockaddr_in6 * sa6;
+#endif
+
+ switch ( saddr->sa_family ) {
+ case AF_INET:
+ sa4 = (struct sockaddr_in *) saddr;
+ strncpy( strptr, inet_ntoa( (struct in_addr) sa4->sin_addr ), len );
+ return;
+#ifdef ENABLE_IPV6
+ case AF_INET6:
+ sa6 = (struct sockaddr_in6 *) saddr;
+ inet_ntop( sa6->sin6_family, &(sa6->sin6_addr), strptr, len );
+ return;
+#endif
+ default:
+ fprintf( stderr, "sockaddrtop unknown address type\n" );
+ strptr[0] = '\0';
+ return;
+ }
+}
+
+/* Address comparison. */
+int addrcmp( char * a, char * b, int af ) {
+ int rc = -1;
+
+ switch ( af ) {
+ case AF_INET:
+ rc = memcmp( a, b, sizeof (struct in_addr) );
+ break;
+#ifdef ENABLE_IPV6
+ case AF_INET6:
+ rc = memcmp( a, b, sizeof (struct in6_addr) );
+ break;
+#endif
+ }
+
+ return rc;
+}
+
+/* Address copy. */
+void addrcpy( char * a, char * b, int af ) {
+
+ switch ( af ) {
+ case AF_INET:
+ memcpy( a, b, sizeof (struct in_addr) );
+ break;
+#ifdef ENABLE_IPV6
+ case AF_INET6:
+ memcpy( a, b, sizeof (struct in6_addr) );
+ break;
+#endif
+ }
+}
*/
/* Prototypes for functions in net.c */
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#ifdef ENABLE_IPV6
+#include <netinet/ip6.h>
+#include <netinet/icmp6.h>
+#endif
-int net_preopen();
-int net_open(int address);
-void net_reopen(int address);
+int net_preopen(void);
+int net_open(struct hostent *host);
+void net_reopen(struct hostent *address);
int net_set_interfaceaddress (char *InterfaceAddress);
-void net_reset();
-void net_close();
-int net_waitfd();
-void net_process_return();
+void net_reset(void);
+void net_close(void);
+int net_waitfd(void);
+void net_process_return(void);
int net_max(void);
int net_min(void);
int net_last(int at);
-int net_addr(int at);
+#ifdef ENABLE_IPV6
+struct in6_addr * net_addr(int at);
+#else
+struct in_addr * net_addr(int at);
+#endif
int net_loss(int at);
int net_drop(int at);
int net_last(int at);
int net_jworst(int at);
int net_javg(int at);
int net_jinta(int at);
-int net_addrs(int at, int i);
-struct in_addr *net_localaddr(void);
+#ifdef ENABLE_IPV6
+struct in6_addr * net_addrs(int at, int i);
+#else
+struct in_addr * net_addrs(int at, int i);
+#endif
+char *net_localaddr(void);
-int net_send_batch();
-void net_end_transit();
+int net_send_batch(void);
+void net_end_transit(void);
int calc_deltatime (float WaitTime);
void net_save_return(int at, int seq, int ms);
int net_duplicate(int at, int seq);
+void sockaddrtop( struct sockaddr * saddr, char * strptr, size_t len );
+int addrcmp( char * a, char * b, int af );
+void addrcpy( char * a, char * b, int af );
+
#define MAXPATH 8
#define MaxHost 256
#define MaxSequence 65536
extern unsigned char fld_active[];
extern char available_options[];
+#ifdef ENABLE_IPV6
+struct in6_addr unspec_addr;
+#else
+struct in_addr unspec_addr;
+#endif
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include <config.h>
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
+#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
+#include "mtr.h"
#include "raw.h"
#include "net.h"
#include "dns.h"
static int havename[MaxHost];
+extern int af;
+
#if 0
-static char *addr_to_str(int addr)
+static char *addr_to_str(ip_t addr)
{
static char buf[20];
- sprintf (buf, "%d.%d.%d.%d",
- (addr >> 0) & 0xff,
- (addr >> 8) & 0xff,
- (addr >> 16) & 0xff,
- (addr >> 24) & 0xff);
+ sprintf (buf, "%s", strlongip( &addr ));
return buf;
}
#endif
}
-void raw_rawhost (int host, int ip_addr)
+void raw_rawhost (int host, ip_t * ip_addr)
{
- struct in_addr in;
-
- in.s_addr = ip_addr;
-
- printf ("h %d %s\n",
- host, inet_ntoa(in));
+ printf ("h %d %s\n", host, strlongip( ip_addr ));
fflush (stdout);
}
-
-
-
-
/* Prototypes for raw.c */
void raw_rawping(int host, int msec);
-void raw_rawhost(int host, int addr);
+#ifdef ENABLE_IPV6
+void raw_rawhost(int host, struct in6_addr * addr);
+#else
+void raw_rawhost(int host, struct in_addr * addr);
+#endif
#include <netinet/in.h>
#include <sys/socket.h>
#include <string.h>
+#include <strings.h>
+#include "mtr.h"
#include "report.h"
#include "net.h"
+#include "dns.h"
extern int dns;
extern char LocalHostname[];
extern int bitpattern;
extern int tos;
extern int MaxPing;
+extern int af;
-void report_open() {}
-void report_close() {
- int i, j, at, max, addr;
- int haddr;
+void report_open(void)
+{
+}
+
+
+void report_close(void)
+{
+ int i, j, at, max;
+ ip_t *addr;
char name[81];
char buf[1024];
char fmt[16];
for(; at < max; at++) {
addr = net_addr(at);
- if(addr == 0) {
+ if( addrcmp( (void *) addr, (void *) &unspec_addr, af ) == 0 ) {
sprintf(name, "???");
} else {
- haddr = htonl(addr);
- host = dns?gethostbyaddr((char *)&haddr, sizeof(int), AF_INET):NULL;
+ host = dns?gethostbyaddr( (void *) addr, sizeof(int), AF_INET):NULL;
if (host != NULL) {
strncpy(name, host->h_name, 80);
name[80] = 0;
} else {
- sprintf(name, "%d.%d.%d.%d", (addr >> 24) & 0xff, (addr >> 16) & 0xff,
- (addr >> 8) & 0xff, addr & 0xff);
+ sprintf(name, "%s", strlongip( addr ) );
}
}
printf("%s\n",buf);
}
}
-void txt_open() {}
-void txt_close() { report_close(); }
+void txt_open(void)
+{
+}
+
+
+void txt_close(void)
+{
+ report_close();
+}
+
+
+
+void xml_open(void)
+{
+}
+
-void xml_open() {}
-void xml_close() {
- int i, j, at, max, addr;
- int haddr;
+void xml_close(void)
+{
+ int i, j, at, max;
+ ip_t *addr;
char name[81];
struct hostent *host;
for(; at < max; at++) {
addr = net_addr(at);
- if(addr == 0) {
+ if( addrcmp( (void *) addr, (void *) &unspec_addr, af ) == 0 ) {
sprintf(name, "???");
} else {
- haddr = htonl(addr);
- host = dns?gethostbyaddr((char *)&haddr, sizeof(int), AF_INET):NULL;
+ host = dns?gethostbyaddr( (void *) addr, sizeof(int), AF_INET):NULL;
if (host != NULL) {
strncpy(name, host->h_name, 80);
name[80] = 0;
} else {
- sprintf(name, "%d.%d.%d.%d", (addr >> 24) & 0xff, (addr >> 16) & 0xff,
- (addr >> 8) & 0xff, addr & 0xff);
+ sprintf(name, "%s", strlongip( addr ) );
}
}
printf("</MTR>\n");
}
-void csv_open() {}
-void csv_close() {
- int i, j, at, max, addr;
- int haddr;
+
+void csv_open(void)
+{
+}
+
+
+void csv_close(void)
+{
+ int i, j, at, max;
+ ip_t *addr;
char name[81];
struct hostent *host;
for(; at < max; at++) {
addr = net_addr(at);
- if(addr == 0) {
+ if( addrcmp( (void *) addr, (void *) &unspec_addr, af ) == 0 ) {
sprintf(name, "???");
} else {
- haddr = htonl(addr);
- host = dns?gethostbyaddr((char *)&haddr, sizeof(int), AF_INET):NULL;
+ host = dns?gethostbyaddr( (void *) addr, sizeof(int), AF_INET):NULL;
if (host != NULL) {
strncpy(name, host->h_name, 80);
name[80] = 0;
} else {
- sprintf(name, "%d.%d.%d.%d", (addr >> 24) & 0xff, (addr >> 16) & 0xff,
- (addr >> 8) & 0xff, addr & 0xff);
+ sprintf(name, "%s", strlongip( addr ) );
}
}
/* Prototypes for report.h */
-void report_open();
-void report_close();
-void txt_open();
-void txt_close();
-void xml_open();
-void xml_close();
-void csv_open();
-void csv_close();
+void report_open(void);
+void report_close(void);
+void txt_open(void);
+void txt_close(void);
+void xml_open(void);
+void xml_close(void);
+void csv_open(void);
+void csv_close(void);
#include <math.h>
#include <errno.h>
+#include "mtr.h"
#include "display.h"
#include "dns.h"
#include "net.h"
int display_offset = 0;
-void select_loop() {
+void select_loop(void) {
fd_set readfd;
int anyset = 0;
int maxfd = 0;
selecttime.tv_usec += 1000000;
}
- if ((selecttime.tv_sec > (time_t)dnsinterval) ||
- ((selecttime.tv_sec == (time_t)dnsinterval) &&
- (selecttime.tv_usec > ((time_t)(dnsinterval * 1000000) % 1000000)))) {
- selecttime.tv_sec = (time_t)dnsinterval;
- selecttime.tv_usec = (time_t)(dnsinterval * 1000000) % 1000000;
+ if (dns) {
+ if ((selecttime.tv_sec > (time_t)dnsinterval) ||
+ ((selecttime.tv_sec == (time_t)dnsinterval) &&
+ (selecttime.tv_usec > ((time_t)(dnsinterval * 1000000) % 1000000)))) {
+ selecttime.tv_sec = (time_t)dnsinterval;
+ selecttime.tv_usec = (time_t)(dnsinterval * 1000000) % 1000000;
+ }
}
rv = select(maxfd, (void *)&readfd, NULL, NULL, &selecttime);
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-void select_loop();
+void select_loop(void);
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include <config.h>
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
+#include <sys/types.h>
+#include "mtr.h"
#include "display.h"
#include "dns.h"
#include "net.h"
#include "split.h"
-
-#include <config.h>
-
#ifdef NO_CURSES
#include <sys/time.h>
#include <sys/types.h>
extern char *Hostname;
extern int WaitTime;
+extern int af;
/* There is 256 hops max in the IP header (coded with a byte) */
#define MAX_LINE_COUNT 256
#define DEBUG 0
-void
-split_redraw() {
+
+void split_redraw(void)
+{
int max;
int at;
- int addr;
+ ip_t *addr;
char *name;
char newLine[MAX_LINE_SIZE];
int i;
for(at = 0; at < max; at++) {
addr = net_addr(at);
- if(addr != 0) {
+ if( addrcmp( (void *) addr, (void *) &unspec_addr, af ) != 0 ) {
name = dns_lookup(addr);
if(name != NULL) {
/* May be we should test name's length */
net_best(at) /1000, net_avg(at)/1000,
net_worst(at)/1000);
} else {
- sprintf(newLine, "%d.%d.%d.%d %d %d %d %d %d %d",
- (addr >> 24) & 0xff, (addr >> 16) & 0xff,
- (addr >> 8) & 0xff, addr & 0xff,
+ sprintf(newLine, "%s %d %d %d %d %d %d",
+ strlongip( addr ),
net_loss(at),
net_returned(at), net_xmit(at),
net_best(at) /1000, net_avg(at)/1000,
}
}
-void
-split_open() {
+
+void split_open(void)
+{
int i;
#if DEBUG
printf("split_open()\n");
}
}
-void
-split_close() {
+
+void split_close(void)
+{
#if DEBUG
printf("split_close()\n");
#endif
}
-int
-split_keyaction() {
+
+int split_keyaction(void)
+{
#ifdef NO_CURSES
fd_set readfds;
struct timeval tv;
*/
/* Prototypes for split.c */
-void split_open();
-void split_close();
-void split_redraw();
-int split_keyaction();
+void split_open(void);
+void split_close(void);
+void split_redraw(void);
+int split_keyaction(void);