New upstream version 0.94
Samuel Henrique
3 years ago
0 | 0.94 |
10 | 10 | |
11 | 11 | The "raw" format is: |
12 | 12 | |
13 | hostline|xmitline|pingline|dnsline|timestampline | |
13 | hostline|xmitline|pingline|dnsline|timestampline|mplsline | |
14 | 14 | |
15 | 15 | hostline: |
16 | 16 | h <pos> <host IP> |
27 | 27 | timestampline: |
28 | 28 | t <pos> <pingtime> <timestamp> |
29 | 29 | |
30 | mplsline: | |
31 | m <pos> <label> <traffic_class> <bottom_stack> <ttl> | |
30 | 32 | |
31 | 33 | Timestampline is not yet implemented. Need to find out how to do |
32 | 34 | ICMP timestamping first. :-) |
54 | 54 | ui/select.c ui/select.h \ |
55 | 55 | ui/utils.c ui/utils.h \ |
56 | 56 | packet/cmdparse.c packet/cmdparse.h \ |
57 | packet/sockaddr.c packet/sockaddr.h \ | |
57 | 58 | ui/mtr-curses.h \ |
58 | 59 | img/mtr_icon.xpm \ |
59 | 60 | ui/mtr-gtk.h |
83 | 84 | mtr_SOURCES += ui/gtk.c |
84 | 85 | endif |
85 | 86 | |
87 | if WITH_LIBASAN | |
88 | ASAN_CFLAGS = -fno-omit-frame-pointer | |
89 | ASAN_CFLAGS += -fsanitize=undefined | |
90 | ASAN_CFLAGS += -fsanitize=address | |
91 | endif | |
92 | ||
86 | 93 | mtr_INCLUDES = $(GLIB_CFLAGS) -I$(top_builddir) -I$(top_srcdir) |
87 | mtr_CFLAGS = $(GTK_CFLAGS) $(NCURSES_CFLAGS) | |
88 | mtr_LDADD = $(GTK_LIBS) $(NCURSES_LIBS) $(RESOLV_LIBS) | |
94 | mtr_CFLAGS = $(GTK_CFLAGS) $(NCURSES_CFLAGS) $(ASAN_CFLAGS) $(JANSSON_CFLAGS) | |
95 | mtr_LDADD = $(GTK_LIBS) $(NCURSES_LIBS) $(RESOLV_LIBS) $(JANSSON_LIBS) | |
89 | 96 | |
90 | 97 | |
91 | 98 | mtr_packet_SOURCES = \ |
3 | 3 | the commit messages here. |
4 | 4 | |
5 | 5 | #NEW_STUFF_HERE this is a tag my script looks for. |
6 | V0.94 | |
7 | Aaron Lipinski (10): | |
8 | gtk_menu_append -> gtk_menu_shell_append | |
9 | GTK_OBJECT -> G_OBJECT | |
10 | gtk_button_new_from_stock -> gtk_button_new_with_label | |
11 | gtk3 | |
12 | hbox/vbox -> gtk_box_new | |
13 | gtk_menu_popup -> gtk_menu_popup_at_pointer | |
14 | show resolved hostname in raw dnsline | |
15 | rely on final return NULL | |
16 | introduce libasan | |
17 | avoid stack use after scope | |
18 | ||
19 | Alejandro Leal (2): | |
20 | few updates to manual page and README.md | |
21 | Updating some comments | |
22 | ||
23 | Chongyu Zhu (1): | |
24 | probe: fix find_source_addr | |
25 | ||
26 | Konrad Bucheli (1): | |
27 | fix segmentation fault if there is no IP address on an interface (fixes #320) | |
28 | ||
29 | Kulemin Alexander (1): | |
30 | report: json: reworked with libjansson | |
31 | ||
32 | Mark Egan-Fuller (1): | |
33 | Add display of destination. | |
34 | ||
35 | Markus Kötter (6): | |
36 | simplification - remove sockaddrtop | |
37 | simplification - remove addrcpy | |
38 | simplification - remove rsa{4,6} | |
39 | simplification - address addrcmp | |
40 | simplification - improve readability | |
41 | ip6 udp - fix probes with local or remote port | |
42 | ||
43 | R.E. Wolff (29): | |
44 | fix warning on recent compilers. | |
45 | Merge branch 'master' of github.com:traviscross/mtr | |
46 | net find local address fix by meingtsla | |
47 | proposed patch for bsd compile error | |
48 | fix closing brace | |
49 | Added include errno --obouizi | |
50 | Merge branch 'master' of github.com:traviscross/mtr | |
51 | More compilation warning fixes from obouizi | |
52 | Added extra help text to configure --yvs | |
53 | Changed MAXPATH to MAX_PATH for AIX compatibility. -- aixtools | |
54 | make the code for gtk2/3 a bit nicer. | |
55 | Merge branch 'gtk3_with_fallback' of https://github.com/krisl/mtr | |
56 | Merge branch 'master' of github.com:traviscross/mtr | |
57 | in hindsight my previous patch wasn't so nice. And nobody told me. | |
58 | ||
59 | Sean Wei (1): | |
60 | Fix parameter in ui/net.c | |
61 | ||
62 | Siyuan Miao (1): | |
63 | show mpls information in raw output | |
64 | ||
65 | atib (1): | |
66 | Added code to print multiple addresses regitered on the same hop count | |
67 | ||
68 | atibdialpad (2): | |
69 | Change TTL dynamically to adjust for path changes | |
70 | TODO list changes | |
71 | ||
72 | meingtsla (2): | |
73 | asn_{open,close}: Always initialize ipinfo hash table | |
74 | Merge branch 'master' of https://github.com/traviscross/mtr into asn-open-always-hcreate | |
75 | ||
6 | 76 | V0.93 |
7 | 77 | Adam (1): |
8 | 78 | Update README |
30 | 30 | |
31 | 31 | ./bootstrap.sh && ./configure && make |
32 | 32 | |
33 | When it looks as if the compilation was succesful, you can | |
33 | When it looks as if the compilation was successful, you can | |
34 | 34 | test mtr with |
35 | 35 | |
36 | 36 | sudo ./mtr <host> |
40 | 40 | - Keep all packets and make the "best" and "worst" columns show the |
41 | 41 | xx-th percentile.... |
42 | 42 | |
43 | - Can the reports generated also include any secondary servers? In | |
44 | the interactive mode, any new servers that are found in the | |
45 | traceroute are added to the list, but it seems to only include | |
46 | one set of servers when using the -r option. | |
47 | ||
48 | 43 | - Being able to expand the "column width" of the hosts listed would |
49 | 44 | be nice, too. |
45 | ||
46 | - Display per host stats when multiple servers respond at a particular | |
47 | hop count. | |
50 | 48 | |
51 | 49 | |
52 | 50 | - Bugs to fix? |
20 | 20 | AC_PROG_CC |
21 | 21 | |
22 | 22 | # Check pkg-config availability. |
23 | m4_ifndef([PKG_PROG_PKG_CONFIG], | |
24 | [m4_fatal( | |
23 | m4_ifndef([PKG_CHECK_MODULES], [m4_defun([PKG_CHECK_MODULES], [AC_MSG_ERROR( | |
25 | 24 | [Could not locate the pkg-config autoconf macros. These are usually located |
26 | 25 | in /usr/share/aclocal/pkg.m4. If your macros are in a different location, |
27 | 26 | try setting the environment variable ACLOCAL_OPTS="-I/other/macro/dir" |
28 | before running ./bootstrap.sh again.]) | |
27 | before running ./bootstrap.sh again, or configure --without-gtk ----without-jansson ])]) | |
29 | 28 | ]) |
30 | 29 | PKG_PROG_PKG_CONFIG |
31 | 30 | |
83 | 82 | |
84 | 83 | AC_CHECK_LIB([m], [floor], [], [AC_MSG_ERROR([No math library found])]) |
85 | 84 | |
85 | # libasan | |
86 | AC_ARG_WITH([libasan], | |
87 | [AS_HELP_STRING([--with-libasan], [Build with AddressSanitizer])], | |
88 | [with_libasan=yes], []) | |
89 | AM_CONDITIONAL([WITH_LIBASAN], [test "x$with_libasan" = "xyes"]) | |
90 | ||
86 | 91 | # Find GTK |
87 | 92 | AC_ARG_WITH([gtk], |
88 | [AS_HELP_STRING([--without-gtk], [Build without the GTK+2.0 interface])], | |
93 | [AS_HELP_STRING([--without-gtk], [Build without the GTK+ interface])], | |
89 | 94 | [], [with_gtk=yes]) |
90 | 95 | AS_IF([test "x$with_gtk" = "xyes"], |
91 | [PKG_CHECK_MODULES([GTK], [gtk+-2.0], | |
92 | [AC_DEFINE([HAVE_GTK], [1], [Define if gtk+-2.0 library available])], | |
93 | [with_gtk=no]) | |
96 | [PKG_CHECK_MODULES([GTK], [gtk+-3.0], | |
97 | [AC_DEFINE([HAVE_GTK], [1], [Define if gtk+ library available])] | |
98 | [AC_DEFINE([HAVE_GTK3], [1], [Define if gtk+-3.0 library available])], | |
99 | [PKG_CHECK_MODULES([GTK], [gtk+-2.0], | |
100 | [AC_DEFINE([HAVE_GTK], [1], [Define if gtk+ library available])], | |
101 | [with_gtk=no])]) | |
94 | 102 | ]) |
95 | 103 | AM_CONDITIONAL([WITH_GTK], [test "x$with_gtk" = xyes]) |
104 | ||
105 | AC_ARG_WITH([jansson], | |
106 | [AS_HELP_STRING([--without-jansson], [Build without JSON output])], | |
107 | [], [with_jansson=yes]) | |
108 | AS_IF([test "x$with_jansson" = "xyes"], | |
109 | [PKG_CHECK_MODULES([JANSSON], [jansson], | |
110 | [AC_DEFINE([HAVE_JANSSON], [1], [Define if jansson library available])], | |
111 | [with_jansson=no]) | |
112 | ]) | |
96 | 113 | |
97 | 114 | # Find ncurses |
98 | 115 | AC_ARG_WITH([ncurses], |
244 | 261 | AM_CONDITIONAL([BUILD_BASH_COMPLETION], [test "x$enable_bash_completion" = xyes]) |
245 | 262 | echo "build options:" |
246 | 263 | echo "--------------" |
264 | echo "libasan :$with_libasan" | |
247 | 265 | echo "ipv6 :$USES_IPV6" |
248 | 266 | echo "ipinfo :$with_ipinfo" |
249 | 267 | echo "ncurses :$with_ncurses" |
250 | 268 | echo "gtk :$with_gtk" |
269 | echo "jansson :$with_jansson" | |
251 | 270 | echo "cap :$have_cap" |
252 | 271 | echo "libs :$LIBS" |
253 | 272 | echo "cflags :$CFLAGS" |
120 | 120 | .I IP-ADDRESS |
121 | 121 | .HP 14 |
122 | 122 | .IP |
123 | The local Internet Procol version 4 address to use when sending probes. | |
123 | The local Internet Protocol version 4 address to use when sending probes. | |
124 | 124 | .HP 7 |
125 | 125 | .IP |
126 | 126 | .B local-ip-6 |
406 | 406 | \&... |
407 | 407 | .RE 0 |
408 | 408 | .LP |
409 | Each interemediate host would respond with a | |
409 | Each intermediate host would respond with a | |
410 | 410 | .B ttl-expired |
411 | 411 | message, and the destination host would respond with a |
412 | 412 | .BR reply : |
137 | 137 | of a bad (or simply overloaded) link. |
138 | 138 | .PP |
139 | 139 | The results are usually reported as round-trip-response times in milliseconds |
140 | and the percentage of packetloss. | |
140 | and the percentage of packet loss. | |
141 | 141 | .SH OPTIONS |
142 | 142 | .TP |
143 | 143 | .B \-h\fR, \fB\-\-help |
266 | 266 | .B mtr |
267 | 267 | to use the JSON output format. This format is better suited for |
268 | 268 | automated processing of the measurement results. |
269 | Jansson library must have been available on the system when | |
270 | .B mtr | |
271 | was built for this to work. | |
269 | 272 | .TP |
270 | 273 | .B \-p\fR, \fB\-\-split |
271 | 274 | Use this option to set |
65 | 65 | structure for later semantic interpretation. Returns EINVAL if the |
66 | 66 | command string is unparseable or zero for success. |
67 | 67 | |
68 | comamnd_string will be modified in-place with NUL characters terminating | |
69 | tokens, and the command_t will use pointers to the conents of | |
68 | command_string will be modified in-place with NUL characters terminating | |
69 | tokens, and the command_t will use pointers to the contents of | |
70 | 70 | command_string without copying, so any interpretation of the |
71 | 71 | command_t structure requires that the command_string memory has not yet |
72 | 72 | been freed or otherwise reused. |
723 | 723 | /* |
724 | 724 | Check the current socket address, and if it is the same |
725 | 725 | as the source address we intend, we will skip the bind. |
726 | This is to accomodate Solaris, which, as of Solaris 11.3, | |
726 | This is to accommodate Solaris, which, as of Solaris 11.3, | |
727 | 727 | will return an EINVAL error on bind if the socket is already |
728 | 728 | bound, even if the same address is used. |
729 | 729 | */ |
753 | 753 | } |
754 | 754 | } |
755 | 755 | |
756 | /* The traffic class in IPv6 is analagous to ToS in IPv4 */ | |
756 | /* The traffic class in IPv6 is analogous to ToS in IPv4 */ | |
757 | 757 | if (setsockopt(send_socket, IPPROTO_IPV6, |
758 | 758 | IPV6_TCLASS, ¶m->type_of_service, sizeof(int))) { |
759 | 759 | return -1; |
37 | 37 | #include "timeval.h" |
38 | 38 | #include "sockaddr.h" |
39 | 39 | |
40 | char *probe_err; | |
41 | ||
40 | 42 | /* Convert the destination address from text to sockaddr */ |
41 | 43 | int decode_address_string( |
42 | 44 | int ip_version, |
97 | 99 | { |
98 | 100 | if (decode_address_string |
99 | 101 | (param->ip_version, param->remote_address, dest_sockaddr)) { |
102 | probe_err = "decode address string remote"; | |
100 | 103 | return -1; |
101 | 104 | } |
102 | 105 | |
103 | 106 | if (param->local_address) { |
104 | 107 | if (decode_address_string |
105 | 108 | (param->ip_version, param->local_address, src_sockaddr)) { |
106 | return -1; | |
107 | } | |
108 | } else { | |
109 | probe_err = "decode address string local"; | |
110 | return -1; | |
111 | } | |
112 | } else { | |
113 | probe_err = "find source address"; | |
109 | 114 | if (find_source_addr(src_sockaddr, dest_sockaddr)) { |
110 | return -1; | |
111 | } | |
115 | //probe_err = "find source address"; | |
116 | return -1; | |
117 | } | |
118 | probe_err = ""; | |
112 | 119 | } |
113 | 120 | /* DGRAM ICMP id is taken from src_port not from ICMP header */ |
114 | 121 | if (param->protocol == IPPROTO_ICMP) { |
310 | 317 | int sock; |
311 | 318 | int len; |
312 | 319 | struct sockaddr_storage dest_with_port; |
320 | #ifdef __linux__ | |
321 | // The Linux code needs these. | |
313 | 322 | struct sockaddr_in *srcaddr4; |
314 | 323 | struct sockaddr_in6 *srcaddr6; |
324 | #endif | |
325 | ||
315 | 326 | |
316 | 327 | dest_with_port = *destaddr; |
317 | 328 | |
322 | 333 | anything to the port. |
323 | 334 | */ |
324 | 335 | *sockaddr_port_offset(&dest_with_port) = htons(1); |
325 | len = sockaddr_addr_size(&dest_with_port); | |
336 | len = sockaddr_size(&dest_with_port); | |
326 | 337 | |
327 | 338 | sock = socket(destaddr->ss_family, SOCK_DGRAM, IPPROTO_UDP); |
328 | 339 | if (sock == -1) { |
340 | probe_err = "open socket"; | |
329 | 341 | return -1; |
330 | 342 | } |
331 | 343 | |
332 | 344 | if (connect(sock, (struct sockaddr *) &dest_with_port, len) == 0) { |
333 | 345 | if (getsockname(sock, (struct sockaddr *) srcaddr, &len)) { |
334 | 346 | close(sock); |
347 | probe_err = "getsockname"; | |
335 | 348 | return -1; |
336 | 349 | } |
337 | 350 | } else { |
340 | 353 | * a case when mtr is run against unreachable host (that can become |
341 | 354 | * reachable) */ |
342 | 355 | if (errno != EHOSTUNREACH) { |
356 | probe_err = "not hostunreach"; | |
343 | 357 | close(sock); |
344 | 358 | return -1; |
345 | 359 | } |
353 | 367 | } |
354 | 368 | #else |
355 | 369 | close(sock); |
370 | probe_err = "connect failed"; | |
356 | 371 | return -1; |
357 | 372 | #endif |
358 | 373 | } |
363 | 378 | Zero the port, as we may later use this address to finding, and |
364 | 379 | we don't want to use the port from the socket we just created. |
365 | 380 | */ |
366 | *sockaddr_port_offset(&srcaddr) = 0; | |
381 | *sockaddr_port_offset(srcaddr) = 0; | |
367 | 382 | |
368 | 383 | return 0; |
369 | 384 | } |
67 | 67 | /* The packet "mark" used for mark-based routing on Linux */ |
68 | 68 | int routing_mark; |
69 | 69 | |
70 | /* Time to live for the transmited probe */ | |
70 | /* Time to live for the transmitted probe */ | |
71 | 71 | int ttl; |
72 | 72 | |
73 | 73 | /* The packet size (in bytes) including protocol headers */ |
206 | 206 | struct sockaddr_storage *srcaddr, |
207 | 207 | const struct sockaddr_storage *destaddr); |
208 | 208 | |
209 | extern char *probe_err; | |
210 | ||
209 | 211 | #endif |
80 | 80 | |
81 | 81 | We use the Cygwin pipe() to create the pipes, but in the ICMP |
82 | 82 | service thread we use the Win32 HANDLE that corresponds to the |
83 | recieving end of the input pipe to wait for ICMP requests. | |
83 | receiving end of the input pipe to wait for ICMP requests. | |
84 | 84 | */ |
85 | 85 | |
86 | 86 | |
93 | 93 | } |
94 | 94 | |
95 | 95 | /* |
96 | Convienience similar to error(), but for reporting Windows | |
96 | Convenience similar to error(), but for reporting Windows | |
97 | 97 | error codes instead of errno codes. |
98 | 98 | */ |
99 | 99 | void error_win(int exit_code, int win_error, const char *str) { |
482 | 482 | HANDLE event; |
483 | 483 | BOOL success; |
484 | 484 | bool read_pending; |
485 | int read_count; | |
485 | DWORD read_count; | |
486 | 486 | int err; |
487 | 487 | |
488 | 488 | /* |
716 | 716 | } |
717 | 717 | |
718 | 718 | /* |
719 | On Windows, an implementation of check_probe_timeout is unnecesary because | |
719 | On Windows, an implementation of check_probe_timeout is unnecessary because | |
720 | 720 | timeouts are managed by ICMP.DLL, including a call to the I/O completion |
721 | 721 | routine when the time fully expires. |
722 | 722 | */ |
51 | 51 | int packet_size, |
52 | 52 | const struct sockaddr_storage *sockaddr) |
53 | 53 | { |
54 | struct sockaddr_storage dst; | |
54 | 55 | int send_socket = 0; |
55 | 56 | int sockaddr_length; |
57 | ||
58 | memcpy(&dst, sockaddr, sizeof(struct sockaddr_storage)); | |
56 | 59 | |
57 | 60 | if (sockaddr->ss_family == AF_INET6) { |
58 | 61 | sockaddr_length = sizeof(struct sockaddr_in6); |
66 | 69 | } else if (param->protocol == IPPROTO_UDP) { |
67 | 70 | if (net_state->platform.ip6_socket_raw) { |
68 | 71 | send_socket = net_state->platform.udp6_send_socket; |
72 | /* we got a ipv6 udp raw socket | |
73 | * the remote port is in the payload | |
74 | * we do not set in the sockaddr | |
75 | */ | |
76 | *sockaddr_port_offset(&dst) = 0; | |
69 | 77 | } else { |
70 | 78 | send_socket = net_state->platform.ip6_txrx_udp_socket; |
71 | 79 | if (param->dest_port) { |
72 | *sockaddr_port_offset(sockaddr) = htons(param->dest_port); | |
80 | *sockaddr_port_offset(&dst) = htons(param->dest_port); | |
73 | 81 | } else { |
74 | *sockaddr_port_offset(sockaddr) = sequence; | |
82 | *sockaddr_port_offset(&dst) = sequence; | |
75 | 83 | } |
76 | 84 | } |
77 | 85 | } |
90 | 98 | } else if (param->protocol == IPPROTO_UDP) { |
91 | 99 | send_socket = net_state->platform.ip4_txrx_udp_socket; |
92 | 100 | if (param->dest_port) { |
93 | *sockaddr_port_offset(sockaddr) = htons(param->dest_port); | |
101 | *sockaddr_port_offset(&dst) = htons(param->dest_port); | |
94 | 102 | } else { |
95 | *sockaddr_port_offset(sockaddr) = sequence; | |
103 | *sockaddr_port_offset(&dst) = sequence; | |
96 | 104 | } |
97 | 105 | } |
98 | 106 | } |
104 | 112 | } |
105 | 113 | |
106 | 114 | return sendto(send_socket, packet, packet_size, 0, |
107 | (struct sockaddr *) sockaddr, sockaddr_length); | |
115 | (struct sockaddr *) &dst, sockaddr_length); | |
108 | 116 | } |
109 | 117 | |
110 | 118 | /* |
144 | 152 | |
145 | 153 | if (resolve_probe_addresses(net_state, ¶m, &p0.remote_addr, |
146 | 154 | &p0.local_addr)) { |
147 | fprintf(stderr, "Error decoding localhost address\n"); | |
155 | fprintf(stderr, "Error decoding localhost address (%s/%s)\n", | |
156 | probe_err, strerror (errno)); | |
148 | 157 | exit(EXIT_FAILURE); |
149 | 158 | } |
150 | 159 | |
682 | 691 | |
683 | 692 | /* |
684 | 693 | Read all available packets through our receiving raw socket, and |
685 | handle any responses to probes we have preivously sent. | |
694 | handle any responses to probes we have previously sent. | |
686 | 695 | */ |
687 | 696 | static |
688 | 697 | void receive_replies_from_recv_socket( |
794 | 803 | memcpy(&remote_addr, SO_EE_OFFENDER(ee), sizeof(remote_addr)); |
795 | 804 | } |
796 | 805 | } |
797 | #endif | |
798 | 806 | |
799 | 807 | #ifdef SO_PROTOCOL |
800 | 808 | if (icmp_connrefused_received) { |
814 | 822 | packet, packet_length, ×tamp); |
815 | 823 | } else { |
816 | 824 | #endif |
825 | #endif | |
817 | 826 | /* ICMP packets received from raw socket */ |
818 | 827 | handle_received_packet(net_state, &remote_addr, packet, |
819 | 828 | packet_length, ×tamp); |
829 | #ifdef HAVE_LINUX_ERRQUEUE_H | |
820 | 830 | #ifdef SO_PROTOCOL |
821 | 831 | } |
832 | #endif | |
822 | 833 | #endif |
823 | 834 | } |
824 | 835 | } |
39 | 39 | struct timeval departure_time; |
40 | 40 | }; |
41 | 41 | |
42 | /* We'll use rack sockets to send and recieve probes on Unix systems */ | |
42 | /* We'll use rack sockets to send and receive probes on Unix systems */ | |
43 | 43 | struct net_state_platform_t { |
44 | 44 | /* true if we were successful at opening IPv4 sockets */ |
45 | 45 | bool ip4_present; |
18 | 18 | #include "wait.h" |
19 | 19 | |
20 | 20 | #include <error.h> |
21 | #include <errno.h> | |
21 | 22 | #include <sys/select.h> |
22 | 23 | |
23 | 24 | #include "command.h" |
103 | 103 | Sleep until we receive a new probe response, a new command on the |
104 | 104 | command stream, or a probe timeout. On Unix systems, this means |
105 | 105 | we use select to wait on file descriptors for the command stream |
106 | and the raw recieve socket. | |
106 | and the raw receive socket. | |
107 | 107 | */ |
108 | 108 | void wait_for_activity( |
109 | 109 | struct command_buffer_t *command_buffer, |
33 | 33 | #define SEQUENCE_NUM 33000 |
34 | 34 | |
35 | 35 | /* |
36 | Check to see if the packet we've recieved is intended for this test | |
36 | Check to see if the packet we've received is intended for this test | |
37 | 37 | process. We expected the ICMP sequence number to be equal to our |
38 | 38 | process ID. |
39 | 39 | */ |
61 | 61 | |
62 | 62 | @unittest.skipIf(sys.platform == 'cygwin', 'No Cygwin test') |
63 | 63 | class TestIPv6Parameters(mtrpacket.MtrPacketTest): |
64 | 'Test packet paramter customization for IPv6' | |
64 | 'Test packet parameter customization for IPv6' | |
65 | 65 | |
66 | 66 | @unittest.skipUnless(mtrpacket.HAVE_IPV6, 'No IPv6') |
67 | 67 | def test_param(self): |
207 | 207 | def test_ttl_expired(self): |
208 | 208 | 'Test sending a probe which will have its time-to-live expire' |
209 | 209 | |
210 | # Probe Goolge's DNS server, but give the probe only one hop | |
210 | # Probe Google's DNS server, but give the probe only one hop | |
211 | 211 | # to live. |
212 | 212 | self.write_command('16 send-probe ip-4 8.8.8.8 ttl 1') |
213 | 213 | reply = self.parse_reply() |
219 | 219 | '''Test sending multiple probes in parallel |
220 | 220 | |
221 | 221 | We will expect the probes to complete out-of-order by sending |
222 | a probe to a distant host immeidately followed by a probe to | |
222 | a probe to a distant host immediately followed by a probe to | |
223 | 223 | the local host.''' |
224 | 224 | |
225 | 225 | success_count = 0 |
299 | 299 | def test_ttl_expired(self): |
300 | 300 | 'Test sending a probe which will have its time-to-live expire' |
301 | 301 | |
302 | # Probe Goolge's DNS server, but give the probe only one hop | |
302 | # Probe Google's DNS server, but give the probe only one hop | |
303 | 303 | # to live. |
304 | 304 | cmd = '53 send-probe ip-6 ' + self.google_addr + ' ttl 1' |
305 | 305 | self.write_command(cmd) |
312 | 312 | void asn_open( |
313 | 313 | struct mtr_ctl *ctl) |
314 | 314 | { |
315 | if (ctl->ipinfo_no >= 0) { | |
316 | DEB_syslog(LOG_INFO, "hcreate(%d)", IIHASH_HI); | |
317 | if (!(iihash = hcreate(IIHASH_HI))) | |
318 | error(0, errno, "ipinfo hash"); | |
319 | } | |
315 | DEB_syslog(LOG_INFO, "hcreate(%d)", IIHASH_HI); | |
316 | if (!(iihash = hcreate(IIHASH_HI))) | |
317 | error(0, errno, "ipinfo hash"); | |
320 | 318 | } |
321 | 319 | |
322 | 320 | void asn_close( |
323 | 321 | struct mtr_ctl *ctl) |
324 | 322 | { |
325 | if ((ctl->ipinfo_no >= 0) && iihash) { | |
323 | if (iihash) { | |
326 | 324 | DEB_syslog(LOG_INFO, "hdestroy()"); |
327 | 325 | hdestroy(); |
328 | 326 | iihash = 0; |
72 | 72 | struct mtr_ctl *ctl, |
73 | 73 | struct packet_command_pipe_t *cmdpipe, |
74 | 74 | const char *cmd, |
75 | struct command_t *result) | |
76 | { | |
77 | char reply[PACKET_REPLY_BUFFER_SIZE]; | |
75 | struct command_t *result, | |
76 | char *reply) | |
77 | { | |
78 | 78 | int command_length; |
79 | 79 | int write_length; |
80 | 80 | int read_length; |
119 | 119 | { |
120 | 120 | char check_command[COMMAND_BUFFER_SIZE]; |
121 | 121 | struct command_t reply; |
122 | char reply_buf[PACKET_REPLY_BUFFER_SIZE]; | |
122 | 123 | |
123 | 124 | snprintf(check_command, COMMAND_BUFFER_SIZE, |
124 | 125 | "1 check-support feature %s\n", feature); |
125 | 126 | |
126 | if (send_synchronous_command(ctl, cmdpipe, check_command, &reply) == | |
127 | if (send_synchronous_command(ctl, cmdpipe, check_command, &reply, reply_buf) == | |
127 | 128 | -1) { |
128 | 129 | return -1; |
129 | 130 | } |
205 | 206 | |
206 | 207 | extern char *myname; |
207 | 208 | /* |
208 | Execute mtr-packet, allowing the MTR_PACKET evironment to override | |
209 | Execute mtr-packet, allowing the MTR_PACKET environment to override | |
209 | 210 | the PATH when locating the executable. |
210 | 211 | */ |
211 | 212 | static |
753 | 754 | /* |
754 | 755 | Terminate the reply string at the newline, which |
755 | 756 | is necessary in the case where we are able to read |
756 | mulitple replies arriving simultaneously. | |
757 | multiple replies arriving simultaneously. | |
757 | 758 | */ |
758 | 759 | *end_of_reply = 0; |
759 | 760 |
423 | 423 | addr = net_addr(at); |
424 | 424 | mpls = net_mpls(at); |
425 | 425 | |
426 | addrcmp_result = addrcmp( | |
427 | (void *) addr, (void *) &ctl->unspec_addr, ctl->af); | |
426 | addrcmp_result = addrcmp(addr, &ctl->unspec_addr, ctl->af); | |
428 | 427 | |
429 | 428 | if (err == 0 && addrcmp_result != 0) { |
430 | 429 | name = dns_lookup(ctl, addr); |
471 | 470 | } |
472 | 471 | |
473 | 472 | /* Multi path */ |
474 | for (i = 0; i < MAXPATH; i++) { | |
473 | for (i = 0; i < MAX_PATH; i++) { | |
475 | 474 | addrs = net_addrs(at, i); |
476 | 475 | mplss = net_mplss(at, i); |
477 | if (addrcmp((void *) addrs, (void *) addr, ctl->af) == 0) | |
476 | if (addrcmp(addrs, addr, ctl->af) == 0) | |
478 | 477 | continue; |
479 | if (addrcmp | |
480 | ((void *) addrs, (void *) &ctl->unspec_addr, | |
481 | ctl->af) == 0) | |
478 | if (addrcmp(addrs, &ctl->unspec_addr,ctl->af) == 0) | |
482 | 479 | break; |
483 | 480 | |
484 | 481 | name = dns_lookup(ctl, addrs); |
644 | 641 | } |
645 | 642 | |
646 | 643 | if (err == 0 |
647 | && addrcmp((void *) addr, (void *) &ctl->unspec_addr, ctl->af)) { | |
644 | && addrcmp(addr, &ctl->unspec_addr, ctl->af)) { | |
648 | 645 | |
649 | 646 | if (!net_up(at)) { |
650 | 647 | attron(A_BOLD); |
700 | 697 | pwcenter(buf); |
701 | 698 | attroff(A_BOLD); |
702 | 699 | |
703 | mvprintw(1, 0, "%s (%s)", ctl->LocalHostname, net_localaddr()); | |
700 | mvprintw(1, 0, "%s (%s) -> %s", ctl->LocalHostname, net_localaddr(), ctl->Hostname); | |
704 | 701 | t = time(NULL); |
705 | 702 | mvprintw(1, maxx - 25, iso_time(&t)); |
706 | 703 | printw("\n"); |
80 | 80 | case DisplayTXT: |
81 | 81 | txt_open(); |
82 | 82 | break; |
83 | #ifdef HAVE_JANSSON | |
83 | 84 | case DisplayJSON: |
84 | 85 | json_open(); |
85 | 86 | break; |
87 | #endif | |
86 | 88 | case DisplayXML: |
87 | 89 | xml_open(); |
88 | 90 | break; |
126 | 128 | case DisplayTXT: |
127 | 129 | txt_close(ctl); |
128 | 130 | break; |
131 | #ifdef HAVE_JANSSON | |
129 | 132 | case DisplayJSON: |
130 | 133 | json_close(ctl); |
131 | 134 | break; |
135 | #endif | |
132 | 136 | case DisplayXML: |
133 | 137 | xml_close(ctl); |
134 | 138 | break; |
224 | 228 | void display_rawhost( |
225 | 229 | struct mtr_ctl *ctl, |
226 | 230 | int host, |
227 | ip_t * ip_addr) | |
231 | ip_t * ip_addr, | |
232 | struct mplslen *mpls) | |
228 | 233 | { |
229 | 234 | if (ctl->DisplayMode == DisplayRaw) |
230 | raw_rawhost(ctl, host, ip_addr); | |
235 | raw_rawhost(ctl, host, ip_addr, mpls); | |
231 | 236 | } |
232 | 237 | |
233 | 238 |
40 | 40 | DisplayXML, |
41 | 41 | DisplayCSV, |
42 | 42 | DisplayTXT, |
43 | DisplayJSON | |
43 | #ifdef HAVE_JANSSON | |
44 | DisplayJSON, | |
45 | #endif | |
44 | 46 | }; |
45 | 47 | |
46 | 48 | enum { |
73 | 75 | extern void display_rawhost( |
74 | 76 | struct mtr_ctl *ctl, |
75 | 77 | int hostnum, |
76 | ip_t * ip_addr); | |
78 | ip_t *ip_addr, | |
79 | struct mplslen *mpls); | |
77 | 80 | extern int display_keyaction( |
78 | 81 | struct mtr_ctl *ctl); |
79 | 82 | extern void display_loop( |
40 | 40 | #include "dns.h" |
41 | 41 | #include "net.h" |
42 | 42 | #include "utils.h" |
43 | #include "packet/sockaddr.h" | |
43 | 44 | |
44 | 45 | struct dns_results { |
45 | 46 | ip_t ip; |
104 | 105 | struct dns_results *t; |
105 | 106 | |
106 | 107 | for (t = results; t; t = t->next) { |
107 | if (addrcmp((void *) ip, (void *) &t->ip, ctl->af) == 0) | |
108 | if (addrcmp(ip, &t->ip, ctl->af) == 0) | |
108 | 109 | return t; |
109 | 110 | } |
110 | 111 | |
116 | 117 | struct sockaddr_storage *sa, |
117 | 118 | ip_t * ip) |
118 | 119 | { |
119 | struct sockaddr_in *sa_in; | |
120 | struct sockaddr_in6 *sa_in6; | |
121 | ||
122 | 120 | memset(sa, 0, sizeof(struct sockaddr_storage)); |
123 | switch (ctl->af) { | |
124 | case AF_INET: | |
125 | sa_in = (struct sockaddr_in *) sa; | |
126 | sa_in->sin_family = ctl->af; | |
127 | addrcpy((void *) &sa_in->sin_addr, (void *) ip, ctl->af); | |
128 | break; | |
129 | case AF_INET6: | |
130 | sa_in6 = (struct sockaddr_in6 *) sa; | |
131 | sa_in6->sin6_family = ctl->af; | |
132 | addrcpy((void *) &sa_in6->sin6_addr, (void *) ip, ctl->af); | |
133 | break; | |
134 | } | |
121 | sa->ss_family = ctl->af; | |
122 | memcpy(sockaddr_addr_offset(sa), ip, sockaddr_addr_size(sa)); | |
135 | 123 | } |
136 | 124 | |
137 | 125 | void dns_open( |
161 | 149 | error(EXIT_FAILURE, errno, "signal"); |
162 | 150 | } |
163 | 151 | |
164 | /* Close all unneccessary FDs. | |
152 | /* Close all unnecessary FDs. | |
165 | 153 | for debugging and error reporting, keep std-in/out/err. */ |
166 | 154 | for (i = 3; i < fromdns[1]; i++) { |
167 | 155 | if (i == todns[0]) |
275 | 263 | /* we've got a result. */ |
276 | 264 | if (r->name) |
277 | 265 | return r->name; |
278 | else | |
279 | return strlongip(ctl, ip); | |
280 | 266 | } else { |
281 | 267 | r = xmalloc(sizeof(struct dns_results)); |
282 | 268 | memcpy(&r->ip, ip, sizeof(r->ip)); |
288 | 274 | if (rv < 0) |
289 | 275 | error(0, errno, "couldn't write to resolver process"); |
290 | 276 | } |
291 | return strlongip(ctl, ip); | |
277 | return NULL; | |
292 | 278 | } |
293 | 279 | |
294 | 280 | |
301 | 287 | if (!ctl->dns || !ctl->use_dns) |
302 | 288 | return NULL; |
303 | 289 | t = dns_lookup2(ctl, ip); |
304 | return t; | |
290 | return t ? t : strlongip(ctl, ip); | |
305 | 291 | } |
306 | 292 | |
307 | 293 | /* XXX check if necessary/exported. */ |
271 | 271 | GtkWidget *Label; |
272 | 272 | GtkAdjustment *Adjustment; |
273 | 273 | |
274 | Button = gtk_button_new_from_stock(GTK_STOCK_QUIT); | |
274 | Button = gtk_button_new_with_label("Quit"); | |
275 | 275 | gtk_box_pack_end(GTK_BOX(Toolbar), Button, FALSE, FALSE, 0); |
276 | g_signal_connect(GTK_OBJECT(Button), "clicked", | |
277 | GTK_SIGNAL_FUNC(Window_destroy), NULL); | |
278 | ||
279 | Button = gtk_button_new_from_stock(GTK_STOCK_ABOUT); | |
276 | g_signal_connect(G_OBJECT(Button), "clicked", | |
277 | G_CALLBACK(Window_destroy), NULL); | |
278 | ||
279 | Button = gtk_button_new_with_label("About"); | |
280 | 280 | gtk_box_pack_end(GTK_BOX(Toolbar), Button, FALSE, FALSE, 0); |
281 | g_signal_connect(GTK_OBJECT(Button), "clicked", | |
282 | GTK_SIGNAL_FUNC(About_clicked), NULL); | |
281 | g_signal_connect(G_OBJECT(Button), "clicked", | |
282 | G_CALLBACK(About_clicked), NULL); | |
283 | 283 | |
284 | 284 | Button = gtk_button_new_with_mnemonic("_Restart"); |
285 | 285 | gtk_box_pack_end(GTK_BOX(Toolbar), Button, FALSE, FALSE, 0); |
286 | g_signal_connect(GTK_OBJECT(Button), "clicked", | |
287 | GTK_SIGNAL_FUNC(Restart_clicked), ctl); | |
286 | g_signal_connect(G_OBJECT(Button), "clicked", | |
287 | G_CALLBACK(Restart_clicked), ctl); | |
288 | 288 | |
289 | 289 | Pause_Button = gtk_toggle_button_new_with_mnemonic("_Pause"); |
290 | 290 | gtk_box_pack_end(GTK_BOX(Toolbar), Pause_Button, FALSE, FALSE, 0); |
291 | g_signal_connect(GTK_OBJECT(Pause_Button), "clicked", | |
292 | GTK_SIGNAL_FUNC(Pause_clicked), ctl); | |
291 | g_signal_connect(G_OBJECT(Pause_Button), "clicked", | |
292 | G_CALLBACK(Pause_clicked), ctl); | |
293 | 293 | |
294 | 294 | /* allow root only to set zero delay */ |
295 | 295 | Adjustment = (GtkAdjustment *) gtk_adjustment_new(ctl->WaitTime, |
300 | 300 | gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(Button), TRUE); |
301 | 301 | gtk_box_pack_end(GTK_BOX(Toolbar), Button, FALSE, FALSE, 0); |
302 | 302 | ctl->gtk_data = Button; |
303 | g_signal_connect(GTK_OBJECT(Adjustment), "value_changed", | |
304 | GTK_SIGNAL_FUNC(WaitTime_changed), ctl); | |
303 | g_signal_connect(G_OBJECT(Adjustment), "value_changed", | |
304 | G_CALLBACK(WaitTime_changed), ctl); | |
305 | 305 | |
306 | 306 | Label = gtk_label_new_with_mnemonic("_Hostname:"); |
307 | 307 | gtk_box_pack_start(GTK_BOX(Toolbar), Label, FALSE, FALSE, 0); |
308 | 308 | |
309 | 309 | Entry = gtk_entry_new(); |
310 | 310 | gtk_entry_set_text(GTK_ENTRY(Entry), ctl->Hostname); |
311 | g_signal_connect(GTK_OBJECT(Entry), "activate", | |
312 | GTK_SIGNAL_FUNC(Host_activate), ctl); | |
311 | g_signal_connect(G_OBJECT(Entry), "activate", | |
312 | G_CALLBACK(Host_activate), ctl); | |
313 | 313 | gtk_box_pack_start(GTK_BOX(Toolbar), Entry, TRUE, TRUE, 0); |
314 | 314 | |
315 | 315 | gtk_label_set_mnemonic_widget(GTK_LABEL(Label), Entry); |
393 | 393 | ReportTreeView = |
394 | 394 | gtk_tree_view_new_with_model(GTK_TREE_MODEL(ReportStore)); |
395 | 395 | |
396 | g_signal_connect(GTK_OBJECT(ReportTreeView), "button_press_event", | |
396 | g_signal_connect(G_OBJECT(ReportTreeView), "button_press_event", | |
397 | 397 | G_CALLBACK(ReportTreeView_clicked), ctl); |
398 | 398 | |
399 | 399 | #ifdef HAVE_IPINFO |
506 | 506 | char str[256] = "???", *name = str; |
507 | 507 | |
508 | 508 | addr = net_addr(row); |
509 | if (addrcmp((void *) addr, (void *) &ctl->unspec_addr, ctl->af)) { | |
509 | if (addrcmp(addr, &ctl->unspec_addr, ctl->af)) { | |
510 | 510 | if ((name = dns_lookup(ctl, addr))) { |
511 | 511 | if (ctl->show_ips) { |
512 | 512 | snprintf(str, sizeof(str), "%s (%s)", name, |
563 | 563 | } |
564 | 564 | } |
565 | 565 | |
566 | // GTK 3 has changed the interface a bit. Here a few defines so that we can | |
567 | // work with GTK2 or GTK3 as required. | |
568 | #ifdef HAVE_GTK3 | |
569 | #define gtk_vbox_new_(orientation,sz) gtk_box_new(orientation, sz) | |
570 | #define gtk_hbox_new_(orientation,sz) gtk_box_new(orientation, sz) | |
571 | #else | |
572 | #define gtk_vbox_new_(orientation,sz) gtk_vbox_new(FALSE, sz) | |
573 | #define gtk_hbox_new_(orientation,sz) gtk_hbox_new(FALSE, sz) | |
574 | #endif | |
566 | 575 | |
567 | 576 | static void Window_fill( |
568 | 577 | struct mtr_ctl *ctl, |
575 | 584 | gtk_window_set_title(GTK_WINDOW(Window), "My traceroute"); |
576 | 585 | gtk_window_set_default_size(GTK_WINDOW(Window), 650, 400); |
577 | 586 | gtk_container_set_border_width(GTK_CONTAINER(Window), 10); |
578 | VBox = gtk_vbox_new(FALSE, 10); | |
579 | ||
580 | Toolbar = gtk_hbox_new(FALSE, 10); | |
587 | ||
588 | VBox = gtk_vbox_new_(GTK_ORIENTATION_VERTICAL, 10); | |
589 | Toolbar = gtk_hbox_new_(GTK_ORIENTATION_HORIZONTAL, 10); | |
590 | ||
581 | 591 | Toolbar_fill(ctl, Toolbar); |
582 | 592 | gtk_box_pack_start(GTK_BOX(VBox), Toolbar, FALSE, FALSE, 0); |
583 | 593 | |
618 | 628 | |
619 | 629 | Window_fill(ctl, main_window); |
620 | 630 | |
621 | g_signal_connect(GTK_OBJECT(main_window), "delete_event", | |
622 | GTK_SIGNAL_FUNC(Window_destroy), NULL); | |
623 | g_signal_connect(GTK_OBJECT(main_window), "destroy", | |
624 | GTK_SIGNAL_FUNC(Window_destroy), NULL); | |
631 | g_signal_connect(G_OBJECT(main_window), "delete_event", | |
632 | G_CALLBACK(Window_destroy), NULL); | |
633 | g_signal_connect(G_OBJECT(main_window), "destroy", | |
634 | G_CALLBACK(Window_destroy), NULL); | |
625 | 635 | |
626 | 636 | gtk_widget_show_all(main_window); |
627 | 637 | } |
800 | 810 | newdestination_item = |
801 | 811 | gtk_menu_item_new_with_label("Set as new destination"); |
802 | 812 | |
803 | gtk_menu_append(GTK_MENU(popup_menu), copy_item); | |
804 | gtk_menu_append(GTK_MENU(popup_menu), newdestination_item); | |
805 | ||
806 | g_signal_connect(GTK_OBJECT(copy_item), "activate", | |
807 | GTK_SIGNAL_FUNC(Copy_activate), path); | |
813 | gtk_menu_shell_append(GTK_MENU_SHELL(popup_menu), copy_item); | |
814 | gtk_menu_shell_append(GTK_MENU_SHELL(popup_menu), newdestination_item); | |
815 | ||
816 | g_signal_connect(G_OBJECT(copy_item), "activate", | |
817 | G_CALLBACK(Copy_activate), path); | |
808 | 818 | |
809 | 819 | ctl->gtk_data = path; |
810 | g_signal_connect(GTK_OBJECT(newdestination_item), "activate", | |
811 | GTK_SIGNAL_FUNC(NewDestination_activate), ctl); | |
820 | g_signal_connect(G_OBJECT(newdestination_item), "activate", | |
821 | G_CALLBACK(NewDestination_activate), ctl); | |
812 | 822 | |
813 | 823 | gtk_widget_show(copy_item); |
814 | 824 | gtk_widget_show(newdestination_item); |
815 | 825 | |
826 | #ifdef HAVE_GTK3 | |
827 | gtk_menu_popup_at_pointer(GTK_MENU(popup_menu), NULL); | |
828 | #else | |
816 | 829 | gtk_menu_popup(GTK_MENU(popup_menu), NULL, NULL, NULL, NULL, |
817 | 830 | 0, event->time); |
831 | #endif | |
818 | 832 | return TRUE; |
819 | 833 | } |
298 | 298 | { |
299 | 299 | int i; |
300 | 300 | |
301 | memset(ctl->fld_index, -1, FLD_INDEX_SZ); | |
301 | memset(ctl->fld_index, -1, FLD_INDEX_SZ*sizeof(ctl->fld_index[0])); | |
302 | 302 | |
303 | 303 | for (i = 0; data_fields[i].key != 0; i++) { |
304 | 304 | ctl->available_options[i] = data_fields[i].key; |
348 | 348 | #endif |
349 | 349 | {"raw", 0, NULL, 'l'}, |
350 | 350 | {"csv", 0, NULL, 'C'}, |
351 | #ifdef HAVE_JANSSON | |
351 | 352 | {"json", 0, NULL, 'j'}, |
353 | #endif | |
352 | 354 | {"displaymode", 1, NULL, OPT_DISPLAYMODE}, |
353 | 355 | {"split", 0, NULL, 'p'}, /* BL */ |
354 | 356 | /* maybe above should change to -d 'x' */ |
444 | 446 | case 'C': |
445 | 447 | ctl->DisplayMode = DisplayCSV; |
446 | 448 | break; |
449 | #ifdef HAVE_JANSSON | |
447 | 450 | case 'j': |
448 | 451 | ctl->DisplayMode = DisplayJSON; |
449 | 452 | break; |
453 | #endif | |
450 | 454 | case 'x': |
451 | 455 | ctl->DisplayMode = DisplayXML; |
452 | 456 | break; |
643 | 647 | |
644 | 648 | if (ctl->DisplayMode == DisplayReport || |
645 | 649 | ctl->DisplayMode == DisplayTXT || |
650 | #ifdef HAVE_JANSSON | |
646 | 651 | ctl->DisplayMode == DisplayJSON || |
652 | #endif | |
647 | 653 | ctl->DisplayMode == DisplayXML || |
648 | 654 | ctl->DisplayMode == DisplayRaw || ctl->DisplayMode == DisplayCSV) |
649 | 655 | ctl->Interactive = 0; |
60 | 60 | |
61 | 61 | /* net related definitions */ |
62 | 62 | #define SAVED_PINGS 200 |
63 | #define MAXPATH 8 | |
63 | #define MAX_PATH 8 | |
64 | 64 | #define MaxHost 256 |
65 | 65 | #define MinPort 1024 |
66 | 66 | #define MaxPort 65535 |
38 | 38 | #include "display.h" |
39 | 39 | #include "dns.h" |
40 | 40 | #include "utils.h" |
41 | #include "packet/sockaddr.h" | |
41 | 42 | |
42 | 43 | #define MinSequence 33000 |
43 | 44 | #define MaxSequence 65536 |
44 | 45 | |
45 | 46 | static int packetsize; /* packet size used by ping */ |
46 | 47 | |
47 | static void sockaddrtop( | |
48 | struct sockaddr *saddr, | |
49 | char *strptr, | |
50 | size_t len); | |
51 | ||
52 | 48 | struct nethost { |
53 | ip_t addr; | |
54 | ip_t addrs[MAXPATH]; /* for multi paths byMin */ | |
49 | ip_t addr; /* Latest host to respond */ | |
50 | ip_t addrs[MAX_PATH]; /* For Multi paths/Path Changes: List of all hosts that have responded */ | |
55 | 51 | int err; |
56 | 52 | int xmit; |
57 | 53 | int returned; |
71 | 67 | int saved[SAVED_PINGS]; |
72 | 68 | int saved_seq_offset; |
73 | 69 | struct mplslen mpls; |
74 | struct mplslen mplss[MAXPATH]; | |
70 | struct mplslen mplss[MAX_PATH]; | |
75 | 71 | }; |
76 | 72 | |
77 | 73 | |
87 | 83 | static struct sequence sequence[MaxSequence]; |
88 | 84 | static struct packet_command_pipe_t packet_command_pipe; |
89 | 85 | |
90 | #ifdef ENABLE_IPV6 | |
91 | 86 | static struct sockaddr_storage sourcesockaddr_struct; |
92 | 87 | static struct sockaddr_storage remotesockaddr_struct; |
93 | static struct sockaddr_in6 *ssa6 = | |
94 | (struct sockaddr_in6 *) &sourcesockaddr_struct; | |
95 | static struct sockaddr_in6 *rsa6 = | |
96 | (struct sockaddr_in6 *) &remotesockaddr_struct; | |
97 | #else | |
98 | static struct sockaddr_in sourcesockaddr_struct; | |
99 | static struct sockaddr_in remotesockaddr_struct; | |
100 | #endif | |
101 | 88 | |
102 | 89 | static struct sockaddr *sourcesockaddr = |
103 | 90 | (struct sockaddr *) &sourcesockaddr_struct; |
104 | 91 | static struct sockaddr *remotesockaddr = |
105 | 92 | (struct sockaddr *) &remotesockaddr_struct; |
106 | static struct sockaddr_in *ssa4 = | |
107 | (struct sockaddr_in *) &sourcesockaddr_struct; | |
108 | static struct sockaddr_in *rsa4 = | |
109 | (struct sockaddr_in *) &remotesockaddr_struct; | |
110 | 93 | |
111 | 94 | static ip_t *sourceaddress; |
112 | 95 | static ip_t *remoteaddress; |
123 | 106 | static int batch_at = 0; |
124 | 107 | static int numhosts = 10; |
125 | 108 | |
109 | ||
110 | #define host_addr_cmp(index, other, af) \ | |
111 | addrcmp((void *) &(host[(index)].addr), (void *) (other), (af)) | |
112 | ||
113 | #define host_addrs_cmp(index, path, other, af) \ | |
114 | addrcmp((void *) &(host[(index)].addrs[path]), (void *) (other), (af)) | |
115 | ||
116 | ||
126 | 117 | /* return the number of microseconds to wait before sending the next |
127 | 118 | ping */ |
128 | 119 | int calc_deltatime( |
183 | 174 | int time_to_live = index + 1; |
184 | 175 | |
185 | 176 | send_probe_command(ctl, &packet_command_pipe, remoteaddress, |
186 | sourceaddress, packetsize, seq, time_to_live); | |
177 | sourceaddress, packet_size, seq, time_to_live); | |
187 | 178 | } |
188 | 179 | |
189 | 180 | |
214 | 205 | |
215 | 206 | Record the round trip time and address of the responding host. |
216 | 207 | */ |
208 | ||
217 | 209 | static void net_process_ping( |
218 | 210 | struct mtr_ctl *ctl, |
219 | 211 | int seq, |
226 | 218 | int oldavg; /* usedByMin */ |
227 | 219 | int oldjavg; /* usedByMin */ |
228 | 220 | int i; /* usedByMin */ |
221 | int found = 0; | |
229 | 222 | #ifdef ENABLE_IPV6 |
230 | 223 | char addrcopy[sizeof(struct in6_addr)]; |
231 | 224 | #else |
232 | 225 | char addrcopy[sizeof(struct in_addr)]; |
233 | 226 | #endif |
234 | ||
235 | addrcpy((void *) &addrcopy, (char *) addr, ctl->af); | |
227 | struct nethost *nh = NULL; | |
228 | ||
229 | memcpy(&addrcopy, addr, sockaddr_addr_size(sourcesockaddr)); | |
236 | 230 | |
237 | 231 | index = mark_sequence_complete(seq); |
238 | 232 | if (index < 0) { |
239 | 233 | return; |
240 | 234 | } |
241 | ||
242 | host[index].err = err; | |
243 | ||
244 | if (addrcmp((void *) &(host[index].addr), | |
245 | (void *) &ctl->unspec_addr, ctl->af) == 0) { | |
246 | /* should be out of if as addr can change */ | |
247 | addrcpy((void *) &(host[index].addr), addrcopy, ctl->af); | |
248 | host[index].mpls = *mpls; | |
249 | display_rawhost(ctl, index, (void *) &(host[index].addr)); | |
250 | ||
251 | /* multi paths */ | |
252 | addrcpy((void *) &(host[index].addrs[0]), addrcopy, ctl->af); | |
253 | host[index].mplss[0] = *mpls; | |
254 | } else { | |
255 | for (i = 0; i < MAXPATH;) { | |
256 | if (addrcmp | |
257 | ((void *) &(host[index].addrs[i]), (void *) &addrcopy, | |
258 | ctl->af) == 0 | |
259 | || addrcmp((void *) &(host[index].addrs[i]), | |
260 | (void *) &ctl->unspec_addr, ctl->af) == 0) { | |
235 | nh = &host[index]; | |
236 | nh->err = err; | |
237 | ||
238 | ||
239 | ||
240 | if (addrcmp(&nh->addr, &addrcopy, ctl->af) != 0) { | |
241 | for (i = 0; i < MAX_PATH;) { | |
242 | if (addrcmp(&nh->addrs[i], &nh->addr, ctl->af) == 0) { | |
243 | found = 1; /* This host is already in the list */ | |
261 | 244 | break; |
245 | } | |
246 | if (addrcmp(&nh->addrs[i], &ctl->unspec_addr, ctl->af) == 0) { | |
247 | break; /* Found first vacant position */ | |
262 | 248 | } |
263 | 249 | i++; |
264 | 250 | } |
265 | 251 | |
266 | if (addrcmp((void *) &(host[index].addrs[i]), addrcopy, ctl->af) != | |
267 | 0 && i < MAXPATH) { | |
268 | addrcpy((void *) &(host[index].addrs[i]), addrcopy, ctl->af); | |
269 | host[index].mplss[i] = *mpls; | |
270 | display_rawhost(ctl, index, (void *) &(host[index].addrs[i])); | |
252 | if (found == 0 && i < MAX_PATH) { | |
253 | memcpy(&nh->addrs[i], &nh->addr, sockaddr_addr_size(sourcesockaddr)); | |
254 | ||
255 | nh->mplss[i] = nh->mpls; | |
256 | display_rawhost(ctl, index, (void *)&(nh->addrs[i]), (void *)&(nh->addrs[i])); | |
271 | 257 | } |
272 | } | |
273 | ||
274 | host[index].jitter = totusec - host[index].last; | |
275 | if (host[index].jitter < 0) { | |
276 | host[index].jitter = -host[index].jitter; | |
277 | } | |
278 | ||
279 | host[index].last = totusec; | |
280 | ||
281 | if (host[index].returned < 1) { | |
282 | host[index].best = host[index].worst = host[index].gmean = totusec; | |
283 | host[index].avg = host[index].ssd = 0; | |
284 | ||
285 | host[index].jitter = host[index].jworst = host[index].jinta = 0; | |
286 | } | |
287 | ||
288 | if (totusec < host[index].best) { | |
289 | host[index].best = totusec; | |
290 | } | |
291 | if (totusec > host[index].worst) { | |
292 | host[index].worst = totusec; | |
293 | } | |
294 | ||
295 | if (host[index].jitter > host[index].jworst) { | |
296 | host[index].jworst = host[index].jitter; | |
297 | } | |
298 | ||
299 | host[index].returned++; | |
300 | oldavg = host[index].avg; | |
301 | host[index].avg += (totusec - oldavg + .0) / host[index].returned; | |
302 | host[index].ssd += | |
303 | (totusec - oldavg + .0) * (totusec - host[index].avg); | |
304 | ||
305 | oldjavg = host[index].javg; | |
306 | host[index].javg += | |
307 | (host[index].jitter - oldjavg) / host[index].returned; | |
258 | ||
259 | /* Always save the latest host in nh->addr. This | |
260 | * allows maxTTL to change whenever path changes. | |
261 | */ | |
262 | memcpy(&nh->addr, addrcopy, sockaddr_addr_size(sourcesockaddr)); | |
263 | nh->mpls = *mpls; | |
264 | display_rawhost(ctl, index, (void *)&(nh->addr), (void *)&(nh->mpls)); | |
265 | } | |
266 | ||
267 | nh->jitter = totusec - nh->last; | |
268 | if (nh->jitter < 0) { | |
269 | nh->jitter = -nh->jitter; | |
270 | } | |
271 | ||
272 | nh->last = totusec; | |
273 | ||
274 | if (nh->returned < 1) { | |
275 | nh->best = nh->worst = nh->gmean = totusec; | |
276 | nh->avg = nh->ssd = 0; | |
277 | ||
278 | nh->jitter = nh->jworst = nh->jinta = 0; | |
279 | } | |
280 | ||
281 | if (totusec < nh->best) { | |
282 | nh->best = totusec; | |
283 | } | |
284 | if (totusec > nh->worst) { | |
285 | nh->worst = totusec; | |
286 | } | |
287 | ||
288 | if (nh->jitter > nh->jworst) { | |
289 | nh->jworst = nh->jitter; | |
290 | } | |
291 | ||
292 | nh->returned++; | |
293 | oldavg = nh->avg; | |
294 | nh->avg += (totusec - oldavg + .0) / nh->returned; | |
295 | nh->ssd += | |
296 | (totusec - oldavg + .0) * (totusec - nh->avg); | |
297 | ||
298 | oldjavg = nh->javg; | |
299 | nh->javg += | |
300 | (nh->jitter - oldjavg) / nh->returned; | |
308 | 301 | /* below algorithm is from rfc1889, A.8 */ |
309 | host[index].jinta += | |
310 | host[index].jitter - ((host[index].jinta + 8) >> 4); | |
311 | ||
312 | if (host[index].returned > 1) { | |
313 | host[index].gmean = | |
314 | pow((double) host[index].gmean, | |
315 | (host[index].returned - 1.0) / host[index].returned) | |
316 | * pow((double) totusec, 1.0 / host[index].returned); | |
317 | } | |
318 | ||
319 | host[index].sent = 0; | |
320 | host[index].up = 1; | |
321 | host[index].transit = 0; | |
302 | nh->jinta += | |
303 | nh->jitter - ((nh->jinta + 8) >> 4); | |
304 | ||
305 | if (nh->returned > 1) { | |
306 | nh->gmean = | |
307 | pow((double) nh->gmean, | |
308 | (nh->returned - 1.0) / nh->returned) | |
309 | * pow((double) totusec, 1.0 / nh->returned); | |
310 | } | |
311 | ||
312 | nh->sent = 0; | |
313 | nh->up = 1; | |
314 | nh->transit = 0; | |
322 | 315 | |
323 | 316 | net_save_return(index, sequence[seq].saved_seq, totusec); |
324 | 317 | display_rawping(ctl, index, totusec, seq); |
474 | 467 | |
475 | 468 | max = 0; |
476 | 469 | for (at = 0; at < ctl->maxTTL; at++) { |
477 | if (addrcmp((void *) &(host[at].addr), | |
478 | (void *) remoteaddress, ctl->af) == 0) { | |
470 | if (host_addr_cmp(at , remoteaddress, ctl->af) == 0) { | |
479 | 471 | return at + 1; |
480 | 472 | } else if (host[at].err != 0) { |
481 | 473 | /* |
484 | 476 | final hop. |
485 | 477 | */ |
486 | 478 | return at + 1; |
487 | } else if (addrcmp((void *) &(host[at].addr), | |
488 | (void *) &ctl->unspec_addr, ctl->af) != 0) { | |
479 | } else if (host_addr_cmp(at, &ctl->unspec_addr, ctl->af) != 0) { | |
489 | 480 | max = at + 2; |
490 | 481 | } |
491 | 482 | } |
545 | 536 | struct mtr_ctl *ctl) |
546 | 537 | { |
547 | 538 | int n_unknown = 0, i; |
539 | int restart = 0; | |
548 | 540 | |
549 | 541 | /* randomized packet size and/or bit pattern if packetsize<0 and/or |
550 | 542 | bitpattern<0. abs(packetsize) and/or abs(bitpattern) will be used |
556 | 548 | have a range for "rand()" that runs to 32768, and the |
557 | 549 | destination range is 10000, you end up with 4 out of 32768 |
558 | 550 | 0-2768's and only 3 out of 32768 for results 2769 .. 9999. |
559 | As our detination range (in the example 10000) is much | |
551 | As our destination range (in the example 10000) is much | |
560 | 552 | smaller (reasonable packet sizes), and our rand() range much |
561 | 553 | larger, this effect is insignificant. Oh! That other formula |
562 | 554 | didn't work. */ |
574 | 566 | net_send_query(ctl, batch_at, abs(packetsize)); |
575 | 567 | |
576 | 568 | for (i = ctl->fstTTL - 1; i < batch_at; i++) { |
577 | if (addrcmp | |
578 | ((void *) &(host[i].addr), (void *) &ctl->unspec_addr, | |
579 | ctl->af) == 0) | |
569 | if (host_addr_cmp(i, &ctl->unspec_addr, ctl->af) == 0) | |
580 | 570 | n_unknown++; |
581 | 571 | |
582 | 572 | /* The second condition in the next "if" statement was added in mtr-0.56, |
584 | 574 | hosts. Removed in 0.65. |
585 | 575 | If the line proves necessary, it should at least NOT trigger that line |
586 | 576 | when host[i].addr == 0 */ |
587 | if ((addrcmp((void *) &(host[i].addr), | |
588 | (void *) remoteaddress, ctl->af) == 0)) | |
589 | n_unknown = MaxHost; /* Make sure we drop into "we should restart" */ | |
577 | if (host_addr_cmp(i, remoteaddress, ctl->af) == 0) { | |
578 | restart = 1; | |
579 | numhosts = i + 1; /* Saves batch_at - index number of probes in the next round!*/ | |
580 | break; | |
581 | } | |
590 | 582 | } |
591 | 583 | |
592 | 584 | if ( /* success in reaching target */ |
593 | (addrcmp((void *) &(host[batch_at].addr), | |
594 | (void *) remoteaddress, ctl->af) == 0) || | |
585 | (host_addr_cmp(batch_at, remoteaddress, ctl->af) == 0) || | |
595 | 586 | /* fail in consecutive maxUnknown (firewall?) */ |
596 | 587 | (n_unknown > ctl->maxUnknown) || |
597 | 588 | /* or reach limit */ |
598 | 589 | (batch_at >= ctl->maxTTL - 1)) { |
590 | restart = 1; | |
599 | 591 | numhosts = batch_at + 1; |
592 | } | |
593 | ||
594 | if(restart) { | |
600 | 595 | batch_at = ctl->fstTTL - 1; |
601 | 596 | return 1; |
602 | 597 | } |
643 | 638 | |
644 | 639 | interface = ifaddrs; |
645 | 640 | while (interface != NULL) { |
646 | if (!strcmp(interface->ifa_name, interface_name)) { | |
641 | if (interface->ifa_addr != NULL && !strcmp(interface->ifa_name, interface_name)) { | |
647 | 642 | found_interface_name = 1; |
648 | 643 | |
649 | 644 | if (interface->ifa_addr->sa_family == address_family) { |
689 | 684 | int udp_socket; |
690 | 685 | int addr_length; |
691 | 686 | struct sockaddr_storage remote_sockaddr; |
692 | struct sockaddr_in *remote4; | |
693 | struct sockaddr_in6 *remote6; | |
694 | 687 | |
695 | 688 | udp_socket = |
696 | 689 | socket(remotesockaddr->sa_family, SOCK_DGRAM, IPPROTO_UDP); |
702 | 695 | We need to set the port to a non-zero value for the connect |
703 | 696 | to succeed. |
704 | 697 | */ |
705 | if (remotesockaddr->sa_family == AF_INET6) { | |
706 | #ifdef ENABLE_IPV6 | |
707 | addr_length = sizeof(struct sockaddr_in6); | |
708 | ||
709 | memcpy(&remote_sockaddr, rsa6, addr_length); | |
710 | remote6 = (struct sockaddr_in6 *) &remote_sockaddr; | |
711 | remote6->sin6_port = htons(1); | |
712 | #endif | |
713 | } else { | |
714 | addr_length = sizeof(struct sockaddr_in); | |
715 | ||
716 | memcpy(&remote_sockaddr, rsa4, addr_length); | |
717 | remote4 = (struct sockaddr_in *) &remote_sockaddr; | |
718 | remote4->sin_port = htons(1); | |
719 | } | |
698 | addr_length = sockaddr_size(&remotesockaddr_struct); | |
699 | memcpy(&remote_sockaddr, &remotesockaddr_struct, addr_length); | |
700 | *sockaddr_port_offset(&remote_sockaddr) = htons(1); | |
720 | 701 | |
721 | 702 | if (connect |
722 | (udp_socket, (struct sockaddr *) &remote_sockaddr, addr_length)) { | |
703 | (udp_socket, (struct sockaddr *) &remote_sockaddr, sockaddr_size(&remote_sockaddr))) { | |
723 | 704 | #ifdef __linux__ |
724 | 705 | /* Linux doesn't require source address, so we can support |
725 | 706 | * a case when mtr is run against unreachable host (that can become |
738 | 719 | error(EXIT_FAILURE, errno, "local address determination failed"); |
739 | 720 | } |
740 | 721 | |
741 | sockaddrtop(sourcesockaddr, localaddr, sizeof(localaddr)); | |
722 | inet_ntop(sourcesockaddr->sa_family, sockaddr_addr_offset(sourcesockaddr), localaddr, sizeof(localaddr)); | |
742 | 723 | |
743 | 724 | close(udp_socket); |
744 | 725 | } |
758 | 739 | |
759 | 740 | net_reset(ctl); |
760 | 741 | |
761 | remotesockaddr->sa_family = hostent->h_addrtype; | |
762 | ||
763 | switch (hostent->h_addrtype) { | |
764 | case AF_INET: | |
765 | addrcpy((void *) &(rsa4->sin_addr), hostent->h_addr, AF_INET); | |
766 | sourceaddress = (ip_t *) & (ssa4->sin_addr); | |
767 | remoteaddress = (ip_t *) & (rsa4->sin_addr); | |
768 | break; | |
769 | #ifdef ENABLE_IPV6 | |
770 | case AF_INET6: | |
771 | addrcpy((void *) &(rsa6->sin6_addr), hostent->h_addr, AF_INET6); | |
772 | sourceaddress = (ip_t *) & (ssa6->sin6_addr); | |
773 | remoteaddress = (ip_t *) & (rsa6->sin6_addr); | |
774 | break; | |
775 | #endif | |
776 | default: | |
777 | error(EXIT_FAILURE, 0, "net_open bad address type"); | |
778 | } | |
742 | remotesockaddr->sa_family = sourcesockaddr->sa_family = hostent->h_addrtype; | |
743 | memcpy(sockaddr_addr_offset(remotesockaddr), hostent->h_addr, sockaddr_addr_size(remotesockaddr)); | |
744 | ||
745 | sourceaddress = sockaddr_addr_offset(sourcesockaddr); | |
746 | remoteaddress = sockaddr_addr_offset(remotesockaddr); | |
779 | 747 | |
780 | 748 | if (ctl->InterfaceAddress) { |
781 | 749 | net_validate_interface_address(ctl->af, ctl->InterfaceAddress); |
782 | 750 | } else if (ctl->InterfaceName) { |
783 | 751 | net_find_interface_address_from_name( |
784 | 752 | &sourcesockaddr_struct, ctl->af, ctl->InterfaceName); |
785 | ||
786 | sockaddrtop(sourcesockaddr, localaddr, sizeof(localaddr)); | |
753 | inet_ntop(sourcesockaddr->sa_family, sockaddr_addr_offset(sourcesockaddr), localaddr, sizeof(localaddr)); | |
787 | 754 | } else { |
788 | 755 | net_find_local_address(); |
789 | 756 | } |
803 | 770 | } |
804 | 771 | |
805 | 772 | remotesockaddr->sa_family = addr->h_addrtype; |
806 | addrcpy((void *) remoteaddress, addr->h_addr, addr->h_addrtype); | |
807 | ||
808 | switch (addr->h_addrtype) { | |
809 | case AF_INET: | |
810 | addrcpy((void *) &(rsa4->sin_addr), addr->h_addr, AF_INET); | |
811 | break; | |
812 | #ifdef ENABLE_IPV6 | |
813 | case AF_INET6: | |
814 | addrcpy((void *) &(rsa6->sin6_addr), addr->h_addr, AF_INET6); | |
815 | break; | |
816 | #endif | |
817 | default: | |
818 | error(EXIT_FAILURE, 0, "net_reopen bad address type"); | |
819 | } | |
820 | ||
773 | memcpy(remoteaddress, addr->h_addr, sockaddr_addr_size(remotesockaddr)); | |
774 | memcpy(sockaddr_addr_offset(remotesockaddr), addr->h_addr, sockaddr_addr_size(remotesockaddr)); | |
821 | 775 | net_reset(ctl); |
822 | 776 | net_send_batch(ctl); |
823 | 777 | } |
906 | 860 | host[at].saved[idx] = ms; |
907 | 861 | } |
908 | 862 | |
909 | /* Similar to inet_ntop but uses a sockaddr as it's argument. */ | |
910 | static void sockaddrtop( | |
911 | struct sockaddr *saddr, | |
912 | char *strptr, | |
913 | size_t len) | |
914 | { | |
915 | struct sockaddr_in *sa4; | |
916 | #ifdef ENABLE_IPV6 | |
917 | struct sockaddr_in6 *sa6; | |
918 | #endif | |
919 | ||
920 | switch (saddr->sa_family) { | |
921 | case AF_INET: | |
922 | sa4 = (struct sockaddr_in *) saddr; | |
923 | xstrncpy(strptr, inet_ntoa(sa4->sin_addr), len - 1); | |
924 | strptr[len - 1] = '\0'; | |
925 | return; | |
926 | #ifdef ENABLE_IPV6 | |
927 | case AF_INET6: | |
928 | sa6 = (struct sockaddr_in6 *) saddr; | |
929 | inet_ntop(sa6->sin6_family, &(sa6->sin6_addr), strptr, len); | |
930 | return; | |
931 | #endif | |
932 | default: | |
933 | error(0, 0, "sockaddrtop unknown address type"); | |
934 | strptr[0] = '\0'; | |
935 | return; | |
936 | } | |
937 | } | |
938 | ||
939 | ||
940 | 863 | /* Address comparison. */ |
941 | 864 | int addrcmp( |
942 | char *a, | |
943 | char *b, | |
865 | void *a, | |
866 | void *b, | |
944 | 867 | int family) |
945 | 868 | { |
946 | 869 | int rc = -1; |
959 | 882 | return rc; |
960 | 883 | } |
961 | 884 | |
962 | /* Address copy. */ | |
963 | void addrcpy( | |
964 | char *a, | |
965 | char *b, | |
966 | int family) | |
967 | { | |
968 | ||
969 | switch (family) { | |
970 | case AF_INET: | |
971 | memcpy(a, b, sizeof(struct in_addr)); | |
972 | break; | |
973 | #ifdef ENABLE_IPV6 | |
974 | case AF_INET6: | |
975 | memcpy(a, b, sizeof(struct in6_addr)); | |
976 | break; | |
977 | #endif | |
978 | } | |
979 | } | |
980 | ||
981 | 885 | /* for GTK frontend */ |
982 | 886 | void net_harvest_fds( |
983 | 887 | struct mtr_ctl *ctl) |
116 | 116 | int ms); |
117 | 117 | |
118 | 118 | extern int addrcmp( |
119 | char *a, | |
120 | char *b, | |
121 | int af); | |
122 | extern void addrcpy( | |
123 | char *a, | |
124 | char *b, | |
119 | void *a, | |
120 | void *b, | |
125 | 121 | int af); |
126 | 122 | |
127 | 123 | extern void net_add_fds( |
63 | 63 | fflush(stdout); |
64 | 64 | } |
65 | 65 | |
66 | ||
67 | 66 | void raw_rawhost( |
68 | 67 | struct mtr_ctl *ctl, |
69 | 68 | int host, |
70 | ip_t * ip_addr) | |
69 | ip_t *ip_addr, | |
70 | struct mplslen *mpls) | |
71 | 71 | { |
72 | 72 | printf("h %d %s\n", host, strlongip(ctl, ip_addr)); |
73 | if (ctl->enablempls) { | |
74 | int k; | |
75 | for (k = 0; k < mpls->labels; k++) | |
76 | printf("m %d %lu %u %u %u\n", | |
77 | host, mpls->label[k], mpls->tc[k], mpls->s[k], mpls->ttl[k]); | |
78 | } | |
79 | ||
73 | 80 | fflush(stdout); |
74 | 81 | } |
29 | 29 | extern void raw_rawhost( |
30 | 30 | struct mtr_ctl *ctl, |
31 | 31 | int host, |
32 | ip_t * addr); | |
32 | ip_t *addr, | |
33 | struct mplslen *mpls); |
25 | 25 | #include <string.h> |
26 | 26 | #include <strings.h> |
27 | 27 | #include <time.h> |
28 | #ifdef HAVE_JANSSON | |
29 | #include <jansson.h> | |
30 | #endif | |
31 | #ifdef HAVE_ERROR_H | |
32 | #include <error.h> | |
33 | #else | |
34 | #include "portability/error.h" | |
35 | #endif | |
28 | 36 | |
29 | 37 | #include "mtr.h" |
30 | 38 | #include "report.h" |
175 | 183 | |
176 | 184 | /* This feature shows 'loadbalances' on routes */ |
177 | 185 | |
178 | /* z is starting at 1 because addrs[0] is the same that addr */ | |
179 | for (z = 1; z < MAXPATH; z++) { | |
186 | /* Print list of all hosts that have responded from ttl = at + 1 away */ | |
187 | for (z = 0; z < MAX_PATH; z++) { | |
180 | 188 | int found = 0; |
181 | 189 | addr2 = net_addrs(at, z); |
182 | 190 | mplss = net_mplss(at, z); |
183 | 191 | if ((addrcmp |
184 | 192 | ((void *) &ctl->unspec_addr, (void *) addr2, |
185 | ctl->af)) == 0) | |
193 | ctl->af)) == 0) { | |
186 | 194 | break; |
195 | } else if ((addrcmp | |
196 | ((void *) addr, (void *) addr2, | |
197 | ctl->af)) == 0) { | |
198 | continue; /* Latest Host is already printed */ | |
199 | } else { | |
200 | snprint_addr(ctl, name, sizeof(name), addr2); | |
201 | snprintf(fmt, sizeof(fmt), " %%-%zus", len_hosts); | |
202 | snprintf(buf, sizeof(buf), fmt, name); | |
203 | printf("%s\n", buf); | |
204 | } | |
187 | 205 | for (w = 0; w < z; w++) |
188 | 206 | /* Ok... checking if there are ips repeated on same hop */ |
189 | 207 | if ((addrcmp |
268 | 286 | report_close(ctl); |
269 | 287 | } |
270 | 288 | |
271 | ||
289 | #ifdef HAVE_JANSSON | |
272 | 290 | void json_open( |
273 | 291 | void) |
274 | 292 | { |
275 | 293 | } |
276 | 294 | |
277 | ||
278 | void json_close( | |
279 | struct mtr_ctl *ctl) | |
280 | { | |
281 | int i, j, at, first, max; | |
295 | void json_close(struct mtr_ctl *ctl) | |
296 | { | |
297 | int i, j, at, max; | |
298 | int ret; | |
299 | char buf[128]; | |
300 | json_t *jreport, *jmtr, *jhubs, *jh; | |
282 | 301 | ip_t *addr; |
283 | 302 | char name[MAX_FORMAT_STR]; |
284 | 303 | |
285 | printf("{\n"); | |
286 | printf(" \"report\": {\n"); | |
287 | printf(" \"mtr\": {\n"); | |
288 | printf(" \"src\": \"%s\",\n", ctl->LocalHostname); | |
289 | printf(" \"dst\": \"%s\",\n", ctl->Hostname); | |
290 | printf(" \"tos\": \"0x%X\",\n", ctl->tos); | |
304 | jmtr = json_pack("{ss ss si si}", | |
305 | "src", ctl->LocalHostname, | |
306 | "dst", ctl->Hostname, | |
307 | "tos", ctl->tos, | |
308 | "tests", ctl->MaxPing); | |
309 | if (!jmtr) | |
310 | goto on_error; | |
311 | ||
291 | 312 | if (ctl->cpacketsize >= 0) { |
292 | printf(" \"psize\": \"%d\",\n", ctl->cpacketsize); | |
313 | snprintf(buf, sizeof(buf), "%d", ctl->cpacketsize); | |
293 | 314 | } else { |
294 | printf(" \"psize\": \"rand(%d-%d)\",\n", MINPACKET, | |
295 | -ctl->cpacketsize); | |
296 | } | |
315 | snprintf(buf, sizeof(buf), "rand(%d-%d)", MINPACKET, -ctl->cpacketsize); | |
316 | } | |
317 | ret = json_object_set_new(jmtr, "psize", json_string(buf)); | |
318 | if (ret == -1) | |
319 | goto on_error; | |
320 | ||
297 | 321 | if (ctl->bitpattern >= 0) { |
298 | printf(" \"bitpattern\": \"0x%02X\",\n", | |
299 | (unsigned char) (ctl->bitpattern)); | |
322 | snprintf(buf, sizeof(buf), "0x%02X", (unsigned char)(ctl->bitpattern)); | |
300 | 323 | } else { |
301 | printf(" \"bitpattern\": \"rand(0x00-FF)\",\n"); | |
302 | } | |
303 | printf(" \"tests\": \"%d\"\n", ctl->MaxPing); | |
304 | printf(" },\n"); | |
305 | ||
306 | printf(" \"hubs\": ["); | |
324 | snprintf(buf, sizeof(buf), "rand(0x00-FF)"); | |
325 | } | |
326 | ||
327 | ret = json_object_set_new(jmtr, "bitpattern", json_string(buf)); | |
328 | if (ret == -1) | |
329 | goto on_error; | |
330 | ||
331 | jhubs = json_array(); | |
332 | if (!jhubs) | |
333 | goto on_error; | |
307 | 334 | |
308 | 335 | max = net_max(ctl); |
309 | at = first = net_min(ctl); | |
336 | at = net_min(ctl); | |
310 | 337 | for (; at < max; at++) { |
311 | 338 | addr = net_addr(at); |
312 | 339 | snprint_addr(ctl, name, sizeof(name), addr); |
313 | 340 | |
314 | if (at == first) { | |
315 | printf("{\n"); | |
316 | } else { | |
317 | printf(" {\n"); | |
318 | } | |
319 | printf(" \"count\": \"%d\",\n", at + 1); | |
320 | printf(" \"host\": \"%s\",\n", name); | |
341 | jh = json_pack("{si ss}", "count", at + 1, "host", name); | |
342 | if (!jh) | |
343 | goto on_error; | |
344 | ||
321 | 345 | #ifdef HAVE_IPINFO |
322 | 346 | if(!ctl->ipinfo_no) { |
323 | char* fmtinfo = fmt_ipinfo(ctl, addr); | |
324 | if (fmtinfo != NULL) fmtinfo = trim(fmtinfo, '\0'); | |
325 | printf(" \"ASN\": \"%s\",\n", fmtinfo); | |
326 | } | |
327 | #endif | |
347 | char* fmtinfo = fmt_ipinfo(ctl, addr); | |
348 | if (fmtinfo != NULL) | |
349 | fmtinfo = trim(fmtinfo, '\0'); | |
350 | ||
351 | ret = json_object_set_new(jh, "ASN", json_string(fmtinfo)); | |
352 | if (ret == -1) | |
353 | goto on_error; | |
354 | } | |
355 | #endif | |
356 | ||
328 | 357 | for (i = 0; i < MAXFLD; i++) { |
329 | const char *format; | |
330 | ||
331 | 358 | j = ctl->fld_index[ctl->fld_active[i]]; |
332 | 359 | |
333 | /* Commas */ | |
334 | if (i + 1 == MAXFLD) { | |
335 | printf("\n"); | |
336 | } else if (j > 0 && i != 0) { | |
337 | printf(",\n"); | |
338 | } | |
339 | ||
340 | 360 | if (j <= 0) |
341 | continue; /* Field nr 0, " " shouldn't be printed in this method. */ | |
342 | ||
343 | /* Format value */ | |
344 | format = data_fields[j].format; | |
345 | if (strchr(format, 'f')) { | |
346 | format = "%.2f"; | |
361 | continue; /* Field nr 0, " " shouldn't be printed in this method. */ | |
362 | ||
363 | if (strchr(data_fields[j].format, 'f')) { | |
364 | ret = json_object_set_new( | |
365 | jh, data_fields[j].title, | |
366 | json_real(data_fields[j].net_xxx(at) / 1000.0)); | |
347 | 367 | } else { |
348 | format = "%d"; | |
349 | } | |
350 | ||
351 | /* Format json line */ | |
352 | snprintf(name, sizeof(name), "%s%s", " \"%s\": ", format); | |
353 | ||
354 | /* Output json line */ | |
355 | if (strchr(data_fields[j].format, 'f')) { | |
356 | /* 1000.0 is a temporay hack for stats usec to ms, impacted net_loss. */ | |
357 | printf(name, | |
358 | data_fields[j].title, | |
359 | data_fields[j].net_xxx(at) / 1000.0); | |
360 | } else { | |
361 | printf(name, | |
362 | data_fields[j].title, data_fields[j].net_xxx(at)); | |
363 | } | |
364 | } | |
365 | if (at + 1 == max) { | |
366 | printf(" }"); | |
367 | } else { | |
368 | printf(" },\n"); | |
369 | } | |
370 | } | |
371 | printf("]\n"); | |
372 | printf(" }\n"); | |
373 | printf("}\n"); | |
374 | } | |
375 | ||
368 | ret = json_object_set_new( | |
369 | jh, data_fields[j].title, | |
370 | json_integer(data_fields[j].net_xxx(at))); | |
371 | } | |
372 | if (ret == -1) | |
373 | goto on_error; | |
374 | } | |
375 | ||
376 | ret = json_array_append_new(jhubs, jh); | |
377 | if (ret == -1) | |
378 | goto on_error; | |
379 | } | |
380 | ||
381 | jreport = json_pack("{s{so so}}", "report", "mtr", jmtr, "hubs", jhubs); | |
382 | ||
383 | ret = json_dumpf(jreport, stdout, JSON_INDENT(4) | JSON_REAL_PRECISION(5)); | |
384 | if (ret == -1) | |
385 | goto on_error; | |
386 | ||
387 | printf("\n"); // bash promt should be on new line | |
388 | json_decref(jreport); | |
389 | return; | |
390 | on_error: | |
391 | error(EXIT_FAILURE, 0, "json_close failed"); | |
392 | } | |
393 | #endif | |
376 | 394 | |
377 | 395 | |
378 | 396 | void xml_open( |