├── portability ├── .gitignore ├── error.h ├── error.c ├── getopt1.c └── getopt.h ├── bootstrap.sh ├── test ├── lint.sh ├── param.py ├── cmdparse.py └── packet_listen.c ├── .gitignore ├── ui ├── select.h ├── split.h ├── mtr-curses.h ├── mtr-gtk.h ├── raw.h ├── asn.h ├── report.h ├── utils.h ├── dns.h ├── raw.c ├── cmdpipe.h ├── display.h ├── net.h ├── split.c ├── utils.c ├── mtr.h ├── display.c ├── dns.c ├── select.c └── asn.c ├── packet ├── command_unix.h ├── wait.h ├── timeval.h ├── construct_unix.h ├── platform.h ├── cmdparse.h ├── deconstruct_unix.h ├── command.h ├── command_cygwin.h ├── wait_cygwin.c ├── timeval.c ├── probe_cygwin.h ├── command_unix.c ├── probe_unix.h ├── packet.c ├── protocols.h ├── cmdparse.c ├── command_cygwin.c ├── wait_unix.c ├── probe.h └── probe.c ├── BSDCOPYING ├── bash-completion └── mtr ├── SECURITY ├── AUTHORS ├── FORMATS ├── README ├── Makefile.am ├── TODO ├── img └── mtr_icon.xpm ├── configure.ac └── man └── mtr-packet.8.in /portability/.gitignore: -------------------------------------------------------------------------------- 1 | /.deps 2 | /.dirstamp 3 | -------------------------------------------------------------------------------- /bootstrap.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | aclocal $ACLOCAL_OPTS 4 | autoheader 5 | automake --add-missing --copy --foreign 6 | autoconf --force 7 | -------------------------------------------------------------------------------- /test/lint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Check the Python test source for good style 4 | 5 | PYTHON_SOURCE=*.py 6 | 7 | pep8 $PYTHON_SOURCE 8 | pylint --reports=n $PYTHON_SOURCE 2>/dev/null 9 | mypy --py2 $PYTHON_SOURCE 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # .gitignore 2 | *.o 3 | *.pyc 4 | 5 | Makefile 6 | Makefile.in 7 | aclocal.m4 8 | confdefs.h 9 | config.* 10 | configure 11 | confinc 12 | confmf 13 | conftest.* 14 | stamp-h1* 15 | 16 | /build-aux/compile 17 | /build-aux/depcomp 18 | /build-aux/install-sh 19 | /build-aux/missing 20 | /build-aux/test-driver 21 | 22 | /autom4te.cache/ 23 | /.deps/ 24 | /packet/.deps/ 25 | /packet/.dirstamp 26 | /packet/testpacket.py.log 27 | /packet/testpacket.py.trs 28 | /test-suite.log 29 | /ChangeLog 30 | /INSTALL 31 | /mtr 32 | /mtr-packet 33 | /mtr-packet-listen 34 | /mtr.8 35 | /mtr-packet.8 36 | /test/.deps/ 37 | /test/.dirstamp 38 | /ui/.deps/ 39 | /ui/.dirstamp 40 | 41 | /test/*.py.log 42 | /test/*.py.trs 43 | 44 | /mtr-*.tar.gz 45 | -------------------------------------------------------------------------------- /ui/select.h: -------------------------------------------------------------------------------- 1 | /* 2 | mtr -- a network diagnostic tool 3 | Copyright (C) 1997,1998 Matt Kimball 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License version 2 as 7 | published by the Free Software Foundation. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along 15 | with this program; if not, write to the Free Software Foundation, Inc., 16 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | extern void select_loop( 20 | struct mtr_ctl *ctl); 21 | -------------------------------------------------------------------------------- /portability/error.h: -------------------------------------------------------------------------------- 1 | /* 2 | Linux error(3) function go around for systems that has err(3) and 3 | warn(3), but no error(3). MacOS is good example of such. 4 | 5 | The GNU C Library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation version 2. 8 | 9 | The GNU C Library is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public 15 | License along with this library; if not, write to the Free Software 16 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 17 | 02110-1301 USA. 18 | */ 19 | 20 | void error(int status, int errnum, const char *format, ...); 21 | -------------------------------------------------------------------------------- /packet/command_unix.h: -------------------------------------------------------------------------------- 1 | /* 2 | mtr -- a network diagnostic tool 3 | Copyright (C) 2016 Matt Kimball 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License version 2 as 7 | published by the Free Software Foundation. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along 15 | with this program; if not, write to the Free Software Foundation, Inc., 16 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #ifndef COMMAND_UNIX_H 20 | #define COMMAND_UNIX_H 21 | 22 | /* No platform specific data is required for Unix command streams */ 23 | struct command_buffer_platform_t { 24 | }; 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /packet/wait.h: -------------------------------------------------------------------------------- 1 | /* 2 | mtr -- a network diagnostic tool 3 | Copyright (C) 2016 Matt Kimball 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License version 2 as 7 | published by the Free Software Foundation. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along 15 | with this program; if not, write to the Free Software Foundation, Inc., 16 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #ifndef WAIT_H 20 | #define WAIT_H 21 | 22 | #include "command.h" 23 | #include "probe.h" 24 | 25 | void wait_for_activity( 26 | struct command_buffer_t *command_buffer, 27 | struct net_state_t *net_state); 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /packet/timeval.h: -------------------------------------------------------------------------------- 1 | /* 2 | mtr -- a network diagnostic tool 3 | Copyright (C) 2016 Matt Kimball 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License version 2 as 7 | published by the Free Software Foundation. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along 15 | with this program; if not, write to the Free Software Foundation, Inc., 16 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #ifndef TIMEVAL_H 20 | #define TIMEVAL_H 21 | 22 | #include 23 | 24 | void normalize_timeval( 25 | struct timeval *timeval); 26 | 27 | int compare_timeval( 28 | struct timeval a, 29 | struct timeval b); 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /ui/split.h: -------------------------------------------------------------------------------- 1 | /* 2 | mtr -- a network diagnostic tool 3 | 4 | split.h -- raw output (for inclusion in KDE Network Utilities) 5 | Copyright (C) 1998 Bertrand Leconte 6 | 7 | This program is free software; you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License version 2 as 9 | published by the Free Software Foundation. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License along 17 | with this program; if not, write to the Free Software Foundation, Inc., 18 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 | */ 20 | 21 | /* Prototypes for split.c */ 22 | extern void split_open( 23 | void); 24 | extern void split_close( 25 | void); 26 | extern void split_redraw( 27 | struct mtr_ctl *ctl); 28 | extern int split_keyaction( 29 | void); 30 | -------------------------------------------------------------------------------- /ui/mtr-curses.h: -------------------------------------------------------------------------------- 1 | /* 2 | mtr -- a network diagnostic tool 3 | Copyright (C) 1997,1998 Matt Kimball 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License version 2 as 7 | published by the Free Software Foundation. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along 15 | with this program; if not, write to the Free Software Foundation, Inc., 16 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | /* Prototypes for curses.c */ 20 | extern void mtr_curses_open( 21 | struct mtr_ctl *ctl); 22 | extern void mtr_curses_close( 23 | void); 24 | extern void mtr_curses_redraw( 25 | struct mtr_ctl *ctl); 26 | extern int mtr_curses_keyaction( 27 | struct mtr_ctl *ctl); 28 | extern void mtr_curses_clear( 29 | struct mtr_ctl *ctl); 30 | -------------------------------------------------------------------------------- /ui/mtr-gtk.h: -------------------------------------------------------------------------------- 1 | /* 2 | mtr -- a network diagnostic tool 3 | Copyright (C) 1997,1998 Matt Kimball 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License version 2 as 7 | published by the Free Software Foundation. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along 15 | with this program; if not, write to the Free Software Foundation, Inc., 16 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | /* Prototypes for gtk.c */ 20 | extern int gtk_detect( 21 | int *argc, 22 | char ***argv); 23 | extern void gtk_open( 24 | struct mtr_ctl *ctl); 25 | extern void gtk_close( 26 | void); 27 | extern void gtk_redraw( 28 | struct mtr_ctl *ctl); 29 | extern int gtk_keyaction( 30 | void); 31 | extern void gtk_loop( 32 | struct mtr_ctl *ctl); 33 | -------------------------------------------------------------------------------- /ui/raw.h: -------------------------------------------------------------------------------- 1 | /* 2 | mtr -- a network diagnostic tool 3 | Copyright (C) 1998 R.E.Wolff@BitWizard.nl 4 | 5 | raw.h -- raw output (for logging for later analysis) 6 | 7 | This program is free software; you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License version 2 as 9 | published by the Free Software Foundation. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License along 17 | with this program; if not, write to the Free Software Foundation, Inc., 18 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 | */ 20 | 21 | /* Prototypes for raw.c */ 22 | extern void raw_rawxmit( 23 | int host, 24 | int seq); 25 | extern void raw_rawping( 26 | struct mtr_ctl *ctl, 27 | int host, 28 | int msec, 29 | int seq); 30 | extern void raw_rawhost( 31 | struct mtr_ctl *ctl, 32 | int host, 33 | ip_t * addr); 34 | -------------------------------------------------------------------------------- /ui/asn.h: -------------------------------------------------------------------------------- 1 | /* 2 | mtr -- a network diagnostic tool 3 | Copyright (C) 1997,1998 Matt Kimball 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License version 2 as 7 | published by the Free Software Foundation. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along 15 | with this program; if not, write to the Free Software Foundation, Inc., 16 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #include "mtr.h" 20 | 21 | extern void asn_open( 22 | struct mtr_ctl *ctl); 23 | extern void asn_close( 24 | struct mtr_ctl *ctl); 25 | extern char *fmt_ipinfo( 26 | struct mtr_ctl *ctl, 27 | ip_t * addr); 28 | extern ATTRIBUTE_CONST size_t get_iiwidth_len( 29 | void); 30 | extern ATTRIBUTE_CONST int get_iiwidth( 31 | int ipinfo_no); 32 | extern int is_printii( 33 | struct mtr_ctl *ctl); 34 | -------------------------------------------------------------------------------- /packet/construct_unix.h: -------------------------------------------------------------------------------- 1 | /* 2 | mtr -- a network diagnostic tool 3 | Copyright (C) 2016 Matt Kimball 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License version 2 as 7 | published by the Free Software Foundation. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along 15 | with this program; if not, write to the Free Software Foundation, Inc., 16 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #ifndef CONSTRUCT_H 20 | #define CONSTRUCT_H 21 | 22 | #include "probe.h" 23 | 24 | int construct_packet( 25 | const struct net_state_t *net_state, 26 | int *packet_socket, 27 | int sequence, 28 | char *packet_buffer, 29 | int packet_buffer_size, 30 | const struct sockaddr_storage *dest_sockaddr, 31 | const struct sockaddr_storage *src_sockaddr, 32 | const struct probe_param_t *param); 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /portability/error.c: -------------------------------------------------------------------------------- 1 | /* 2 | Linux error(3) function go around for systems that has err(3) and 3 | warn(3), but no error(3). MacOS is good example of such. 4 | 5 | The GNU C Library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation version 2. 8 | 9 | The GNU C Library is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 | Lesser General Public License for more details. 13 | 14 | You should have received a copy of the GNU Lesser General Public 15 | License along with this library; if not, write to the Free Software 16 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 17 | 02110-1301 USA. 18 | */ 19 | 20 | #include 21 | #include 22 | 23 | void error(int status, int errnum, const char *format, ...) { 24 | va_list arg; 25 | 26 | va_start(arg, format); 27 | if (errnum == 0) { 28 | if (status == 0) 29 | vwarnx(format, arg); 30 | else 31 | verrx(status, format, arg); 32 | } else { 33 | if (status == 0) 34 | vwarn(format, arg); 35 | else 36 | verr(status, format, arg); 37 | } 38 | va_end(arg); 39 | } 40 | -------------------------------------------------------------------------------- /ui/report.h: -------------------------------------------------------------------------------- 1 | /* 2 | mtr -- a network diagnostic tool 3 | Copyright (C) 1997,1998 Matt Kimball 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License version 2 as 7 | published by the Free Software Foundation. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along 15 | with this program; if not, write to the Free Software Foundation, Inc., 16 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | /* Prototypes for report.h */ 20 | 21 | extern void report_open( 22 | void); 23 | extern void report_close( 24 | struct mtr_ctl *ctl); 25 | extern void txt_open( 26 | void); 27 | extern void txt_close( 28 | struct mtr_ctl *ctl); 29 | extern void json_open( 30 | void); 31 | extern void json_close( 32 | struct mtr_ctl *ctl); 33 | extern void xml_open( 34 | void); 35 | extern void xml_close( 36 | struct mtr_ctl *ctl); 37 | extern void csv_open( 38 | void); 39 | extern void csv_close( 40 | struct mtr_ctl *ctl, 41 | time_t now); 42 | -------------------------------------------------------------------------------- /packet/platform.h: -------------------------------------------------------------------------------- 1 | /* 2 | mtr -- a network diagnostic tool 3 | Copyright (C) 2016 Matt Kimball 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License version 2 as 7 | published by the Free Software Foundation. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along 15 | with this program; if not, write to the Free Software Foundation, Inc., 16 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #ifndef PLATFORM_H 20 | #define PLATFORM_H 21 | 22 | /* 23 | Determine the most appropriate PLATFORM_* define for our 24 | current target. 25 | */ 26 | 27 | #if defined(__CYGWIN__) 28 | 29 | #define PLATFORM_CYGWIN 30 | 31 | #elif defined(__APPLE__) && defined(__MACH__) 32 | 33 | #define PLATFORM_OS_X 34 | 35 | #elif defined(__gnu_linux__) 36 | 37 | #define PLATFORM_LINUX 38 | 39 | #elif defined (__FreeBSD__) 40 | 41 | #define PLATFORM_FREEBSD 42 | 43 | #elif defined(__unix__) 44 | 45 | #define PLATFORM_UNIX_UNKNOWN 46 | 47 | #else 48 | 49 | #error Unsupported platform 50 | 51 | #endif 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /ui/utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | mtr -- a network diagnostic tool 3 | Copyright (C) 1997,1998 Matt Kimball 4 | Copyright (C) 2005 R.E.Wolff@BitWizard.nl 5 | 6 | This program is free software; you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License version 2 as 8 | published by the Free Software Foundation. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License along 16 | with this program; if not, write to the Free Software Foundation, Inc., 17 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | enum { 21 | STRTO_INT, 22 | STRTO_U32INT 23 | }; 24 | 25 | extern char *trim( 26 | char *s, 27 | const char c); 28 | extern int strtonum_or_err( 29 | const char *str, 30 | const char *errmesg, 31 | const int type); 32 | extern float strtofloat_or_err( 33 | const char *str, 34 | const char *errmesg); 35 | 36 | /* Like strncpy(3) but ensure null termination. */ 37 | static inline void xstrncpy( 38 | char *dest, 39 | const char *src, 40 | size_t n) 41 | { 42 | strncpy(dest, src, n - 1); 43 | dest[n - 1] = 0; 44 | } 45 | 46 | extern void *xmalloc( 47 | const size_t size); 48 | extern char *xstrdup( 49 | const char *str); 50 | 51 | extern void close_stdout( 52 | void); 53 | 54 | extern const char *iso_time( 55 | const time_t * t); 56 | -------------------------------------------------------------------------------- /ui/dns.h: -------------------------------------------------------------------------------- 1 | /* 2 | mtr -- a network diagnostic tool 3 | Copyright (C) 1997,1998 Matt Kimball 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License version 2 as 7 | published by the Free Software Foundation. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along 15 | with this program; if not, write to the Free Software Foundation, Inc., 16 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | /* Prototypes for dns.c */ 24 | 25 | extern void dns_open( 26 | struct mtr_ctl *ctl); 27 | extern int dns_waitfd( 28 | void); 29 | extern void dns_ack( 30 | struct mtr_ctl *ctl); 31 | #ifdef ENABLE_IPV6 32 | extern int dns_waitfd6( 33 | void); 34 | extern void dns_ack6( 35 | void); 36 | #endif 37 | 38 | extern char *dns_lookup( 39 | struct mtr_ctl *ctl, 40 | ip_t * address); 41 | extern char *dns_lookup2( 42 | struct mtr_ctl *ctl, 43 | ip_t * address); 44 | extern struct hostent *dns_forward( 45 | const char *name); 46 | extern char *strlongip( 47 | struct mtr_ctl *ctl, 48 | ip_t * ip); 49 | 50 | extern void addr2ip6arpa( 51 | ip_t * ip, 52 | char *buf); 53 | extern struct hostent *addr2host( 54 | const char *addr, 55 | int type); 56 | -------------------------------------------------------------------------------- /BSDCOPYING: -------------------------------------------------------------------------------- 1 | Portions of this software have the following copyright. 2 | 3 | -- 4 | 5 | Copyright (c) 1991, 1993 6 | The Regents of the University of California. All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions 10 | are met: 11 | 1. Redistributions of source code must retain the above copyright 12 | notice, this list of conditions and the following disclaimer. 13 | 2. Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | 4. Neither the name of the University nor the names of its contributors 17 | may be used to endorse or promote products derived from this software 18 | without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 | ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 | OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 | SUCH DAMAGE. 31 | -------------------------------------------------------------------------------- /packet/cmdparse.h: -------------------------------------------------------------------------------- 1 | /* 2 | mtr -- a network diagnostic tool 3 | Copyright (C) 2016 Matt Kimball 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License version 2 as 7 | published by the Free Software Foundation. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along 15 | with this program; if not, write to the Free Software Foundation, Inc., 16 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #ifndef CMDPARSE_H 20 | #define CMDPARSE_H 21 | 22 | enum { 23 | MAX_COMMAND_ARGUMENTS = 16, 24 | MAX_COMMAND_TOKENS = MAX_COMMAND_ARGUMENTS * 2 + 2 25 | }; 26 | 27 | /* Parsed commands, or command replies, ready for semantic interpretation */ 28 | struct command_t { 29 | /* A unique value for matching command requests with replies */ 30 | int token; 31 | 32 | /* Text indiciating the command type, or reply type */ 33 | char *command_name; 34 | 35 | /* The number of key, value argument pairs used */ 36 | int argument_count; 37 | 38 | /* Names for each argument */ 39 | char *argument_name[MAX_COMMAND_ARGUMENTS]; 40 | 41 | /* Values for each argument, parallel to the argument_name array */ 42 | char *argument_value[MAX_COMMAND_ARGUMENTS]; 43 | }; 44 | 45 | int parse_command( 46 | struct command_t *command, 47 | char *command_string); 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /packet/deconstruct_unix.h: -------------------------------------------------------------------------------- 1 | /* 2 | mtr -- a network diagnostic tool 3 | Copyright (C) 2016 Matt Kimball 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License version 2 as 7 | published by the Free Software Foundation. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along 15 | with this program; if not, write to the Free Software Foundation, Inc., 16 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #ifndef DECONSTRUCT_H 20 | #define DECONSTRUCT_H 21 | 22 | #include "probe.h" 23 | 24 | typedef void ( 25 | *received_packet_func_t) ( 26 | struct net_state_t * net_state, 27 | const struct sockaddr_storage * remote_addr, 28 | const void *packet, 29 | int packet_length, 30 | struct timeval * timestamp); 31 | 32 | void handle_received_ip4_packet( 33 | struct net_state_t *net_state, 34 | const struct sockaddr_storage *remote_addr, 35 | const void *packet, 36 | int packet_length, 37 | struct timeval *timestamp); 38 | 39 | void handle_received_ip6_packet( 40 | struct net_state_t *net_state, 41 | const struct sockaddr_storage *remote_addr, 42 | const void *packet, 43 | int packet_length, 44 | struct timeval *timestamp); 45 | 46 | void handle_error_queue_packet( 47 | struct net_state_t *net_state, 48 | const struct sockaddr_storage *remote_addr, 49 | int icmp_result, 50 | int proto, 51 | char *packet, 52 | int packet_length, 53 | struct timeval *timestamp); 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /packet/command.h: -------------------------------------------------------------------------------- 1 | /* 2 | mtr -- a network diagnostic tool 3 | Copyright (C) 2016 Matt Kimball 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License version 2 as 7 | published by the Free Software Foundation. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along 15 | with this program; if not, write to the Free Software Foundation, Inc., 16 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #ifndef COMMAND_H 20 | #define COMMAND_H 21 | 22 | #include "platform.h" 23 | #include "probe.h" 24 | 25 | #define COMMAND_BUFFER_SIZE 4096 26 | 27 | #ifdef PLATFORM_CYGWIN 28 | #include "command_cygwin.h" 29 | #else 30 | #include "command_unix.h" 31 | #endif 32 | 33 | /* Storage for incoming commands, prior to command parsing */ 34 | struct command_buffer_t { 35 | /* The file descriptor of the incoming command stream */ 36 | int command_stream; 37 | 38 | /* Storage to read commands into */ 39 | char incoming_buffer[COMMAND_BUFFER_SIZE]; 40 | 41 | /* The number of bytes read so far in incoming_buffer */ 42 | int incoming_read_position; 43 | 44 | /* Platform specific */ 45 | struct command_buffer_platform_t platform; 46 | }; 47 | 48 | void init_command_buffer( 49 | struct command_buffer_t *command_buffer, 50 | int command_stream); 51 | 52 | int read_commands( 53 | struct command_buffer_t *buffer); 54 | 55 | void dispatch_buffer_commands( 56 | struct command_buffer_t *buffer, 57 | struct net_state_t *net_state); 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /packet/command_cygwin.h: -------------------------------------------------------------------------------- 1 | /* 2 | mtr -- a network diagnostic tool 3 | Copyright (C) 2016 Matt Kimball 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License version 2 as 7 | published by the Free Software Foundation. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along 15 | with this program; if not, write to the Free Software Foundation, Inc., 16 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #ifndef COMMAND_CYGWIN_H 20 | #define COMMAND_CYGWIN_H 21 | 22 | /* 23 | Though Cygwin supports the usual Unix non-blocking reads on 24 | the command stream, we've got to use Overlapped I/O instead because 25 | ICMP.DLL's support for sending probes requires Overlapped I/O 26 | and alertable waits for notification of replies. Since we need 27 | alertable waits, we can't use Cygwin's select to determine when 28 | command stream data is available, but Overlapped I/O completion 29 | will work. 30 | */ 31 | 32 | /* Overlapped I/O manament for Windows command buffer reads */ 33 | struct command_buffer_platform_t { 34 | /* true if an overlapped I/O read is active */ 35 | bool read_active; 36 | 37 | /* true if the command pipe is still open */ 38 | bool pipe_open; 39 | 40 | /* Windows OVERLAPPED I/O data */ 41 | OVERLAPPED overlapped; 42 | 43 | /* The buffer which active OVERLAPPED reads read into */ 44 | char overlapped_buffer[COMMAND_BUFFER_SIZE]; 45 | }; 46 | 47 | struct command_buffer_t; 48 | 49 | void start_read_command( 50 | struct command_buffer_t *buffer); 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /ui/raw.c: -------------------------------------------------------------------------------- 1 | /* 2 | mtr -- a network diagnostic tool 3 | Copyright (C) 1998 R.E.Wolff@BitWizard.nl 4 | 5 | raw.c -- raw output (for logging for later analysis) 6 | 7 | This program is free software; you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License version 2 as 9 | published by the Free Software Foundation. 10 | 11 | This program is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | GNU General Public License for more details. 15 | 16 | You should have received a copy of the GNU General Public License along 17 | with this program; if not, write to the Free Software Foundation, Inc., 18 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 | */ 20 | 21 | #include "config.h" 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include "mtr.h" 32 | #include "raw.h" 33 | #include "net.h" 34 | #include "dns.h" 35 | 36 | 37 | /* Log an echo request, or a "ping" */ 38 | void raw_rawxmit( 39 | int host, 40 | int seq) 41 | { 42 | printf("x %d %d\n", host, seq); 43 | fflush(stdout); 44 | } 45 | 46 | /* Log an echo reply, or a "pong" */ 47 | void raw_rawping( 48 | struct mtr_ctl *ctl, 49 | int host, 50 | int msec, 51 | int seq) 52 | { 53 | static int havename[MaxHost]; 54 | char *name; 55 | 56 | if (ctl->dns && !havename[host]) { 57 | name = dns_lookup2(ctl, net_addr(host)); 58 | if (name) { 59 | havename[host]++; 60 | printf("d %d %s\n", host, name); 61 | } 62 | } 63 | printf("p %d %d %d\n", host, msec, seq); 64 | fflush(stdout); 65 | } 66 | 67 | 68 | void raw_rawhost( 69 | struct mtr_ctl *ctl, 70 | int host, 71 | ip_t * ip_addr) 72 | { 73 | printf("h %d %s\n", host, strlongip(ctl, ip_addr)); 74 | fflush(stdout); 75 | } 76 | -------------------------------------------------------------------------------- /packet/wait_cygwin.c: -------------------------------------------------------------------------------- 1 | /* 2 | mtr -- a network diagnostic tool 3 | Copyright (C) 2016 Matt Kimball 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License version 2 as 7 | published by the Free Software Foundation. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along 15 | with this program; if not, write to the Free Software Foundation, Inc., 16 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #include "wait.h" 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | #include "command.h" 26 | 27 | /* 28 | Sleep until we receive a new probe response, a new command on the 29 | command stream, or a probe timeout. On Windows, this means that 30 | we will sleep with an alertable wait, as all of these conditions 31 | use I/O completion routines as notifications of these events. 32 | */ 33 | void wait_for_activity( 34 | struct command_buffer_t *command_buffer, 35 | struct net_state_t *net_state) 36 | { 37 | DWORD wait_result; 38 | 39 | /* 40 | Start the command read overlapped I/O just prior to sleeping. 41 | During development of the Cygwin port, there was a bug where the 42 | overlapped I/O was started earlier in the mtr-packet loop, and 43 | an intermediate alertable wait could leave us in this Sleep 44 | without an active command read. So now we do this here, instead. 45 | */ 46 | start_read_command(command_buffer); 47 | 48 | /* Sleep until an I/O completion routine runs */ 49 | wait_result = SleepEx(INFINITE, TRUE); 50 | 51 | if (wait_result == WAIT_FAILED) { 52 | fprintf(stderr, "SleepEx failure %d\n", GetLastError()); 53 | exit(EXIT_FAILURE); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /bash-completion/mtr: -------------------------------------------------------------------------------- 1 | _mtr_module() 2 | { 3 | local cur prev OPTS 4 | COMPREPLY=() 5 | cur="${COMP_WORDS[COMP_CWORD]}" 6 | prev="${COMP_WORDS[COMP_CWORD-1]}" 7 | case $prev in 8 | '-F'|'--filename') 9 | local IFS=$'\n' 10 | compopt -o filenames 11 | COMPREPLY=( $(compgen -f -- $cur) ) 12 | return 0 13 | ;; 14 | '-a'|'--address') 15 | COMPREPLY=( $(compgen -W "ADDRESS" -- $cur) ) 16 | return 0 17 | ;; 18 | '-f'|'--first-ttl'|'-m'|'--max-ttl'|'-m'|'--max-unknown'|'-B'|'--bitpattern'|'-Q'|'--tos'|'-c'|'--report-cycles') 19 | COMPREPLY=( $(compgen -W "NUMBER" -- $cur) ) 20 | return 0 21 | ;; 22 | '-P'|'--port'|'-L'|'--localport') 23 | COMPREPLY=( $(compgen -W "PORT" -- $cur) ) 24 | return 0 25 | ;; 26 | '-s'|'--psize') 27 | COMPREPLY=( $(compgen -W "SIZE" -- $cur) ) 28 | return 0 29 | ;; 30 | '-i'|'--interval'|'-G'|'--gracetime'|'-Z'|'--timeout') 31 | COMPREPLY=( $(compgen -W "SECONDS" -- $cur) ) 32 | return 0 33 | ;; 34 | '-M'|'--mark') 35 | COMPREPLY=( $(compgen -W "MARK" -- $cur) ) 36 | return 0 37 | ;; 38 | '--displaymode') 39 | COMPREPLY=( $(compgen -W "{0..2}" -- $cur) ) 40 | return 0 41 | ;; 42 | '-y'|'--ipinfo') 43 | COMPREPLY=( $(compgen -W "{0..4}" -- $cur) ) 44 | return 0 45 | ;; 46 | '-o'|'--order') 47 | COMPREPLY=( $(compgen -W "LDRSNBAWVGJMXI" -- $cur) ) 48 | return 0 49 | ;; 50 | esac 51 | case $cur in 52 | -*) 53 | OPTS=' 54 | --filename --inet --inet6 --udp --tcp --address --first-ttl 55 | --max-ttl --max-unknown --port --localport --psize --bitpattern 56 | --interval --gracetime --tos --mpls --timeout --mark --report 57 | --report-wide --report-cycles --json --xml --csv --raw --split 58 | --curses --displaymode --gtk --no-dns --show-ips --order --ipinfo 59 | --aslookup --help --version 60 | ' 61 | COMPREPLY=( $(compgen -W "${OPTS[*]}" -- $cur) ) 62 | return 0 63 | ;; 64 | esac 65 | COMPREPLY=( $(compgen -W "ip_address hostname" -- $cur) ) 66 | return 0 67 | } 68 | complete -F _mtr_module mtr 69 | -------------------------------------------------------------------------------- /packet/timeval.c: -------------------------------------------------------------------------------- 1 | /* 2 | mtr -- a network diagnostic tool 3 | Copyright (C) 2016 Matt Kimball 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License version 2 as 7 | published by the Free Software Foundation. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along 15 | with this program; if not, write to the Free Software Foundation, Inc., 16 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #include "timeval.h" 20 | 21 | /* 22 | Ensure that a timevalue has a microsecond value in the range 23 | [0.0, 1.0e6) microseconds by converting microseconds to full seconds. 24 | */ 25 | void normalize_timeval( 26 | struct timeval *timeval) 27 | { 28 | int full_sec; 29 | 30 | /* 31 | If tv_usec has overflowed a full second, convert the overflow 32 | to tv_sec. 33 | */ 34 | full_sec = timeval->tv_usec / 1000000; 35 | timeval->tv_sec += full_sec; 36 | timeval->tv_usec -= 1000000 * full_sec; 37 | 38 | /* If tv_usec is negative, make it positive by rolling tv_sec back */ 39 | if (timeval->tv_usec < 0) { 40 | timeval->tv_sec--; 41 | timeval->tv_usec += 1000000; 42 | } 43 | 44 | /* If the entire time value is negative, clamp to zero */ 45 | if (timeval->tv_sec < 0) { 46 | timeval->tv_sec = 0; 47 | timeval->tv_usec = 0; 48 | } 49 | } 50 | 51 | /* 52 | Compare two time values. Return: 53 | 54 | -1 if a < b 55 | 0 if a == b 56 | 1 if a > b 57 | */ 58 | int compare_timeval( 59 | struct timeval a, 60 | struct timeval b) 61 | { 62 | if (a.tv_sec > b.tv_sec) { 63 | return 1; 64 | } 65 | if (a.tv_sec < b.tv_sec) { 66 | return -1; 67 | } 68 | 69 | if (a.tv_usec > b.tv_usec) { 70 | return 1; 71 | } 72 | if (a.tv_usec < b.tv_usec) { 73 | return -1; 74 | } 75 | 76 | return 0; 77 | } 78 | -------------------------------------------------------------------------------- /ui/cmdpipe.h: -------------------------------------------------------------------------------- 1 | /* 2 | mtr -- a network diagnostic tool 3 | Copyright (C) 2016 Matt Kimball 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License version 2 as 7 | published by the Free Software Foundation. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along 15 | with this program; if not, write to the Free Software Foundation, Inc., 16 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #ifndef CMDPIPE_H 20 | #define CMDPIPE_H 21 | 22 | #include "mtr.h" 23 | 24 | #define COMMAND_BUFFER_SIZE 4096 25 | #define PACKET_REPLY_BUFFER_SIZE 4096 26 | 27 | /* We use a pipe to the mtr-packet subprocess to generate probes */ 28 | struct packet_command_pipe_t { 29 | /* the process id of mtr-packet */ 30 | pid_t pid; 31 | 32 | /* the end of the pipe we read for replies */ 33 | int read_fd; 34 | 35 | /* the end of the pipe we write for commands */ 36 | int write_fd; 37 | 38 | /* storage for incoming replies */ 39 | char reply_buffer[PACKET_REPLY_BUFFER_SIZE]; 40 | 41 | /* the number of bytes currently used in reply_buffer */ 42 | size_t reply_buffer_used; 43 | }; 44 | 45 | typedef 46 | void ( 47 | *probe_reply_func_t) ( 48 | struct mtr_ctl * ctl, 49 | int sequence, 50 | int err, 51 | struct mplslen * mpls, 52 | ip_t * addr, 53 | int round_trip_time); 54 | 55 | int open_command_pipe( 56 | struct mtr_ctl *ctl, 57 | struct packet_command_pipe_t *cmdpipe); 58 | 59 | void close_command_pipe( 60 | struct packet_command_pipe_t *cmdpipe); 61 | 62 | void send_probe_command( 63 | struct mtr_ctl *ctl, 64 | struct packet_command_pipe_t *cmdpipe, 65 | ip_t * address, 66 | ip_t * localaddress, 67 | int packet_size, 68 | int sequence, 69 | int time_to_live); 70 | 71 | void handle_command_replies( 72 | struct mtr_ctl *ctl, 73 | struct packet_command_pipe_t *cmdpipe, 74 | probe_reply_func_t reply_func); 75 | 76 | #endif 77 | -------------------------------------------------------------------------------- /packet/probe_cygwin.h: -------------------------------------------------------------------------------- 1 | /* 2 | mtr -- a network diagnostic tool 3 | Copyright (C) 2016 Matt Kimball 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License version 2 as 7 | published by the Free Software Foundation. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along 15 | with this program; if not, write to the Free Software Foundation, Inc., 16 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #ifndef PROBE_CYGWIN_H 20 | #define PROBE_CYGWIN_H 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | /* 28 | This should be in the Windows headers, but is missing from 29 | Cygwin's Windows headers. 30 | */ 31 | typedef struct icmpv6_echo_reply_lh { 32 | /* 33 | Although Windows uses an IPV6_ADDRESS_EX here, we are using uint8_t 34 | fields to avoid structure padding differences between gcc and 35 | Visual C++. (gcc wants to align the flow info to a 4 byte boundary, 36 | and Windows uses it unaligned.) 37 | */ 38 | uint8_t PortBits[2]; 39 | uint8_t FlowInfoBits[4]; 40 | uint8_t AddressBits[16]; 41 | uint8_t ScopeIdBits[4]; 42 | 43 | ULONG Status; 44 | unsigned int RoundTripTime; 45 | } ICMPV6_ECHO_REPLY, 46 | *PICMPV6_ECHO_REPLY; 47 | 48 | /* 49 | Windows requires an echo reply structure for each in-flight 50 | ICMP probe. 51 | */ 52 | struct probe_platform_t { 53 | /* 54 | We need a backpointer to the net_state because of the way 55 | IcmpSendEcho2 passes our context. 56 | */ 57 | struct net_state_t *net_state; 58 | 59 | /* IP version (4 or 6) used for the probe */ 60 | int ip_version; 61 | 62 | union { 63 | ICMP_ECHO_REPLY *reply4; 64 | ICMPV6_ECHO_REPLY *reply6; 65 | }; 66 | }; 67 | 68 | /* A Windows HANDLE for the ICMP session */ 69 | struct net_state_platform_t { 70 | HANDLE icmp4; 71 | HANDLE icmp6; 72 | bool ip4_socket_raw; 73 | bool ip6_socket_raw; 74 | }; 75 | 76 | #endif 77 | -------------------------------------------------------------------------------- /ui/display.h: -------------------------------------------------------------------------------- 1 | /* 2 | mtr -- a network diagnostic tool 3 | Copyright (C) 1997,1998 Matt Kimball 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License version 2 as 7 | published by the Free Software Foundation. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along 15 | with this program; if not, write to the Free Software Foundation, Inc., 16 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #include 20 | 21 | /* Don't put a trailing comma in enumeration lists. Some compilers 22 | (notably the one on Irix 5.2) do not like that. */ 23 | enum { ActionNone, ActionQuit, ActionReset, ActionDisplay, 24 | ActionClear, ActionPause, ActionResume, ActionMPLS, ActionDNS, 25 | #ifdef HAVE_IPINFO 26 | ActionII, ActionAS, 27 | #endif 28 | ActionScrollDown, ActionScrollUp 29 | }; 30 | 31 | enum { 32 | DisplayReport, 33 | #ifdef HAVE_CURSES 34 | DisplayCurses, 35 | #endif 36 | #ifdef HAVE_GTK 37 | DisplayGTK, 38 | #endif 39 | DisplaySplit, 40 | DisplayRaw, 41 | DisplayXML, 42 | DisplayCSV, 43 | DisplayTXT, 44 | DisplayJSON 45 | }; 46 | 47 | enum { 48 | DisplayModeDefault, 49 | DisplayModeBlockmap, 50 | DisplayModeBlockmapScale, 51 | DisplayModeMAX /* this must be the last DisplayMode entry */ 52 | }; 53 | 54 | /* Prototypes for display.c */ 55 | extern void display_detect( 56 | struct mtr_ctl *ctl, 57 | int *argc, 58 | char ***argv); 59 | extern void display_open( 60 | struct mtr_ctl *ctl); 61 | extern void display_close( 62 | struct mtr_ctl *ctl); 63 | extern void display_redraw( 64 | struct mtr_ctl *ctl); 65 | extern void display_rawxmit( 66 | struct mtr_ctl *ctl, 67 | int hostnum, 68 | int seq); 69 | extern void display_rawping( 70 | struct mtr_ctl *ctl, 71 | int hostnum, 72 | int msec, 73 | int seq); 74 | extern void display_rawhost( 75 | struct mtr_ctl *ctl, 76 | int hostnum, 77 | ip_t * ip_addr); 78 | extern int display_keyaction( 79 | struct mtr_ctl *ctl); 80 | extern void display_loop( 81 | struct mtr_ctl *ctl); 82 | extern void display_clear( 83 | struct mtr_ctl *ctl); 84 | extern char *host_error_to_string( 85 | int err); 86 | -------------------------------------------------------------------------------- /SECURITY: -------------------------------------------------------------------------------- 1 | SECURITY ISSUES RELATED TO MTR 2 | 3 | mtr invokes a sub-process, mtr-packet, which requires extra privileges 4 | to send custom packets, and there are security implications from 5 | granting this. 6 | 7 | There are several different ways to provide the privileges: 8 | 9 | 1. Add limited privileges on systems that support this. (Preferred.) 10 | 2. Run mtr as the root user. 11 | 3. Make mtr-packet a setuid-root binary. 12 | 13 | Details: 14 | 15 | 1. Add limited privileges on systems that support this. 16 | 17 | Some operating systems allow binaries to be run with only the subset 18 | of security privileges that are actually needed. 19 | 20 | Linux: 21 | On Linux, privileges are known as capabilities. The only additional 22 | capability that mtr-packet needs is cap_net_raw. To give this 23 | capability to the mtr-packet binary, run the following command as root: 24 | 25 | # setcap cap_net_raw+ep mtr-packet 26 | 27 | 28 | 2. Run mtr as the root user. 29 | 30 | You can limit mtr usage to the root user by not putting a setuid bit 31 | on the mtr-packet binary. In that case, the security implications are 32 | minimal. 33 | 34 | 35 | 3. Make mtr-packet a setuid-root binary. 36 | 37 | The mtr-packet binary can be made setuid-root, which is what "make install" 38 | does by default. 39 | 40 | When mtr-packet is installed as suid-root, some concern over security is 41 | justified. mtr-packet does the following two things after it is launched: 42 | 43 | * mtr-packet open sockets for sending raw packets and for receiving 44 | ICMP packets. 45 | * mtr-packet drops root privileges by setting the effective uid to 46 | match uid or the user calling mtr. 47 | * If capabilities support is available, mtr-packet drops all privileged 48 | capabilities. 49 | 50 | See main() in packet.c and init_net_state_privileged() in probe_unix.c 51 | for the details of this process. 52 | 53 | This should limit the possibilities of using mtr to breach system security. 54 | The worst case scenario is as follows: 55 | 56 | Due to some oversight in the mtr-packet code, a malicious user is able to 57 | overrun one of mtr-packets's internal buffers with binary code that is 58 | eventually executed. The malicious user is still not able to read 59 | from or write to any system files other than those normally accessible 60 | by the user running mtr. The only privileges gained are access to the raw 61 | socket, which would allow the malicious user to listen to all ICMP packets 62 | arriving at the system, and to send forged packets with arbitrary contents. 63 | 64 | 65 | If you have further questions or comments about security issues, 66 | please see the README file for details on how to submit them. 67 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | 2 | Matt Kimball is the primary author of mtr. 3 | 4 | Roger Wolff is currently maintaining mtr. 5 | 6 | 7 | Bug reports and feature requests should be sent as described in 8 | the README file. 9 | 10 | Thanks to everyone who has provided feedback on mtr. 11 | 12 | Thanks especially to those of you who have sent code: 13 | (Reverse alphabetical order, and sometimes I just add people at 14 | the end... ) 15 | 16 | Bohdan Vlasyuk 17 | Evgeniy Tretyak 18 | John Thacker 19 | Juha Takala 20 | David Sward 21 | David Stone 22 | Andrew Stesin 23 | Greg Stark 24 | Robert Sparks 25 | Mike Simons 26 | Aaron Scarisbrick 27 | Craig Milo Rogers 28 | Antonio Querubin 29 | Russell Nelson 30 | Davin Milun 31 | Josh Martin 32 | Alexander V. Lukyanov 33 | Charles Levert 34 | Bertrand Leconte 35 | Anand Kumria 36 | Olav Kvittem 37 | Adam Kramer 38 | Philip Kizer 39 | Simon Kirby 40 | Sami Kerola 41 | Christophe Kalt 42 | Steve Kann 43 | Brett Johnson 44 | Roland Illig 45 | Damian Gryski 46 | Rob Foehl 47 | Mircea Damian 48 | Cougar 49 | Travis Cross 50 | Brian Casey 51 | Andrew Brown 52 | Bill Bogstad 53 | Marc Bejarano 54 | Moritz Barsnick 55 | Thomas Klausner 56 | Roderick Groesbeek 57 | Kyle J. McKay 58 | Joseph Carter 59 | Thales 60 | "Min" 61 | Vaibhav Bajpai 62 | Jürgen Schönwälder 63 | 64 | and anyone who has slipped through the cracks of my mail file. 65 | 66 | Authors: If you want your Email mentioned here, send it to me. 67 | If you don't want your Email mentioned here, tell me. 68 | 69 | -- REW 70 | -------------------------------------------------------------------------------- /test/param.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # mtr -- a network diagnostic tool 4 | # Copyright (C) 2016 Matt Kimball 5 | # 6 | # This program is free software; you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License version 2 as 8 | # published by the Free Software Foundation. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License along 16 | # with this program; if not, write to the Free Software Foundation, Inc., 17 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | # 19 | 20 | '''Test probe customization parameters''' 21 | 22 | import sys 23 | import unittest 24 | 25 | import mtrpacket 26 | 27 | 28 | @unittest.skipIf(sys.platform == 'cygwin', 'No Cygwin test') 29 | class TestParameters(mtrpacket.MtrPacketTest): 30 | 'Use parameter arguments to mtr-packet and examine the resulting packet' 31 | 32 | def test_size(self): 33 | 'Test probes sent with an explicit packet size' 34 | 35 | with mtrpacket.PacketListen('-4') as listen: 36 | cmd = '20 send-probe ip-4 127.0.0.1 size 512' 37 | 38 | self.write_command(cmd) 39 | 40 | self.assertEqual(listen.attrib['size'], '512') 41 | 42 | def test_pattern(self): 43 | 'Test probes are filled with the requested bit pattern' 44 | 45 | with mtrpacket.PacketListen('-4') as listen: 46 | cmd = '20 send-probe ip-4 127.0.0.1 bit-pattern 44' 47 | 48 | self.write_command(cmd) 49 | 50 | self.assertEqual(listen.attrib['bitpattern'], '44') 51 | 52 | def test_tos(self): 53 | 'Test setting the TOS field' 54 | 55 | with mtrpacket.PacketListen('-4') as listen: 56 | cmd = '20 send-probe ip-4 127.0.0.1 tos 62' 57 | 58 | self.write_command(cmd) 59 | 60 | self.assertEqual(listen.attrib['tos'], '62') 61 | 62 | 63 | @unittest.skipIf(sys.platform == 'cygwin', 'No Cygwin test') 64 | class TestIPv6Parameters(mtrpacket.MtrPacketTest): 65 | 'Test packet paramter customization for IPv6' 66 | 67 | @unittest.skipUnless(mtrpacket.HAVE_IPV6, 'No IPv6') 68 | def test_param(self): 69 | 'Test a variety of packet parameters' 70 | 71 | with mtrpacket.PacketListen('-6') as listen: 72 | param = 'size 256 bit-pattern 51 tos 77' 73 | cmd = '20 send-probe ip-6 ::1 ' + param 74 | 75 | self.write_command(cmd) 76 | 77 | self.assertEqual(listen.attrib['size'], '256') 78 | self.assertEqual(listen.attrib['bitpattern'], '51') 79 | 80 | 81 | if __name__ == '__main__': 82 | mtrpacket.check_running_as_root() 83 | unittest.main() 84 | -------------------------------------------------------------------------------- /packet/command_unix.c: -------------------------------------------------------------------------------- 1 | /* 2 | mtr -- a network diagnostic tool 3 | Copyright (C) 2016 Matt Kimball 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License version 2 as 7 | published by the Free Software Foundation. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along 15 | with this program; if not, write to the Free Software Foundation, Inc., 16 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #include "command.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | /* 29 | Initialize the command buffer and put the command stream in 30 | non-blocking mode. 31 | */ 32 | void init_command_buffer( 33 | struct command_buffer_t *command_buffer, 34 | int command_stream) 35 | { 36 | int flags; 37 | 38 | memset(command_buffer, 0, sizeof(struct command_buffer_t)); 39 | command_buffer->command_stream = command_stream; 40 | 41 | /* Get the current command stream flags */ 42 | flags = fcntl(command_stream, F_GETFL, 0); 43 | if (flags == -1) { 44 | perror("Unexpected command stream error"); 45 | exit(EXIT_FAILURE); 46 | } 47 | 48 | /* Set the O_NONBLOCK bit */ 49 | if (fcntl(command_stream, F_SETFL, flags | O_NONBLOCK)) { 50 | perror("Unexpected command stream error"); 51 | exit(EXIT_FAILURE); 52 | } 53 | } 54 | 55 | /* Read currently available data from the command stream */ 56 | int read_commands( 57 | struct command_buffer_t *buffer) 58 | { 59 | int space_remaining = 60 | COMMAND_BUFFER_SIZE - buffer->incoming_read_position - 1; 61 | char *read_position = 62 | &buffer->incoming_buffer[buffer->incoming_read_position]; 63 | int read_count; 64 | int command_stream = buffer->command_stream; 65 | 66 | read_count = read(command_stream, read_position, space_remaining); 67 | 68 | /* If the command stream has been closed, read will return zero. */ 69 | if (read_count == 0) { 70 | errno = EPIPE; 71 | return -1; 72 | } 73 | 74 | if (read_count > 0) { 75 | /* Account for the newly read data */ 76 | buffer->incoming_read_position += read_count; 77 | } 78 | 79 | if (read_count < 0) { 80 | /* EAGAIN simply means there is no available data to read */ 81 | /* EINTR indicates we received a signal during read */ 82 | if (errno != EINTR && errno != EAGAIN) { 83 | perror("Unexpected command buffer read error"); 84 | exit(EXIT_FAILURE); 85 | } 86 | } 87 | 88 | return 0; 89 | } 90 | -------------------------------------------------------------------------------- /ui/net.h: -------------------------------------------------------------------------------- 1 | /* 2 | mtr -- a network diagnostic tool 3 | Copyright (C) 1997,1998 Matt Kimball 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License version 2 as 7 | published by the Free Software Foundation. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along 15 | with this program; if not, write to the Free Software Foundation, Inc., 16 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | /* Prototypes for functions in net.c */ 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #ifdef ENABLE_IPV6 27 | #include 28 | #endif 29 | 30 | #include 31 | 32 | #include "mtr.h" 33 | 34 | extern int net_open( 35 | struct mtr_ctl *ctl, 36 | struct hostent *host); 37 | extern void net_reopen( 38 | struct mtr_ctl *ctl, 39 | struct hostent *address); 40 | extern void net_reset( 41 | struct mtr_ctl *ctl); 42 | extern void net_close( 43 | void); 44 | extern int net_waitfd( 45 | void); 46 | extern void net_process_return( 47 | struct mtr_ctl *ctl); 48 | extern void net_harvest_fds( 49 | struct mtr_ctl *ctl); 50 | 51 | extern int net_max( 52 | struct mtr_ctl *ctl); 53 | extern int net_min( 54 | struct mtr_ctl *ctl); 55 | extern int net_last( 56 | int at); 57 | extern ip_t *net_addr( 58 | int at); 59 | extern int net_err( 60 | int at); 61 | extern void *net_mpls( 62 | int at); 63 | extern void *net_mplss( 64 | int, 65 | int); 66 | extern int net_loss( 67 | int at); 68 | extern int net_drop( 69 | int at); 70 | extern int net_best( 71 | int at); 72 | extern int net_worst( 73 | int at); 74 | extern int net_avg( 75 | int at); 76 | extern int net_gmean( 77 | int at); 78 | extern int net_stdev( 79 | int at); 80 | extern int net_jitter( 81 | int at); 82 | extern int net_jworst( 83 | int at); 84 | extern int net_javg( 85 | int at); 86 | extern int net_jinta( 87 | int at); 88 | extern ip_t *net_addrs( 89 | int at, 90 | int i); 91 | extern char *net_localaddr( 92 | void); 93 | 94 | extern int net_send_batch( 95 | struct mtr_ctl *ctl); 96 | extern void net_end_transit( 97 | void); 98 | 99 | extern int calc_deltatime( 100 | float WaitTime); 101 | 102 | extern int net_returned( 103 | int at); 104 | extern int net_xmit( 105 | int at); 106 | 107 | extern int net_up( 108 | int at); 109 | 110 | extern int *net_saved_pings( 111 | int at); 112 | extern void net_save_xmit( 113 | int at); 114 | extern void net_save_return( 115 | int at, 116 | int seq, 117 | int ms); 118 | 119 | extern int addrcmp( 120 | char *a, 121 | char *b, 122 | int af); 123 | extern void addrcpy( 124 | char *a, 125 | char *b, 126 | int af); 127 | 128 | extern void net_add_fds( 129 | fd_set * writefd, 130 | int *maxfd); 131 | -------------------------------------------------------------------------------- /FORMATS: -------------------------------------------------------------------------------- 1 | 2 | The "split" format is for a separating the gui from the main program. 3 | The main program can be installed setuid, and you don't want to link a 4 | gui-library with a setuid program. 5 | 6 | 7 | The split format is: 8 | 9 | 10 | 11 | 12 | The "raw" format is: 13 | 14 | hostline|xmitline|pingline|dnsline|timestampline 15 | 16 | hostline: 17 | h 18 | 19 | xmitline: 20 | x 21 | 22 | pingline: 23 | p 24 | 25 | dnsline: 26 | d 27 | 28 | timestampline: 29 | t 30 | 31 | 32 | Timestampline is not yet implemented. Need to find out how to do 33 | ICMP timestamping first. :-) 34 | 35 | 36 | Someone suggested to put the following text here. As to context: Some 37 | people are wondering why mtr sometimes reports hosts beyond the 38 | destination host. 39 | 40 | 41 | The FINAL host will occasionally be mentioned at position n, n+1, n+2 42 | etc. 43 | 44 | You know traceroute, right? It sends a packet, waits for the reply to 45 | come back and when it comes back, it sends the next packet. 46 | 47 | If say hosts 5-8 do not send "time exceeded" packets, you'll wait a 48 | 4*3 = twelve seconds extra before you get any results on hosts 9 and 49 | further. MTR doesn't work like that. 50 | 51 | In theory we could send out a probe for host 1-40 all at once. But 52 | this would pose an unnecessary burden on the network. So what we do, 53 | is we send out probes for a max of 5 hosts beyond where we've seen a 54 | reply. So in the example above, we'd see a reply from router at 55 | position 4, then we'd send out 5-9 (and because the max-host is now at 56 | 9, we'll send them out at 1s/9 = 111ms intervals). When the reply from 57 | host 9 comes back, we'll start probing for host 10-15 (at about 60ms 58 | intervals). But suppose the network delay up to host 9 is already 200ms 59 | and suppose our destination host is at position 11. Then by the time 60 | the packet from host 11 comes back, we'll already have sent probe 61 | packets for position 12, 13, and 14! Those will come back as 62 | "destination reached" and be reported by the "raw" mode. 63 | 64 | Curses mode will stop showing hosts with position numbers beyond the 65 | first reply of the destination host. It could gather the information 66 | about replies to packets sent as probes FURTHER than it actually is 67 | into the line displayed at its true position, but it doesn't (yet). 68 | 69 | In fact the above example is almost completely true: 70 | 71 | % mtr -r -n -c 2 152.179.99.218 | tail -5 72 | 13.|-- 144.232.18.238 0.0% 2 94.8 95.4 94.8 96.0 0.8 73 | 14.|-- 152.63.16.182 0.0% 2 95.1 95.5 95.1 95.8 0.5 74 | 15.|-- 152.63.64.106 0.0% 2 163.9 163.9 163.9 164.0 0.1 75 | 16.|-- 152.63.50.89 50.0% 2 163.7 163.7 163.7 163.7 0.0 76 | 17.|-- 152.179.99.218 50.0% 2 168.2 168.2 168.2 168.2 0.0 77 | % mtr -l -c 2 152.179.99.218 | grep -v "^[dp]" |tail -7 78 | h 10 144.232.1.41 79 | h 11 144.232.4.96 80 | h 16 152.179.99.218 81 | h 17 152.179.99.218 82 | h 18 152.179.99.218 83 | h 12 144.232.18.238 84 | h 13 152.63.16.182 85 | 86 | As you can see we get the reply from the destination host at position 87 | 16 AFTER we've sent probes for position 17 and 18. When those come 88 | back, they are reported. That's what raw mode does. It reports the raw 89 | information. 90 | 91 | If you write a backend for the raw mode, it's up to you to 92 | filter/display the results. 93 | 94 | h 10 144.232.1.41 95 | h 11 144.232.4.96 96 | h 12 144.232.18.238 97 | h 13 152.63.16.182 98 | h 14 152.63.64.106 99 | h 15 152.63.50.89 100 | h 16 152.179.99.218 101 | h 17 152.179.99.218 102 | h 18 152.179.99.218 103 | 104 | -------------------------------------------------------------------------------- /packet/probe_unix.h: -------------------------------------------------------------------------------- 1 | /* 2 | mtr -- a network diagnostic tool 3 | Copyright (C) 2016 Matt Kimball 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License version 2 as 7 | published by the Free Software Foundation. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along 15 | with this program; if not, write to the Free Software Foundation, Inc., 16 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #ifndef PROBE_UNIX_H 20 | #define PROBE_UNIX_H 21 | 22 | /* The range of local port numbers to use for probes */ 23 | #define MIN_PORT 33000 24 | #define MAX_PORT 65535 25 | 26 | /* We need to track the transmission and timeouts on Unix systems */ 27 | struct probe_platform_t { 28 | /* The socket for the outgoing connection (used by TCP probes) */ 29 | int socket; 30 | 31 | /* The time at which the probe is considered lost */ 32 | struct timeval timeout_time; 33 | 34 | /* The time at which the probe was sent */ 35 | struct timeval departure_time; 36 | }; 37 | 38 | /* We'll use rack sockets to send and recieve probes on Unix systems */ 39 | struct net_state_platform_t { 40 | /* true if we were successful at opening IPv4 sockets */ 41 | bool ip4_present; 42 | 43 | /* true if we were successful at opening IPv6 sockets */ 44 | bool ip6_present; 45 | 46 | /* true if ipv4 socket is raw socket */ 47 | bool ip4_socket_raw; 48 | 49 | /* true if ipv6 socket is raw socket */ 50 | bool ip6_socket_raw; 51 | 52 | /* Socket used to send raw IPv4 packets */ 53 | int ip4_send_socket; 54 | 55 | /* Socket used to receive IPv4 ICMP replies */ 56 | int ip4_recv_socket; 57 | 58 | /* Socket used to probe byte order */ 59 | int ip4_tmp_icmp_socket; 60 | 61 | /* Socket used to tx & rx non-raw IPv4 icmp packets */ 62 | int ip4_txrx_icmp_socket; 63 | 64 | /* Socket used to send IPv4 udp packets and receive icmp err packets */ 65 | int ip4_txrx_udp_socket; 66 | 67 | /* Send socket for ICMPv6 packets */ 68 | int icmp6_send_socket; 69 | 70 | /* Send socket for UDPv6 packets */ 71 | int udp6_send_socket; 72 | 73 | /* Receive socket for IPv6 packets */ 74 | int ip6_recv_socket; 75 | 76 | /* Socket used to tx & rx non-raw IPv6 icmp packets */ 77 | int ip6_txrx_icmp_socket; 78 | 79 | /* Socket used to send IPv6 udp packets and receive icmp err packets */ 80 | int ip6_txrx_udp_socket; 81 | 82 | /* 83 | true if we should encode the IP header length in host order. 84 | (as opposed to network order) 85 | */ 86 | bool ip_length_host_order; 87 | 88 | /* true if the operating system supports SCTP sockets */ 89 | bool sctp_support; 90 | 91 | /* The next port number to use when creating a new probe */ 92 | int next_sequence; 93 | }; 94 | 95 | struct net_state_t; 96 | struct probe_t; 97 | struct mpls_label_t; 98 | 99 | void set_socket_nonblocking( 100 | int socket); 101 | 102 | void receive_probe( 103 | struct net_state_t *net_state, 104 | struct probe_t *probe, 105 | int icmp_type, 106 | const struct sockaddr_storage *remote_addr, 107 | struct timeval *timestamp, 108 | int mpls_count, 109 | struct mpls_label_t *mpls); 110 | 111 | int gather_probe_sockets( 112 | const struct net_state_t *net_state, 113 | fd_set * write_set); 114 | 115 | #endif 116 | -------------------------------------------------------------------------------- /test/cmdparse.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # mtr -- a network diagnostic tool 4 | # Copyright (C) 2016 Matt Kimball 5 | # 6 | # This program is free software; you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License version 2 as 8 | # published by the Free Software Foundation. 9 | # 10 | # This program is distributed in the hope that it will be useful, 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | # GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License along 16 | # with this program; if not, write to the Free Software Foundation, Inc., 17 | # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | # 19 | 20 | '''Test mtr-packet's command parsing.''' 21 | 22 | 23 | import time 24 | import unittest 25 | 26 | import mtrpacket 27 | 28 | 29 | class TestCommandParse(mtrpacket.MtrPacketTest): 30 | '''Test cases with malformed commands and version checks''' 31 | 32 | def test_unknown_command(self): 33 | 'Test sending a command unknown to mtr-packet' 34 | 35 | self.write_command('13 argle-bargle') 36 | self.assertEqual(self.read_reply(), '13 unknown-command') 37 | 38 | def test_malformed_command(self): 39 | 'Test sending a malformed command request to mtr-packet' 40 | 41 | self.write_command('malformed') 42 | self.assertEqual(self.read_reply(), '0 command-parse-error') 43 | 44 | def test_exit_on_stdin_closed(self): 45 | '''Test that the packet process terminates after stdin is closed 46 | 47 | Test that, when outstanding requests are complete, the process 48 | terminates following stdin being closed.''' 49 | 50 | self.write_command('15 send-probe ip-4 8.8.254.254 timeout 1') 51 | self.packet_process.stdin.close() 52 | time.sleep(2) 53 | self.read_reply() 54 | exit_code = self.packet_process.poll() 55 | self.assertIsNotNone(exit_code) 56 | 57 | def test_invalid_argument(self): 58 | 'Test sending invalid arguments with probe requests' 59 | 60 | bad_commands = [ 61 | '22 send-probe', 62 | '23 send-probe ip-4 str-value', 63 | '24 send-probe ip-4 8.8.8.8 timeout str-value', 64 | '25 send-probe ip-4 8.8.8.8 ttl str-value', 65 | ] 66 | 67 | for cmd in bad_commands: 68 | self.write_command(cmd) 69 | reply = self.parse_reply() 70 | self.assertEqual(reply.command_name, 'invalid-argument') 71 | 72 | def test_versioning(self): 73 | 'Test version checks and feature support checks' 74 | 75 | feature_tests = [ 76 | ('31 check-support feature ip-4', 'ok'), 77 | ('32 check-support feature send-probe', 'ok'), 78 | ('33 check-support feature bogus-feature', 'no') 79 | ] 80 | 81 | self.write_command('30 check-support feature version') 82 | reply = self.parse_reply() 83 | self.assertEqual(reply.token, 30) 84 | self.assertEqual(reply.command_name, 'feature-support') 85 | self.assertIn('support', reply.argument) 86 | 87 | for (request, expected) in feature_tests: 88 | self.write_command(request) 89 | reply = self.parse_reply() 90 | self.assertEqual(reply.command_name, 'feature-support') 91 | self.assertIn('support', reply.argument) 92 | self.assertEqual(reply.argument['support'], expected) 93 | 94 | def test_command_overflow(self): 95 | 'Test overflowing the incoming command buffer' 96 | 97 | big_buffer = 'x' * (64 * 1024) 98 | self.write_command(big_buffer) 99 | 100 | reply = self.read_reply() 101 | self.assertEqual(reply, '0 command-buffer-overflow') 102 | 103 | 104 | if __name__ == '__main__': 105 | mtrpacket.check_running_as_root() 106 | unittest.main() 107 | -------------------------------------------------------------------------------- /packet/packet.c: -------------------------------------------------------------------------------- 1 | /* 2 | mtr -- a network diagnostic tool 3 | Copyright (C) 2016 Matt Kimball 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License version 2 as 7 | published by the Free Software Foundation. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along 15 | with this program; if not, write to the Free Software Foundation, Inc., 16 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #include "config.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #ifdef HAVE_LIBCAP 28 | #include 29 | #endif 30 | 31 | #include "wait.h" 32 | 33 | /* Drop SUID privileges. To be used after accquiring raw sockets. */ 34 | static 35 | int drop_elevated_permissions( 36 | void) 37 | { 38 | #ifdef HAVE_LIBCAP 39 | cap_t cap; 40 | #endif 41 | 42 | /* Drop any suid permissions granted */ 43 | if (setgid(getgid()) || setuid(getuid())) { 44 | return -1; 45 | } 46 | 47 | if (geteuid() != getuid() || getegid() != getgid()) { 48 | return -1; 49 | } 50 | 51 | /* 52 | Drop all process capabilities. 53 | This will revoke anything granted by a commandline 'setcap' 54 | */ 55 | #ifdef HAVE_LIBCAP 56 | cap = cap_get_proc(); 57 | if (cap == NULL) { 58 | return -1; 59 | } 60 | if (cap_clear(cap)) { 61 | return -1; 62 | } 63 | if (cap_set_proc(cap)) { 64 | return -1; 65 | } 66 | #endif 67 | 68 | return 0; 69 | } 70 | 71 | int main( 72 | int argc, 73 | char **argv) 74 | { 75 | bool command_pipe_open; 76 | struct command_buffer_t command_buffer; 77 | struct net_state_t net_state; 78 | 79 | /* 80 | To minimize security risk, the only thing done prior to 81 | dropping SUID should be opening the network state for 82 | raw sockets. 83 | */ 84 | init_net_state_privileged(&net_state); 85 | if (drop_elevated_permissions()) { 86 | perror("Unable to drop elevated permissions"); 87 | exit(EXIT_FAILURE); 88 | } 89 | init_net_state(&net_state); 90 | 91 | init_command_buffer(&command_buffer, fileno(stdin)); 92 | 93 | command_pipe_open = true; 94 | 95 | /* 96 | Dispatch commands and respond to probe replies until the 97 | command stream is closed. 98 | */ 99 | while (true) { 100 | /* Ensure any responses are written before waiting */ 101 | fflush(stdout); 102 | wait_for_activity(&command_buffer, &net_state); 103 | 104 | /* 105 | Receive replies first so that the timestamps are as 106 | close to the response arrival time as possible. 107 | */ 108 | receive_replies(&net_state); 109 | 110 | if (command_pipe_open) { 111 | if (read_commands(&command_buffer)) { 112 | if (errno == EPIPE) { 113 | command_pipe_open = false; 114 | } 115 | } 116 | } 117 | 118 | check_probe_timeouts(&net_state); 119 | 120 | /* 121 | Dispatch commands late so that the window between probe 122 | departure and arriving replies is as small as possible. 123 | */ 124 | dispatch_buffer_commands(&command_buffer, &net_state); 125 | 126 | /* 127 | If the command pipe has been closed, exit after all 128 | in-flight probes have reported their status. 129 | */ 130 | if (!command_pipe_open) { 131 | if (net_state.outstanding_probe_count == 0) { 132 | break; 133 | } 134 | } 135 | } 136 | 137 | return 0; 138 | } 139 | -------------------------------------------------------------------------------- /packet/protocols.h: -------------------------------------------------------------------------------- 1 | /* 2 | mtr -- a network diagnostic tool 3 | Copyright (C) 2016 Matt Kimball 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License version 2 as 7 | published by the Free Software Foundation. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along 15 | with this program; if not, write to the Free Software Foundation, Inc., 16 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #ifndef PROTOCOLS_H 20 | #define PROTOCOLS_H 21 | 22 | /* ICMPv4 type codes */ 23 | #define ICMP_ECHOREPLY 0 24 | #define ICMP_DEST_UNREACH 3 25 | #define ICMP_ECHO 8 26 | #define ICMP_TIME_EXCEEDED 11 27 | 28 | /* ICMP_DEST_UNREACH codes */ 29 | #define ICMP_PORT_UNREACH 3 30 | 31 | /* ICMPv6 type codes */ 32 | #define ICMP6_DEST_UNREACH 1 33 | #define ICMP6_TIME_EXCEEDED 3 34 | #define ICMP6_ECHO 128 35 | #define ICMP6_ECHOREPLY 129 36 | 37 | /* ICMP6_DEST_UNREACH codes */ 38 | #define ICMP6_PORT_UNREACH 4 39 | 40 | /* 41 | The minimum size of the ICMP "original datagram" when 42 | using ICMP extensions 43 | */ 44 | #define ICMP_ORIGINAL_DATAGRAM_MIN_SIZE 128 45 | 46 | /* The classnum and type of MPLS labels in an ICMP extension object */ 47 | #define ICMP_EXT_MPLS_CLASSNUM 1 48 | #define ICMP_EXT_MPLS_CTYPE 1 49 | 50 | #define HTTP_PORT 80 51 | 52 | /* We can't rely on header files to provide this information, because 53 | the fields have different names between, for instance, Linux and 54 | Solaris */ 55 | struct ICMPHeader { 56 | uint8_t type; 57 | uint8_t code; 58 | uint16_t checksum; 59 | uint16_t id; 60 | uint16_t sequence; 61 | }; 62 | 63 | /* ICMP extension header, which might contain MPLS labels */ 64 | /* See RFC 4884 */ 65 | struct ICMPExtensionHeader { 66 | uint8_t version; 67 | uint8_t reserved; 68 | uint16_t checksum; 69 | }; 70 | 71 | /* An object in an extended ICMP object */ 72 | struct ICMPExtensionObject { 73 | uint16_t len; 74 | uint8_t classnum; 75 | uint8_t ctype; 76 | }; 77 | 78 | /* An MPLS label included in an ICMP extension */ 79 | /* See RFC 4950 */ 80 | struct ICMPExtMPLSLabel { 81 | uint8_t label[3]; // Low 4 bits are Experimental Use, Stack 82 | uint8_t ttl; 83 | }; 84 | 85 | /* Structure of an UDP header. */ 86 | struct UDPHeader { 87 | uint16_t srcport; 88 | uint16_t dstport; 89 | uint16_t length; 90 | uint16_t checksum; 91 | }; 92 | 93 | /* Structure of an TCP header, as far as we need it. */ 94 | struct TCPHeader { 95 | uint16_t srcport; 96 | uint16_t dstport; 97 | uint32_t seq; 98 | }; 99 | 100 | /* Structure of an SCTP header */ 101 | struct SCTPHeader { 102 | uint16_t srcport; 103 | uint16_t dstport; 104 | uint32_t veri_tag; 105 | }; 106 | 107 | /* Structure of an IPv4 UDP pseudoheader. */ 108 | struct UDPPseudoHeader { 109 | uint32_t saddr; 110 | uint32_t daddr; 111 | uint8_t zero; 112 | uint8_t protocol; 113 | uint16_t len; 114 | }; 115 | 116 | /* Structure of an IP header. */ 117 | struct IPHeader { 118 | uint8_t version; 119 | uint8_t tos; 120 | uint16_t len; 121 | uint16_t id; 122 | uint16_t frag; 123 | uint8_t ttl; 124 | uint8_t protocol; 125 | uint16_t check; 126 | uint32_t saddr; 127 | uint32_t daddr; 128 | }; 129 | 130 | /* IP version 6 header */ 131 | struct IP6Header { 132 | uint8_t version; 133 | uint8_t flow[3]; 134 | uint16_t len; 135 | uint8_t protocol; 136 | uint8_t ttl; 137 | uint8_t saddr[16]; 138 | uint8_t daddr[16]; 139 | }; 140 | 141 | /* The pseudo-header used for checksum computation for ICMPv6 and UDPv6 */ 142 | struct IP6PseudoHeader { 143 | uint8_t saddr[16]; 144 | uint8_t daddr[16]; 145 | uint32_t len; 146 | uint8_t zero[3]; 147 | uint8_t protocol; 148 | }; 149 | 150 | #endif 151 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | WHAT IS MTR? 2 | 3 | mtr combines the functionality of the 'traceroute' and 'ping' programs 4 | in a single network diagnostic tool. 5 | 6 | As mtr starts, it investigates the network connection between the host 7 | mtr runs on and a user-specified destination host. After it 8 | determines the address of each network hop between the machines, 9 | it sends a sequence of ICMP ECHO requests to each one to determine the 10 | quality of the link to each machine. As it does this, it prints 11 | running statistics about each machine. 12 | 13 | mtr is distributed under the GNU General Public License version 2. 14 | See the COPYING file for details. 15 | 16 | INSTALLING 17 | 18 | If you're building this from a tarball, compiling mtr is as 19 | simple as: 20 | 21 | ./configure && make 22 | 23 | (in the past, there was a Makefile in the distribution that did 24 | the ./configure for you and then ran make again with the generated 25 | Makefile, but this has suffered some bitrot. It didn't work well 26 | with git.) 27 | 28 | If you're building from the git repository, you'll need to run: 29 | 30 | ./bootstrap.sh && ./configure && make 31 | 32 | When it looks as if the compilation was succesful, you can 33 | test mtr with 34 | 35 | sudo ./mtr 36 | 37 | (fill in a hostname or IP address where it says ) or 38 | immediately continue on to installing: 39 | 40 | make install 41 | 42 | Note that mtr-packet must be suid-root because it requires access to 43 | raw IP sockets. See SECURITY for security information. 44 | 45 | Older versions used to require a non-existent path to GTK for a 46 | correct build of a non-gtk version while GTK was installed. This is 47 | no longer necessary. ./configure --without-gtk should now work. 48 | If it doesn't, try "make WITHOUT_X11=YES" as the make step. 49 | 50 | On Solaris, you'll need to use GNU make to build. 51 | (Use 'gmake' rather than 'make'.) 52 | 53 | On Solaris (and possibly other systems) the "gtk" library may be 54 | installed in a directory where the dynamic linker refuses to look when 55 | a binary is setuid. Roman Shterenzon reports that adding 56 | -Wl,-rpath=/usr/lib 57 | to the commandline will work if you are using gnu LD. He tells me that 58 | you're out of luck when you use the sun LD. That's not quite true, as 59 | you can move the gtk libraries to /usr/lib instead of leaving them in 60 | /usr/local/lib. (when the ld tells you that /usr/local/lib is untrusted 61 | and /usr/lib is trusted, and you trust the gtk libs enough to want them 62 | in a setuid program, then there is something to say for moving them 63 | to the "trusted" directory.) 64 | 65 | Building on MacOS should not require any special steps. 66 | 67 | BUILDING FOR WINDOWS 68 | 69 | Building for Windows requires Cygwin. To obtain Cygwin, see 70 | https://cygwin.com/install.html. When installing Cygwin, select 71 | the 'lynx' package for installation. lynx is required by apt-cyg. 72 | 73 | Next, install apt-cyg for easy installation of the remaining 74 | components. See https://github.com/transcode-open/apt-cyg. 75 | 76 | Install the packages required for building: 77 | 78 | apt-cyg install automake pkg-config make gcc-core libncurses-devel 79 | 80 | Build as under Unix: 81 | 82 | ./bootstrap.sh && ./configure && make 83 | 84 | Finally, install the built binaries: 85 | 86 | make install 87 | 88 | WHERE CAN I GET THE LATEST VERSION OR MORE INFORMATION? 89 | 90 | mtr is now hosted on github. 91 | https://github.com/traviscross/mtr 92 | 93 | See the mtr web page at 94 | http://www.BitWizard.nl/mtr/ 95 | 96 | Bug reports and feature requests should be submitted to the Github 97 | bug tracking system. 98 | 99 | Patches can be submitted by cloning the Github repository and issuing 100 | a pull request, or by email to me. Please use unified diffs. Usually 101 | the diff is sort of messy, so please check that the diff is clean and 102 | doesn't contain too much of your local stuff (for example, I don't 103 | want/need the "configure" script that /your/ automake made for you). 104 | 105 | (There used to be a mailinglist, but all it got was spam. So 106 | when the server was upgraded, the mailing list died.) 107 | 108 | -- REW 109 | 110 | -------------------------------------------------------------------------------- /packet/cmdparse.c: -------------------------------------------------------------------------------- 1 | /* 2 | mtr -- a network diagnostic tool 3 | Copyright (C) 2016 Matt Kimball 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License version 2 as 7 | published by the Free Software Foundation. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along 15 | with this program; if not, write to the Free Software Foundation, Inc., 16 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #include "cmdparse.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | /* 27 | NUL terminate the whitespace separated tokens in the command string. 28 | This modifies command_string in-place with NUL characters. 29 | Fill the tokens array with pointers to the tokens, and return the 30 | number of tokens found. 31 | */ 32 | static 33 | int tokenize_command( 34 | char **tokens, 35 | int max_tokens, 36 | char *command_string) 37 | { 38 | int token_count = 0; 39 | int on_space = 1; 40 | int i; 41 | 42 | for (i = 0; command_string[i]; i++) { 43 | if (on_space) { 44 | if (!isspace((unsigned char) command_string[i])) { 45 | /* Take care not to exceed the token array length */ 46 | if (token_count >= max_tokens) { 47 | return -1; 48 | } 49 | 50 | tokens[token_count++] = &command_string[i]; 51 | on_space = 0; 52 | } 53 | } else { 54 | if (isspace((unsigned char) command_string[i])) { 55 | command_string[i] = 0; 56 | on_space = 1; 57 | } 58 | } 59 | } 60 | 61 | return token_count; 62 | } 63 | 64 | /* 65 | Parse a command string (or command reply string) into a command_t 66 | structure for later semantic interpretation. Returns EINVAL if the 67 | command string is unparseable or zero for success. 68 | 69 | comamnd_string will be modified in-place with NUL characters terminating 70 | tokens, and the command_t will use pointers to the conents of 71 | command_string without copying, so any interpretation of the 72 | command_t structure requires that the command_string memory has not yet 73 | been freed or otherwise reused. 74 | */ 75 | int parse_command( 76 | struct command_t *command, 77 | char *command_string) 78 | { 79 | char *tokens[MAX_COMMAND_TOKENS]; 80 | int token_count; 81 | int i; 82 | 83 | memset(command, 0, sizeof(struct command_t)); 84 | 85 | /* Tokenize the string using whitespace */ 86 | token_count = 87 | tokenize_command(tokens, MAX_COMMAND_TOKENS, command_string); 88 | if (token_count < 2) { 89 | errno = EINVAL; 90 | return -1; 91 | } 92 | 93 | /* Expect the command token to be a numerical value */ 94 | errno = 0; 95 | command->token = strtol(tokens[0], NULL, 10); 96 | if (errno) { 97 | errno = EINVAL; 98 | return -1; 99 | } 100 | command->command_name = tokens[1]; 101 | 102 | /* 103 | The tokens beyond the command name are expected to be in 104 | name, value pairs. 105 | */ 106 | i = 2; 107 | command->argument_count = 0; 108 | while (i < token_count) { 109 | /* It's an error if we get a name without a key */ 110 | if (i + 1 >= token_count) { 111 | errno = EINVAL; 112 | return -1; 113 | } 114 | 115 | /* It's an error if we get more arguments than we have space for */ 116 | if (command->argument_count >= MAX_COMMAND_ARGUMENTS) { 117 | errno = EINVAL; 118 | return -1; 119 | } 120 | 121 | command->argument_name[command->argument_count] = tokens[i]; 122 | command->argument_value[command->argument_count] = tokens[i + 1]; 123 | command->argument_count++; 124 | 125 | i += 2; 126 | } 127 | 128 | return 0; 129 | } 130 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | EXTRA_DIST = \ 2 | BSDCOPYING \ 3 | SECURITY \ 4 | build-aux/mtr.bat \ 5 | img/mtr_icon.xpm 6 | $(TEST_FILES) 7 | 8 | sbin_PROGRAMS = mtr mtr-packet 9 | TESTS = \ 10 | test/cmdparse.py \ 11 | test/param.py \ 12 | test/probe.py 13 | 14 | TEST_FILES = \ 15 | test/cmdparse.py \ 16 | test/mtrpacket.py \ 17 | test/param.py \ 18 | test/probe.py \ 19 | test/lint.sh 20 | EXTRA_DIST += $(TEST_FILES) 21 | 22 | PATHFILES = 23 | CLEANFILES = $(PATHFILES) 24 | EXTRA_DIST += $(PATHFILES:=.in) 25 | 26 | # 27 | # We would use % pattern matching here, but that is a GNU make 28 | # extension and doesn't work on FreeBSD. 29 | # 30 | mtr-packet.8: $(srcdir)/man/mtr-packet.8.in 31 | $(AM_V_GEN) $(srcdir)/build-aux/mangen.sh "$(VERSION)" \ 32 | $(srcdir)/man/mtr-packet.8.in $@ 33 | 34 | mtr.8: $(srcdir)/man/mtr.8.in 35 | $(AM_V_GEN) $(srcdir)/build-aux/mangen.sh "$(VERSION)" \ 36 | $(srcdir)/man/mtr.8.in $@ 37 | 38 | $(PATHFILES): Makefile 39 | 40 | dist_man_MANS = mtr.8 mtr-packet.8 41 | PATHFILES += man/mtr.8 man/mtr-packet.8 42 | 43 | install-exec-hook: 44 | `setcap cap_net_raw+ep $(DESTDIR)$(sbindir)/mtr-packet` \ 45 | || chmod u+s $(DESTDIR)$(sbindir)/mtr-packet 46 | 47 | mtr_SOURCES = ui/mtr.c ui/mtr.h \ 48 | ui/net.c ui/net.h \ 49 | ui/cmdpipe.c ui/cmdpipe.h \ 50 | ui/dns.c ui/dns.h \ 51 | ui/raw.c ui/raw.h \ 52 | ui/split.c ui/split.h \ 53 | ui/display.c ui/display.h \ 54 | ui/report.c ui/report.h \ 55 | ui/select.c ui/select.h \ 56 | ui/utils.c ui/utils.h \ 57 | packet/cmdparse.c packet/cmdparse.h \ 58 | ui/mtr-curses.h \ 59 | img/mtr_icon.xpm \ 60 | ui/mtr-gtk.h 61 | 62 | if WITH_ERROR 63 | mtr_SOURCES += \ 64 | portability/error.h \ 65 | portability/error.c 66 | endif 67 | 68 | if WITH_GETOPT 69 | mtr_SOURCES += \ 70 | portability/getopt.h \ 71 | portability/getopt.c \ 72 | portability/getopt1.c 73 | endif 74 | 75 | if WITH_IPINFO 76 | mtr_SOURCES += ui/asn.c ui/asn.h 77 | endif 78 | 79 | if WITH_CURSES 80 | mtr_SOURCES += ui/curses.c 81 | endif 82 | 83 | if WITH_GTK 84 | mtr_SOURCES += ui/gtk.c 85 | endif 86 | 87 | mtr_INCLUDES = $(GLIB_CFLAGS) -I$(top_builddir) -I$(top_srcdir) 88 | mtr_CFLAGS = $(GTK_CFLAGS) $(NCURSES_CFLAGS) 89 | mtr_LDADD = $(GTK_LIBS) $(NCURSES_LIBS) $(RESOLV_LIBS) 90 | 91 | 92 | mtr_packet_SOURCES = \ 93 | portability/queue.h \ 94 | packet/packet.c \ 95 | packet/cmdparse.c packet/cmdparse.h \ 96 | packet/command.c packet/command.h \ 97 | packet/platform.h \ 98 | packet/probe.c packet/probe.h \ 99 | packet/protocols.h \ 100 | packet/timeval.c packet/timeval.h \ 101 | packet/wait.h 102 | 103 | mtr_packet_LDADD = $(CAP_LIBS) 104 | 105 | 106 | if CYGWIN 107 | 108 | mtr_packet_SOURCES += \ 109 | packet/command_cygwin.c packet/command_cygwin.h \ 110 | packet/probe_cygwin.c packet/probe_cygwin.h \ 111 | packet/wait_cygwin.c 112 | mtr_packet_LDADD += -lcygwin -liphlpapi -lws2_32 113 | 114 | dist_windows_aux = \ 115 | $(srcdir)/build-aux/mtr.bat \ 116 | $(srcdir)/AUTHORS \ 117 | $(srcdir)/BSDCOPYING \ 118 | $(srcdir)/COPYING \ 119 | $(srcdir)/README \ 120 | $(srcdir)/NEWS 121 | 122 | distwindir = $(distdir)-win-$(host_cpu) 123 | 124 | # Bundle necessary files for a Windows binary distribution 125 | distdir-win: $(dist_windows_aux) mtr.exe mtr-packet.exe 126 | rm -fr $(distwindir) 127 | mkdir -p $(distwindir) $(distwindir)/bin $(distwindir)/terminfo 128 | cp $(dist_windows_aux) -t $(distwindir) 129 | cp mtr.exe mtr-packet.exe -t $(distwindir)/bin 130 | ldd mtr.exe | grep -v cygdrive | awk '{ print $$3 }' | xargs cp -t $(distwindir)/bin 131 | cp `find /usr/share/terminfo -name cygwin | xargs dirname` -r $(distwindir)/terminfo 132 | 133 | # Zip up a Windows binary distribution 134 | dist-windows-bin: distdir-win 135 | rm -f $(distwindir).zip 136 | zip -rq $(distwindir).zip $(distwindir) 137 | rm -fr $(distwindir) 138 | 139 | else # if CYGWIN 140 | 141 | check_PROGRAMS = mtr-packet-listen 142 | 143 | mtr_packet_SOURCES += \ 144 | packet/command_unix.c packet/command_unix.h \ 145 | packet/construct_unix.c packet/construct_unix.h \ 146 | packet/deconstruct_unix.c packet/deconstruct_unix.h \ 147 | packet/probe_unix.c packet/probe_unix.h \ 148 | packet/wait_unix.c 149 | 150 | mtr_packet_listen_SOURCES = \ 151 | test/packet_listen.c 152 | 153 | endif # if CYGWIN 154 | 155 | 156 | if BUILD_BASH_COMPLETION 157 | dist_bashcompletion_DATA = bash-completion/mtr 158 | endif 159 | -------------------------------------------------------------------------------- /portability/getopt1.c: -------------------------------------------------------------------------------- 1 | /* getopt_long and getopt_long_only entry points for GNU getopt. 2 | Copyright (C) 1987, 88, 89, 90, 91, 92, 1993, 1994 3 | Free Software Foundation, Inc. 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License version 2 as 7 | published by the Free Software Foundation. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along 15 | with this program; if not, write to the Free Software Foundation, Inc., 16 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ 17 | 18 | #ifdef HAVE_CONFIG_H 19 | #include "config.h" 20 | #endif 21 | 22 | #include "getopt.h" 23 | 24 | #if !defined (__STDC__) || !__STDC__ 25 | /* This is a separate conditional since some stdc systems 26 | reject `defined (const)'. */ 27 | #ifndef const 28 | #define const 29 | #endif 30 | #endif 31 | 32 | #include 33 | 34 | /* Comment out all this code if we are using the GNU C Library, and are not 35 | actually compiling the library itself. This code is part of the GNU C 36 | Library, but also included in many other GNU distributions. Compiling 37 | and linking in this code is a waste when using the GNU C library 38 | (especially if it is a shared library). Rather than having every GNU 39 | program understand `configure --with-gnu-libc' and omit the object files, 40 | it is simpler to just do this in the source for each such file. */ 41 | 42 | #if defined (_LIBC) || !defined (__GNU_LIBRARY__) 43 | 44 | 45 | /* This needs to come after some library #include 46 | to get __GNU_LIBRARY__ defined. */ 47 | #ifdef __GNU_LIBRARY__ 48 | #include 49 | #else 50 | char *getenv (); 51 | #endif 52 | 53 | #ifndef NULL 54 | #define NULL 0 55 | #endif 56 | 57 | int 58 | getopt_long (argc, argv, options, long_options, opt_index) 59 | int argc; 60 | char *const *argv; 61 | const char *options; 62 | const struct option *long_options; 63 | int *opt_index; 64 | { 65 | return _getopt_internal (argc, argv, options, long_options, opt_index, 0); 66 | } 67 | 68 | /* Like getopt_long, but '-' as well as '--' can indicate a long option. 69 | If an option that starts with '-' (not '--') doesn't match a long option, 70 | but does match a short option, it is parsed as a short option 71 | instead. */ 72 | 73 | int 74 | getopt_long_only (argc, argv, options, long_options, opt_index) 75 | int argc; 76 | char *const *argv; 77 | const char *options; 78 | const struct option *long_options; 79 | int *opt_index; 80 | { 81 | return _getopt_internal (argc, argv, options, long_options, opt_index, 1); 82 | } 83 | 84 | 85 | #endif /* _LIBC or not __GNU_LIBRARY__. */ 86 | 87 | #ifdef TEST 88 | 89 | #include 90 | 91 | int 92 | main (argc, argv) 93 | int argc; 94 | char **argv; 95 | { 96 | int c; 97 | int digit_optind = 0; 98 | 99 | while (1) 100 | { 101 | int this_option_optind = optind ? optind : 1; 102 | int option_index = 0; 103 | static struct option long_options[] = 104 | { 105 | {"add", 1, 0, 0}, 106 | {"append", 0, 0, 0}, 107 | {"delete", 1, 0, 0}, 108 | {"verbose", 0, 0, 0}, 109 | {"create", 0, 0, 0}, 110 | {"file", 1, 0, 0}, 111 | {0, 0, 0, 0} 112 | }; 113 | 114 | c = getopt_long (argc, argv, "abc:d:0123456789", 115 | long_options, &option_index); 116 | if (c == EOF) 117 | break; 118 | 119 | switch (c) 120 | { 121 | case 0: 122 | printf ("option %s", long_options[option_index].name); 123 | if (optarg) 124 | printf (" with arg %s", optarg); 125 | printf ("\n"); 126 | break; 127 | 128 | case '0': 129 | case '1': 130 | case '2': 131 | case '3': 132 | case '4': 133 | case '5': 134 | case '6': 135 | case '7': 136 | case '8': 137 | case '9': 138 | if (digit_optind != 0 && digit_optind != this_option_optind) 139 | printf ("digits occur in two different argv-elements.\n"); 140 | digit_optind = this_option_optind; 141 | printf ("option %c\n", c); 142 | break; 143 | 144 | case 'a': 145 | printf ("option a\n"); 146 | break; 147 | 148 | case 'b': 149 | printf ("option b\n"); 150 | break; 151 | 152 | case 'c': 153 | printf ("option c with value `%s'\n", optarg); 154 | break; 155 | 156 | case 'd': 157 | printf ("option d with value `%s'\n", optarg); 158 | break; 159 | 160 | case '?': 161 | break; 162 | 163 | default: 164 | printf ("?? getopt returned character code 0%o ??\n", c); 165 | } 166 | } 167 | 168 | if (optind < argc) 169 | { 170 | printf ("non-option ARGV-elements: "); 171 | while (optind < argc) 172 | printf ("%s ", argv[optind++]); 173 | printf ("\n"); 174 | } 175 | 176 | exit(EXIT_SUCCESS); 177 | } 178 | 179 | #endif /* TEST */ 180 | -------------------------------------------------------------------------------- /ui/split.c: -------------------------------------------------------------------------------- 1 | /* 2 | mtr -- a network diagnostic tool 3 | Copyright (C) 1997 Matt Kimball 4 | 5 | split.c -- raw output (for inclusion in KDE Network Utilities or others 6 | GUI based tools) 7 | Copyright (C) 1998 Bertrand Leconte 8 | 9 | This program is free software; you can redistribute it and/or modify 10 | it under the terms of the GNU General Public License version 2 as 11 | published by the Free Software Foundation. 12 | 13 | This program is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License along 19 | with this program; if not, write to the Free Software Foundation, Inc., 20 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 21 | */ 22 | 23 | #include "config.h" 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #include "mtr.h" 32 | #include "display.h" 33 | #include "dns.h" 34 | 35 | #include "net.h" 36 | #include "split.h" 37 | #include "utils.h" 38 | 39 | #ifdef HAVE_CURSES 40 | #if defined(HAVE_NCURSES_H) 41 | #include 42 | #elif defined(HAVE_NCURSES_CURSES_H) 43 | #include 44 | #elif defined(HAVE_CURSES_H) 45 | #include 46 | #else 47 | #error No curses header file available 48 | #endif 49 | #else 50 | #include 51 | #include 52 | #include 53 | #endif 54 | 55 | 56 | /* There is 256 hops max in the IP header (coded with a byte) */ 57 | #define MAX_LINE_COUNT 256 58 | #define MAX_LINE_SIZE 256 59 | 60 | static char Lines[MAX_LINE_COUNT][MAX_LINE_SIZE]; 61 | static int LineCount; 62 | 63 | 64 | #define DEBUG 0 65 | 66 | 67 | void split_redraw( 68 | struct mtr_ctl *ctl) 69 | { 70 | int max; 71 | int at; 72 | ip_t *addr; 73 | char newLine[MAX_LINE_SIZE]; 74 | int i; 75 | 76 | #if DEBUG 77 | fprintf(stderr, "split_redraw()\n"); 78 | #endif 79 | 80 | /* 81 | * If there is less lines than last time, we delete them 82 | * TEST THIS PLEASE 83 | */ 84 | max = net_max(ctl); 85 | for (i = LineCount; i > max; i--) { 86 | printf("-%d\n", i); 87 | LineCount--; 88 | } 89 | 90 | /* 91 | * For each line, we compute the new one and we compare it to the old one 92 | */ 93 | for (at = 0; at < max; at++) { 94 | addr = net_addr(at); 95 | if (addrcmp((void *) addr, (void *) &ctl->unspec_addr, ctl->af)) { 96 | char str[256], *name; 97 | if (!(name = dns_lookup(ctl, addr))) 98 | name = strlongip(ctl, addr); 99 | if (ctl->show_ips) { 100 | snprintf(str, sizeof(str), "%s %s", name, 101 | strlongip(ctl, addr)); 102 | name = str; 103 | } 104 | /* May be we should test name's length */ 105 | snprintf(newLine, sizeof(newLine), "%s %d %d %d %d %d %d", 106 | name, net_loss(at), net_returned(at), net_xmit(at), 107 | net_best(at) / 1000, net_avg(at) / 1000, 108 | net_worst(at) / 1000); 109 | } else { 110 | snprintf(newLine, sizeof(newLine), "???"); 111 | } 112 | 113 | if (strcmp(newLine, Lines[at]) == 0) { 114 | /* The same, so do nothing */ 115 | #if DEBUG 116 | printf("SAME LINE\n"); 117 | #endif 118 | } else { 119 | printf("%d %s\n", at + 1, newLine); 120 | fflush(stdout); 121 | xstrncpy(Lines[at], newLine, MAX_LINE_SIZE); 122 | if (LineCount < (at + 1)) { 123 | LineCount = at + 1; 124 | } 125 | } 126 | } 127 | } 128 | 129 | 130 | void split_open( 131 | void) 132 | { 133 | int i; 134 | #if DEBUG 135 | printf("split_open()\n"); 136 | #endif 137 | LineCount = -1; 138 | for (i = 0; i < MAX_LINE_COUNT; i++) { 139 | xstrncpy(Lines[i], "???", MAX_LINE_SIZE); 140 | } 141 | } 142 | 143 | 144 | void split_close( 145 | void) 146 | { 147 | #if DEBUG 148 | printf("split_close()\n"); 149 | #endif 150 | } 151 | 152 | 153 | int split_keyaction( 154 | void) 155 | { 156 | #ifdef HAVE_CURSES 157 | unsigned char c = getch(); 158 | #else 159 | fd_set readfds; 160 | struct timeval tv; 161 | char c; 162 | 163 | FD_ZERO(&readfds); 164 | FD_SET(0, &readfds); 165 | tv.tv_sec = 0; 166 | tv.tv_usec = 0; 167 | 168 | if (select(1, &readfds, NULL, NULL, &tv) > 0) { 169 | read(0, &c, 1); 170 | } else 171 | return 0; 172 | #endif 173 | 174 | #if DEBUG 175 | printf("split_keyaction()\n"); 176 | #endif 177 | if (tolower(c) == 'q') 178 | return ActionQuit; 179 | if (c == 3) 180 | return ActionQuit; 181 | if (tolower(c) == 'r') 182 | return ActionReset; 183 | 184 | return 0; 185 | } 186 | -------------------------------------------------------------------------------- /ui/utils.c: -------------------------------------------------------------------------------- 1 | /* 2 | mtr -- a network diagnostic tool 3 | Copyright (C) 1997,1998 Matt Kimball 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License version 2 as 7 | published by the Free Software Foundation. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along 15 | with this program; if not, write to the Free Software Foundation, Inc., 16 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #include "config.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | #ifdef HAVE_ERROR_H 32 | #include 33 | #else 34 | #include "portability/error.h" 35 | #endif 36 | 37 | #ifdef HAVE_STDIO_EXT_H 38 | #include 39 | #endif 40 | 41 | #include "utils.h" 42 | 43 | char *trim( 44 | char *str, 45 | const char c) 46 | { 47 | char *p = str; 48 | size_t len; 49 | 50 | /* left trim */ 51 | while (*p && (isspace((unsigned char) *p) || (c && *p == c))) 52 | p++; 53 | if (str < p) { 54 | len = strlen(str); 55 | memmove(str, p, len + 1); 56 | } 57 | 58 | /* right trim */ 59 | len = strlen(str); 60 | while (len) { 61 | len--; 62 | if (isspace((unsigned char) str[len]) || (c && str[len] == c)) { 63 | continue; 64 | } 65 | len++; 66 | break; 67 | } 68 | str[len] = '\0'; 69 | return str; 70 | } 71 | 72 | /* Parse string, and return positive signed int. */ 73 | int strtonum_or_err( 74 | const char *str, 75 | const char *errmesg, 76 | const int type) 77 | { 78 | unsigned long int num; 79 | char *end = NULL; 80 | 81 | if (str != NULL && *str != '\0') { 82 | errno = 0; 83 | num = strtoul(str, &end, 10); 84 | if (errno == 0 && str != end && end != NULL && *end == '\0') { 85 | switch (type) { 86 | case STRTO_INT: 87 | if (num < INT_MAX) 88 | return num; 89 | break; 90 | case STRTO_U32INT: 91 | if (num < UINT32_MAX) 92 | return num; 93 | break; 94 | } 95 | } 96 | } 97 | error(EXIT_FAILURE, errno, "%s: '%s'", errmesg, str); 98 | return 0; 99 | } 100 | 101 | float strtofloat_or_err( 102 | const char *str, 103 | const char *errmesg) 104 | { 105 | double num; 106 | char *end = NULL; 107 | 108 | if (str != NULL && *str != '\0') { 109 | errno = 0; 110 | num = strtod(str, &end); 111 | if (errno == 0 && str != end && end != NULL && *end == '\0' 112 | #ifdef FLT_MAX 113 | && num < FLT_MAX 114 | #endif 115 | ) 116 | return num; 117 | } 118 | error(EXIT_FAILURE, errno, "%s: '%s'", errmesg, str); 119 | return 0; 120 | } 121 | 122 | void *xmalloc( 123 | const size_t size) 124 | { 125 | void *ret = malloc(size); 126 | 127 | if (!ret && size) 128 | error(EXIT_FAILURE, errno, "cannot allocate %zu bytes", size); 129 | return ret; 130 | } 131 | 132 | char *xstrdup( 133 | const char *str) 134 | { 135 | char *ret; 136 | 137 | if (!str) 138 | return NULL; 139 | ret = strdup(str); 140 | if (!ret) 141 | error(EXIT_FAILURE, errno, "cannot duplicate string: %s", str); 142 | return ret; 143 | } 144 | 145 | #ifndef HAVE___FPENDING 146 | static inline int __fpending( 147 | FILE * stream __attribute__ ((__unused__))) 148 | { 149 | return 0; 150 | } 151 | #endif 152 | static inline int close_stream( 153 | FILE * stream) 154 | { 155 | const int some_pending = (__fpending(stream) != 0); 156 | const int prev_fail = (ferror(stream) != 0); 157 | const int fclose_fail = (fclose(stream) != 0); 158 | 159 | if (prev_fail || (fclose_fail && (some_pending || errno != EBADF))) { 160 | if (!fclose_fail && !(errno == EPIPE)) 161 | errno = 0; 162 | return EOF; 163 | } 164 | return 0; 165 | } 166 | 167 | /* Meant to be used atexit(close_stdout); */ 168 | void close_stdout( 169 | void) 170 | { 171 | if (close_stream(stdout) != 0 && !(errno == EPIPE)) { 172 | error(0, errno, "write error"); 173 | _exit(EXIT_FAILURE); 174 | } 175 | if (close_stream(stderr) != 0) 176 | _exit(EXIT_FAILURE); 177 | } 178 | 179 | /* ctime() replacement that will reteturn ISO-8601 timestamp string such as: 180 | * 2016-08-29T19:25:02+01:00 */ 181 | const char *iso_time( 182 | const time_t * t) 183 | { 184 | static char s[32]; 185 | struct tm *tm; 186 | 187 | tm = localtime(t); 188 | strftime(s, sizeof(s), "%Y-%m-%dT%H:%M:%S%z", tm); 189 | return s; 190 | } 191 | -------------------------------------------------------------------------------- /packet/command_cygwin.c: -------------------------------------------------------------------------------- 1 | /* 2 | mtr -- a network diagnostic tool 3 | Copyright (C) 2016 Matt Kimball 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License version 2 as 7 | published by the Free Software Foundation. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along 15 | with this program; if not, write to the Free Software Foundation, Inc., 16 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #include "command.h" 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | /* 26 | A completion routine to be called by Windows when a read from 27 | the command stream has completed. 28 | */ 29 | static 30 | void CALLBACK finish_read_command( 31 | DWORD status, 32 | DWORD size_read, 33 | OVERLAPPED * overlapped) 34 | { 35 | struct command_buffer_t *buffer; 36 | char *read_position; 37 | 38 | /* 39 | hEvent is unusuaed by ReadFileEx, so we use it to pass 40 | our command_buffer structure. 41 | */ 42 | buffer = (struct command_buffer_t *) overlapped->hEvent; 43 | 44 | if (status) { 45 | /* When the stream is closed ERROR_BROKEN_PIPE will be the result */ 46 | if (status == ERROR_BROKEN_PIPE) { 47 | buffer->platform.pipe_open = false; 48 | return; 49 | } 50 | 51 | fprintf(stderr, "ReadFileEx completion failure %d\n", status); 52 | exit(EXIT_FAILURE); 53 | } 54 | 55 | /* Copy from the overlapped I/O buffer to the incoming command buffer */ 56 | read_position = 57 | &buffer->incoming_buffer[buffer->incoming_read_position]; 58 | memcpy(read_position, buffer->platform.overlapped_buffer, size_read); 59 | 60 | /* Account for the newly read data */ 61 | buffer->incoming_read_position += size_read; 62 | buffer->platform.read_active = false; 63 | } 64 | 65 | /* 66 | An APC which does nothing, to be used only to wake from the current 67 | alertable wait. 68 | */ 69 | static 70 | void CALLBACK empty_apc( 71 | ULONG * param) 72 | { 73 | } 74 | 75 | /* Wake from the next alertable wait without waiting for newly read data */ 76 | static 77 | void queue_empty_apc( 78 | void) 79 | { 80 | if (QueueUserAPC((PAPCFUNC) empty_apc, GetCurrentThread(), 0) == 0) { 81 | fprintf(stderr, "Unexpected QueueUserAPC failure %d\n", 82 | GetLastError()); 83 | exit(EXIT_FAILURE); 84 | } 85 | } 86 | 87 | /* Start a new overlapped I/O read from the command stream */ 88 | void start_read_command( 89 | struct command_buffer_t *buffer) 90 | { 91 | HANDLE command_stream = (HANDLE) get_osfhandle(buffer->command_stream); 92 | int space_remaining = 93 | COMMAND_BUFFER_SIZE - buffer->incoming_read_position - 1; 94 | int err; 95 | 96 | /* If a read is already active, or the pipe is closed, do nothing */ 97 | if (!buffer->platform.pipe_open || buffer->platform.read_active) { 98 | return; 99 | } 100 | 101 | memset(&buffer->platform.overlapped, 0, sizeof(OVERLAPPED)); 102 | buffer->platform.overlapped.hEvent = (HANDLE) buffer; 103 | 104 | if (!ReadFileEx 105 | (command_stream, buffer->platform.overlapped_buffer, 106 | space_remaining, &buffer->platform.overlapped, 107 | finish_read_command)) { 108 | 109 | err = GetLastError(); 110 | 111 | if (err == ERROR_BROKEN_PIPE) { 112 | /* If the command stream has been closed, we need to wake from 113 | the next altertable wait to exit the main loop */ 114 | buffer->platform.pipe_open = false; 115 | queue_empty_apc(); 116 | 117 | return; 118 | } else if (err != WAIT_IO_COMPLETION) { 119 | fprintf(stderr, "Unexpected ReadFileEx failure %d\n", 120 | GetLastError()); 121 | exit(EXIT_FAILURE); 122 | } 123 | } 124 | 125 | /* Remember that we have started an overlapped read already */ 126 | buffer->platform.read_active = true; 127 | } 128 | 129 | /* Initialize the command buffer, and start the first overlapped read */ 130 | void init_command_buffer( 131 | struct command_buffer_t *command_buffer, 132 | int command_stream) 133 | { 134 | memset(command_buffer, 0, sizeof(struct command_buffer_t)); 135 | command_buffer->command_stream = command_stream; 136 | command_buffer->platform.pipe_open = true; 137 | } 138 | 139 | /* 140 | Return with errno EPIPE if the command stream has been closed. 141 | Otherwise, not much to do for Cygwin, since we are using Overlapped I/O 142 | to read commands. 143 | */ 144 | int read_commands( 145 | struct command_buffer_t *buffer) 146 | { 147 | if (!buffer->platform.pipe_open) { 148 | errno = EPIPE; 149 | return -1; 150 | } 151 | 152 | return 0; 153 | } 154 | -------------------------------------------------------------------------------- /packet/wait_unix.c: -------------------------------------------------------------------------------- 1 | /* 2 | mtr -- a network diagnostic tool 3 | Copyright (C) 2016 Matt Kimball 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License version 2 as 7 | published by the Free Software Foundation. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along 15 | with this program; if not, write to the Free Software Foundation, Inc., 16 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #include "wait.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | /* 30 | Gather all the file descriptors which should wake our select call when 31 | they become readable. 32 | */ 33 | static 34 | int gather_read_fds( 35 | const struct command_buffer_t *command_buffer, 36 | const struct net_state_t *net_state, 37 | fd_set * read_set, 38 | fd_set * write_set) 39 | { 40 | int nfds; 41 | int probe_nfds; 42 | int ip4_socket; 43 | int ip6_socket; 44 | int command_stream = command_buffer->command_stream; 45 | 46 | FD_ZERO(read_set); 47 | FD_ZERO(write_set); 48 | 49 | FD_SET(command_stream, read_set); 50 | nfds = command_stream + 1; 51 | 52 | if (net_state->platform.ip4_socket_raw) { 53 | ip4_socket = net_state->platform.ip4_recv_socket; 54 | FD_SET(ip4_socket, read_set); 55 | if (ip4_socket >= nfds) { 56 | nfds = ip4_socket + 1; 57 | } 58 | } else { 59 | ip4_socket = net_state->platform.ip4_txrx_icmp_socket; 60 | FD_SET(ip4_socket, read_set); 61 | if (ip4_socket >= nfds) { 62 | nfds = ip4_socket + 1; 63 | } 64 | ip4_socket = net_state->platform.ip4_txrx_udp_socket; 65 | FD_SET(ip4_socket, read_set); 66 | if (ip4_socket >= nfds) { 67 | nfds = ip4_socket + 1; 68 | } 69 | } 70 | 71 | if (net_state->platform.ip6_socket_raw) { 72 | ip6_socket = net_state->platform.ip6_recv_socket; 73 | FD_SET(ip6_socket, read_set); 74 | if (ip6_socket >= nfds) { 75 | nfds = ip6_socket + 1; 76 | } 77 | } else { 78 | ip6_socket = net_state->platform.ip6_txrx_icmp_socket; 79 | FD_SET(ip6_socket, read_set); 80 | if (ip6_socket >= nfds) { 81 | nfds = ip6_socket + 1; 82 | } 83 | ip6_socket = net_state->platform.ip6_txrx_udp_socket; 84 | FD_SET(ip6_socket, read_set); 85 | if (ip6_socket >= nfds) { 86 | nfds = ip6_socket + 1; 87 | } 88 | } 89 | 90 | probe_nfds = gather_probe_sockets(net_state, write_set); 91 | if (probe_nfds > nfds) { 92 | nfds = probe_nfds; 93 | } 94 | 95 | return nfds; 96 | } 97 | 98 | /* 99 | Sleep until we receive a new probe response, a new command on the 100 | command stream, or a probe timeout. On Unix systems, this means 101 | we use select to wait on file descriptors for the command stream 102 | and the raw recieve socket. 103 | */ 104 | void wait_for_activity( 105 | struct command_buffer_t *command_buffer, 106 | struct net_state_t *net_state) 107 | { 108 | int nfds; 109 | fd_set read_set; 110 | fd_set write_set; 111 | struct timeval probe_timeout; 112 | struct timeval *select_timeout; 113 | int ready_count; 114 | 115 | nfds = 116 | gather_read_fds(command_buffer, net_state, &read_set, &write_set); 117 | 118 | while (true) { 119 | select_timeout = NULL; 120 | 121 | /* Use the soonest probe timeout time as our maximum wait time */ 122 | if (get_next_probe_timeout(net_state, &probe_timeout)) { 123 | assert(probe_timeout.tv_sec >= 0); 124 | select_timeout = &probe_timeout; 125 | } 126 | 127 | ready_count = 128 | select(nfds, &read_set, &write_set, NULL, select_timeout); 129 | 130 | /* 131 | If we didn't have an error, either one of our descriptors is 132 | readable, or we timed out. So we can now return. 133 | */ 134 | if (ready_count != -1) { 135 | break; 136 | } 137 | 138 | /* 139 | We will get EINTR if we received a signal during the select, so 140 | retry in that case. We may get EAGAIN if "the kernel was 141 | (perhaps temporarily) unable to allocate the requested number of 142 | file descriptors." I haven't seen this in practice, but selecting 143 | again seems like the right thing to do. 144 | */ 145 | if (errno != EINTR && errno != EAGAIN) { 146 | /* We don't expect other errors, so report them */ 147 | perror("unexpected select error"); 148 | exit(EXIT_FAILURE); 149 | } 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | 2 | Hi everyone, 3 | 4 | This is the "todo" file for mtr. I just realized that some people 5 | might think that this is all in MY queue to implement. That is not 6 | true: This is the "for everybody" todo list. Feel free to pick a 7 | "project" and implement something off this list. 8 | 9 | Students: Feel free to take up one of these as a programming exercise 10 | for one of your courses. 11 | 12 | Everybody: If you want to start on something, contact me first, so 13 | that the effort isn't wasted by someone who finishes just a tad 14 | earlier. I'll happily provide "coaching" to anyone who wants to 15 | implement something on this list. That way we get the design of 16 | these things the way I like them. This should result in a better 17 | maintainable mtr. 18 | 19 | Oh, Feel free to provide suggestions for this list. 20 | 21 | 22 | -- REW 23 | 24 | ---------------------------------------------------------------------- 25 | 26 | 27 | - Stuff to implement: 28 | 29 | - Allow mtr to log the return packets, for later analysis. 30 | Done: 0.25 . Todo: allow the user interface(s) to work while 31 | still logging to a file. Write a "logfile displaying" mode to 32 | mtr. 33 | 34 | - Request timestamping at the remote site. 35 | Andreas Fasbender has an algorithm that will allow us to 36 | convert these measurements into one-way measurements, not just 37 | round-trip. 38 | 39 | - allow "keyboard navigation" in the GTK version. 40 | 41 | - Keep all packets and make the "best" and "worst" columns show the 42 | xx-th percentile.... 43 | 44 | - Can the reports generated also include any secondary servers? In 45 | the interactive mode, any new servers that are found in the 46 | traceroute are added to the list, but it seems to only include 47 | one set of servers when using the -r option. 48 | 49 | - Being able to expand the "column width" of the hosts listed would 50 | be nice, too. 51 | 52 | 53 | - Bugs to fix? 54 | 55 | - Do something useful if host couldn't be resolved. 56 | -- Done. 57 | 58 | - Revert to curses mode even if DISPLAY is set, but a problem 59 | prevents us from running in X11 mode. 60 | --> The problem is that gtk_init simply calls exit for us if 61 | it finds a problem. Tricky! Suggestions welcome. 62 | --> Call "gtk_check_init" when available. (i.e. new enough 63 | (1.2?) GTK version). 64 | 65 | - Nice to have: 66 | 67 | - stop sending packets when a new host is getting entered. 68 | 69 | - Show state ("looking up host") while doing the DNS lookup for a new 70 | host. 71 | 72 | - to have a choice of icmp, tcp, and udp pings. -- Matt Martini 73 | 74 | - Autoconf 2.13 has a neat function that can be used to find the 75 | res_init function: 76 | 77 | AC_SEARCH_LIBS(res_init, bind resolv, , 78 | AC_MSG_ERROR(No resolver library found)) 79 | 80 | At the moment (march 1999) autoconf 2.13 is still too new to require 81 | everyone to upgrade. About a year from now we can put this in.... 82 | 83 | - Implement rfc2317 mechanism to do reverse lookups for networks that 84 | have DNS delegations on non-octet boundaries. -- Daniel Bergstrom 85 | (noa@melody.se) 86 | 87 | - The longer MTR runs, the less meaningful the packet loss 88 | statistic. Or more meaningful, depending on your point of view. 89 | Perhaps MTR should use a circular buffer of some configurable 90 | number of results, and calculate the loss against that. -- Jacob Elder 91 | 92 | - It would be nice if the window size wasn't fixed. If I'm only 5 93 | hops from the host I'm monitoring, MTR wastes a lot of screen real 94 | estate. -- Jacob Elder 95 | 96 | - Colors in the curses version. -- Amix 97 | 98 | - If we run a mtr to monitor a connection it would be nice if the time at 99 | which mtr was started is print somewhere. -- Sebastian Ganschow 100 | 101 | 102 | 103 | ------------------------------------------------------------------------ 104 | 105 | Things that shouldn't be on the TODO list because they're done. ;-) 106 | 107 | - Allow a toggle between hostname/IP number display. (for example a 108 | click on the hostname could revert to ip number display in gtk version. 109 | curses: "n" key toggles hostnames/ipnumbers?) 110 | 111 | - Allow mtr to also send larger packets. 112 | This will enable us to get a feel for the speed of the links 113 | we're traversing. (Van Jacobson was working on this His tool 114 | was slow, mtr will rock with this feature.... :-) 115 | (Anybody have the statistics experience to tell me how 116 | to do the data analysis?) 117 | -- DONE. Thanks to Olav Kvittem ... 118 | 119 | - The "don't probe all hosts at once" strategy can be improved a bit. 120 | It should not probe more than 10 unknown hosts, but the counter need 121 | not be reset at the start of the "round". This way if you probe 122 | slowly (relative to the RTT time to the end host), it can probe 123 | all hosts in the first "round". 124 | -- DONE. 125 | 126 | - Read environment variable "MTR_DEFAULTS" as a commandline before 127 | parsing the commandline. -- DONE. (ok it's MTR_OPTIONS.) 128 | 129 | -------------------------------------------------------------------------------- /ui/mtr.h: -------------------------------------------------------------------------------- 1 | /* 2 | mtr -- a network diagnostic tool 3 | Copyright (C) 1997,1998 Matt Kimball 4 | Copyright (C) 2005 R.E.Wolff@BitWizard.nl 5 | 6 | This program is free software; you can redistribute it and/or modify 7 | it under the terms of the GNU General Public License version 2 as 8 | published by the Free Software Foundation. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License along 16 | with this program; if not, write to the Free Software Foundation, Inc., 17 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 | */ 19 | 20 | #ifndef MTR_MTR_H 21 | #define MTR_MTR_H 22 | 23 | #include "config.h" 24 | 25 | #include 26 | #include 27 | #include 28 | 29 | #ifdef HAVE_NETINET_IN_H 30 | #include 31 | #endif 32 | 33 | /* Typedefs */ 34 | #ifdef ENABLE_IPV6 35 | typedef struct in6_addr ip_t; 36 | #else 37 | typedef struct in_addr ip_t; 38 | #endif 39 | 40 | #ifndef HAVE_TIME_T 41 | typedef int time_t; 42 | #endif 43 | 44 | /* The __unused__ attribute was added in gcc 3.2.7. */ 45 | #if __GNUC__ >= 3 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7) 46 | #define ATTRIBUTE_UNUSED __attribute__((__unused__)) 47 | #else 48 | #define ATTRIBUTE_UNUSED /* empty */ 49 | #endif 50 | 51 | /* The __const__ attribute was added in gcc 2.95. */ 52 | #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95) 53 | #define ATTRIBUTE_CONST __attribute__ ((__const__)) 54 | #else 55 | #define ATTRIBUTE_CONST /* empty */ 56 | #endif 57 | 58 | /* stuff used by display such as report, curses... */ 59 | #define MAXFLD 20 /* max stats fields to display */ 60 | #define FLD_INDEX_SZ 256 61 | 62 | /* net related definitions */ 63 | #define SAVED_PINGS 200 64 | #define MAXPATH 8 65 | #define MaxHost 256 66 | #define MinPort 1024 67 | #define MaxPort 65535 68 | #define MAXPACKET 4470 /* largest test packet size */ 69 | #define MINPACKET 28 /* 20 bytes IP header and 8 bytes ICMP or UDP */ 70 | #define MAXLABELS 8 /* http://kb.juniper.net/KB2190 (+ 3 just in case) */ 71 | 72 | /* Stream Control Transmission Protocol is defined in netinet/in.h */ 73 | #ifdef IPPROTO_SCTP 74 | #define HAS_SCTP 1 75 | #endif 76 | 77 | #ifndef HAVE_SOCKLEN_T 78 | typedef int socklen_t; 79 | #endif 80 | 81 | struct mtr_ctl { 82 | int MaxPing; 83 | float WaitTime; 84 | float GraceTime; 85 | char *Hostname; 86 | char *InterfaceName; 87 | char *InterfaceAddress; 88 | char LocalHostname[128]; 89 | int ipinfo_no; 90 | int ipinfo_max; 91 | int cpacketsize; /* packet size used by ping */ 92 | int bitpattern; /* packet bit pattern used by ping */ 93 | int tos; /* type of service set in ping packet */ 94 | #ifdef SO_MARK 95 | uint32_t mark; 96 | #endif 97 | ip_t unspec_addr; 98 | int af; /* address family of remote target */ 99 | int mtrtype; /* type of query packet used */ 100 | int fstTTL; /* initial hub(ttl) to ping byMin */ 101 | int maxTTL; /* last hub to ping byMin */ 102 | int maxUnknown; /* stop ping threshold */ 103 | int remoteport; /* target port for TCP tracing */ 104 | int localport; /* source port for UDP tracing */ 105 | int probe_timeout; /* timeout for probe sockets */ 106 | unsigned char fld_active[2 * MAXFLD]; /* SO_MARK to set for ping packet */ 107 | int display_mode; /* display mode selector */ 108 | int fld_index[FLD_INDEX_SZ]; /* default display field (defined by key in net.h) and order */ 109 | char available_options[MAXFLD]; 110 | int display_offset; /* only used in text mode */ 111 | void *gtk_data; /* pointer to hold arbitrary gtk data */ 112 | unsigned int /* bit field to hold named booleans */ 113 | ForceMaxPing:1, 114 | use_dns:1, 115 | show_ips:1, 116 | enablempls:1, dns:1, reportwide:1, Interactive:1, DisplayMode:5; 117 | }; 118 | 119 | /* dynamic field drawing */ 120 | struct fields { 121 | const unsigned char key; 122 | const char *descr; 123 | const char *title; 124 | const char *format; 125 | const int length; 126 | int ( 127 | *net_xxx) ( 128 | int); 129 | }; 130 | /* defined in mtr.c */ 131 | extern const struct fields data_fields[MAXFLD]; 132 | 133 | /* MPLS label object */ 134 | struct mplslen { 135 | unsigned long label[MAXLABELS]; /* label value */ 136 | uint8_t exp[MAXLABELS]; /* experimental bits */ 137 | uint8_t ttl[MAXLABELS]; /* MPLS TTL */ 138 | char s[MAXLABELS]; /* bottom of stack */ 139 | char labels; /* how many labels did we get? */ 140 | }; 141 | 142 | 143 | #ifdef USING_CYGWIN 144 | #define running_as_root() 1 145 | #else 146 | #define running_as_root() (getuid() == 0) 147 | #endif 148 | 149 | #endif /* MTR_MTR_H */ 150 | -------------------------------------------------------------------------------- /packet/probe.h: -------------------------------------------------------------------------------- 1 | /* 2 | mtr -- a network diagnostic tool 3 | Copyright (C) 2016 Matt Kimball 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License version 2 as 7 | published by the Free Software Foundation. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along 15 | with this program; if not, write to the Free Software Foundation, Inc., 16 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #ifndef PROBE_H 20 | #define PROBE_H 21 | 22 | #include "platform.h" 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include "portability/queue.h" 30 | 31 | #ifdef PLATFORM_CYGWIN 32 | #include "probe_cygwin.h" 33 | #else 34 | #include "probe_unix.h" 35 | #endif 36 | 37 | #define MAX_PROBES 1024 38 | 39 | /* Use the "jumbo" frame size as the max packet size */ 40 | #define PACKET_BUFFER_SIZE 9000 41 | 42 | /* Parameters for sending a new probe */ 43 | struct probe_param_t { 44 | /* The version of the Internet Protocol to use. (4 or 6) */ 45 | int ip_version; 46 | 47 | /* The command token used to identify a probe when it is completed */ 48 | int command_token; 49 | 50 | /* The IP address to probe */ 51 | const char *remote_address; 52 | 53 | /* The local address from which to send probes */ 54 | const char *local_address; 55 | 56 | /* Protocol for the probe, using the IPPROTO_* defines */ 57 | int protocol; 58 | 59 | /* The destination port for non-ICMP probes */ 60 | int dest_port; 61 | 62 | /* The local port number to use when sending probes */ 63 | int local_port; 64 | 65 | /* The "type of service" field in the IP header */ 66 | int type_of_service; 67 | 68 | /* The packet "mark" used for mark-based routing on Linux */ 69 | int routing_mark; 70 | 71 | /* Time to live for the transmited probe */ 72 | int ttl; 73 | 74 | /* The packet size (in bytes) including protocol headers */ 75 | int packet_size; 76 | 77 | /* The value with which to fill the bytes of the packet. */ 78 | int bit_pattern; 79 | 80 | /* The number of seconds to wait before assuming the probe was lost */ 81 | int timeout; 82 | 83 | /* true is the probe is to test byte order */ 84 | bool is_probing_byte_order; 85 | }; 86 | 87 | /* Tracking information for an outstanding probe */ 88 | struct probe_t { 89 | /* Our entry in the probe list */ 90 | LIST_ENTRY( 91 | probe_t) probe_list_entry; 92 | 93 | /* 94 | Also the ICMP sequence ID used to identify the probe. 95 | 96 | Also used as the port number to use when binding stream protocol 97 | sockets for this probe. (i.e. TCP or SCTP) 98 | */ 99 | int sequence; 100 | 101 | /* Command token of the probe request */ 102 | int token; 103 | 104 | /* The address being probed */ 105 | struct sockaddr_storage remote_addr; 106 | 107 | /* Platform specific probe tracking */ 108 | struct probe_platform_t platform; 109 | }; 110 | 111 | /* Global state for interacting with the network */ 112 | struct net_state_t { 113 | /* The number of entries in the outstanding_probes list */ 114 | int outstanding_probe_count; 115 | 116 | /* Tracking information for in-flight probes */ 117 | LIST_HEAD( 118 | probe_list_head_t, 119 | probe_t) outstanding_probes; 120 | 121 | /* Platform specific tracking information */ 122 | struct net_state_platform_t platform; 123 | }; 124 | 125 | /* Multiprotocol Label Switching information */ 126 | struct mpls_label_t { 127 | uint32_t label; 128 | uint8_t experimental_use; 129 | uint8_t bottom_of_stack; 130 | uint8_t ttl; 131 | }; 132 | 133 | void init_net_state_privileged( 134 | struct net_state_t *net_state); 135 | 136 | void init_net_state( 137 | struct net_state_t *net_state); 138 | 139 | bool is_ip_version_supported( 140 | struct net_state_t *net_state, 141 | int ip_version); 142 | 143 | bool is_protocol_supported( 144 | struct net_state_t *net_state, 145 | int protocol); 146 | 147 | bool get_next_probe_timeout( 148 | const struct net_state_t *net_state, 149 | struct timeval *timeout); 150 | 151 | void send_probe( 152 | struct net_state_t *net_state, 153 | const struct probe_param_t *param); 154 | 155 | void receive_replies( 156 | struct net_state_t *net_state); 157 | 158 | void check_probe_timeouts( 159 | struct net_state_t *net_state); 160 | 161 | void respond_to_probe( 162 | struct net_state_t *net_state, 163 | struct probe_t *probe, 164 | int icmp_type, 165 | const struct sockaddr_storage *remote_addr, 166 | unsigned int round_trip_us, 167 | int mpls_count, 168 | const struct mpls_label_t *mpls); 169 | 170 | int decode_address_string( 171 | int ip_version, 172 | const char *address_string, 173 | struct sockaddr_storage *address); 174 | 175 | int resolve_probe_addresses( 176 | struct net_state_t *net_state, 177 | const struct probe_param_t *param, 178 | struct sockaddr_storage *dest_sockaddr, 179 | struct sockaddr_storage *src_sockaddr); 180 | 181 | struct probe_t *alloc_probe( 182 | struct net_state_t *net_state, 183 | int token); 184 | 185 | void free_probe( 186 | struct net_state_t *net_state, 187 | struct probe_t *probe); 188 | 189 | void platform_alloc_probe( 190 | struct net_state_t *net_state, 191 | struct probe_t *probe); 192 | 193 | void platform_free_probe( 194 | struct probe_t *probe); 195 | 196 | struct probe_t *find_probe( 197 | struct net_state_t *net_state, 198 | int protocol, 199 | int icmp_id, 200 | int icmp_sequence); 201 | 202 | int find_source_addr( 203 | struct sockaddr_storage *srcaddr, 204 | const struct sockaddr_storage *destaddr); 205 | 206 | #endif 207 | -------------------------------------------------------------------------------- /ui/display.c: -------------------------------------------------------------------------------- 1 | /* 2 | mtr -- a network diagnostic tool 3 | Copyright (C) 1997,1998 Matt Kimball 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License version 2 as 7 | published by the Free Software Foundation. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along 15 | with this program; if not, write to the Free Software Foundation, Inc., 16 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #include "config.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include "mtr.h" 29 | #include "display.h" 30 | #include "report.h" 31 | #include "select.h" 32 | #include "raw.h" 33 | #include "dns.h" 34 | #include "asn.h" 35 | 36 | #ifdef HAVE_CURSES 37 | #include "mtr-curses.h" 38 | #endif 39 | 40 | #ifdef HAVE_GTK 41 | #include "mtr-gtk.h" 42 | #endif 43 | 44 | #include "split.h" 45 | 46 | #ifdef HAVE_CURSES 47 | #define DEFAULT_DISPLAY DisplayCurses 48 | #else 49 | #define DEFAULT_DISPLAY DisplayReport 50 | #endif 51 | 52 | #ifdef HAVE_GTK 53 | #define UNUSED_IF_NO_GTK /* empty */ 54 | #else 55 | #define UNUSED_IF_NO_GTK ATTRIBUTE_UNUSED 56 | #endif 57 | 58 | void display_detect( 59 | struct mtr_ctl *ctl, 60 | int *argc UNUSED_IF_NO_GTK, 61 | char ***argv UNUSED_IF_NO_GTK) 62 | { 63 | ctl->DisplayMode = DEFAULT_DISPLAY; 64 | 65 | #ifdef HAVE_GTK 66 | if (gtk_detect(argc, argv)) { 67 | ctl->DisplayMode = DisplayGTK; 68 | } 69 | #endif 70 | } 71 | 72 | 73 | void display_open( 74 | struct mtr_ctl *ctl) 75 | { 76 | switch (ctl->DisplayMode) { 77 | 78 | case DisplayReport: 79 | report_open(); 80 | break; 81 | case DisplayTXT: 82 | txt_open(); 83 | break; 84 | case DisplayJSON: 85 | json_open(); 86 | break; 87 | case DisplayXML: 88 | xml_open(); 89 | break; 90 | case DisplayCSV: 91 | csv_open(); 92 | break; 93 | #ifdef HAVE_CURSES 94 | case DisplayCurses: 95 | mtr_curses_open(ctl); 96 | #ifdef HAVE_IPINFO 97 | asn_open(ctl); 98 | #endif 99 | break; 100 | #endif 101 | case DisplaySplit: 102 | split_open(); 103 | break; 104 | #ifdef HAVE_GTK 105 | case DisplayGTK: 106 | gtk_open(ctl); 107 | #ifdef HAVE_IPINFO 108 | asn_open(ctl); 109 | #endif 110 | break; 111 | #endif 112 | } 113 | } 114 | 115 | 116 | void display_close( 117 | struct mtr_ctl *ctl) 118 | { 119 | time_t now; 120 | 121 | now = time(NULL); 122 | 123 | switch (ctl->DisplayMode) { 124 | case DisplayReport: 125 | report_close(ctl); 126 | break; 127 | case DisplayTXT: 128 | txt_close(ctl); 129 | break; 130 | case DisplayJSON: 131 | json_close(ctl); 132 | break; 133 | case DisplayXML: 134 | xml_close(ctl); 135 | break; 136 | case DisplayCSV: 137 | csv_close(ctl, now); 138 | break; 139 | #ifdef HAVE_CURSES 140 | case DisplayCurses: 141 | #ifdef HAVE_IPINFO 142 | asn_close(ctl); 143 | #endif 144 | mtr_curses_close(); 145 | break; 146 | #endif 147 | case DisplaySplit: 148 | split_close(); 149 | break; 150 | #ifdef HAVE_GTK 151 | case DisplayGTK: 152 | gtk_close(); 153 | break; 154 | #endif 155 | } 156 | } 157 | 158 | 159 | void display_redraw( 160 | struct mtr_ctl *ctl) 161 | { 162 | switch (ctl->DisplayMode) { 163 | 164 | #ifdef HAVE_CURSES 165 | case DisplayCurses: 166 | mtr_curses_redraw(ctl); 167 | break; 168 | #endif 169 | 170 | case DisplaySplit: 171 | split_redraw(ctl); 172 | break; 173 | 174 | #ifdef HAVE_GTK 175 | case DisplayGTK: 176 | gtk_redraw(ctl); 177 | break; 178 | #endif 179 | } 180 | } 181 | 182 | 183 | int display_keyaction( 184 | struct mtr_ctl *ctl) 185 | { 186 | switch (ctl->DisplayMode) { 187 | #ifdef HAVE_CURSES 188 | case DisplayCurses: 189 | return mtr_curses_keyaction(ctl); 190 | #endif 191 | 192 | case DisplaySplit: 193 | return split_keyaction(); 194 | 195 | #ifdef HAVE_GTK 196 | case DisplayGTK: 197 | return gtk_keyaction(); 198 | #endif 199 | } 200 | return 0; 201 | } 202 | 203 | 204 | void display_rawxmit( 205 | struct mtr_ctl *ctl, 206 | int host, 207 | int seq) 208 | { 209 | if (ctl->DisplayMode == DisplayRaw) 210 | raw_rawxmit(host, seq); 211 | } 212 | 213 | 214 | void display_rawping( 215 | struct mtr_ctl *ctl, 216 | int host, 217 | int msec, 218 | int seq) 219 | { 220 | if (ctl->DisplayMode == DisplayRaw) 221 | raw_rawping(ctl, host, msec, seq); 222 | } 223 | 224 | 225 | void display_rawhost( 226 | struct mtr_ctl *ctl, 227 | int host, 228 | ip_t * ip_addr) 229 | { 230 | if (ctl->DisplayMode == DisplayRaw) 231 | raw_rawhost(ctl, host, ip_addr); 232 | } 233 | 234 | 235 | void display_loop( 236 | struct mtr_ctl *ctl) 237 | { 238 | #ifdef HAVE_GTK 239 | if (ctl->DisplayMode == DisplayGTK) 240 | gtk_loop(ctl); 241 | else 242 | #endif 243 | select_loop(ctl); 244 | } 245 | 246 | 247 | void display_clear( 248 | struct mtr_ctl *ctl) 249 | { 250 | #ifdef HAVE_CURSES 251 | if (ctl->DisplayMode == DisplayCurses) 252 | mtr_curses_clear(ctl); 253 | #endif 254 | } 255 | 256 | 257 | /* 258 | Given an errno error code corresponding to a host entry, return a 259 | user readable error string. 260 | */ 261 | char *host_error_to_string( 262 | int err) 263 | { 264 | if (err == ENETUNREACH) { 265 | return "no route to host"; 266 | } 267 | 268 | if (err == ENETDOWN) { 269 | return "network down"; 270 | } 271 | 272 | if (err == 0) { 273 | return "waiting for reply"; 274 | } 275 | 276 | return strerror(err); 277 | } 278 | -------------------------------------------------------------------------------- /portability/getopt.h: -------------------------------------------------------------------------------- 1 | /* Declarations for getopt. 2 | Copyright (C) 1989-1994,1996-1999,2001,2003,2004 3 | Free Software Foundation, Inc. 4 | This file is part of the GNU C Library. 5 | 6 | The GNU C Library is free software; you can redistribute it and/or 7 | modify it under the terms of the GNU Lesser General Public 8 | License as published by the Free Software Foundation version 2. 9 | 10 | The GNU C Library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 18 | 02110-1301 USA. */ 19 | 20 | #ifndef _GETOPT_H 21 | 22 | #ifndef __need_getopt 23 | #define _GETOPT_H 1 24 | #endif 25 | 26 | /* If __GNU_LIBRARY__ is not already defined, either we are being used 27 | standalone, or this is the first header included in the source file. 28 | If we are being used with glibc, we need to include , but 29 | that does not exist if we are standalone. So: if __GNU_LIBRARY__ is 30 | not defined, include , which will pull in for us 31 | if it's from glibc. (Why ctype.h? It's guaranteed to exist and it 32 | doesn't flood the namespace with stuff the way some other headers do.) */ 33 | #if !defined __GNU_LIBRARY__ 34 | # include 35 | #endif 36 | 37 | #ifndef __THROW 38 | # ifndef __GNUC_PREREQ 39 | # define __GNUC_PREREQ(maj, min) (0) 40 | # endif 41 | # if defined __cplusplus && __GNUC_PREREQ (2,8) 42 | # define __THROW throw () 43 | # else 44 | # define __THROW 45 | # endif 46 | #endif 47 | 48 | #ifdef __cplusplus 49 | extern "C" { 50 | #endif 51 | 52 | /* For communication from `getopt' to the caller. 53 | When `getopt' finds an option that takes an argument, 54 | the argument value is returned here. 55 | Also, when `ordering' is RETURN_IN_ORDER, 56 | each non-option ARGV-element is returned here. */ 57 | 58 | extern char *optarg; 59 | 60 | /* Index in ARGV of the next element to be scanned. 61 | This is used for communication to and from the caller 62 | and for communication between successive calls to `getopt'. 63 | 64 | On entry to `getopt', zero means this is the first call; initialize. 65 | 66 | When `getopt' returns -1, this is the index of the first of the 67 | non-option elements that the caller should itself scan. 68 | 69 | Otherwise, `optind' communicates from one call to the next 70 | how much of ARGV has been scanned so far. */ 71 | 72 | extern int optind; 73 | 74 | /* Callers store zero here to inhibit the error message `getopt' prints 75 | for unrecognized options. */ 76 | 77 | extern int opterr; 78 | 79 | /* Set to an option character which was unrecognized. */ 80 | 81 | extern int optopt; 82 | 83 | #ifndef __need_getopt 84 | /* Describe the long-named options requested by the application. 85 | The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector 86 | of `struct option' terminated by an element containing a name which is 87 | zero. 88 | 89 | The field `has_arg' is: 90 | no_argument (or 0) if the option does not take an argument, 91 | required_argument (or 1) if the option requires an argument, 92 | optional_argument (or 2) if the option takes an optional argument. 93 | 94 | If the field `flag' is not NULL, it points to a variable that is set 95 | to the value given in the field `val' when the option is found, but 96 | left unchanged if the option is not found. 97 | 98 | To have a long-named option do something other than set an `int' to 99 | a compiled-in constant, such as set a value from `optarg', set the 100 | option's `flag' field to zero and its `val' field to a nonzero 101 | value (the equivalent single-letter option character, if there is 102 | one). For long options that have a zero `flag' field, `getopt' 103 | returns the contents of the `val' field. */ 104 | 105 | struct option 106 | { 107 | const char *name; 108 | /* has_arg can't be an enum because some compilers complain about 109 | type mismatches in all the code that assumes it is an int. */ 110 | int has_arg; 111 | int *flag; 112 | int val; 113 | }; 114 | 115 | /* Names for the values of the `has_arg' field of `struct option'. */ 116 | 117 | #define no_argument 0 118 | #define required_argument 1 119 | #define optional_argument 2 120 | #endif /* need getopt */ 121 | 122 | 123 | /* Get definitions and prototypes for functions to process the 124 | arguments in ARGV (ARGC of them, minus the program name) for 125 | options given in OPTS. 126 | 127 | Return the option character from OPTS just read. Return -1 when 128 | there are no more options. For unrecognized options, or options 129 | missing arguments, `optopt' is set to the option letter, and '?' is 130 | returned. 131 | 132 | The OPTS string is a list of characters which are recognized option 133 | letters, optionally followed by colons, specifying that that letter 134 | takes an argument, to be placed in `optarg'. 135 | 136 | If a letter in OPTS is followed by two colons, its argument is 137 | optional. This behavior is specific to the GNU `getopt'. 138 | 139 | The argument `--' causes premature termination of argument 140 | scanning, explicitly telling `getopt' that there are no more 141 | options. 142 | 143 | If OPTS begins with `--', then non-option arguments are treated as 144 | arguments to the option '\0'. This behavior is specific to the GNU 145 | `getopt'. */ 146 | 147 | #ifdef __GNU_LIBRARY__ 148 | /* Many other libraries have conflicting prototypes for getopt, with 149 | differences in the consts, in stdlib.h. To avoid compilation 150 | errors, only prototype getopt for the GNU C library. */ 151 | extern int getopt (int ___argc, char *const *___argv, const char *__shortopts) 152 | __THROW; 153 | #else /* not __GNU_LIBRARY__ */ 154 | extern int getopt (); 155 | #endif /* __GNU_LIBRARY__ */ 156 | 157 | #ifndef __need_getopt 158 | extern int getopt_long (int ___argc, char *const *___argv, 159 | const char *__shortopts, 160 | const struct option *__longopts, int *__longind) 161 | __THROW; 162 | extern int getopt_long_only (int ___argc, char *const *___argv, 163 | const char *__shortopts, 164 | const struct option *__longopts, int *__longind) 165 | __THROW; 166 | 167 | #endif 168 | 169 | #ifdef __cplusplus 170 | } 171 | #endif 172 | 173 | /* Make sure we later can get all the definitions and declarations. */ 174 | #undef __need_getopt 175 | 176 | #endif /* getopt.h */ 177 | -------------------------------------------------------------------------------- /test/packet_listen.c: -------------------------------------------------------------------------------- 1 | /* 2 | mtr -- a network diagnostic tool 3 | Copyright (C) 2016 Matt Kimball 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License version 2 as 7 | published by the Free Software Foundation. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along 15 | with this program; if not, write to the Free Software Foundation, Inc., 16 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "packet/protocols.h" 27 | 28 | #define MAX_PACKET_SIZE 9000 29 | 30 | /* 31 | The first probe sent by mtr-packet will have this sequence number, 32 | so wait for an ICMP packet with this sequence ID. 33 | */ 34 | #define SEQUENCE_NUM 33000 35 | 36 | /* 37 | Check to see if the packet we've recieved is intended for this test 38 | process. We expected the ICMP sequence number to be equal to our 39 | process ID. 40 | */ 41 | bool is_packet_for_us4( 42 | char *packet, 43 | int packet_size) 44 | { 45 | int ip_icmp_size = sizeof(struct IPHeader) + sizeof(struct ICMPHeader); 46 | int expected_sequence; 47 | struct IPHeader *ip; 48 | struct ICMPHeader *icmp; 49 | 50 | if (packet_size < ip_icmp_size) { 51 | return false; 52 | } 53 | 54 | ip = (struct IPHeader *)packet; 55 | icmp = (struct ICMPHeader *)(ip + 1); 56 | 57 | expected_sequence = htons(SEQUENCE_NUM); 58 | if (icmp->sequence == expected_sequence) { 59 | return true; 60 | } 61 | 62 | return false; 63 | } 64 | 65 | /* 66 | Check to see if the ICMPv6 packet is for us. 67 | Unlike ICMPv4 packets, ICMPv6 packets don't include the IP header. 68 | */ 69 | bool is_packet_for_us6( 70 | char *packet, 71 | int packet_size) 72 | { 73 | int expected_sequence; 74 | struct ICMPHeader *icmp; 75 | 76 | if (packet_size < sizeof(struct ICMPHeader)) { 77 | return false; 78 | } 79 | 80 | icmp = (struct ICMPHeader *)packet; 81 | 82 | expected_sequence = htons(SEQUENCE_NUM); 83 | if (icmp->sequence == expected_sequence) { 84 | return true; 85 | } 86 | 87 | return false; 88 | } 89 | 90 | /* 91 | Check that all the bytes in the body of the packet have the same value. 92 | If so, return that value. If not, return -1. 93 | */ 94 | int get_packet_pattern( 95 | unsigned char *packet, 96 | int packet_size) 97 | { 98 | int fill_value; 99 | int i; 100 | 101 | if (packet_size <= 0) { 102 | return -1; 103 | } 104 | 105 | fill_value = packet[0]; 106 | for (i = 1; i < packet_size; i++) { 107 | if (packet[i] != fill_value) { 108 | return -1; 109 | } 110 | } 111 | 112 | return fill_value; 113 | } 114 | 115 | /* Print information about the ICMPv4 packet we received */ 116 | void dump_packet_info4( 117 | char *packet, 118 | int packet_size) 119 | { 120 | int ip_icmp_size = sizeof(struct IPHeader) + sizeof(struct ICMPHeader); 121 | int pattern; 122 | struct IPHeader *ip; 123 | struct ICMPHeader *icmp; 124 | unsigned char *body; 125 | int body_size; 126 | 127 | ip = (struct IPHeader *)packet; 128 | icmp = (struct ICMPHeader *)(ip + 1); 129 | body = (unsigned char *)(icmp + 1); 130 | body_size = packet_size - ip_icmp_size; 131 | 132 | printf("size %d\n", packet_size); 133 | printf("tos %d\n", ip->tos); 134 | 135 | pattern = get_packet_pattern(body, body_size); 136 | if (pattern < 0) { 137 | printf("bitpattern none\n"); 138 | } else { 139 | printf("bitpattern %d\n", pattern); 140 | } 141 | } 142 | 143 | /* Print information about an ICMPv6 packet */ 144 | void dump_packet_info6( 145 | char *packet, 146 | int packet_size) 147 | { 148 | int pattern; 149 | struct ICMPHeader *icmp; 150 | unsigned char *body; 151 | int body_size; 152 | int total_size; 153 | 154 | icmp = (struct ICMPHeader *)packet; 155 | body = (unsigned char *)(icmp + 1); 156 | body_size = packet_size - sizeof(struct ICMPHeader); 157 | 158 | total_size = packet_size + sizeof(struct IP6Header); 159 | printf("size %d\n", total_size); 160 | 161 | pattern = get_packet_pattern(body, body_size); 162 | if (pattern < 0) { 163 | printf("bitpattern none\n"); 164 | } else { 165 | printf("bitpattern %d\n", pattern); 166 | } 167 | } 168 | 169 | /* Receive ICMP packets until we get one intended for this test process */ 170 | void loop_on_receive( 171 | int icmp_socket, 172 | int ip_version) 173 | { 174 | int packet_size; 175 | char packet[MAX_PACKET_SIZE]; 176 | 177 | while (true) { 178 | packet_size = recv(icmp_socket, packet, MAX_PACKET_SIZE, 0); 179 | if (packet_size < -1) { 180 | perror("Failure during receive"); 181 | exit(EXIT_FAILURE); 182 | } 183 | 184 | if (ip_version == 6) { 185 | if (is_packet_for_us6(packet, packet_size)) { 186 | dump_packet_info6(packet, packet_size); 187 | return; 188 | } 189 | } else { 190 | if (is_packet_for_us4(packet, packet_size)) { 191 | dump_packet_info4(packet, packet_size); 192 | return; 193 | } 194 | } 195 | } 196 | } 197 | 198 | /* Parse the commandline arguments */ 199 | void parse_cmdline( 200 | int argc, 201 | char **argv, 202 | int *ip_version) 203 | { 204 | int opt; 205 | 206 | *ip_version = 4; 207 | 208 | while ((opt = getopt(argc, argv, "46")) != -1) { 209 | if (opt == '4') { 210 | *ip_version = 4; 211 | } 212 | 213 | if (opt == '6') { 214 | *ip_version = 6; 215 | } 216 | } 217 | } 218 | 219 | /* 220 | A helper for mtr-packet testing which waits for an ICMP packet 221 | intended for this test process, and then prints information about 222 | it. 223 | */ 224 | int main( 225 | int argc, 226 | char **argv) 227 | { 228 | int icmp_socket; 229 | int ip_version; 230 | 231 | parse_cmdline(argc, argv, &ip_version); 232 | 233 | if (ip_version == 6) { 234 | icmp_socket = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); 235 | } else { 236 | icmp_socket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); 237 | } 238 | if (icmp_socket < 0) { 239 | perror("Failure opening listening socket"); 240 | exit(EXIT_FAILURE); 241 | } 242 | 243 | printf("status listening\n"); 244 | fflush(stdout); 245 | 246 | loop_on_receive(icmp_socket, ip_version); 247 | 248 | return EXIT_SUCCESS; 249 | } 250 | -------------------------------------------------------------------------------- /img/mtr_icon.xpm: -------------------------------------------------------------------------------- 1 | /* XPM */ 2 | static const char * mtr_icon[] = { 3 | "48 48 131 2", 4 | " c #000000", 5 | ". c #020204", 6 | "+ c #3E7E3C", 7 | "@ c #62BA64", 8 | "# c #4E9E4C", 9 | "$ c #628664", 10 | "% c #6EDA6C", 11 | "& c #7A9E7C", 12 | "* c #468E44", 13 | "= c #6ACA6C", 14 | "- c #224224", 15 | "; c #56AE54", 16 | "> c #326234", 17 | ", c #567E54", 18 | "' c #7ABA7C", 19 | ") c #3A723C", 20 | "! c #629E64", 21 | "~ c #428644", 22 | "{ c #6E926C", 23 | "] c #7AEA7C", 24 | "^ c #4A964C", 25 | "/ c #62C264", 26 | "( c #52A654", 27 | "_ c #4A7E4C", 28 | ": c #82AE84", 29 | "< c #366A34", 30 | "[ c #5AB65C", 31 | "} c #4A764C", 32 | "| c #6AD26C", 33 | "1 c #8EC68C", 34 | "2 c #7A9A7C", 35 | "3 c #7AE27C", 36 | "4 c #82A684", 37 | "5 c #568E54", 38 | "6 c #568654", 39 | "7 c #3E7A3C", 40 | "8 c #6AC26C", 41 | "9 c #3E6A3C", 42 | "0 c #468244", 43 | "a c #56A254", 44 | "b c #4E8E4C", 45 | "c c #5EAE5C", 46 | "d c #86C684", 47 | "e c #427244", 48 | "f c #62A664", 49 | "g c #769A74", 50 | "h c #82F284", 51 | "i c #5A9A5C", 52 | "j c #5AA65C", 53 | "k c #428244", 54 | "l c #66BE64", 55 | "m c #6A8E6C", 56 | "n c #76DA74", 57 | "o c #7E9E7C", 58 | "p c #2A522C", 59 | "q c #5E825C", 60 | "r c #82BE84", 61 | "s c #669E64", 62 | "t c #6E966C", 63 | "u c #529A54", 64 | "v c #62C664", 65 | "w c #4A824C", 66 | "x c #366E34", 67 | "y c #72D674", 68 | "z c #427E3C", 69 | "A c #5EBE5C", 70 | "B c #52A254", 71 | "C c #628A64", 72 | "D c #4A924C", 73 | "E c #6ACE6C", 74 | "F c #5AB25C", 75 | "G c #326634", 76 | "H c #568254", 77 | "I c #7ABE7C", 78 | "J c #3A763C", 79 | "K c #468A44", 80 | "L c #7EEE7C", 81 | "M c #4E9A4C", 82 | "N c #56AA54", 83 | "O c #86B684", 84 | "P c #62B664", 85 | "Q c #162A14", 86 | "R c #529E54", 87 | "S c #72DA74", 88 | "T c #76A274", 89 | "U c #4A8E4C", 90 | "V c #264A24", 91 | "W c #5AAE5C", 92 | "X c #5EA25C", 93 | "Y c #468644", 94 | "Z c #729274", 95 | "` c #7EEA7C", 96 | " . c #4E964C", 97 | ".. c #66C264", 98 | "+. c #56A654", 99 | "@. c #4E7E4C", 100 | "#. c #8AB28C", 101 | "$. c #3A6A3C", 102 | "%. c #5EB65C", 103 | "&. c #527A54", 104 | "*. c #6ED26C", 105 | "=. c #92C694", 106 | "-. c #7E9A7C", 107 | ";. c #7AE67C", 108 | ">. c #86AA84", 109 | ",. c #5E865C", 110 | "'. c #6AC66C", 111 | "). c #3E6E3C", 112 | "!. c #5AA25C", 113 | "~. c #4E924C", 114 | "{. c #5EB25C", 115 | "]. c #467244", 116 | "^. c #86F284", 117 | "/. c #5AAA5C", 118 | "(. c #76DE74", 119 | "_. c #829E84", 120 | ":. c #325E34", 121 | "<. c #66A264", 122 | "[. c #729674", 123 | "}. c #66C664", 124 | "|. c #4E824C", 125 | "1. c #3A6E3C", 126 | "2. c #76D674", 127 | "3. c #427E44", 128 | "4. c #62BE64", 129 | "5. c #668A64", 130 | "6. c #6ECE6C", 131 | "7. c #366634", 132 | "8. c #5A825C", 133 | "9. c #7EBE7C", 134 | "0. c #3E763C", 135 | "G 7.G G G G G 7.G < z . .* k 1.G G G G G G 0.K x 7.7.7.7.7.< J Y D M D ) 7.7.7.7.7.7.< 7.7.7.7.", 136 | "7.G 7.> > > 7.G ) D M K 7 < > > > > > > > > + * < G G G G G G 7.G x k * M K x G G G G G G G G G ", 137 | "G G 7.G > > < ~ M D + G > > G > > 7.7.7.7.> 7 D x 7.7.7.7.7.G 7.7.G < ) ~ D M 7 7.7.7.7.7.7.7.7.", 138 | "7.7.G > 7.< * M ~ x > G > G > > 7.> > > > G 7 * 1.G G G G G 7.G G 7.G G G J * M ~ < G G G G G G ", 139 | "> G G > x D M k < G > G > > G > > G G G > 7.7 * x 7.7.7.7.G 7.7.G 7.7.7.7.G x ~ # Y < 7.7.7.7.7.", 140 | "G > > x ^ .0.G G G 7.> > > > > G > > > 7.> 7 U 1.G G G G 7.G G 7.G G G G 7.G < k # K < G G G G ", 141 | "G G < .^ J G G 7.G 7.> G > > > > 7.7.> 7.7.7 * x 7.7.7.G 7.7.G 7.7.7.7.G 7.G G 7.+ B ~ < 7.7.7.", 142 | "> < D M 7 G > > > G > G > > G > 7.> > G > > + U 1.G G G 7.G G 7.G G G G 7.G 7.7.G < k B + < G G ", 143 | "G k # k < 7.7.G > G > > G > > > > G x k .R F A N R U 7 x 7.G 7.7.7.7.G 7.G G 7.G G < K # J $.8.", 144 | ") ( K < > > G G 7.G G > > > G G + M +.B M D B W ^ ^ # ( +.^ ) G G G G 7.G 7.7.G 7.7.7.x u ! & o ", 145 | "^ .x > > > > G 7.7.G > > > 0. .+.M K + ) < + D ) < J k * R +.D x 7.G 7.G G 7.G G G 7.e T =.& H ", 146 | "+.+ < G G G 7.G > G G > G ~ ( B ~ ) G > G > 7 U < 7.7.G < J * B B 7 7.G 7.7.G 7.7.9 5.o Z s a ) ", 147 | "D x > > > > > G > G G < K ( D 0.> G 7.> G 7.+ * < G 7.7.G G < + # ( + G G 7.G $.,.2 [.$ ).0.( k ", 148 | "7 7.G G G G 7.G G > 7.K +.K x > G > > G > > 7 D < 7.G G 7.7.G 7.) M +.7 7.< &.[.2 C &.7.7.7.* B ", 149 | "x 7.> > > > > 7.7.G k +.* < > > > G > 7.G G 7 * < 7.7.G G 7.G G G ) M B &.[.o m &.7.G 7.G 7.) %.", 150 | "7.G 7.7.7.G 7.G G x B ^ ) > G > 7.> 7.> > > + D 7.G G 7.7.G 7.7.7.< w r #.{ , 9 7.7.7.G 7.G < ( ", 151 | "> G G > 7.G > 7.7.* ( 7 G > > > > > G 7.1.z B F D 7 < G 7.G G G $.q o : I _ < > G G 7.G 7.G 7.~ ", 152 | "7.7.> G > 7.7.> x +.* 7.> > G > G G < k # # +.[ B N ( k G 7.$.&.2 2 C |.B D < 7.7.7.G 7.G 7.G < ", 153 | "> 7.> G > G G > ~ +.+ > > > > > > < K R K + K M 3.K B W K } Z -.m &.< < Y W ) G G 7.G 7.G 7.G 7.", 154 | "> G G > > > 7.G # ^ ) > G > G > 7.~ # + < > 7 * < G J j d 4 { , $.G 7.G 7 F + 7.7.G 7.G 7.G 7.G ", 155 | "> > > G G > 7.7.N * 7.> > > > > J D Y > G 7.3.D < ).$ 4 1 ' e 7.7.G G G ) # D < G G 7.G 7.G 7.7.", 156 | "> 7.G > > G > x +.Y G > G > G > Y ~.x G > > 7 ~.8.-.2 5.i A 7 G G 7.7.7.< D # x 7.7.G 7.G 7.G G ", 157 | "< < x x < x x + ; * x x x x x ) ^ .1.) 1.) 5 r o t 6 0.K A D J ) ) ) J 7 .F k 7 7 7 7 J 0.0.x ", 158 | "D D * * D U U # A ( * * * K * * N W U U * K X 9.<.D K K R ..N U * * * * U ( A D K K K K U * K ) ", 159 | "7 z z 7 7 z 7 K {.M 7 7 7 0.0.7 # B J 7 7 7 U R 0.7 7 7 D / D 0.0.7 0.J 7 .F + 0.J 0.J 0.J 0.< ", 160 | "G > > > G > G < N K 7.> > G G > ~ D 1.G > > 3.U G G G G * A J G G G G 7.x D # x G 7.G 7.G 7.G G ", 161 | "G G G > G > G < ( * 7.> > > > > J ^ K G G > + D 7.7.7.7 N ( < 7.7.7.G G ) B * < G 7.G 7.G 7.7.G ", 162 | "G G > > > 7.G G # .) G > > G > > k u 0 7.G z U G G 7 ( F + < G G G 7.7.7 W + < 7.G 7.G 7.G G 7.", 163 | "> 7.G 7.> > > 7.~ B + > > > G G > x ~ # .+ ~ .7 D ; ; k G 7.7.7.G G G K W x G 7.G 7.G 7.7.G 7.", 164 | "7.G 7.> G 7.7.G < ( D < G > > > > > < z D # %.A +.B .7 < K = G G 7.7.J B D < 7.G 7.G 7.G G 7.x ", 165 | "G G G > > > > G G K ( 7 > > > > > G > G 1.+ R N K 7 x G ` (./.7.G G < K ; J G 7.G 7.G 7.7.G 7.Y ", 166 | "7.G G > > G G G G x B M ) > > G G > G G > > + D G G 7.7.;.E 4.G 7.7.7 N K < 7.G 7.G 7.G G 7.< ; ", 167 | "1.> G G > > > ` ] %.+ L 3 (.S S +.> /.L ;.(.S y 7.G 6.3 6.= = y ;...B # ` ] @ *.;.S B 7.G G J A ", 168 | "z G > > G 7.7.% = '.n ~.K %.= = = y *.u .4.= = {.7.c /.= = ..u M M B J y = E 6.!.b z G 7.< D W ", 169 | "M ) G > > G G y = ..7.. . +.@ '.= @ V . . 1.}.= {.. G 7.6.= B . . . . 7.y = ..> . . . . G ) [ D ", 170 | "[ + G G G > 7.S = a . . . . 4.E = z . . . G y = @ . . G (.6.a . . . . G y = .. . . . . < ^ W J ", 171 | "N B ) G G G 7.y = .. . . 7.}.6.'.0.. . . G (.= %.. . ~ y = B . . . 7.G *.'.0 . . . G 7.7 [ K < ", 172 | "+ [ D < > > G % = R . . > > }.6.}.0.. . +.+.3 = {.. . B (.E W . . G G 7.y = K . . G 7.x +.( J G ", 173 | "< D {.Y 7.> 7.y = u . . > > ..6.'.0.. . K U (.= %.. . + y = +.. . 7.G 7.y }.Y . . G < ^ F z 7.7.", 174 | "> x B ; + G > y = ( . . G > }.6.}.0.. . > G (.= {.. . G (.= {.. . G 7.G y = k . . < * [ U < G G ", 175 | "> G J +.N + G S '.R . . > G }.6.}.0.. . G G (.= [ . . G *.= }.J . G 7.G *.= ~ . . ~ %.^ x 7.7.7.", 176 | "G > G 7 +.N z y E B . . G > ..6.'.0.. . > > 3 = {.. . 7.'.= = = (.3 p 7.y '.0 . . {.# ) 7.G G G ", 177 | "G > G G 7 ( ; @ N ~.. . > > 4.W +.1.. . G 7.= /.B . . G > {.l 4.%.R G 7.@ /.+ . . M ) G 7.7.7.7.", 178 | "> 7.> > G 0.# %.^ . . . > > > > > . . > > > + D . . . 7.7.7.- - Q . . G < . . . . ) G 7.G G G G ", 179 | "G G 7.> 7.7.) ^ F . . < G > > > G . . 7.G > 3.D 7.. G G G 7.7.. . . . x D F . . < 7.G 7.7.7.7.7.", 180 | "> 7.G G > G G < ~ ( [ B + < > G > > > > > 7.+ U G 7.7.7.7.G G 7.G x K W [ R + < G G 7.G G G G G ", 181 | "> > > G > > > > 7.J D +.[ ; K x G 7.G 7.> 7.) z G G G G 7.7.< 0. .F F B ~ 1.G 7.7.G 7.7.7.7.7.7.", 182 | "G 7.7.> > G 7.G > 7.< M E | +.7 > > > > G > x ) 7.> 7.7.G G < k F % / ~ G G 7.G G 7.G G G G G G "}; 183 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_PREREQ([2.59]) 2 | AC_INIT([mtr], 3 | [m4_esyscmd([build-aux/git-version-gen .tarball-version])], 4 | [R.E.Wolff@BitWizard.nl], [], 5 | [http://www.BitWizard.nl/mtr/]) 6 | AC_CONFIG_SRCDIR([ui/mtr.c]) 7 | AC_CONFIG_AUX_DIR([build-aux]) 8 | AC_USE_SYSTEM_EXTENSIONS 9 | AM_INIT_AUTOMAKE([ 10 | 1.7.9 11 | foreign 12 | subdir-objects 13 | ]) 14 | 15 | # --enable-silent-rules 16 | m4_ifdef([AM_SILENT_RULES], 17 | [AM_SILENT_RULES([yes])], 18 | [AC_SUBST([AM_DEFAULT_VERBOSITY], [1])]) 19 | 20 | AC_CANONICAL_HOST 21 | AC_PROG_CC 22 | 23 | # Check pkg-config availability. 24 | m4_ifndef([PKG_PROG_PKG_CONFIG], 25 | [m4_fatal( 26 | [Could not locate the pkg-config autoconf macros. These are usually located 27 | in /usr/share/aclocal/pkg.m4. If your macros are in a different location, 28 | try setting the environment variable ACLOCAL_OPTS="-I/other/macro/dir" 29 | before running ./bootstrap.sh again.]) 30 | ]) 31 | PKG_PROG_PKG_CONFIG 32 | 33 | AM_CONDITIONAL([CYGWIN], [test "$host_os" = cygwin]) 34 | AM_COND_IF([CYGWIN], 35 | [AC_DEFINE([USING_CYGWIN], [1], [Building Under Cygwin.])], 36 | []) 37 | 38 | # Check bytes in types. 39 | AC_CHECK_SIZEOF([unsigned char], [1]) 40 | AC_CHECK_SIZEOF([unsigned short], [2]) 41 | AC_CHECK_SIZEOF([unsigned int], [4]) 42 | AC_CHECK_SIZEOF([unsigned long], [4]) 43 | 44 | # Check headers. 45 | AC_CHECK_HEADERS([ \ 46 | arpa/nameser_compat.h \ 47 | curses.h \ 48 | cursesX.h \ 49 | error.h \ 50 | fcntl.h \ 51 | linux/icmp.h \ 52 | linux/errqueue.h \ 53 | ncurses.h \ 54 | ncurses/curses.h \ 55 | netinet/in.h \ 56 | socket.h \ 57 | sys/cdefs.h \ 58 | sys/limits.h \ 59 | sys/socket.h \ 60 | stdio_ext.h \ 61 | sys/types.h \ 62 | sys/xti.h \ 63 | values.h \ 64 | ]) 65 | 66 | # Check functions. 67 | AC_CHECK_FUNCS([ \ 68 | __fpending \ 69 | fcntl \ 70 | ]) 71 | 72 | AC_CHECK_FUNC([error], [with_error=no], 73 | [AC_CHECK_FUNCS([verr verrx vwarn vwarnx], [with_error=yes], 74 | [AC_MSG_ERROR([cannot find working error printing function]) 75 | ]) 76 | ]) 77 | AM_CONDITIONAL([WITH_ERROR], [test "x$with_error" = "xyes"]) 78 | 79 | AC_CHECK_FUNC([getopt_long], [with_getopt=no], [with_getopt=yes]) 80 | AS_IF([test "x$with_getopt" = "xno"], [ 81 | AC_DEFINE([HAVE_GETOPT], [1], [Define if libc has getopt_long]) 82 | ]) 83 | AM_CONDITIONAL([WITH_GETOPT], [test "x$with_getopt" = "xyes"]) 84 | 85 | AC_CHECK_LIB([m], [floor], [], [AC_MSG_ERROR([No math library found])]) 86 | 87 | # Find GTK 88 | AC_ARG_WITH([gtk], 89 | [AS_HELP_STRING([--without-gtk], [Build without the GTK+2.0 interface])], 90 | [], [with_gtk=yes]) 91 | AS_IF([test "x$with_gtk" = "xyes"], 92 | [PKG_CHECK_MODULES([GTK], [gtk+-2.0], 93 | [AC_DEFINE([HAVE_GTK], [1], [Define if gtk+-2.0 library available])], 94 | [with_gtk=no]) 95 | ]) 96 | AM_CONDITIONAL([WITH_GTK], [test "x$with_gtk" = xyes]) 97 | 98 | # Find ncurses 99 | AC_ARG_WITH([ncurses], 100 | [AS_HELP_STRING([--without-ncurses], [Build without the ncurses interface])], 101 | [], [with_ncurses=yes]) 102 | AS_IF([test "x$with_ncurses" = "xyes"], 103 | 104 | # Prefer ncurses over curses, if both are available. 105 | # (On Solaris 11.3, ncurses builds and links for us, but curses does not.) 106 | [AC_SEARCH_LIBS( 107 | [initscr], [ncurses curses], 108 | [AC_DEFINE([HAVE_CURSES], [1], [Define if a curses library available])], 109 | [with_ncurses=no]) 110 | ]) 111 | AM_CONDITIONAL([WITH_CURSES], [test "x$with_ncurses" = xyes]) 112 | 113 | AC_CHECK_LIB([cap], [cap_set_proc], [], 114 | AS_IF([test "$host_os" = linux-gnu], 115 | AC_MSG_WARN([Capabilities support is strongly recommended for increased security. See SECURITY for more information.]))) 116 | 117 | # Enable ipinfo 118 | AC_ARG_WITH([ipinfo], 119 | [AS_HELP_STRING([--without-ipinfo], [Do not try to use ipinfo lookup at all])], 120 | [], [with_ipinfo=yes]) 121 | AM_CONDITIONAL([WITH_IPINFO], [test "x$with_ipinfo" = "xyes"]) 122 | AS_IF([test "x$with_ipinfo" = "xyes"], [ 123 | AC_DEFINE([HAVE_IPINFO], [1], [Define when ipinfo lookups are in use]) 124 | ]) 125 | 126 | AC_ARG_ENABLE([ipv6], 127 | [AS_HELP_STRING([--disable-ipv6], [Do not enable IPv6])], 128 | [WANTS_IPV6=$enableval], [WANTS_IPV6=yes]) 129 | 130 | AS_IF([test "x$WANTS_IPV6" = "xyes"], [ 131 | AC_DEFINE([ENABLE_IPV6], [1], [Define to enable IPv6]) 132 | USES_IPV6=yes 133 | ]) 134 | 135 | AC_CHECK_FUNC([socket], [], 136 | [AC_CHECK_LIB([socket], [socket], [], [AC_MSG_ERROR([No socket library found])])]) 137 | 138 | AC_CHECK_FUNC([gethostbyname], [], 139 | [AC_CHECK_LIB([nsl], [gethostbyname], [], [AC_MSG_ERROR([No nameservice library found])])]) 140 | 141 | # Find resolver library. 142 | AC_CHECK_FUNC([res_query], [RESOLV_LIBS=""], [ 143 | AC_CHECK_LIB([resolv], [__res_query], [RESOLV_LIBS="-lresolv"], [ 144 | AC_CHECK_LIB([resolv], [res_query], [RESOLV_LIBS="-lresolv"], [ 145 | AC_CHECK_LIB([bind], [res_query], [RESOLV_LIBS="-lbind"], [ 146 | AC_MSG_ERROR([No resolver library found]) 147 | ]) 148 | ]) 149 | ]) 150 | ]) 151 | dnl MacOS has res_query in libc, but needs libresolv for dn_expand(). 152 | AS_IF([test "x" = "x$RESOLV_LIBS"], [ 153 | AC_CHECK_LIB([resolv], [dn_expand], [RESOLV_LIBS="-lresolv"]) 154 | ]) 155 | AC_SUBST([RESOLV_LIBS]) 156 | 157 | # Check errno and socket data types. 158 | AC_CHECK_DECLS([errno], [], [], [[ 159 | #include 160 | #include 161 | ]]) 162 | 163 | AC_CHECK_TYPE([socklen_t], 164 | [AC_DEFINE([HAVE_SOCKLEN_T], [], [Define if your system has socklen_t])], [], 165 | [[#include 166 | #ifdef HAVE_SOCKET_H 167 | #include 168 | #endif 169 | #ifdef HAVE_SYS_SOCKET_H 170 | #include 171 | #endif]]) 172 | 173 | AC_CHECK_TYPES([time_t], [], [], [[ 174 | #include 175 | ]]) 176 | 177 | # Add C flags to display more warnings 178 | AC_MSG_CHECKING([for C flags to get more warnings]) 179 | ac_save_CFLAGS="$CFLAGS" 180 | 181 | AS_IF([test "x$ac_cv_c_compiler_gnu" = "xyes"], [ 182 | dnl gcc is the easiest C compiler 183 | warning_CFLAGS="-Wall" 184 | # Check if compiler supports -Wno-pointer-sign and add it if supports 185 | CFLAGS_saved="$CFLAGS" 186 | CFLAGS="$CFLAGS -Wno-pointer-sign" 187 | AC_COMPILE_IFELSE([AC_LANG_SOURCE([[int foo;]])], 188 | [warning_CFLAGS="${warning_CFLAGS} -Wno-pointer-sign"], []) 189 | CFLAGS="$CFLAGS_saved" 190 | ], [ 191 | dnl Vendor supplied C compilers are a bit tricky 192 | AS_CASE([$host_os], 193 | dnl SGI IRIX with the MipsPRO C compiler 194 | [irix*], [ 195 | CFLAGS="$CFLAGS -fullwarn" 196 | AC_COMPILE_IFELSE([ 197 | AC_LANG_PROGRAM( 198 | [[#include ]], 199 | [[printf("test");]])], 200 | [warning_CFLAGS="-fullwarn"], [] 201 | ) 202 | ], 203 | dnl SunOS 4.x with the SparcWorks(?) acc compiler 204 | [sunos*], [ 205 | AS_IF([test "$CC" = "acc"], [ 206 | CFLAGS="$CFLAGS -vc" 207 | AC_COMPILE_IFELSE([ 208 | AC_LANG_PROGRAM( 209 | [[#include ]], 210 | [[printf("test");]])], 211 | [warning_CFLAGS="-vc"], [] 212 | ) 213 | ]) 214 | ] 215 | dnl Unknown, do nothing 216 | [*], [ 217 | warning_CFLAGS="none" 218 | ] 219 | ) 220 | ]) 221 | CFLAGS="$ac_save_CFLAGS" 222 | 223 | AS_IF([test "$warning_CFLAGS" = "none"], [ 224 | AC_MSG_RESULT([none]) 225 | ], [ 226 | CFLAGS="$CFLAGS $warning_CFLAGS" 227 | AC_MSG_RESULT([$warning_CFLAGS]) 228 | ]) 229 | 230 | # bash-completion 231 | AC_ARG_WITH([bashcompletiondir], 232 | AS_HELP_STRING([--with-bashcompletiondir=DIR], [Bash completions directory]), 233 | [], 234 | [AS_IF([`$PKG_CONFIG --exists bash-completion`], [ 235 | with_bashcompletiondir=`$PKG_CONFIG --variable=completionsdir bash-completion` 236 | ], [ 237 | with_bashcompletiondir=${datadir}/bash-completion/completions 238 | ]) 239 | ]) 240 | AC_SUBST([bashcompletiondir], [$with_bashcompletiondir]) 241 | AC_ARG_ENABLE([bash-completion], 242 | AS_HELP_STRING([--disable-bash-completion], [do not install bash completion files]), 243 | [], [enable_bash_completion=yes] 244 | ) 245 | AM_CONDITIONAL([BUILD_BASH_COMPLETION], [test "x$enable_bash_completion" = xyes]) 246 | 247 | # Prepare config.h, Makefile, and output them. 248 | AC_CONFIG_HEADERS([config.h]) 249 | AC_CONFIG_FILES([Makefile]) 250 | AC_OUTPUT 251 | -------------------------------------------------------------------------------- /ui/dns.c: -------------------------------------------------------------------------------- 1 | /* 2 | mtr -- a network diagnostic tool 3 | Copyright (C) 1997,1998 Matt Kimball 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License version 2 as 7 | published by the Free Software Foundation. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along 15 | with this program; if not, write to the Free Software Foundation, Inc., 16 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | /* 20 | Non-blocking DNS portion -- 21 | Copyright (C) 1998 by Simon Kirby 22 | Released under GPL, as above. 23 | */ 24 | 25 | #include "config.h" 26 | 27 | #ifdef HAVE_ERROR_H 28 | #include 29 | #else 30 | #include "portability/error.h" 31 | #endif 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | 40 | #include "mtr.h" 41 | #include "dns.h" 42 | #include "net.h" 43 | #include "utils.h" 44 | 45 | struct dns_results { 46 | ip_t ip; 47 | char *name; 48 | struct dns_results *next; 49 | }; 50 | 51 | static struct dns_results *results; 52 | 53 | char *strlongip( 54 | struct mtr_ctl *ctl, 55 | ip_t * ip) 56 | { 57 | #ifdef ENABLE_IPV6 58 | static char addrstr[INET6_ADDRSTRLEN]; 59 | 60 | return (char *) inet_ntop(ctl->af, ip, addrstr, sizeof addrstr); 61 | #else 62 | return inet_ntoa(*ip); 63 | #endif 64 | } 65 | 66 | 67 | #ifdef ENABLE_IPV6 68 | #define UNUSED_IF_NO_IPV6 /* empty */ 69 | #else 70 | #define UNUSED_IF_NO_IPV6 ATTRIBUTE_UNUSED 71 | #endif 72 | 73 | static int todns[2], fromdns[2]; 74 | static FILE *fromdnsfp; 75 | 76 | static int longipstr( 77 | char *s, 78 | ip_t * dst, 79 | int family UNUSED_IF_NO_IPV6) 80 | { 81 | #ifdef ENABLE_IPV6 82 | return inet_pton(family, s, dst); 83 | #else 84 | return inet_aton(s, dst); 85 | #endif 86 | } 87 | 88 | 89 | struct hostent *dns_forward( 90 | const char *name) 91 | { 92 | struct hostent *host; 93 | 94 | if ((host = gethostbyname(name))) 95 | return host; 96 | else 97 | return NULL; 98 | } 99 | 100 | 101 | static struct dns_results *findip( 102 | struct mtr_ctl *ctl, 103 | ip_t * ip) 104 | { 105 | struct dns_results *t; 106 | 107 | for (t = results; t; t = t->next) { 108 | if (addrcmp((void *) ip, (void *) &t->ip, ctl->af) == 0) 109 | return t; 110 | } 111 | 112 | return NULL; 113 | } 114 | 115 | static void set_sockaddr_ip( 116 | struct mtr_ctl *ctl, 117 | struct sockaddr_storage *sa, 118 | ip_t * ip) 119 | { 120 | struct sockaddr_in *sa_in; 121 | struct sockaddr_in6 *sa_in6; 122 | 123 | memset(sa, 0, sizeof(struct sockaddr_storage)); 124 | switch (ctl->af) { 125 | case AF_INET: 126 | sa_in = (struct sockaddr_in *) sa; 127 | sa_in->sin_family = ctl->af; 128 | addrcpy((void *) &sa_in->sin_addr, (void *) ip, ctl->af); 129 | break; 130 | case AF_INET6: 131 | sa_in6 = (struct sockaddr_in6 *) sa; 132 | sa_in6->sin6_family = ctl->af; 133 | addrcpy((void *) &sa_in6->sin6_addr, (void *) ip, ctl->af); 134 | break; 135 | } 136 | } 137 | 138 | void dns_open( 139 | struct mtr_ctl *ctl) 140 | { 141 | int pid; 142 | 143 | if (pipe(todns) < 0) { 144 | error(EXIT_FAILURE, errno, "can't make a pipe for DNS process"); 145 | } 146 | 147 | if (pipe(fromdns) < 0) { 148 | error(EXIT_FAILURE, errno, "can't make a pipe for DNS process"); 149 | } 150 | fflush(stdout); 151 | pid = fork(); 152 | if (pid < 0) { 153 | error(EXIT_FAILURE, errno, "can't fork for DNS process"); 154 | } 155 | if (pid == 0) { 156 | char buf[2048]; 157 | int i; 158 | FILE *infp; 159 | 160 | /* Automatically reap children. */ 161 | if (signal(SIGCHLD, SIG_IGN) == SIG_ERR) { 162 | error(EXIT_FAILURE, errno, "signal"); 163 | } 164 | 165 | /* Close all unneccessary FDs. 166 | for debugging and error reporting, keep std-in/out/err. */ 167 | for (i = 3; i < fromdns[1]; i++) { 168 | if (i == todns[0]) 169 | continue; 170 | if (i == fromdns[1]) 171 | continue; 172 | close(i); 173 | } 174 | infp = fdopen(todns[0], "r"); 175 | 176 | while (fgets(buf, sizeof(buf), infp)) { 177 | ip_t host; 178 | struct sockaddr_storage sa; 179 | socklen_t salen; 180 | char hostname[NI_MAXHOST]; 181 | char result[INET6_ADDRSTRLEN + NI_MAXHOST + 2]; 182 | 183 | if (!fork()) { 184 | int rv; 185 | 186 | buf[strlen(buf) - 1] = 0; /* chomp newline. */ 187 | 188 | longipstr(buf, &host, ctl->af); 189 | set_sockaddr_ip(ctl, &sa, &host); 190 | salen = (ctl->af == AF_INET) ? sizeof(struct sockaddr_in) : 191 | sizeof(struct sockaddr_in6); 192 | 193 | rv = getnameinfo((struct sockaddr *) &sa, salen, 194 | hostname, sizeof(hostname), NULL, 0, 0); 195 | if (rv == 0) { 196 | snprintf(result, sizeof(result), 197 | "%s %s\n", strlongip(ctl, &host), hostname); 198 | 199 | rv = write(fromdns[1], result, strlen(result)); 200 | if (rv < 0) 201 | error(0, errno, "write DNS lookup result"); 202 | } 203 | 204 | exit(EXIT_SUCCESS); 205 | } 206 | } 207 | exit(EXIT_SUCCESS); 208 | } else { 209 | int flags; 210 | 211 | /* the parent. */ 212 | close(todns[0]); /* close the pipe ends we don't need. */ 213 | close(fromdns[1]); 214 | fromdnsfp = fdopen(fromdns[0], "r"); 215 | flags = fcntl(fromdns[0], F_GETFL, 0); 216 | flags |= O_NONBLOCK; 217 | fcntl(fromdns[0], F_SETFL, flags); 218 | } 219 | } 220 | 221 | int dns_waitfd( 222 | void) 223 | { 224 | return fromdns[0]; 225 | } 226 | 227 | 228 | void dns_ack( 229 | struct mtr_ctl *ctl) 230 | { 231 | char buf[2048], host[NI_MAXHOST], name[NI_MAXHOST]; 232 | ip_t hostip; 233 | struct dns_results *r; 234 | 235 | while (fgets(buf, sizeof(buf), fromdnsfp)) { 236 | sscanf(buf, "%s %s", host, name); 237 | 238 | longipstr(host, &hostip, ctl->af); 239 | r = findip(ctl, &hostip); 240 | if (r) 241 | r->name = xstrdup(name); 242 | else 243 | error(0, 0, "dns_ack: Couldn't find host %s", host); 244 | } 245 | } 246 | 247 | 248 | 249 | #ifdef ENABLE_IPV6 250 | 251 | int dns_waitfd6( 252 | void) 253 | { 254 | return -1; 255 | } 256 | 257 | void dns_ack6( 258 | void) 259 | { 260 | return; 261 | } 262 | 263 | #endif 264 | 265 | 266 | char *dns_lookup2( 267 | struct mtr_ctl *ctl, 268 | ip_t * ip) 269 | { 270 | struct dns_results *r; 271 | char buf[INET6_ADDRSTRLEN + 1]; 272 | int rv; 273 | 274 | r = findip(ctl, ip); 275 | if (r) { 276 | /* we've got a result. */ 277 | if (r->name) 278 | return r->name; 279 | else 280 | return strlongip(ctl, ip); 281 | } else { 282 | r = xmalloc(sizeof(struct dns_results)); 283 | memcpy(&r->ip, ip, sizeof(r->ip)); 284 | r->name = NULL; 285 | r->next = results; 286 | results = r; 287 | snprintf(buf, sizeof(buf), "%s\n", strlongip(ctl, ip)); 288 | rv = write(todns[1], buf, strlen(buf)); 289 | if (rv < 0) 290 | error(0, errno, "couldn't write to resolver process"); 291 | } 292 | return strlongip(ctl, ip); 293 | } 294 | 295 | 296 | char *dns_lookup( 297 | struct mtr_ctl *ctl, 298 | ip_t * ip) 299 | { 300 | char *t; 301 | 302 | if (!ctl->dns || !ctl->use_dns) 303 | return NULL; 304 | t = dns_lookup2(ctl, ip); 305 | return t; 306 | } 307 | 308 | /* XXX check if necessary/exported. */ 309 | 310 | /* Resolve an IP address to a hostname. */ 311 | struct hostent *addr2host( 312 | const char *addr, 313 | int family) 314 | { 315 | int len = 0; 316 | switch (family) { 317 | case AF_INET: 318 | len = sizeof(struct in_addr); 319 | break; 320 | #ifdef ENABLE_IPV6 321 | case AF_INET6: 322 | len = sizeof(struct in6_addr); 323 | break; 324 | #endif 325 | } 326 | return gethostbyaddr(addr, len, family); 327 | } 328 | -------------------------------------------------------------------------------- /ui/select.c: -------------------------------------------------------------------------------- 1 | /* 2 | mtr -- a network diagnostic tool 3 | Copyright (C) 1997,1998 Matt Kimball 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License version 2 as 7 | published by the Free Software Foundation. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along 15 | with this program; if not, write to the Free Software Foundation, Inc., 16 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #include "config.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #ifdef HAVE_ERROR_H 32 | #include 33 | #else 34 | #include "portability/error.h" 35 | #endif 36 | 37 | #include "mtr.h" 38 | #include "dns.h" 39 | #include "net.h" 40 | #include "asn.h" 41 | #include "display.h" 42 | #include "select.h" 43 | 44 | void select_loop( 45 | struct mtr_ctl *ctl) 46 | { 47 | fd_set readfd; 48 | fd_set writefd; 49 | int anyset = 0; 50 | int maxfd = 0; 51 | int dnsfd, netfd; 52 | #ifdef ENABLE_IPV6 53 | int dnsfd6; 54 | #endif 55 | int NumPing = 0; 56 | int paused = 0; 57 | struct timeval lasttime, thistime, selecttime; 58 | struct timeval startgrace; 59 | int dt; 60 | int rv; 61 | int graceperiod = 0; 62 | struct timeval intervaltime; 63 | static double dnsinterval = 0; 64 | 65 | memset(&startgrace, 0, sizeof(startgrace)); 66 | 67 | gettimeofday(&lasttime, NULL); 68 | 69 | while (1) { 70 | dt = calc_deltatime(ctl->WaitTime); 71 | intervaltime.tv_sec = dt / 1000000; 72 | intervaltime.tv_usec = dt % 1000000; 73 | 74 | FD_ZERO(&readfd); 75 | FD_ZERO(&writefd); 76 | 77 | maxfd = 0; 78 | 79 | if (ctl->Interactive) { 80 | FD_SET(0, &readfd); 81 | maxfd = 1; 82 | } 83 | #ifdef ENABLE_IPV6 84 | if (ctl->dns) { 85 | dnsfd6 = dns_waitfd6(); 86 | if (dnsfd6 >= 0) { 87 | FD_SET(dnsfd6, &readfd); 88 | if (dnsfd6 >= maxfd) 89 | maxfd = dnsfd6 + 1; 90 | } else { 91 | dnsfd6 = 0; 92 | } 93 | } else 94 | dnsfd6 = 0; 95 | #endif 96 | if (ctl->dns) { 97 | dnsfd = dns_waitfd(); 98 | FD_SET(dnsfd, &readfd); 99 | if (dnsfd >= maxfd) 100 | maxfd = dnsfd + 1; 101 | } else 102 | dnsfd = 0; 103 | 104 | netfd = net_waitfd(); 105 | FD_SET(netfd, &readfd); 106 | if (netfd >= maxfd) 107 | maxfd = netfd + 1; 108 | 109 | do { 110 | if (anyset || paused) { 111 | /* Set timeout to 0.1s. 112 | * While this is almost instantaneous for human operators, 113 | * it's slow enough for computers to go do something else; 114 | * this prevents mtr from hogging 100% CPU time on one core. 115 | */ 116 | selecttime.tv_sec = 0; 117 | selecttime.tv_usec = paused ? 100000 : 0; 118 | 119 | rv = select(maxfd, (void *) &readfd, &writefd, NULL, 120 | &selecttime); 121 | 122 | } else { 123 | if (ctl->Interactive) 124 | display_redraw(ctl); 125 | 126 | gettimeofday(&thistime, NULL); 127 | 128 | if (thistime.tv_sec > lasttime.tv_sec + intervaltime.tv_sec 129 | || (thistime.tv_sec == 130 | lasttime.tv_sec + intervaltime.tv_sec 131 | && thistime.tv_usec >= 132 | lasttime.tv_usec + intervaltime.tv_usec)) { 133 | lasttime = thistime; 134 | 135 | if (!graceperiod) { 136 | if (NumPing >= ctl->MaxPing 137 | && (!ctl->Interactive || ctl->ForceMaxPing)) { 138 | graceperiod = 1; 139 | startgrace = thistime; 140 | } 141 | 142 | /* do not send out batch when we've already initiated grace period */ 143 | if (!graceperiod && net_send_batch(ctl)) 144 | NumPing++; 145 | } 146 | } 147 | 148 | if (graceperiod) { 149 | dt = (thistime.tv_usec - startgrace.tv_usec) + 150 | 1000000 * (thistime.tv_sec - startgrace.tv_sec); 151 | if ((ctl->GraceTime * 1000 * 1000) < dt) 152 | return; 153 | } 154 | 155 | selecttime.tv_usec = (thistime.tv_usec - lasttime.tv_usec); 156 | selecttime.tv_sec = (thistime.tv_sec - lasttime.tv_sec); 157 | if (selecttime.tv_usec < 0) { 158 | --selecttime.tv_sec; 159 | selecttime.tv_usec += 1000000; 160 | } 161 | selecttime.tv_usec = 162 | intervaltime.tv_usec - selecttime.tv_usec; 163 | selecttime.tv_sec = 164 | intervaltime.tv_sec - selecttime.tv_sec; 165 | if (selecttime.tv_usec < 0) { 166 | --selecttime.tv_sec; 167 | selecttime.tv_usec += 1000000; 168 | } 169 | 170 | if (ctl->dns) { 171 | if ((selecttime.tv_sec > (time_t) dnsinterval) || 172 | ((selecttime.tv_sec == (time_t) dnsinterval) && 173 | (selecttime.tv_usec > 174 | ((time_t) (dnsinterval * 1000000) % 1000000)))) { 175 | selecttime.tv_sec = (time_t) dnsinterval; 176 | selecttime.tv_usec = 177 | (time_t) (dnsinterval * 1000000) % 1000000; 178 | } 179 | } 180 | 181 | rv = select(maxfd, (void *) &readfd, NULL, NULL, 182 | &selecttime); 183 | } 184 | } while ((rv < 0) && (errno == EINTR)); 185 | 186 | if (rv < 0) { 187 | error(EXIT_FAILURE, errno, "Select failed"); 188 | } 189 | anyset = 0; 190 | 191 | /* Have we got new packets back? */ 192 | if (FD_ISSET(netfd, &readfd)) { 193 | net_process_return(ctl); 194 | anyset = 1; 195 | } 196 | 197 | if (ctl->dns) { 198 | /* Handle any pending resolver events */ 199 | dnsinterval = ctl->WaitTime; 200 | } 201 | 202 | /* Have we finished a nameservice lookup? */ 203 | #ifdef ENABLE_IPV6 204 | if (ctl->dns && dnsfd6 && FD_ISSET(dnsfd6, &readfd)) { 205 | dns_ack6(); 206 | anyset = 1; 207 | } 208 | #endif 209 | if (ctl->dns && dnsfd && FD_ISSET(dnsfd, &readfd)) { 210 | dns_ack(ctl); 211 | anyset = 1; 212 | } 213 | 214 | /* Has a key been pressed? */ 215 | if (FD_ISSET(0, &readfd)) { 216 | switch (display_keyaction(ctl)) { 217 | case ActionQuit: 218 | return; 219 | break; 220 | case ActionReset: 221 | net_reset(ctl); 222 | break; 223 | case ActionDisplay: 224 | ctl->display_mode = 225 | (ctl->display_mode + 1) % DisplayModeMAX; 226 | break; 227 | case ActionClear: 228 | display_clear(ctl); 229 | break; 230 | case ActionPause: 231 | paused = 1; 232 | break; 233 | case ActionResume: 234 | paused = 0; 235 | break; 236 | case ActionMPLS: 237 | ctl->enablempls = !ctl->enablempls; 238 | display_clear(ctl); 239 | break; 240 | case ActionDNS: 241 | if (ctl->dns) { 242 | ctl->use_dns = !ctl->use_dns; 243 | display_clear(ctl); 244 | } 245 | break; 246 | #ifdef HAVE_IPINFO 247 | case ActionII: 248 | ctl->ipinfo_no++; 249 | if (ctl->ipinfo_no > ctl->ipinfo_max) 250 | ctl->ipinfo_no = 0; 251 | break; 252 | case ActionAS: 253 | ctl->ipinfo_no = ctl->ipinfo_no ? 0 : ctl->ipinfo_max; 254 | break; 255 | #endif 256 | 257 | case ActionScrollDown: 258 | ctl->display_offset += 5; 259 | break; 260 | case ActionScrollUp: 261 | ctl->display_offset -= 5; 262 | if (ctl->display_offset < 0) { 263 | ctl->display_offset = 0; 264 | } 265 | break; 266 | } 267 | anyset = 1; 268 | } 269 | } 270 | return; 271 | } 272 | -------------------------------------------------------------------------------- /ui/asn.c: -------------------------------------------------------------------------------- 1 | /* 2 | mtr -- a network diagnostic tool 3 | Copyright (C) 1997,1998 Matt Kimball 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License version 2 as 7 | published by the Free Software Foundation. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along 15 | with this program; if not, write to the Free Software Foundation, Inc., 16 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #include "config.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #ifdef HAVE_ERROR_H 26 | #include 27 | #else 28 | #include "portability/error.h" 29 | #endif 30 | #include 31 | 32 | #ifdef __APPLE__ 33 | #define BIND_8_COMPAT 34 | #endif 35 | #include 36 | #ifdef HAVE_ARPA_NAMESER_COMPAT_H 37 | #include 38 | #endif 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | 46 | #include "mtr.h" 47 | #include "asn.h" 48 | #include "utils.h" 49 | 50 | /* #define IIDEBUG */ 51 | #ifdef IIDEBUG 52 | #include 53 | #define DEB_syslog syslog 54 | #else 55 | #define DEB_syslog(...) do {} while (0) 56 | #endif 57 | 58 | #define IIHASH_HI 128 59 | #define ITEMSMAX 15 60 | #define ITEMSEP '|' 61 | #define NAMELEN 127 62 | #define UNKN "???" 63 | 64 | static int iihash = 0; 65 | static char fmtinfo[32]; 66 | 67 | /* items width: ASN, Route, Country, Registry, Allocated */ 68 | static const int iiwidth[] = { 7, 19, 4, 8, 11 }; /* item len + space */ 69 | 70 | typedef char *items_t[ITEMSMAX + 1]; 71 | static items_t items_a; /* without hash: items */ 72 | static char txtrec[NAMELEN + 1]; /* without hash: txtrec */ 73 | static items_t *items = &items_a; 74 | 75 | 76 | static char *ipinfo_lookup( 77 | const char *domain) 78 | { 79 | unsigned char answer[PACKETSZ], *pt; 80 | char host[128]; 81 | char *txt; 82 | int len, exp, size, txtlen, type; 83 | 84 | 85 | if (res_init() < 0) { 86 | error(0, 0, "@res_init failed"); 87 | return NULL; 88 | } 89 | 90 | memset(answer, 0, PACKETSZ); 91 | if ((len = res_query(domain, C_IN, T_TXT, answer, PACKETSZ)) < 0) { 92 | if (iihash) 93 | DEB_syslog(LOG_INFO, "Malloc-txt: %s", UNKN); 94 | return xstrdup(UNKN); 95 | } 96 | 97 | pt = answer + sizeof(HEADER); 98 | 99 | if ((exp = 100 | dn_expand(answer, answer + len, pt, host, sizeof(host))) < 0) { 101 | printf("@dn_expand failed\n"); 102 | return NULL; 103 | } 104 | 105 | pt += exp; 106 | 107 | GETSHORT(type, pt); 108 | if (type != T_TXT) { 109 | printf("@Broken DNS reply.\n"); 110 | return NULL; 111 | } 112 | 113 | pt += INT16SZ; /* class */ 114 | 115 | if ((exp = 116 | dn_expand(answer, answer + len, pt, host, sizeof(host))) < 0) { 117 | printf("@second dn_expand failed\n"); 118 | return NULL; 119 | } 120 | 121 | pt += exp; 122 | GETSHORT(type, pt); 123 | if (type != T_TXT) { 124 | printf("@Not a TXT record\n"); 125 | return NULL; 126 | } 127 | 128 | pt += INT16SZ; /* class */ 129 | pt += INT32SZ; /* ttl */ 130 | GETSHORT(size, pt); 131 | txtlen = *pt; 132 | 133 | 134 | if (txtlen >= size || !txtlen) { 135 | printf("@Broken TXT record (txtlen = %d, size = %d)\n", txtlen, 136 | size); 137 | return NULL; 138 | } 139 | 140 | if (txtlen > NAMELEN) 141 | txtlen = NAMELEN; 142 | 143 | if (iihash) { 144 | txt = xmalloc(txtlen + 1); 145 | } else 146 | txt = (char *) txtrec; 147 | 148 | pt++; 149 | xstrncpy(txt, (char *) pt, txtlen + 1); 150 | 151 | if (iihash) 152 | DEB_syslog(LOG_INFO, "Malloc-txt(%p): %s", txt, txt); 153 | 154 | return txt; 155 | } 156 | 157 | /* originX.asn.cymru.com txtrec: ASN | Route | Country | Registry | Allocated */ 158 | static char *split_txtrec( 159 | struct mtr_ctl *ctl, 160 | char *txt_rec) 161 | { 162 | char *prev; 163 | char *next; 164 | int i = 0, j; 165 | 166 | if (!txt_rec) 167 | return NULL; 168 | if (iihash) { 169 | DEB_syslog(LOG_INFO, "Malloc-tbl: %s", txt_rec); 170 | if (!(items = malloc(sizeof(*items)))) { 171 | DEB_syslog(LOG_INFO, "Free-txt(%p)", txt_rec); 172 | free(txt_rec); 173 | return NULL; 174 | } 175 | } 176 | 177 | prev = txt_rec; 178 | 179 | while ((next = strchr(prev, ITEMSEP)) && (i < ITEMSMAX)) { 180 | *next = '\0'; 181 | next++; 182 | (*items)[i] = trim(prev, ITEMSEP); 183 | prev = next; 184 | i++; 185 | } 186 | (*items)[i] = trim(prev, ITEMSEP); 187 | 188 | if (i < ITEMSMAX) 189 | i++; 190 | for (j = i; j <= ITEMSMAX; j++) 191 | (*items)[j] = NULL; 192 | 193 | if (i > ctl->ipinfo_max) 194 | ctl->ipinfo_max = i; 195 | if (ctl->ipinfo_no >= i) { 196 | if (ctl->ipinfo_no >= ctl->ipinfo_max) 197 | ctl->ipinfo_no = 0; 198 | return (*items)[0]; 199 | } else 200 | return (*items)[ctl->ipinfo_no]; 201 | } 202 | 203 | #ifdef ENABLE_IPV6 204 | /* from dns.c:addr2ip6arpa() */ 205 | static void reverse_host6( 206 | struct in6_addr *addr, 207 | char *buff, 208 | int buff_length) 209 | { 210 | int i; 211 | char *b = buff; 212 | for (i = (sizeof(*addr) / 2 - 1); i >= 0; i--, b += 4) /* 64b portion */ 213 | snprintf(b, buff_length, 214 | "%x.%x.", addr->s6_addr[i] & 0xf, addr->s6_addr[i] >> 4); 215 | 216 | buff[strlen(buff) - 1] = '\0'; 217 | } 218 | #endif 219 | 220 | static char *get_ipinfo( 221 | struct mtr_ctl *ctl, 222 | ip_t * addr) 223 | { 224 | char key[NAMELEN]; 225 | char lookup_key[NAMELEN]; 226 | char *val = NULL; 227 | ENTRY item; 228 | 229 | if (!addr) 230 | return NULL; 231 | 232 | if (ctl->af == AF_INET6) { 233 | #ifdef ENABLE_IPV6 234 | reverse_host6(addr, key, NAMELEN); 235 | if (snprintf(lookup_key, NAMELEN, "%s.origin6.asn.cymru.com", key) 236 | >= NAMELEN) 237 | return NULL; 238 | #else 239 | return NULL; 240 | #endif 241 | } else { 242 | unsigned char buff[4]; 243 | memcpy(buff, addr, 4); 244 | if (snprintf 245 | (key, NAMELEN, "%d.%d.%d.%d", buff[3], buff[2], buff[1], 246 | buff[0]) >= NAMELEN) 247 | return NULL; 248 | if (snprintf(lookup_key, NAMELEN, "%s.origin.asn.cymru.com", key) 249 | >= NAMELEN) 250 | return NULL; 251 | } 252 | 253 | if (iihash) { 254 | ENTRY *found_item; 255 | 256 | DEB_syslog(LOG_INFO, ">> Search: %s", key); 257 | item.key = key;; 258 | if ((found_item = hsearch(item, FIND))) { 259 | if (!(val = (*((items_t *) found_item->data))[ctl->ipinfo_no])) 260 | val = (*((items_t *) found_item->data))[0]; 261 | DEB_syslog(LOG_INFO, "Found (hashed): %s", val); 262 | } 263 | } 264 | 265 | if (!val) { 266 | DEB_syslog(LOG_INFO, "Lookup: %s", key); 267 | if ((val = split_txtrec(ctl, ipinfo_lookup(lookup_key)))) { 268 | DEB_syslog(LOG_INFO, "Looked up: %s", key); 269 | if (iihash) 270 | if ((item.key = xstrdup(key))) { 271 | item.data = (void *) items; 272 | hsearch(item, ENTER); 273 | DEB_syslog(LOG_INFO, "Insert into hash: %s", key); 274 | } 275 | } 276 | } 277 | 278 | return val; 279 | } 280 | 281 | ATTRIBUTE_CONST size_t get_iiwidth_len( 282 | void) 283 | { 284 | return (sizeof(iiwidth) / sizeof((iiwidth)[0])); 285 | } 286 | 287 | ATTRIBUTE_CONST int get_iiwidth( 288 | int ipinfo_no) 289 | { 290 | static const int len = (sizeof(iiwidth) / sizeof((iiwidth)[0])); 291 | 292 | if (ipinfo_no < len) 293 | return iiwidth[ipinfo_no]; 294 | return iiwidth[ipinfo_no % len]; 295 | } 296 | 297 | char *fmt_ipinfo( 298 | struct mtr_ctl *ctl, 299 | ip_t * addr) 300 | { 301 | char *ipinfo = get_ipinfo(ctl, addr); 302 | char fmt[8]; 303 | snprintf(fmt, sizeof(fmt), "%s%%-%ds", ctl->ipinfo_no ? "" : "AS", 304 | get_iiwidth(ctl->ipinfo_no)); 305 | snprintf(fmtinfo, sizeof(fmtinfo), fmt, ipinfo ? ipinfo : UNKN); 306 | return fmtinfo; 307 | } 308 | 309 | int is_printii( 310 | struct mtr_ctl *ctl) 311 | { 312 | return ((ctl->ipinfo_no >= 0) && (ctl->ipinfo_no != ctl->ipinfo_max)); 313 | } 314 | 315 | void asn_open( 316 | struct mtr_ctl *ctl) 317 | { 318 | if (ctl->ipinfo_no >= 0) { 319 | DEB_syslog(LOG_INFO, "hcreate(%d)", IIHASH_HI); 320 | if (!(iihash = hcreate(IIHASH_HI))) 321 | error(0, errno, "ipinfo hash"); 322 | } 323 | } 324 | 325 | void asn_close( 326 | struct mtr_ctl *ctl) 327 | { 328 | if ((ctl->ipinfo_no >= 0) && iihash) { 329 | DEB_syslog(LOG_INFO, "hdestroy()"); 330 | hdestroy(); 331 | iihash = 0; 332 | } 333 | } 334 | -------------------------------------------------------------------------------- /man/mtr-packet.8.in: -------------------------------------------------------------------------------- 1 | .TH MTR-PACKET 8 "@VERSION@" "mtr-packet" "System Administration" 2 | .HP 7 3 | .SH NAME 4 | mtr-packet - send and receive network probes 5 | .SH DESCRIPTION 6 | .B mtr-packet 7 | is a tool for sending network probes to measure network connectivity and 8 | performance. Many network probes can be sent simultaneously by a single 9 | process instance of 10 | .B mtr-packet 11 | and additional probes can be generated by an instance of 12 | .B mtr-packet 13 | which already has network probes in flight. It is intended to be used 14 | by programs which invoke it with Unix pipes attached to its standard input 15 | and output streams. 16 | .LP 17 | .B mtr-packet 18 | reads command requests from 19 | .IR stdin , 20 | each separated by a newline character, and responds with command replies to 21 | .IR stdout , 22 | also each separated by a newline character. The syntactic structure of 23 | requests and replies are the same. The following format is used: 24 | .LP 25 | .RS 26 | .I TOKEN 27 | .I COMMAND 28 | [\c 29 | .I ARGUMENT-NAME 30 | .I ARGUMENT-VALUE 31 | \&...] 32 | .RE 33 | .LP 34 | .I TOKEN 35 | is a unique integer value. The same value will be used as the 36 | .I TOKEN 37 | for the response. This is necessary for associating replies with requests, 38 | as commands may be completed in a different order than they are requested. 39 | The invoker of 40 | .B mtr-packet 41 | should always use the 42 | .I TOKEN 43 | value to determine which command request has completed. 44 | .LP 45 | .I COMMAND 46 | is a string identifying the command request type. A common command is 47 | .BR send-probe , 48 | which will transmit one network probe. 49 | .LP 50 | .I ARGUMENT-NAME 51 | strings and 52 | .I ARGUMENT-VALUE 53 | strings always come in pairs. It is a syntactic error to provide an 54 | .I ARGUMENT-NAME 55 | without a corresponding 56 | .IR ARGUMENT-VALUE . 57 | Valid 58 | .I ARGUMENT-NAME 59 | strings depend on the 60 | .I COMMAND 61 | being used. 62 | .SH REQUESTS 63 | .TP 64 | .B send-probe 65 | Send a network probe to a particular IP address. Either an 66 | .B ip-4 67 | or 68 | .B ip-6 69 | argument must be provided. 70 | A valid 71 | .B send-probe 72 | command will reply with 73 | .BR reply , 74 | .BR no-reply , 75 | or 76 | .BR ttl-expired . 77 | .IP 78 | The following arguments may be used: 79 | .IP 80 | .B ip-4 81 | .I IP-ADDRESS 82 | .HP 14 83 | .IP 84 | The Internet Protocol version 4 address to probe. 85 | .HP 7 86 | .IP 87 | .B ip-6 88 | .I IP-ADDRESS 89 | .HP 14 90 | .IP 91 | The Internet Protocol version 6 address to probe. 92 | .HP 7 93 | .IP 94 | .B protocol 95 | .I PROTOCOL 96 | .HP 14 97 | .IP 98 | The protocol to use for the network probe. 99 | .BR icmp , 100 | .BR sctp , 101 | .BR tcp , 102 | and 103 | .B udp 104 | may be used. The default protocol is 105 | .BR icmp. 106 | .HP 7 107 | .IP 108 | .B port 109 | .I PORT-NUMBER 110 | .HP 14 111 | .IP 112 | The destination port to use for 113 | .BR sctp , 114 | .BR tcp , 115 | or 116 | .B udp 117 | probes. 118 | .HP 7 119 | .IP 120 | .B local-ip-4 121 | .I IP-ADDRESS 122 | .HP 14 123 | .IP 124 | The local Internet Procol version 4 address to use when sending probes. 125 | .HP 7 126 | .IP 127 | .B local-ip-6 128 | .I IP-ADDRESS 129 | .HP 14 130 | .IP 131 | The local Internet Protocol version 6 address to use when sending probes. 132 | .HP 7 133 | .IP 134 | .B local-port 135 | .I PORT-NUMBER 136 | .HP 14 137 | .IP 138 | For 139 | .B udp 140 | probes, the local port number from which to send probes. 141 | .HP 7 142 | .IP 143 | .B timeout 144 | .I TIMEOUT-SECONDS 145 | .HP 14 146 | .IP 147 | The number of seconds to wait for a response to the probe before discarding 148 | the probe as lost, and generating a 149 | .B no-reply 150 | command reply. 151 | .HP 7 152 | .IP 153 | .B ttl 154 | .I TIME-TO-LIVE 155 | .HP 14 156 | .IP 157 | The time-to-live value for the Internet Protocol packet header used in 158 | constructing the probe. This value determines the number of network hops 159 | through which the probe will travel before a response is generated by an 160 | intermediate network host. 161 | .HP 7 162 | .IP 163 | .B size 164 | .I PACKET-SIZE 165 | .HP 14 166 | .IP 167 | The size of the packet used to send the probe, in bytes, including the 168 | Internet Protocol header and transport protocol header. 169 | .HP 7 170 | .IP 171 | .B bit-pattern 172 | .I PATTERN-VALUE 173 | .HP 14 174 | .IP 175 | The packet payload is filled with bytes of the value specified. 176 | Valid pattern values are in the range 0 through 255. 177 | .HP 7 178 | .IP 179 | .IP 180 | .B tos 181 | .I TYPE-OF-SERVICE 182 | .HP 14 183 | .IP 184 | In the case of IPv4, the "type of service" field in the IP header 185 | is set to this value. In the case of IPv6, the "traffic class" 186 | field is set. 187 | .HP 7 188 | .IP 189 | .B mark 190 | .I ROUTING-MARK 191 | .HP 14 192 | .IP 193 | The packet mark value to be used by mark-based routing. 194 | (Available only on Linux.) 195 | .HP 7 196 | .TP 197 | .B check-support 198 | Check for support for a particular feature in this version of 199 | .B mtr-packet 200 | and in this particular operating environment. 201 | .B check-support 202 | will reply with 203 | .BR feature-supported . 204 | A 205 | .B feature 206 | argument is required. 207 | .HP 7 208 | .IP 209 | .B feature 210 | .I FEATURE-NAME 211 | .HP 14 212 | .IP 213 | The name of a feature requested. 214 | .HP 7 215 | .IP 216 | Some features which can be checked are 217 | .BR send-probe , 218 | .BR ip-4 , 219 | .BR ip-6 , 220 | .BR icmp , 221 | .BR sctp , 222 | .BR tcp , 223 | .BR udp , 224 | and 225 | .BR mark . 226 | The feature 227 | .B version 228 | can be checked to retrieve the version of 229 | .BR mtr-packet . 230 | .SH REPLIES 231 | .TP 232 | .B reply 233 | The destination host received the 234 | .B send-probe 235 | probe and replied. Arguments of 236 | .B reply 237 | are: 238 | .HP 7 239 | .IP 240 | .B ip-4 241 | .I IP-ADDRESS 242 | .HP 14 243 | .IP 244 | The Internet Protocol version 4 address of the host which replied 245 | to the probe. 246 | .HP 7 247 | .IP 248 | .B ip-6 249 | .I IP-ADDRESS 250 | .HP 14 251 | .IP 252 | The Internet Protocol version 6 address of the host which replied 253 | to the probe. 254 | .HP 7 255 | .IP 256 | .B round-trip-time 257 | .I TIME 258 | .HP 14 259 | .IP 260 | The time which passed between the transmission of the probe and its 261 | response. The time is provided as a integral number of microseconds 262 | elapsed. 263 | .HP 7 264 | .TP 265 | .B no-reply 266 | No response to the probe request was received before the timeout 267 | expired. 268 | .TP 269 | .B ttl-expired 270 | The time-to-live value of the transmitted probe expired before the probe 271 | arrived at its intended destination. Arguments of 272 | .B ttl-expired 273 | are: 274 | .HP 7 275 | .IP 276 | .B ip-4 277 | .I IP-ADDRESS 278 | .HP 14 279 | .IP 280 | The Internet Protocol version 4 address of the host at which the 281 | time-to-live value expired. 282 | .HP 7 283 | .IP 284 | .B ip-6 285 | .I IP-ADDRESS 286 | .HP 14 287 | .IP 288 | The Internet Protocol version 6 address of the host at which the 289 | time-to-live value expired. 290 | .HP 7 291 | .IP 292 | .B round-trip-time 293 | .I TIME 294 | .HP 14 295 | .IP 296 | The time which passed between the transmission of the probe and its 297 | response. The time is provided as a integral number of microseconds 298 | elapsed. 299 | .HP 7 300 | .IP 301 | .B mpls 302 | .I MPLS-LABEL-LIST 303 | .HP 14 304 | .IP 305 | A list of Multiprotocol Label Switching values returned 306 | with the probe response. 307 | If the 308 | .B mpls 309 | argument is present, one or more MPLS labels will be represented by 310 | a comma separated list of values. The values are provided in groups 311 | of four. The first four values in the list correspond to the 312 | first MPLS label, the next four values correspond to the second MPLS 313 | label, and so on. The values are provided in this order: 314 | .IR label , 315 | .IR experimental-use , 316 | .IR bottom-of-stack , 317 | .IR ttl . 318 | .HP 7 319 | .TP 320 | .B no-route 321 | There was no route to the host used in a 322 | .B send-probe 323 | request. 324 | .TP 325 | .B network-down 326 | A probe could not be sent because the network is down. 327 | .TP 328 | .B probes-exhausted 329 | A probe could not be sent because there are already too many unresolved 330 | probes in flight. 331 | .TP 332 | .B permission-denied 333 | The operating system denied permission to send the probe with the 334 | specified options. 335 | .TP 336 | .B invalid-argument 337 | The command request contained arguments which are invalid. 338 | .TP 339 | .B feature-support 340 | A reply to provided to 341 | .B check-support 342 | indicating the availability of a particular feature. The argument provided 343 | is: 344 | .HP 7 345 | .IP 346 | .B support 347 | .I PRESENT 348 | .HP 14 349 | .IP 350 | In most cases, the 351 | .I PRESENT 352 | value will be either 353 | .BR ok , 354 | indicating the feature is supported, or 355 | .BR no , 356 | indicating no support for the feature. 357 | .IP 358 | In the case that 359 | .B version 360 | is the requested 361 | .IR FEATURE-NAME , 362 | the version of 363 | .B mtr-packet 364 | is provided as the 365 | .I PRESENT 366 | value. 367 | .HP 7 368 | .IP 369 | .SH EXAMPLES 370 | A controlling program may start 371 | .B mtr-packet 372 | as a child process and issue the following command on 373 | .IR stdin : 374 | .LP 375 | .RS 376 | 42 send-probe ip-4 127.0.0.1 377 | .RE 378 | .LP 379 | This will send a network probe to the loopback interface. When the probe 380 | completes, 381 | .B 382 | mtr-packet 383 | will provide a response on 384 | .I stdout 385 | such as the following: 386 | .LP 387 | .RS 388 | 42 reply ip-4 127.0.0.1 round-trip-time 126 389 | .RE 390 | .LP 391 | This indicates that the loopback address replied to the probe, and the 392 | round-trip time of the probe was 126 microseconds. 393 | .LP 394 | In order to trace the route to a remote host, multiple 395 | .B send-probe 396 | commands, each with a different 397 | .B ttl 398 | value, are used. 399 | .LP 400 | .RS 401 | 11 send-probe ip-4 8.8.8.8 ttl 1 402 | .RS 0 403 | 12 send-probe ip-4 8.8.8.8 ttl 2 404 | .RS 0 405 | 13 send-probe ip-4 8.8.8.8 ttl 3 406 | .RS 0 407 | \&... 408 | .RE 0 409 | .LP 410 | Each interemediate host would respond with a 411 | .B ttl-expired 412 | message, and the destination host would respond with a 413 | .BR reply : 414 | .LP 415 | .RS 416 | 11 ttl-expired ip-4 192.168.254.254 round-trip-time 1634 417 | .RS 0 418 | 12 ttl-expired ip-4 184.19.243.240 round-trip-time 7609 419 | .RS 0 420 | 13 ttl-expired ip-4 172.76.20.169 round-trip-time 8643 421 | .RS 0 422 | 14 ttl-expired ip-4 74.40.1.101 round-trip-time 9755 423 | .RS 0 424 | 15 ttl-expired ip-4 74.40.5.126 round-trip-time 10695 425 | .RS 0 426 | 17 ttl-expired ip-4 108.170.245.97 round-trip-time 14077 427 | .RS 0 428 | 16 ttl-expired ip-4 74.40.26.131 round-trip-time 15253 429 | .RS 0 430 | 18 ttl-expired ip-4 209.85.245.101 round-trip-time 17080 431 | .RS 0 432 | 19 reply ip-4 8.8.8.8 round-trip-time 17039 433 | .RE 0 434 | .LP 435 | Note that the replies in this example are printed out of order. 436 | (The reply to probe 17 arrives prior to the reply to probe 16.) 437 | This is the reason that it is important to send commands with unique 438 | token values, and to use those token values to match replies with 439 | their originating commands. 440 | .SH CONTACT INFORMATION 441 | .PP 442 | For the latest version, see the mtr web page at 443 | .UR http://\:www.\:bitwizard.\:nl/\:mtr/ 444 | .UE 445 | .PP 446 | For patches, bug reports, or feature requests, please open an issue on 447 | GitHub at: 448 | .UR https://\:github\:.com/\:traviscross/\:mtr 449 | .UE . 450 | .SH "SEE ALSO" 451 | .BR mtr (8), 452 | .BR icmp (7), 453 | .BR tcp (7), 454 | .BR udp (7), 455 | TCP/IP Illustrated (Stevens, ISBN 0201633469). 456 | -------------------------------------------------------------------------------- /packet/probe.c: -------------------------------------------------------------------------------- 1 | /* 2 | mtr -- a network diagnostic tool 3 | Copyright (C) 2016 Matt Kimball 4 | 5 | This program is free software; you can redistribute it and/or modify 6 | it under the terms of the GNU General Public License version 2 as 7 | published by the Free Software Foundation. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License along 15 | with this program; if not, write to the Free Software Foundation, Inc., 16 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 | */ 18 | 19 | #include "probe.h" 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | #include "command.h" 31 | #include "platform.h" 32 | #include "protocols.h" 33 | #include "timeval.h" 34 | 35 | #define IP_TEXT_LENGTH 64 36 | 37 | /* Convert the destination address from text to sockaddr */ 38 | int decode_address_string( 39 | int ip_version, 40 | const char *address_string, 41 | struct sockaddr_storage *address) 42 | { 43 | struct in_addr addr4; 44 | struct in6_addr addr6; 45 | struct sockaddr_in *sockaddr4; 46 | struct sockaddr_in6 *sockaddr6; 47 | 48 | if (address == NULL) { 49 | errno = EINVAL; 50 | return -1; 51 | } 52 | 53 | if (ip_version == 6) { 54 | sockaddr6 = (struct sockaddr_in6 *) address; 55 | 56 | if (inet_pton(AF_INET6, address_string, &addr6) != 1) { 57 | errno = EINVAL; 58 | return -1; 59 | } 60 | 61 | sockaddr6->sin6_family = AF_INET6; 62 | sockaddr6->sin6_port = 0; 63 | sockaddr6->sin6_flowinfo = 0; 64 | sockaddr6->sin6_addr = addr6; 65 | sockaddr6->sin6_scope_id = 0; 66 | } else if (ip_version == 4) { 67 | sockaddr4 = (struct sockaddr_in *) address; 68 | 69 | if (inet_pton(AF_INET, address_string, &addr4) != 1) { 70 | errno = EINVAL; 71 | return -1; 72 | } 73 | 74 | sockaddr4->sin_family = AF_INET; 75 | sockaddr4->sin_port = 0; 76 | sockaddr4->sin_addr = addr4; 77 | } else { 78 | errno = EINVAL; 79 | return -1; 80 | } 81 | 82 | return 0; 83 | } 84 | 85 | /* 86 | Resolve the probe parameters into a remote and local address 87 | for the probe. 88 | */ 89 | int resolve_probe_addresses( 90 | struct net_state_t *net_state, 91 | const struct probe_param_t *param, 92 | struct sockaddr_storage *dest_sockaddr, 93 | struct sockaddr_storage *src_sockaddr) 94 | { 95 | if (decode_address_string 96 | (param->ip_version, param->remote_address, dest_sockaddr)) { 97 | return -1; 98 | } 99 | 100 | if (param->local_address) { 101 | if (decode_address_string 102 | (param->ip_version, param->local_address, src_sockaddr)) { 103 | return -1; 104 | } 105 | } else { 106 | if (find_source_addr(src_sockaddr, dest_sockaddr)) { 107 | return -1; 108 | } 109 | } 110 | /* DGRAM ICMP id is taken from src_port not from ICMP header */ 111 | if (param->protocol == IPPROTO_ICMP) { 112 | if (src_sockaddr->ss_family == AF_INET) { 113 | if (!net_state->platform.ip4_socket_raw) { 114 | struct sockaddr_in *sin_src = 115 | (struct sockaddr_in *) src_sockaddr; 116 | sin_src->sin_port = htons(getpid()); 117 | } 118 | } else if (src_sockaddr->ss_family == AF_INET6) { 119 | if (!net_state->platform.ip6_socket_raw) { 120 | struct sockaddr_in6 *sin6_src = 121 | (struct sockaddr_in6 *) src_sockaddr; 122 | sin6_src->sin6_port = htons(getpid()); 123 | } 124 | } 125 | } 126 | 127 | return 0; 128 | } 129 | 130 | /* Allocate a structure for tracking a new probe */ 131 | struct probe_t *alloc_probe( 132 | struct net_state_t *net_state, 133 | int token) 134 | { 135 | struct probe_t *probe; 136 | 137 | if (net_state->outstanding_probe_count >= MAX_PROBES) { 138 | return NULL; 139 | } 140 | 141 | probe = malloc(sizeof(struct probe_t)); 142 | if (probe == NULL) { 143 | return NULL; 144 | } 145 | 146 | memset(probe, 0, sizeof(struct probe_t)); 147 | probe->token = token; 148 | 149 | platform_alloc_probe(net_state, probe); 150 | 151 | net_state->outstanding_probe_count++; 152 | LIST_INSERT_HEAD(&net_state->outstanding_probes, probe, 153 | probe_list_entry); 154 | 155 | return probe; 156 | } 157 | 158 | /* Mark a probe tracking structure as unused */ 159 | void free_probe( 160 | struct net_state_t *net_state, 161 | struct probe_t *probe) 162 | { 163 | LIST_REMOVE(probe, probe_list_entry); 164 | net_state->outstanding_probe_count--; 165 | 166 | platform_free_probe(probe); 167 | 168 | free(probe); 169 | } 170 | 171 | /* 172 | Find an existing probe structure by ICMP id and sequence number. 173 | Returns NULL if non is found. 174 | */ 175 | struct probe_t *find_probe( 176 | struct net_state_t *net_state, 177 | int protocol, 178 | int id, 179 | int sequence) 180 | { 181 | struct probe_t *probe; 182 | 183 | /* 184 | ICMP has room for an id to check against our process, but 185 | UDP doesn't. 186 | */ 187 | if (protocol == IPPROTO_ICMP) { 188 | /* 189 | If the ICMP id doesn't match our process ID, it wasn't a 190 | probe generated by this process, so ignore it. 191 | */ 192 | if (id != htons(getpid())) { 193 | return NULL; 194 | } 195 | } 196 | 197 | LIST_FOREACH(probe, &net_state->outstanding_probes, probe_list_entry) { 198 | if (htons(probe->sequence) == sequence) { 199 | return probe; 200 | } 201 | } 202 | 203 | return NULL; 204 | } 205 | 206 | /* 207 | Format a list of MPLS labels into a string appropriate for including 208 | as an argument to a probe reply. 209 | */ 210 | static 211 | void format_mpls_string( 212 | char *str, 213 | int buffer_size, 214 | int mpls_count, 215 | const struct mpls_label_t *mpls_list) 216 | { 217 | int i; 218 | char *append_pos = str; 219 | const struct mpls_label_t *mpls; 220 | 221 | /* Start with an empty string */ 222 | str[0] = 0; 223 | 224 | for (i = 0; i < mpls_count; i++) { 225 | mpls = &mpls_list[i]; 226 | 227 | if (i > 0) { 228 | strncat(append_pos, ",", buffer_size - 1); 229 | 230 | buffer_size -= strlen(append_pos); 231 | append_pos += strlen(append_pos); 232 | } 233 | 234 | snprintf(append_pos, buffer_size, "%d,%d,%d,%d", 235 | mpls->label, mpls->experimental_use, 236 | mpls->bottom_of_stack, mpls->ttl); 237 | 238 | buffer_size -= strlen(append_pos); 239 | append_pos += strlen(append_pos); 240 | } 241 | } 242 | 243 | /* 244 | After a probe reply has arrived, respond to the command request which 245 | sent the probe. 246 | */ 247 | void respond_to_probe( 248 | struct net_state_t *net_state, 249 | struct probe_t *probe, 250 | int icmp_type, 251 | const struct sockaddr_storage *remote_addr, 252 | unsigned int round_trip_us, 253 | int mpls_count, 254 | const struct mpls_label_t *mpls) 255 | { 256 | char ip_text[IP_TEXT_LENGTH]; 257 | char response[COMMAND_BUFFER_SIZE]; 258 | char mpls_str[COMMAND_BUFFER_SIZE]; 259 | int remaining_size; 260 | const char *result; 261 | const char *ip_argument; 262 | struct sockaddr_in *sockaddr4; 263 | struct sockaddr_in6 *sockaddr6; 264 | void *addr; 265 | 266 | if (icmp_type == ICMP_TIME_EXCEEDED) { 267 | result = "ttl-expired"; 268 | } else if (icmp_type == ICMP_DEST_UNREACH) { 269 | result = "no-route"; 270 | } else { 271 | assert(icmp_type == ICMP_ECHOREPLY); 272 | result = "reply"; 273 | } 274 | 275 | if (remote_addr->ss_family == AF_INET6) { 276 | ip_argument = "ip-6"; 277 | sockaddr6 = (struct sockaddr_in6 *) remote_addr; 278 | addr = &sockaddr6->sin6_addr; 279 | } else { 280 | ip_argument = "ip-4"; 281 | sockaddr4 = (struct sockaddr_in *) remote_addr; 282 | addr = &sockaddr4->sin_addr; 283 | } 284 | 285 | if (inet_ntop(remote_addr->ss_family, addr, ip_text, IP_TEXT_LENGTH) == 286 | NULL) { 287 | 288 | perror("inet_ntop failure"); 289 | exit(EXIT_FAILURE); 290 | } 291 | 292 | snprintf(response, COMMAND_BUFFER_SIZE, 293 | "%d %s %s %s round-trip-time %d", 294 | probe->token, result, ip_argument, ip_text, round_trip_us); 295 | 296 | if (mpls_count) { 297 | format_mpls_string(mpls_str, COMMAND_BUFFER_SIZE, mpls_count, 298 | mpls); 299 | 300 | remaining_size = COMMAND_BUFFER_SIZE - strlen(response) - 1; 301 | strncat(response, " mpls ", remaining_size); 302 | 303 | remaining_size = COMMAND_BUFFER_SIZE - strlen(response) - 1; 304 | strncat(response, mpls_str, remaining_size); 305 | } 306 | 307 | puts(response); 308 | free_probe(net_state, probe); 309 | } 310 | 311 | /* 312 | Find the source address for transmitting to a particular destination 313 | address. Remember that hosts can have multiple addresses, for example 314 | a unique address for each network interface. So we will bind a UDP 315 | socket to our destination and check the socket address after binding 316 | to get the source for that destination, which will allow the kernel 317 | to do the routing table work for us. 318 | 319 | (connecting UDP sockets, unlike TCP sockets, doesn't transmit any packets. 320 | It's just an association.) 321 | */ 322 | int find_source_addr( 323 | struct sockaddr_storage *srcaddr, 324 | const struct sockaddr_storage *destaddr) 325 | { 326 | int sock; 327 | int len; 328 | struct sockaddr_in *destaddr4; 329 | struct sockaddr_in6 *destaddr6; 330 | struct sockaddr_storage dest_with_port; 331 | struct sockaddr_in *srcaddr4; 332 | struct sockaddr_in6 *srcaddr6; 333 | 334 | dest_with_port = *destaddr; 335 | 336 | /* 337 | MacOS requires a non-zero sin_port when used as an 338 | address for a UDP connect. If we provide a zero port, 339 | the connect will fail. We aren't actually sending 340 | anything to the port. 341 | */ 342 | if (destaddr->ss_family == AF_INET6) { 343 | destaddr6 = (struct sockaddr_in6 *) &dest_with_port; 344 | destaddr6->sin6_port = htons(1); 345 | 346 | len = sizeof(struct sockaddr_in6); 347 | } else { 348 | destaddr4 = (struct sockaddr_in *) &dest_with_port; 349 | destaddr4->sin_port = htons(1); 350 | 351 | len = sizeof(struct sockaddr_in); 352 | } 353 | 354 | sock = socket(destaddr->ss_family, SOCK_DGRAM, IPPROTO_UDP); 355 | if (sock == -1) { 356 | return -1; 357 | } 358 | 359 | if (connect(sock, (struct sockaddr *) &dest_with_port, len)) { 360 | close(sock); 361 | return -1; 362 | } 363 | 364 | if (getsockname(sock, (struct sockaddr *) srcaddr, &len)) { 365 | close(sock); 366 | return -1; 367 | } 368 | 369 | close(sock); 370 | 371 | /* 372 | Zero the port, as we may later use this address to finding, and 373 | we don't want to use the port from the socket we just created. 374 | */ 375 | if (destaddr->ss_family == AF_INET6) { 376 | srcaddr6 = (struct sockaddr_in6 *) srcaddr; 377 | 378 | srcaddr6->sin6_port = 0; 379 | } else { 380 | srcaddr4 = (struct sockaddr_in *) srcaddr; 381 | 382 | srcaddr4->sin_port = 0; 383 | } 384 | 385 | return 0; 386 | } 387 | --------------------------------------------------------------------------------