|
|
| version 1.1, 2019/10/21 14:25:31 | version 1.1.1.2, 2021/03/17 00:07:30 |
|---|---|
| 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 70 | Line 70 |
| #endif | #endif |
| char *myname; | |
| 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 112 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 161 static void __attribute__ ((__noreturn__)) usage(FILE | Line 165 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 299 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 349 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 370 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 447 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 472 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 489 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 648 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 696 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. | |
| */ | |
| static int get_hostent_from_name( | |
| struct mtr_ctl *ctl, | |
| struct hostent *host, | |
| const char *name, | |
| char **alptr) | |
| { | |
| int gai_error; | |
| struct addrinfo hints, *res; | |
| struct sockaddr_in *sa4; | |
| #ifdef ENABLE_IPV6 | |
| struct sockaddr_in6 *sa6; | |
| #endif | |
| /* 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; | |
| } | |
| /* Convert the first addrinfo into a hostent. */ | |
| memset(host, 0, sizeof(struct hostent)); | |
| 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"); | |
| errno = EINVAL; | |
| return -1; | |
| } | |
| alptr[1] = NULL; | |
| return 0; | |
| } | |
| int main( | int main( |
| int argc, | int argc, |
| char **argv) | char **argv) |
| { | { |
| struct hostent *host = NULL; | struct hostent *host = NULL; |
| struct addrinfo hints, *res; | |
| int gai_error; | |
| struct hostent trhost; | struct hostent trhost; |
| char *alptr[2]; | 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 837 int main( |
| sizeof(ctl.LocalHostname)); | sizeof(ctl.LocalHostname)); |
| } | } |
| /* 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(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) | |
| exit(EXIT_FAILURE); | |
| else { | |
| names_walk = names_walk->next; | |
| continue; | |
| } | |
| } | |
| /* Convert the first addrinfo into a hostent. */ | |
| host = &trhost; | host = &trhost; |
| memset(host, 0, sizeof trhost); | if (get_hostent_from_name(&ctl, host, ctl.Hostname, alptr) != 0) { |
| 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) | if (ctl.Interactive) |
| exit(EXIT_FAILURE); | exit(EXIT_FAILURE); |
| else { | else { |
| Line 809 int main( | Line 846 int main( |
| continue; | continue; |
| } | } |
| } | } |
| alptr[1] = NULL; | |
| if (net_open(&ctl, host) != 0) { | if (net_open(&ctl, host) != 0) { |
| error(0, 0, "Unable to start net module"); | error(0, 0, "Unable to start net module"); |