From 0697fbe70740022b207b3c9bf93e4316db64a1b2 Mon Sep 17 00:00:00 2001 From: Roger Wolff Date: Tue, 19 Aug 2008 00:00:00 +0000 Subject: [PATCH] mtr v0.74 - Martin Pels' patch to allow UDP probes. - KES reported a build problem. Turns out I need to install gtk-1.2 on my development sytem, otherwise my release script causes the build to break. - changed some docs to advertise the new mailing list. added documentation for the Mac OS X compilation problem. added -Wno-pointer-sign to the compiler options. - Nico Lichtmaier's cleanup-gtk patch. (now mtr uses a more modern dialect of gtk). source: ftp://ftp.bitwizard.nl/mtr/mtr-0.74.tar.gz --- NEWS | 12 ++ README | 35 +++-- configure.in | 39 ++--- curses.c | 15 +- dns.c | 12 +- dns.h | 2 +- gtk.c | 397 +++++++++++++++++++++++++++++---------------------- mtr.8 | 7 +- mtr.c | 17 ++- mtr.h | 36 +++++ net.c | 278 +++++++++++++++++++++++++++++------- net.h | 7 +- 12 files changed, 586 insertions(+), 271 deletions(-) diff --git a/NEWS b/NEWS index faeeb60..58de1fb 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,16 @@ WHAT'S NEW? + v0.74 Martin Pels' patch to allow UDP probes. + KES reported a build problem. Turns out I need to install gtk-1.2 + on my development sytem, otherwise my release script causes the + build to break. + changed some docs to advertise the new mailing list. + added documentation for the Mac OS X compilation problem. + added -Wno-pointer-sign to the compiler options. + Nico Lichtmaier's cleanup-gtk patch. (now mtr uses a more modern + dialect of gtk). + v0.73 Some securty patches. Although MTR drops privileges as soon + as possible after opening the sockets, it still had some + sprintf calls, which have now been converted into snprintf. v0.72 Fix signed/unsigned bug in IPV6 part improved random packet size behaviour. --REW v0.71 Some IPV6 fixes, introduce packet size cmdline option. diff --git a/README b/README index b35de7d..1eca21c 100644 --- a/README +++ b/README @@ -32,14 +32,10 @@ INSTALLING Note that mtr must be suid-root because it requires access to raw IP sockets. See SECURITY for security information. - If you want to build a version that doesn't use GTK, but if you - DO have GTK installed, you can use - - ./configure --with-gtk-prefix=/we_dont_want_gtk_so_we_use_a_name_that_certainly_doesnt_exist - - It seems the --no_gtk (whatever) doesn't work. Feel free to submit - a patch for this, I'm not that familiar with autoconf (it works for - me :-). + Older versions used to require a non-existant path to GTK for a + correct build of a non-gtk version while GTK was installed. This is + no longer neccesary. ./configure --WITHOUT_GTK should now work. + If it doesn't, try "make WITHOUT_X11=YES" as the make step. On Solaris (and possibly other systems) the "gtk" library may be installed in a directory where the dynamic linker refuses to look when @@ -59,6 +55,11 @@ INSTALLING doing the linking into a terminal window, and add "-lcurses" by hand. Then it will link. Help on how to catch this in autoconf appreciated. + On Mac OS X the nameserver8_compat.h needs to be included. I put the + include inside an "#if 0" section in the file "dns.c". If someone + knows how to make this automatic using autoconf / the configure script, + please tell me.... + WHERE CAN I GET THE LATEST VERSION OR MORE INFORMATION? @@ -67,16 +68,20 @@ WHERE CAN I GET THE LATEST VERSION OR MORE INFORMATION? Subscribe to the mtr mailing list. All mtr related announcements are posted to the mtr mailing list. To subscribe, send email to - 'majordomo@lists.xmission.com' with 'subscribe mtr' in the body of - the message. To send a message to the mailing list, mail to - 'mtr@lists.xmission.com'. + the 'mtr-subscribe' with the hostname part set to 'BitWizard.nl'. + The body or subject of the message doesn't matter. To send an + Email to the list, mail to the username part set to 'mtr'. To + prevent SPAM to this list, please don't put the full name on + the internet. - Bug reports and feature requests should be submitted into the - jitterbug bug-tracking system at http://www.BitWizard.nl/cgi-bin/mtr . - If you don't have web-access, mail the mailinglist. + Bug reports and feature requests should be submitted the mailing + list. Patches can be submitted by Email to me, or submitted to the - bug tracking system. Please use unified diffs. + mailing list. Please use unified diffs. Usually the diff is sort of + messy, so please check that the diff is clean and doesn't contain too + much of your local stuff (for example, I don't want/need the "configure" + script that /your/ automake made for you). -- REW diff --git a/configure.in b/configure.in index 2f89aa7..b9b23f8 100644 --- a/configure.in +++ b/configure.in @@ -1,5 +1,5 @@ AC_INIT(mtr.c) -AM_INIT_AUTOMAKE(mtr, 0.73) +AM_INIT_AUTOMAKE(mtr, 0.74) AC_SUBST(GTK_OBJ) @@ -29,7 +29,7 @@ AC_CHECK_FUNC(initscr, , AC_CHECK_LIB(curses, initscr, , AC_CHECK_LIB(cursesX, initscr, , AC_MSG_WARN(Building without curses display support) - AC_DEFINE(NO_CURSES) + AC_DEFINE(NO_CURSES, 1, Define if you don't have the curses libraries available.) CURSES_OBJ=)))) AC_CHECK_FUNCS(attron) @@ -45,28 +45,16 @@ AC_ARG_WITH(gtk, [ --without-gtk Do not try to use GTK+ at all], WANTS_GTK=$withval, WANTS_GTK=yes) -AC_ARG_ENABLE(gtk2, -[ --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" + AM_PATH_GTK_2_0(2.4.0, CFLAGS="$CFLAGS $GTK_CFLAGS" LIBS="$LIBS $GTK_LIBS -lm", AC_MSG_WARN(Building without GTK2 display support) - AC_DEFINE(NO_GTK) - GTK_OBJ="") - else - AM_PATH_GTK(1.0.0, CFLAGS="$CFLAGS $GTK_CFLAGS" - LIBS="$LIBS $GTK_LIBS", - AC_MSG_WARN(Building without GTK+ display support) - AC_DEFINE(NO_GTK) + AC_DEFINE(NO_GTK, 1, [Define if you don't have the GTK+ libraries available.]) GTK_OBJ="") - fi else AC_DEFINE(NO_GTK) GTK_OBJ="" @@ -95,8 +83,8 @@ AC_CHECK_FUNC(res_mkquery, , # removing it hurts your OS.... -- REW #LIBS="$LIBS -lresolv" -AC_CHECK_FUNC(herror, , AC_DEFINE(NO_HERROR)) -AC_CHECK_FUNC(strerror, , AC_DEFINE(NO_STRERROR)) +AC_CHECK_FUNC(herror, , AC_DEFINE(NO_HERROR, 1, [Define if you don't have the herror() function available.])) +AC_CHECK_FUNC(strerror, , AC_DEFINE(NO_STRERROR, 1, [Define if you don't have the strerror() function available.])) AC_CHECK_FUNC(getaddrinfo, [if test "$WANTS_IPV6" = "yes"; then @@ -119,25 +107,23 @@ AC_CHECK_TYPE(struct in_addr, AC_DEFINE([HAVE_STRUCT_INADDR], [], [Define if you dnl Add C flags to display more warnings AC_MSG_CHECKING(for C flags to get more warnings) ac_save_CFLAGS="$CFLAGS" -if test "x$ac_cv_prog_gcc" = "xyes" ; then +if test "x$ac_cv_c_compiler_gnu" = "xyes" ; then dnl gcc is the easiest C compiler - warning_CFLAGS="-Wall" + warning_CFLAGS="-Wall -Wno-pointer-sign" else dnl Vendor supplied C compilers are a bit tricky case "$host_os" in dnl SGI IRIX with the MipsPRO C compiler irix*) CFLAGS="$CFLAGS -fullwarn" - AC_TRY_COMPILE([#include ],[printf("test");], - warning_CFLAGS="-fullwarn",) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[printf("test");]])],[warning_CFLAGS="-fullwarn"],[]) ;; dnl SunOS 4.x with the SparcWorks(?) acc compiler sunos*) if "$CC" = "acc" ; then CFLAGS="$CFLAGS -vc" - AC_TRY_COMPILE([#include ],[printf("test");], - warning_CFLAGS="-vc",) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], [[printf("test");]])],[warning_CFLAGS="-vc"],[]) fi ;; @@ -158,6 +144,7 @@ fi -AM_CONFIG_HEADER(config.h) -AC_OUTPUT(Makefile img/Makefile) +AC_CONFIG_HEADERS([config.h]) +AC_CONFIG_FILES([Makefile img/Makefile]) +AC_OUTPUT diff --git a/curses.c b/curses.c index 23c3b4e..db4209d 100644 --- a/curses.c +++ b/curses.c @@ -76,6 +76,7 @@ extern int bitpattern; extern int tos; extern float WaitTime; extern int af; +extern int mtrtype; void pwcenter(char *str) { @@ -247,6 +248,17 @@ int mtr_curses_keyaction(void) } return ActionNone; } + if (tolower(c) == 'u') { + switch ( mtrtype ) { + case IPPROTO_ICMP: + mtrtype = IPPROTO_UDP; + break; + case IPPROTO_UDP: + mtrtype = IPPROTO_ICMP; + break; + } + return ActionNone; + } /* reserve to display help message -Min */ if (tolower(c) == '?'|| tolower(c) == 'h') { mvprintw(2, 0, "Command:\n" ); @@ -261,7 +273,8 @@ int mtr_curses_keyaction(void) printw(" m set the max time-to-live, default n= # of hops\n" ); printw(" s set the packet size to n or random(n<0)\n" ); printw(" b set ping bit pattern to c(0..255) or random(c<0)\n" ); - printw(" Q set ping packet's TOS to t\n\n\n" ); + printw(" Q 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..." ); getch(); /* get any key */ diff --git a/dns.c b/dns.c index 9c48b45..70ad17f 100644 --- a/dns.c +++ b/dns.c @@ -32,6 +32,7 @@ #include #include #include + #define BIND_8_COMPAT #include #include @@ -49,6 +50,15 @@ #include "dns.h" #include "net.h" +/* OSX Needs this. I don't know how to enable this for them automatically. + * Should be easy with autoconf. Please submit a patch if you know + * autoconf.... -- REW + */ +#if 0 +#include "nameser8_compat.h" +#endif + + #ifdef NO_STRERROR extern int sys_nerr; extern char *sys_errlist[]; @@ -453,7 +463,7 @@ int longipstr( char *s, ip_t *dst, int af ) } -struct hostent * dns_forward(char *name) +struct hostent * dns_forward(const char *name) { struct hostent *host; diff --git a/dns.h b/dns.h index e33c2d2..47ed4be 100644 --- a/dns.h +++ b/dns.h @@ -28,7 +28,7 @@ void dns_ack(void); void dns_events(double *sinterval); char *dns_lookup(ip_t * address); char *dns_lookup2(ip_t * address); -struct hostent * dns_forward(char *name); +struct hostent * dns_forward(const char *name); char *strlongip(ip_t * ip); void addr2ip6arpa( ip_t * ip, char * buf ); diff --git a/gtk.c b/gtk.c index 356a271..6a4f8a9 100644 --- a/gtk.c +++ b/gtk.c @@ -56,7 +56,7 @@ void gtk_add_ping_timeout (void) int dt; dt = calc_deltatime (WaitTime); - tag = gtk_timeout_add(dt / 1000, gtk_ping, NULL); + tag = g_timeout_add(dt / 1000, gtk_ping, NULL); } @@ -109,7 +109,7 @@ gint Pause_clicked(UNUSED GtkWidget *Button, UNUSED gpointer data) if (paused) { gtk_add_ping_timeout (); } else { - gtk_timeout_remove (tag); + g_source_remove (tag); } paused = ! paused; gtk_redraw(); @@ -129,8 +129,8 @@ gint Pause_clicked(UNUSED GtkWidget *Button, UNUSED gpointer data) 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); + WaitTime = gtk_spin_button_get_value(GTK_SPIN_BUTTON(Button)); + g_source_remove (tag); gtk_add_ping_timeout (); gtk_redraw(); @@ -147,10 +147,11 @@ gint Host_activate(GtkWidget *Entry, UNUSED gpointer data) net_reopen(addr); /* If we are "Paused" at this point it is usually because someone entered a non-existing host. Therefore do the go-ahead... --REW */ - gtk_toggle_button_set_state( GTK_TOGGLE_BUTTON( Pause_Button ) , 0); + gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( Pause_Button ) , 0); } else { - gtk_toggle_button_set_state( GTK_TOGGLE_BUTTON( Pause_Button ) , 1); - gtk_entry_append_text( GTK_ENTRY(Entry), ": not found" ); + int pos = strlen(gtk_entry_get_text( GTK_ENTRY(Entry))); + gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( Pause_Button ) , 1); + gtk_editable_insert_text( GTK_EDITABLE(Entry), ": not found", -1, &pos); } return FALSE; @@ -172,27 +173,24 @@ void Toolbar_fill(GtkWidget *Toolbar) GtkWidget *Entry; GtkAdjustment *Adjustment; - Button = gtk_button_new_with_label("Quit"); + Button = gtk_button_new_from_stock(GTK_STOCK_QUIT); gtk_box_pack_end(GTK_BOX(Toolbar), Button, FALSE, FALSE, 0); - gtk_signal_connect(GTK_OBJECT(Button), "clicked", + g_signal_connect(GTK_OBJECT(Button), "clicked", GTK_SIGNAL_FUNC(Window_destroy), NULL); - gtk_widget_show(Button); - Button = gtk_button_new_with_label("Restart"); + Button = gtk_button_new_with_mnemonic("_Restart"); gtk_box_pack_end(GTK_BOX(Toolbar), Button, FALSE, FALSE, 0); - gtk_signal_connect(GTK_OBJECT(Button), "clicked", + g_signal_connect(GTK_OBJECT(Button), "clicked", GTK_SIGNAL_FUNC(Restart_clicked), NULL); - gtk_widget_show(Button); - Pause_Button = gtk_toggle_button_new_with_label("Pause"); + Pause_Button = gtk_toggle_button_new_with_mnemonic("_Pause"); gtk_box_pack_end(GTK_BOX(Toolbar), Pause_Button, FALSE, FALSE, 0); - gtk_signal_connect(GTK_OBJECT(Pause_Button), "clicked", + g_signal_connect(GTK_OBJECT(Pause_Button), "clicked", GTK_SIGNAL_FUNC(Pause_clicked), NULL); - gtk_widget_show(Pause_Button); /* allow root only to set zero delay */ Adjustment = (GtkAdjustment *)gtk_adjustment_new(WaitTime, - getuid()==0 ? 0.00:1.00, + getuid()==0 ? 0.01:1.00, 999.99, 1.0, 10.0, 0.0); @@ -202,127 +200,182 @@ void Toolbar_fill(GtkWidget *Toolbar) /* gtk_spin_button_set_set_update_policy(GTK_SPIN_BUTTON(Button), GTK_UPDATE_IF_VALID); */ gtk_box_pack_end(GTK_BOX(Toolbar), Button, FALSE, FALSE, 0); - gtk_signal_connect(GTK_OBJECT(Adjustment), "value_changed", + g_signal_connect(GTK_OBJECT(Adjustment), "value_changed", GTK_SIGNAL_FUNC(WaitTime_changed), Button); - gtk_widget_show(Button); - Label = gtk_label_new("Hostname"); + Label = gtk_label_new_with_mnemonic("_Hostname:"); gtk_box_pack_start(GTK_BOX(Toolbar), Label, FALSE, FALSE, 0); - gtk_widget_show(Label); Entry = gtk_entry_new(); gtk_entry_set_text(GTK_ENTRY(Entry), Hostname); - gtk_signal_connect(GTK_OBJECT(Entry), "activate", + g_signal_connect(GTK_OBJECT(Entry), "activate", GTK_SIGNAL_FUNC(Host_activate), NULL); gtk_box_pack_start(GTK_BOX(Toolbar), Entry, TRUE, TRUE, 0); - 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 *ReportBody; - -GtkWidget *GetRow(int index) -{ - ip_t * addr; - char *name; - GtkWidget *Row, *Label; - - Row = gtk_fixed_new(); - addr = net_addr(index); - name = "???"; - if ( addrcmp( (void *) addr, (void *) &unspec_addr, af ) != 0 ) { - name = dns_lookup(addr); - if(!name) { - /* Actually this is not neccesary: - dns_lookup always returns a printable string */ - name = strlongip (addr); - } - } - - Label = gtk_label_new(name); - gtk_fixed_put(GTK_FIXED(Row), Label, Report_Positions[0], 0); - gtk_widget_show(Label); - - return Row; + gtk_label_set_mnemonic_widget(GTK_LABEL(Label), Entry); } - -GtkWidget *Scrollarea_create(void) +static GtkWidget *ReportTreeView; +static GtkListStore *ReportStore; + +enum { + COL_HOSTNAME, + COL_LOSS, + COL_RCV, + COL_SNT, + COL_LAST, + COL_BEST, + COL_AVG, + COL_WORST, + COL_STDEV, + COL_COLOR, + N_COLS +}; + +void float_formatter(GtkTreeViewColumn *tree_column, + GtkCellRenderer *cell, + GtkTreeModel *tree_model, + GtkTreeIter *iter, + gpointer data) { - GtkWidget *List; - GtkWidget *scroll; - int count; - - for(count = 0; Report_Positions[count]; count++); - - List = GTK_WIDGET(gtk_clist_new_with_titles(count, Report_Text)); - scroll = gtk_scrolled_window_new(NULL, NULL); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - for(count = 0; Report_Positions[count + 1]; count++) { - gtk_clist_set_column_width(GTK_CLIST(List), count, - Report_Positions[count + 1] - - Report_Positions[count]); - } - gtk_clist_set_column_width(GTK_CLIST(List), count, 0); - for(count = 1; Report_Positions[count]; count++) { - gtk_clist_set_column_justification(GTK_CLIST(List), count, GTK_JUSTIFY_RIGHT); - } - gtk_container_add(GTK_CONTAINER(scroll), List); - gtk_widget_show(List); - - ReportBody = List; - return scroll; + gfloat f; + gchar text[64]; + gtk_tree_model_get(tree_model, iter, (gint)data, &f, -1); + sprintf(text, "%.2f", f); + g_object_set(cell, "text", text, NULL); } - -void gtk_add_row(GtkWidget *List) +void percent_formatter(GtkTreeViewColumn *tree_column, + GtkCellRenderer *cell, + GtkTreeModel *tree_model, + GtkTreeIter *iter, + gpointer data) { - int at; - GtkWidget *Row, *Label; - - Row = gtk_fixed_new(); - - for(at = 0; Report_Positions[at] != 0; at++) { - Label = gtk_label_new("-"); - if(at) { - gtk_widget_set_usize(Label, 40, 0); - gtk_label_set_justify(GTK_LABEL(Label), GTK_JUSTIFY_RIGHT); - } - gtk_fixed_put(GTK_FIXED(Row), Label, Report_Positions[at], 0); - gtk_widget_show(Label); - } - - gtk_box_pack_start(GTK_BOX(List), Row, FALSE, FALSE, 0); - gtk_widget_show(Row); + gfloat f; + gchar text[64]; + gtk_tree_model_get(tree_model, iter, (gint)data, &f, -1); + sprintf(text, "%.1f%%", f); + g_object_set(cell, "text", text, NULL); } - -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) +void TreeViewCreate(void) { - char str[32]; + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + + ReportStore = gtk_list_store_new(N_COLS, + G_TYPE_STRING, + G_TYPE_FLOAT, + G_TYPE_INT, + G_TYPE_INT, + G_TYPE_INT, + G_TYPE_INT, + G_TYPE_INT, + G_TYPE_INT, + G_TYPE_FLOAT, + G_TYPE_STRING + ); + + ReportTreeView = gtk_tree_view_new_with_model(GTK_TREE_MODEL(ReportStore)); + + renderer = gtk_cell_renderer_text_new (); + column = gtk_tree_view_column_new_with_attributes ("Hostname", + renderer, + "text", COL_HOSTNAME, + "foreground", COL_COLOR, + NULL); + gtk_tree_view_column_set_expand(column, TRUE); + gtk_tree_view_column_set_resizable(column, TRUE); + gtk_tree_view_append_column (GTK_TREE_VIEW(ReportTreeView), column); + + renderer = gtk_cell_renderer_text_new (); + g_object_set (G_OBJECT(renderer), "xalign", 1.0, NULL); + column = gtk_tree_view_column_new_with_attributes ("Loss", + renderer, + "text", COL_LOSS, + "foreground", COL_COLOR, + NULL); + gtk_tree_view_column_set_resizable(column, TRUE); + gtk_tree_view_column_set_cell_data_func(column, renderer, percent_formatter, (void*)COL_LOSS, NULL); + gtk_tree_view_append_column (GTK_TREE_VIEW(ReportTreeView), column); + + renderer = gtk_cell_renderer_text_new (); + g_object_set (G_OBJECT(renderer), "xalign", 1.0, NULL); + column = gtk_tree_view_column_new_with_attributes ("Rcv", + renderer, + "text", 2, + "foreground", COL_COLOR, + NULL); + gtk_tree_view_column_set_resizable(column, TRUE); + gtk_tree_view_append_column (GTK_TREE_VIEW(ReportTreeView), column); + + renderer = gtk_cell_renderer_text_new (); + g_object_set (G_OBJECT(renderer), "xalign", 1.0, NULL); + column = gtk_tree_view_column_new_with_attributes ("Snt", + renderer, + "text", 3, + "foreground", COL_COLOR, + NULL); + gtk_tree_view_column_set_resizable(column, TRUE); + gtk_tree_view_append_column (GTK_TREE_VIEW(ReportTreeView), column); + + renderer = gtk_cell_renderer_text_new (); + g_object_set (G_OBJECT(renderer), "xalign", 1.0, NULL); + column = gtk_tree_view_column_new_with_attributes ("Last", + renderer, + "text", 4, + "foreground", COL_COLOR, + NULL); + gtk_tree_view_column_set_resizable(column, TRUE); + gtk_tree_view_append_column (GTK_TREE_VIEW(ReportTreeView), column); + + renderer = gtk_cell_renderer_text_new (); + g_object_set (G_OBJECT(renderer), "xalign", 1.0, NULL); + column = gtk_tree_view_column_new_with_attributes ("Best", + renderer, + "text", 5, + "foreground", COL_COLOR, + NULL); + gtk_tree_view_column_set_resizable(column, TRUE); + gtk_tree_view_append_column (GTK_TREE_VIEW(ReportTreeView), column); + + renderer = gtk_cell_renderer_text_new (); + g_object_set (G_OBJECT(renderer), "xalign", 1.0, NULL); + column = gtk_tree_view_column_new_with_attributes ("Avg", + renderer, + "text", 6, + "foreground", COL_COLOR, + NULL); + gtk_tree_view_column_set_resizable(column, TRUE); + gtk_tree_view_append_column (GTK_TREE_VIEW(ReportTreeView), column); + + renderer = gtk_cell_renderer_text_new (); + g_object_set (G_OBJECT(renderer), "xalign", 1.0, NULL); + column = gtk_tree_view_column_new_with_attributes ("Worst", + renderer, + "text", 7, + "foreground", COL_COLOR, + NULL); + gtk_tree_view_column_set_resizable(column, TRUE); + gtk_tree_view_append_column (GTK_TREE_VIEW(ReportTreeView), column); + + renderer = gtk_cell_renderer_text_new (); + g_object_set (G_OBJECT(renderer), "xalign", 1.0, NULL); + column = gtk_tree_view_column_new_with_attributes ("StDev", + renderer, + "text", 8, + "foreground", COL_COLOR, + NULL); + gtk_tree_view_column_set_resizable(column, TRUE); + gtk_tree_view_column_set_cell_data_func(column, renderer, float_formatter, (void*)COL_STDEV, NULL); + gtk_tree_view_append_column (GTK_TREE_VIEW(ReportTreeView), column); - sprintf(str, format, num); - gtk_set_field(List, row, ix, str); } - -void gtk_update_row(GtkCList *List, int row) +void update_tree_row(int row, GtkTreeIter *iter) { ip_t *addr; char str[256], *name; - GdkColor color; - GdkColormap *cmap; addr = net_addr(row); name = "???"; @@ -334,54 +387,46 @@ void gtk_update_row(GtkCList *List, int row) } } - cmap = gtk_widget_get_colormap(ReportBody); - if (net_up(row)) { - gdk_color_black(cmap, &color); - } else { - color.red = 0xffff; - color.green = 0; - color.blue = 0; - } - gdk_color_alloc (cmap, &color); - gtk_clist_set_foreground(List, row, &color); + gtk_list_store_set(ReportStore, iter, + COL_HOSTNAME, name, + COL_LOSS, (float)(net_loss(row)/1000.0), - /* changed the format type and added stdev and first/max TTL byMin */ - /* the row - net_min() is kind of not clean, need some more work */ - gtk_set_field(List, row - net_min(), 0, name); + COL_RCV, net_returned(row), + COL_SNT, net_xmit(row), - 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(), 4, "%.0f", net_last(row)/1000.0); - gtk_set_field_num(List, row - net_min(), 5, "%.0f", net_best(row)/1000.0); - 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); -} + COL_LAST, net_last(row)/1000, + COL_BEST, net_best(row)/1000, + COL_AVG, net_avg(row)/1000, + COL_WORST, net_worst(row)/1000, + COL_STDEV, (float)(net_stdev(row)/1000.0), + + COL_COLOR, net_up(row) ? "black" : "red", + -1); +} void gtk_redraw(void) { - int at = net_min(); /* changed from 0 to net_min for TTL stuff byMin */ int max = net_max(); - - gtk_clist_freeze(GTK_CLIST(ReportBody)); - - while(GTK_CLIST(ReportBody)->rows < max -at) { /* byMin */ - gtk_clist_append(GTK_CLIST(ReportBody), Report_Text); - } - - while(GTK_CLIST(ReportBody)->rows > max) { - gtk_clist_remove(GTK_CLIST(ReportBody), GTK_CLIST(ReportBody)->rows - 1); + + GtkTreeIter iter; + int row = net_min(); + gboolean valid; + + valid = gtk_tree_model_get_iter_first(GTK_TREE_MODEL(ReportStore), &iter); + + while(valid) { + if(row < max) { + update_tree_row(row++, &iter); + valid = gtk_tree_model_iter_next(GTK_TREE_MODEL(ReportStore), &iter); + } else { + valid = gtk_list_store_remove(ReportStore, &iter); + } } - - /* for(at=0; at < max; at++) { replaced byMin */ - for(; at < max; at++) { - gtk_update_row(GTK_CLIST(ReportBody), at); + while(row < max) { + gtk_list_store_append(ReportStore, &iter); + update_tree_row(row++, &iter); } - - gtk_clist_thaw(GTK_CLIST(ReportBody)); } @@ -389,25 +434,25 @@ void Window_fill(GtkWidget *Window) { GtkWidget *VBox; GtkWidget *Toolbar; - GtkWidget *List; + GtkWidget *scroll; gtk_window_set_title(GTK_WINDOW(Window), "My traceroute [v" VERSION "]"); - gtk_window_set_wmclass(GTK_WINDOW(Window), "mtr", "Mtr"); - gtk_widget_set_usize(Window, 600, 400); - gtk_container_border_width(GTK_CONTAINER(Window), 10); + gtk_window_set_default_size(GTK_WINDOW(Window), 650, 400); + gtk_container_set_border_width(GTK_CONTAINER(Window), 10); VBox = gtk_vbox_new(FALSE, 10); Toolbar = gtk_hbox_new(FALSE, 10); Toolbar_fill(Toolbar); gtk_box_pack_start(GTK_BOX(VBox), Toolbar, FALSE, FALSE, 0); - gtk_widget_show(Toolbar); - - List = Scrollarea_create(); - gtk_box_pack_start(GTK_BOX(VBox), List, TRUE, TRUE, 0); - gtk_widget_show(List); + TreeViewCreate(); + scroll = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scroll), GTK_SHADOW_IN); + gtk_container_add(GTK_CONTAINER(scroll), ReportTreeView); + gtk_box_pack_start(GTK_BOX(VBox), scroll, TRUE, TRUE, 0); + gtk_container_add(GTK_CONTAINER(Window), VBox); - gtk_widget_show(VBox); } @@ -429,14 +474,13 @@ void gtk_open(void) Window_fill(Window); - gtk_signal_connect_object(GTK_OBJECT(Window), "delete_event", - GTK_SIGNAL_FUNC(gtk_widget_destroy), - GTK_OBJECT(Window)); - gtk_signal_connect(GTK_OBJECT(Window), "destroy", + g_signal_connect(GTK_OBJECT(Window), "delete_event", + GTK_SIGNAL_FUNC(Window_destroy), NULL); + g_signal_connect(GTK_OBJECT(Window), "destroy", GTK_SIGNAL_FUNC(Window_destroy), NULL); icon = gtk_load_pixmap(mtr_icon); - gtk_widget_show(Window); + gtk_widget_show_all(Window); gdk_window_set_icon(Window->window, NULL, icon, NULL); gdk_window_set_icon_name(Window->window, "mtr"); } @@ -457,30 +501,37 @@ gint gtk_ping(UNUSED gpointer data) { gtk_redraw(); net_send_batch(); - gtk_timeout_remove (tag); + g_source_remove (tag); gtk_add_ping_timeout (); return TRUE; } -void gtk_net_data(UNUSED gpointer data, UNUSED gint fd, UNUSED GdkInputCondition cond) +gboolean gtk_net_data(UNUSED GIOChannel *channel, UNUSED GIOCondition cond, UNUSED gpointer data) { net_process_return(); + return TRUE; } -void gtk_dns_data(UNUSED gpointer data, UNUSED gint fd, UNUSED GdkInputCondition cond) +gboolean gtk_dns_data(UNUSED GIOChannel *channel, UNUSED GIOCondition cond, UNUSED gpointer data) { dns_ack(); gtk_redraw(); + return TRUE; } void gtk_loop(void) { + GIOChannel *net_iochannel, *dns_iochannel; + gtk_add_ping_timeout (); - gdk_input_add(net_waitfd(), GDK_INPUT_READ, gtk_net_data, NULL); - gdk_input_add(dns_waitfd(), GDK_INPUT_READ, gtk_dns_data, NULL); + + net_iochannel = g_io_channel_unix_new(net_waitfd()); + g_io_add_watch(net_iochannel, G_IO_IN, gtk_net_data, NULL); + dns_iochannel = g_io_channel_unix_new(dns_waitfd()); + g_io_add_watch(dns_iochannel, G_IO_IN, gtk_dns_data, NULL); gtk_main(); } diff --git a/mtr.8 b/mtr.8 index c1c0918..30485b2 100644 --- a/mtr.8 +++ b/mtr.8 @@ -8,7 +8,7 @@ mtr \- a network diagnostic tool .SH SYNOPSIS .B mtr [\c -.B \-hvrctglspni46\c +.B \-hvrctglspniu46\c ] [\c .B \-\-help\c @@ -217,6 +217,11 @@ what you want). 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 \-u +.br +Use UDP datagrams instead of ICMP ECHO. + .TP .B \-4 .br diff --git a/mtr.c b/mtr.c index eb2abca..8849a1c 100644 --- a/mtr.c +++ b/mtr.c @@ -65,6 +65,7 @@ int cpacketsize = 64; /* default packet size */ int bitpattern = 0; int tos = 0; int af = DEFAULT_AF; +int mtrtype = IPPROTO_ICMP; /* Use ICMP as default packet type */ /* begin ttl windows addByMin */ int fstTTL = 1; /* default start at first hop */ @@ -143,6 +144,7 @@ void parse_arg (int argc, char **argv) { "address", 1, 0, 'a' }, { "first-ttl", 1, 0, 'f' }, /* -f & -m are borrowed from traceroute */ { "max-ttl", 1, 0, 'm' }, + { "udp", 0, 0, 'u' }, /* UDP (default is ICMP) */ { "inet", 0, 0, '4' }, /* IPv4 only */ { "inet6", 0, 0, '6' }, /* IPv6 only */ { 0, 0, 0, 0 } @@ -152,7 +154,7 @@ void parse_arg (int argc, char **argv) while(1) { /* added f:m:o: byMin */ opt = getopt_long(argc, argv, - "vhrxtglpo:i:c:s:b:Q:na:f:m:46", long_options, NULL); + "vhrxtglpo:i:c:s:b:Q:na:f:m:u46", long_options, NULL); if(opt == -1) break; @@ -238,7 +240,7 @@ void parse_arg (int argc, char **argv) exit (1); } } - strcpy (fld_active, optarg); + strcpy ((char*)fld_active, optarg); break; case 'b': bitpattern = atoi (optarg); @@ -253,6 +255,9 @@ void parse_arg (int argc, char **argv) tos = 0; } break; + case 'u': + mtrtype = IPPROTO_UDP; + break; case '4': af = AF_INET; break; @@ -354,13 +359,19 @@ int main(int argc, char **argv) parse_arg (argc, argv); + /* Now that we know mtrtype we can select which socket to use */ + if (net_selectsocket() != 0) { + fprintf( stderr, "mtr: Couldn't determine raw socket type.\n" ); + exit( EXIT_FAILURE ); + } + if (PrintVersion) { printf ("mtr " VERSION "\n"); exit(0); } if (PrintHelp) { - printf("usage: %s [-hvrctglspni46] [--help] [--version] [--report]\n" + printf("usage: %s [-hvrctglspniu46] [--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/-s bytes]\n" /* ok */ diff --git a/mtr.h b/mtr.h index 31ebc76..e2efd32 100644 --- a/mtr.h +++ b/mtr.h @@ -20,6 +20,42 @@ /* Typedefs */ +#if 0 + +// Neat trick! However, on my system, "config.h" already defines these types +// so I get a compiler error if I leave this in. -- REW + +/* Find the proper type for 8 bits */ +#if SIZEOF_UNSIGNED_CHAR == 1 +typedef unsigned char uint8; +#else +#error No 8 bit type +#endif + +/* Find the proper type for 16 bits */ +#if SIZEOF_UNSIGNED_SHORT == 2 +typedef unsigned short uint16; +#elif SIZEOF_UNSIGNED_INT == 2 +typedef unsigned int uint16; +#elif SIZEOF_UNSIGNED_LONG == 2 +typedef unsigned long uint16; +#else +#error No 16 bit type +#endif + +/* Find the proper type for 32 bits */ +#if SIZEOF_UNSIGNED_SHORT == 4 +typedef unsigned short uint32; +#elif SIZEOF_UNSIGNED_INT == 4 +typedef unsigned int uint32; +#elif SIZEOF_UNSIGNED_LONG == 4 +typedef unsigned long uint32; +#else +#error No 32 bit type +#endif + +#endif + typedef unsigned char byte; typedef unsigned short word; typedef unsigned long dword; diff --git a/net.c b/net.c index 8f32aea..ebd3eda 100644 --- a/net.c +++ b/net.c @@ -54,6 +54,22 @@ struct ICMPHeader { uint16 sequence; }; +/* Structure of an UDP header. */ +struct UDPHeader { + uint16 srcport; + uint16 dstport; + uint16 length; + uint16 checksum; +}; + +/* Structure of an IPv4 UDP pseudoheader. */ +struct UDPv4PHeader { + uint32 saddr; + uint32 daddr; + uint8 zero; + uint8 protocol; + uint16 len; +}; /* Structure of an IP header. */ struct IPHeader { @@ -77,6 +93,7 @@ struct IPHeader { #define ICMP_TSTAMPREPLY 14 #define ICMP_TIME_EXCEEDED 11 +#define ICMP_UNREACHABLE 3 #ifndef SOL_IP #define SOL_IP 0 @@ -131,8 +148,12 @@ static struct timeval reset = { 0, 0 }; int timestamp; int sendsock4; +int sendsock4_icmp; +int sendsock4_udp; int recvsock4; int sendsock6; +int sendsock6_icmp; +int sendsock6_udp; int recvsock6; int sendsock; int recvsock; @@ -175,7 +196,7 @@ static 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 */ - +extern int mtrtype; /* type of query packet used */ /* return the number of microseconds to wait before sending the next ping */ @@ -206,14 +227,40 @@ int checksum(void *data, int sz) } +/* Prepend pseudoheader to the udp datagram and calculate checksum */ +int udp_checksum(void *pheader, void *udata, int psize, int dsize) +{ + unsigned int tsize = psize + dsize; + char csumpacket[tsize]; + memset(csumpacket, (unsigned char) abs(bitpattern), abs(tsize)); + + struct UDPv4PHeader *prepend = (struct UDPv4PHeader *) csumpacket; + struct UDPv4PHeader *udppheader = (struct UDPv4PHeader *) pheader; + prepend->saddr = udppheader->saddr; + prepend->daddr = udppheader->daddr; + prepend->zero = 0; + prepend->protocol = udppheader->protocol; + prepend->len = udppheader->len; + + struct UDPHeader *content = (struct UDPHeader *)(csumpacket + psize); + struct UDPHeader *udpdata = (struct UDPHeader *) udata; + content->srcport = udpdata->srcport; + content->dstport = udpdata->dstport; + content->length = udpdata->length; + content->checksum = udpdata->checksum; + + return checksum(csumpacket,tsize); +} + + int new_sequence(int index) { - static int next_sequence = 0; + static int next_sequence = MinSequence; int seq; seq = next_sequence++; if (next_sequence >= MaxSequence) - next_sequence = 0; + next_sequence = MinSequence; sequence[seq].index = index; sequence[seq].transit = 1; @@ -236,15 +283,21 @@ void net_send_query(int index) /*ok char packet[sizeof(struct IPHeader) + sizeof(struct ICMPHeader)];*/ char packet[MAXPACKET]; struct IPHeader *ip = (struct IPHeader *) packet; - struct ICMPHeader *icmp; + struct ICMPHeader *icmp = NULL; + struct UDPHeader *udp = NULL; + struct UDPv4PHeader *udpp = NULL; + uint16 mypid; /*ok int packetsize = sizeof(struct IPHeader) + sizeof(struct ICMPHeader) + datasize;*/ int rv; static int first=1; - int ttl, iphsize = 0, echotype = 0, salen = 0; + int ttl, iphsize = 0, echotype = 0, salen = 0, udphsize = 0; ttl = index + 1; + /* offset for ipv6 checksum calculation */ + int offset = 6; + if ( packetsize < MINPACKET ) packetsize = MINPACKET; if ( packetsize > MAXPACKET ) packetsize = MAXPACKET; @@ -271,7 +324,7 @@ void net_send_query(int index) ip->id = 0; ip->frag = 0; /* 1, if want to find mtu size? Min */ ip->ttl = ttl; - ip->protocol = IPPROTO_ICMP; + ip->protocol = mtrtype; ip->check = 0; /* BSD needs the source address here, Linux & others do not... */ @@ -295,22 +348,71 @@ void net_send_query(int index) #endif } - 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); + switch ( mtrtype ) { + case IPPROTO_ICMP: + 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); + + gettimeofday(&sequence[icmp->sequence].time, NULL); + break; + + case IPPROTO_UDP: + udp = (struct UDPHeader *)(packet + iphsize); + udphsize = sizeof (struct UDPHeader); + udp->checksum = 0; + mypid = (uint16)getpid(); + if (mypid < MinPort) + mypid += MinPort; + + udp->srcport = htons(mypid); + udp->length = abs(packetsize) - iphsize; + if(!BSDfix) + udp->length = htons(udp->length); + + udp->dstport = new_sequence(index); + gettimeofday(&sequence[udp->dstport].time, NULL); + udp->dstport = htons(udp->dstport); + break; + } switch ( af ) { case AF_INET: + switch ( mtrtype ) { + case IPPROTO_UDP: + /* checksum is not mandatory. only calculate if we know ip->saddr */ + if (ip->saddr) { + udpp = (struct UDPv4PHeader *)(malloc(sizeof(struct UDPv4PHeader))); + udpp->saddr = ip->saddr; + udpp->daddr = ip->daddr; + udpp->protocol = ip->protocol; + udpp->len = udp->length; + udp->checksum = udp_checksum(udpp, udp, sizeof(struct UDPv4PHeader), abs(packetsize) - iphsize); + } + break; + } + ip->check = checksum(packet, abs(packetsize)); break; +#ifdef ENABLE_IPV6 + case AF_INET6: + switch ( mtrtype ) { + case IPPROTO_UDP: + /* kernel checksum calculation */ + if ( setsockopt(sendsock, IPPROTO_IPV6, IPV6_CHECKSUM, &offset, sizeof(offset)) ) { + perror( "setsockopt IPV6_CHECKSUM" ); + exit( EXIT_FAILURE); + } + break; + } + break; +#endif } - gettimeofday(&sequence[icmp->sequence].time, NULL); - rv = sendto(sendsock, packet, abs(packetsize), 0, remotesockaddr, salen); if (first && (rv < 0) && ((errno == EINVAL) || (errno == EMSGSIZE))) { @@ -450,9 +552,11 @@ void net_process_return(void) socklen_t fromsockaddrsize; int num; struct ICMPHeader *header = NULL; + struct UDPHeader *udpheader = NULL; struct timeval now; ip_t * fromaddress = NULL; - int echoreplytype = 0, timeexceededtype = 0; + int echoreplytype = 0, timeexceededtype = 0, unreachabletype = 0; + int sequence = 0; gettimeofday(&now, NULL); switch ( af ) { @@ -461,6 +565,7 @@ void net_process_return(void) fromaddress = (ip_t *) &(fsa4->sin_addr); echoreplytype = ICMP_ECHOREPLY; timeexceededtype = ICMP_TIME_EXCEEDED; + unreachabletype = ICMP_UNREACHABLE; break; #ifdef ENABLE_IPV6 case AF_INET6: @@ -468,6 +573,7 @@ void net_process_return(void) fromaddress = (ip_t *) &(fsa6->sin6_addr); echoreplytype = ICMP6_ECHO_REPLY; timeexceededtype = ICMP6_TIME_EXCEEDED; + unreachabletype = ICMP6_DST_UNREACH; break; #endif } @@ -490,41 +596,78 @@ void net_process_return(void) break; #endif } - if (header->type == echoreplytype) { - if(header->id != (uint16)getpid()) - return; - - 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)) + switch ( mtrtype ) { + case IPPROTO_ICMP: + if (header->type == echoreplytype) { + if(header->id != (uint16)getpid()) return; - header = (struct ICMPHeader *)(packet + sizeof (struct IPHeader) + - sizeof (struct ICMPHeader) + - sizeof (struct IPHeader)); - break; + + sequence = header->sequence; + } 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) ) + 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; - header = (struct ICMPHeader *) ( packet + - sizeof (struct ICMPHeader) + - sizeof (struct ip6_hdr) ); + + sequence = header->sequence; + } + break; + + case IPPROTO_UDP: + if (header->type == timeexceededtype || header->type == unreachabletype) { + switch ( af ) { + case AF_INET: + + if ((size_t) num < sizeof(struct IPHeader) + + sizeof(struct ICMPHeader) + + sizeof (struct IPHeader) + + sizeof (struct UDPHeader)) + return; + udpheader = (struct UDPHeader *)(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 UDPHeader) ) + return; + udpheader = (struct UDPHeader *) ( packet + + sizeof (struct ICMPHeader) + + sizeof (struct ip6_hdr) ); + break; #endif + } + sequence = ntohs(udpheader->dstport); } - - if (header->id != (uint16)getpid()) - return; - - net_process_ping(header->sequence, (void *)fromaddress, now); + break; } + + if (sequence) + net_process_ping(sequence, (void *)fromaddress, now); } @@ -758,14 +901,16 @@ int net_preopen(void) int trueopt = 1; #if !defined(IP_HDRINCL) && defined(IP_TOS) && defined(IP_TTL) - sendsock4 = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); + sendsock4_icmp = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); + sendsock4_udp = socket(AF_INET, SOCK_RAW, IPPROTO_UDP); #else sendsock4 = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); #endif if (sendsock4 < 0) return -1; #ifdef ENABLE_IPV6 - sendsock6 = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); + sendsock6_icmp = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); + sendsock6_udp = socket(AF_INET6, SOCK_RAW, IPPROTO_UDP); #endif #ifdef IP_HDRINCL @@ -787,7 +932,38 @@ int net_preopen(void) return 0; } - + +int net_selectsocket(void) +{ +#if !defined(IP_HDRINCL) && defined(IP_TOS) && defined(IP_TTL) + switch ( mtrtype ) { + case IPPROTO_ICMP: + sendsock4 = sendsock4_icmp; + break; + case IPPROTO_UDP: + sendsock4 = sendsock4_udp; + break; + } +#endif + if (sendsock4 < 0) + return -1; +#ifdef ENABLE_IPV6 + switch ( mtrtype ) { + case IPPROTO_ICMP: + sendsock6 = sendsock6_icmp; + break; + case IPPROTO_UDP: + sendsock6 = sendsock6_udp; + break; + } + if (sendsock6 < 0) + return -1; +#endif + + return 0; +} + + int net_open(struct hostent * host) { #ifdef ENABLE_IPV6 @@ -946,9 +1122,15 @@ int net_set_interfaceaddress (char *InterfaceAddress) void net_close(void) { - if (sendsock4 >= 0) close(sendsock4); + if (sendsock4 >= 0) { + close(sendsock4_icmp); + close(sendsock4_udp); + } if (recvsock4 >= 0) close(recvsock4); - if (sendsock6 >= 0) close(sendsock6); + if (sendsock6 >= 0) { + close(sendsock6_icmp); + close(sendsock6_udp); + } if (recvsock6 >= 0) close(recvsock6); } diff --git a/net.h b/net.h index 2fc4897..5807042 100644 --- a/net.h +++ b/net.h @@ -28,6 +28,7 @@ #endif int net_preopen(void); +int net_selectsocket(void); int net_open(struct hostent *host); void net_reopen(struct hostent *address); int net_set_interfaceaddress (char *InterfaceAddress); @@ -80,10 +81,12 @@ void addrcpy( char * a, char * b, int af ); #define MAXPATH 8 #define MaxHost 256 +#define MinSequence 33000 #define MaxSequence 65536 +#define MinPort 1024 -#define MAXPACKET 4470 /* largest test ICMP packet size */ -#define MINPACKET 28 /* 20 bytes IP header and 8 bytes ICMP */ +#define MAXPACKET 4470 /* largest test packet size */ +#define MINPACKET 28 /* 20 bytes IP header and 8 bytes ICMP or UDP */ /* stuff used by display such as report, curses... --Min */ #define MAXFLD 20 /* max stats fields to display */ -- 2.47.2