version 1.1.1.1, 2019/10/21 14:25:31
|
version 1.1.1.3, 2023/09/27 11:18:58
|
Line 11
|
Line 11
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
GNU General Public License for more details. |
GNU General Public License for more details. |
|
|
You should have received a copy of the GNU General Public License | You should have received a copy of the GNU General Public License along |
along with this program; if not, write to the Free Software | with this program; if not, write to the Free Software Foundation, Inc., |
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
*/ |
*/ |
|
|
#include "config.h" |
#include "config.h" |
Line 38
|
Line 38
|
#include <sys/limits.h> |
#include <sys/limits.h> |
#endif |
#endif |
|
|
#include <netdb.h> |
|
#include <netinet/in.h> |
#include <netinet/in.h> |
#include <sys/socket.h> |
#include <sys/socket.h> |
#include <ctype.h> |
#include <ctype.h> |
Line 63
|
Line 62
|
#include "portability/getopt.h" |
#include "portability/getopt.h" |
#endif |
#endif |
|
|
#ifdef ENABLE_IPV6 | char *myname; |
#define DEFAULT_AF AF_UNSPEC | |
#else | |
#define DEFAULT_AF AF_INET | |
#endif | |
|
|
|
|
const struct fields data_fields[MAXFLD] = { |
const struct fields data_fields[MAXFLD] = { |
/* key, Remark, Header, Format, Width, CallBackFunc */ |
/* key, Remark, Header, Format, Width, CallBackFunc */ |
{' ', "<sp>: Space between fields", " ", " ", 1, &net_drop}, |
{' ', "<sp>: Space between fields", " ", " ", 1, &net_drop}, |
Line 110 static void __attribute__ ((__noreturn__)) usage(FILE
|
Line 104 static void __attribute__ ((__noreturn__)) usage(FILE
|
out); |
out); |
fputs(" -T, --tcp use TCP instead of ICMP echo\n", |
fputs(" -T, --tcp use TCP instead of ICMP echo\n", |
out); |
out); |
|
fputs(" -I, --interface NAME use named network interface\n", |
|
out); |
fputs |
fputs |
(" -a, --address ADDRESS bind the outgoing socket to ADDRESS\n", |
(" -a, --address ADDRESS bind the outgoing socket to ADDRESS\n", |
out); |
out); |
Line 146 static void __attribute__ ((__noreturn__)) usage(FILE
|
Line 142 static void __attribute__ ((__noreturn__)) usage(FILE
|
fputs(" -w, --report-wide output wide report\n", out); |
fputs(" -w, --report-wide output wide report\n", out); |
fputs(" -c, --report-cycles COUNT set the number of pings sent\n", |
fputs(" -c, --report-cycles COUNT set the number of pings sent\n", |
out); |
out); |
|
#ifdef HAVE_JANSSON |
fputs(" -j, --json output json\n", out); |
fputs(" -j, --json output json\n", out); |
|
#endif |
fputs(" -x, --xml output xml\n", out); |
fputs(" -x, --xml output xml\n", out); |
fputs(" -C, --csv output comma separated values\n", |
fputs(" -C, --csv output comma separated values\n", |
out); |
out); |
Line 161 static void __attribute__ ((__noreturn__)) usage(FILE
|
Line 159 static void __attribute__ ((__noreturn__)) usage(FILE
|
#ifdef HAVE_GTK |
#ifdef HAVE_GTK |
fputs(" -g, --gtk use GTK+ xwindow interface\n", out); |
fputs(" -g, --gtk use GTK+ xwindow interface\n", out); |
#endif |
#endif |
fputs(" -n, --no-dns do not resove host names\n", out); | fputs(" -n, --no-dns do not resolve host names\n", out); |
fputs(" -b, --show-ips show IP numbers and host names\n", |
fputs(" -b, --show-ips show IP numbers and host names\n", |
out); |
out); |
fputs(" -o, --order FIELDS select output fields\n", out); |
fputs(" -o, --order FIELDS select output fields\n", out); |
Line 295 static void init_fld_options(
|
Line 293 static void init_fld_options(
|
{ |
{ |
int i; |
int i; |
|
|
memset(ctl->fld_index, -1, FLD_INDEX_SZ); | memset(ctl->fld_index, -1, FLD_INDEX_SZ*sizeof(ctl->fld_index[0])); |
|
|
for (i = 0; data_fields[i].key != 0; i++) { |
for (i = 0; data_fields[i].key != 0; i++) { |
ctl->available_options[i] = data_fields[i].key; |
ctl->available_options[i] = data_fields[i].key; |
ctl->fld_index[data_fields[i].key] = i; |
ctl->fld_index[data_fields[i].key] = i; |
} |
} |
|
ctl->available_options[i++] = '_'; |
ctl->available_options[i] = 0; |
ctl->available_options[i] = 0; |
} |
} |
|
|
Line 344 static void parse_arg(
|
Line 343 static void parse_arg(
|
#endif |
#endif |
{"raw", 0, NULL, 'l'}, |
{"raw", 0, NULL, 'l'}, |
{"csv", 0, NULL, 'C'}, |
{"csv", 0, NULL, 'C'}, |
|
#ifdef HAVE_JANSSON |
{"json", 0, NULL, 'j'}, |
{"json", 0, NULL, 'j'}, |
|
#endif |
{"displaymode", 1, NULL, OPT_DISPLAYMODE}, |
{"displaymode", 1, NULL, OPT_DISPLAYMODE}, |
{"split", 0, NULL, 'p'}, /* BL */ |
{"split", 0, NULL, 'p'}, /* BL */ |
/* maybe above should change to -d 'x' */ |
/* maybe above should change to -d 'x' */ |
Line 363 static void parse_arg(
|
Line 364 static void parse_arg(
|
{"bitpattern", 1, NULL, 'B'}, /* overload B>255, ->rand(0,255) */ |
{"bitpattern", 1, NULL, 'B'}, /* overload B>255, ->rand(0,255) */ |
{"tos", 1, NULL, 'Q'}, /* typeof service (0,255) */ |
{"tos", 1, NULL, 'Q'}, /* typeof service (0,255) */ |
{"mpls", 0, NULL, 'e'}, |
{"mpls", 0, NULL, 'e'}, |
|
{"interface", 1, NULL, 'I'}, |
{"address", 1, NULL, 'a'}, |
{"address", 1, NULL, 'a'}, |
{"first-ttl", 1, NULL, 'f'}, /* -f & -m are borrowed from traceroute */ |
{"first-ttl", 1, NULL, 'f'}, /* -f & -m are borrowed from traceroute */ |
{"max-ttl", 1, NULL, 'm'}, |
{"max-ttl", 1, NULL, 'm'}, |
Line 439 static void parse_arg(
|
Line 441 static void parse_arg(
|
case 'C': |
case 'C': |
ctl->DisplayMode = DisplayCSV; |
ctl->DisplayMode = DisplayCSV; |
break; |
break; |
|
#ifdef HAVE_JANSSON |
case 'j': |
case 'j': |
ctl->DisplayMode = DisplayJSON; |
ctl->DisplayMode = DisplayJSON; |
break; |
break; |
|
#endif |
case 'x': |
case 'x': |
ctl->DisplayMode = DisplayXML; |
ctl->DisplayMode = DisplayXML; |
break; |
break; |
Line 462 static void parse_arg(
|
Line 466 static void parse_arg(
|
ctl->cpacketsize = |
ctl->cpacketsize = |
strtonum_or_err(optarg, "invalid argument", STRTO_INT); |
strtonum_or_err(optarg, "invalid argument", STRTO_INT); |
break; |
break; |
|
case 'I': |
|
ctl->InterfaceName = optarg; |
|
break; |
case 'a': |
case 'a': |
ctl->InterfaceAddress = optarg; |
ctl->InterfaceAddress = optarg; |
break; |
break; |
Line 476 static void parse_arg(
|
Line 483 static void parse_arg(
|
if (ctl->WaitTime <= 0.0) { |
if (ctl->WaitTime <= 0.0) { |
error(EXIT_FAILURE, 0, "wait time must be positive"); |
error(EXIT_FAILURE, 0, "wait time must be positive"); |
} |
} |
if (getuid() != 0 && ctl->WaitTime < 1.0) { | if (!running_as_root() && ctl->WaitTime < 1.0) { |
error(EXIT_FAILURE, 0, |
error(EXIT_FAILURE, 0, |
"non-root users cannot request an interval < 1.0 seconds"); |
"non-root users cannot request an interval < 1.0 seconds"); |
} |
} |
Line 635 static void parse_arg(
|
Line 642 static void parse_arg(
|
|
|
if (ctl->DisplayMode == DisplayReport || |
if (ctl->DisplayMode == DisplayReport || |
ctl->DisplayMode == DisplayTXT || |
ctl->DisplayMode == DisplayTXT || |
|
#ifdef HAVE_JANSSON |
ctl->DisplayMode == DisplayJSON || |
ctl->DisplayMode == DisplayJSON || |
|
#endif |
ctl->DisplayMode == DisplayXML || |
ctl->DisplayMode == DisplayXML || |
ctl->DisplayMode == DisplayRaw || ctl->DisplayMode == DisplayCSV) |
ctl->DisplayMode == DisplayRaw || ctl->DisplayMode == DisplayCSV) |
ctl->Interactive = 0; |
ctl->Interactive = 0; |
Line 681 static void init_rand(
|
Line 690 static void init_rand(
|
srand((getpid() << 16) ^ getuid() ^ tv.tv_sec ^ tv.tv_usec); |
srand((getpid() << 16) ^ getuid() ^ tv.tv_sec ^ tv.tv_usec); |
} |
} |
|
|
|
/* |
|
For historical reasons, we need a hostent structure to represent |
|
our remote target for probing. The obsolete way of doing this |
|
would be to use gethostbyname(). We'll use getaddrinfo() instead |
|
to generate the hostent. |
|
*/ |
|
int get_addrinfo_from_name( |
|
struct mtr_ctl *ctl, |
|
struct addrinfo **res, |
|
const char *name) |
|
{ |
|
int gai_error; |
|
struct addrinfo hints; |
|
|
|
/* gethostbyname2() is deprecated so we'll use getaddrinfo() instead. */ |
|
memset(&hints, 0, sizeof hints); |
|
hints.ai_family = ctl->af; |
|
hints.ai_socktype = SOCK_DGRAM; |
|
gai_error = getaddrinfo(name, NULL, &hints, res); |
|
if (gai_error) { |
|
if (gai_error == EAI_SYSTEM) |
|
error(0, 0, "Failed to resolve host: %s", name); |
|
else |
|
error(0, 0, "Failed to resolve host: %s: %s", name, |
|
gai_strerror(gai_error)); |
|
|
|
return -1; |
|
} |
|
|
|
ctl->af = (*res)->ai_family; |
|
return 0; |
|
} |
|
|
|
|
int main( |
int main( |
int argc, |
int argc, |
char **argv) |
char **argv) |
{ |
{ |
struct hostent *host = NULL; |
|
struct addrinfo hints, *res; |
|
int gai_error; |
|
struct hostent trhost; |
|
char *alptr[2]; |
|
struct sockaddr_in *sa4; |
|
#ifdef ENABLE_IPV6 |
|
struct sockaddr_in6 *sa6; |
|
#endif |
|
names_t *names_head = NULL; |
names_t *names_head = NULL; |
names_t *names_walk; |
names_t *names_walk; |
|
|
|
myname = argv[0]; |
struct mtr_ctl ctl; |
struct mtr_ctl ctl; |
memset(&ctl, 0, sizeof(ctl)); |
memset(&ctl, 0, sizeof(ctl)); |
/* initialize non-null values */ |
/* initialize non-null values */ |
Line 761 int main(
|
Line 796 int main(
|
sizeof(ctl.LocalHostname)); |
sizeof(ctl.LocalHostname)); |
} |
} |
|
|
/* gethostbyname2() is deprecated so we'll use getaddrinfo() instead. */ | struct addrinfo *res = NULL; |
memset(&hints, 0, sizeof hints); | if (get_addrinfo_from_name(&ctl, &res, ctl.Hostname) != 0) { |
hints.ai_family = ctl.af; | |
hints.ai_socktype = SOCK_DGRAM; | |
gai_error = getaddrinfo(ctl.Hostname, NULL, &hints, &res); | |
if (gai_error) { | |
if (gai_error == EAI_SYSTEM) | |
error(0, 0, "Failed to resolve host: %s", ctl.Hostname); | |
else | |
error(0, 0, "Failed to resolve host: %s: %s", ctl.Hostname, | |
gai_strerror(gai_error)); | |
| |
if (ctl.Interactive) |
if (ctl.Interactive) |
exit(EXIT_FAILURE); |
exit(EXIT_FAILURE); |
else { |
else { |
Line 780 int main(
|
Line 805 int main(
|
continue; |
continue; |
} |
} |
} |
} |
/* Convert the first addrinfo into a hostent. */ |
|
host = &trhost; |
|
memset(host, 0, sizeof trhost); |
|
host->h_name = res->ai_canonname; |
|
host->h_aliases = NULL; |
|
host->h_addrtype = res->ai_family; |
|
ctl.af = res->ai_family; |
|
host->h_length = res->ai_addrlen; |
|
host->h_addr_list = alptr; |
|
switch (ctl.af) { |
|
case AF_INET: |
|
sa4 = (struct sockaddr_in *) res->ai_addr; |
|
alptr[0] = (void *) &(sa4->sin_addr); |
|
break; |
|
#ifdef ENABLE_IPV6 |
|
case AF_INET6: |
|
sa6 = (struct sockaddr_in6 *) res->ai_addr; |
|
alptr[0] = (void *) &(sa6->sin6_addr); |
|
break; |
|
#endif |
|
default: |
|
error(0, 0, "unknown address type"); |
|
if (ctl.Interactive) |
|
exit(EXIT_FAILURE); |
|
else { |
|
names_walk = names_walk->next; |
|
continue; |
|
} |
|
} |
|
alptr[1] = NULL; |
|
|
|
if (net_open(&ctl, host) != 0) { | if (net_open(&ctl, res) != 0) { |
error(0, 0, "Unable to start net module"); |
error(0, 0, "Unable to start net module"); |
if (ctl.Interactive) |
if (ctl.Interactive) |
exit(EXIT_FAILURE); |
exit(EXIT_FAILURE); |
Line 821 int main(
|
Line 816 int main(
|
} |
} |
} |
} |
|
|
|
freeaddrinfo(res); |
|
|
lock(stdout); |
lock(stdout); |
dns_open(&ctl); | dns_open(); |
display_open(&ctl); |
display_open(&ctl); |
|
|
display_loop(&ctl); |
display_loop(&ctl); |