|
Packit |
b802ec |
/*
|
|
Packit |
b802ec |
mtr -- a network diagnostic tool
|
|
Packit |
b802ec |
Copyright (C) 2016 Matt Kimball
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
This program is free software; you can redistribute it and/or modify
|
|
Packit |
b802ec |
it under the terms of the GNU General Public License version 2 as
|
|
Packit |
b802ec |
published by the Free Software Foundation.
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
This program is distributed in the hope that it will be useful,
|
|
Packit |
b802ec |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
b802ec |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
b802ec |
GNU General Public License for more details.
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
You should have received a copy of the GNU General Public License
|
|
Packit |
b802ec |
along with this program; if not, write to the Free Software
|
|
Packit |
b802ec |
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
Packit |
b802ec |
*/
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
#include "config.h"
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
#include <errno.h>
|
|
Packit |
b802ec |
#include <stdio.h>
|
|
Packit |
b802ec |
#include <stdlib.h>
|
|
Packit |
b802ec |
#include <string.h>
|
|
Packit |
b802ec |
#include <unistd.h>
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
#ifdef HAVE_LIBCAP
|
|
Packit |
b802ec |
#include <sys/capability.h>
|
|
Packit |
b802ec |
#endif
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
#include "wait.h"
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
/* Drop SUID privileges. To be used after accquiring raw sockets. */
|
|
Packit |
b802ec |
static
|
|
Packit |
b802ec |
int drop_elevated_permissions(
|
|
Packit |
b802ec |
void)
|
|
Packit |
b802ec |
{
|
|
Packit |
b802ec |
#ifdef HAVE_LIBCAP
|
|
Packit |
b802ec |
cap_t cap;
|
|
Packit |
b802ec |
#endif
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
/* Drop any suid permissions granted */
|
|
Packit |
b802ec |
if (setgid(getgid()) || setuid(getuid())) {
|
|
Packit |
b802ec |
return -1;
|
|
Packit |
b802ec |
}
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
if (geteuid() != getuid() || getegid() != getgid()) {
|
|
Packit |
b802ec |
return -1;
|
|
Packit |
b802ec |
}
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
/*
|
|
Packit |
b802ec |
Drop all process capabilities.
|
|
Packit |
b802ec |
This will revoke anything granted by a commandline 'setcap'
|
|
Packit |
b802ec |
*/
|
|
Packit |
b802ec |
#ifdef HAVE_LIBCAP
|
|
Packit |
b802ec |
cap = cap_get_proc();
|
|
Packit |
b802ec |
if (cap == NULL) {
|
|
Packit |
b802ec |
return -1;
|
|
Packit |
b802ec |
}
|
|
Packit |
b802ec |
if (cap_clear(cap)) {
|
|
Packit |
b802ec |
return -1;
|
|
Packit |
b802ec |
}
|
|
Packit |
b802ec |
if (cap_set_proc(cap)) {
|
|
Packit |
b802ec |
return -1;
|
|
Packit |
b802ec |
}
|
|
Packit |
b802ec |
#endif
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
return 0;
|
|
Packit |
b802ec |
}
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
int main(
|
|
Packit |
b802ec |
int argc,
|
|
Packit |
b802ec |
char **argv)
|
|
Packit |
b802ec |
{
|
|
Packit |
b802ec |
bool command_pipe_open;
|
|
Packit |
b802ec |
struct command_buffer_t command_buffer;
|
|
Packit |
b802ec |
struct net_state_t net_state;
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
/*
|
|
Packit |
b802ec |
To minimize security risk, the only thing done prior to
|
|
Packit |
b802ec |
dropping SUID should be opening the network state for
|
|
Packit |
b802ec |
raw sockets.
|
|
Packit |
b802ec |
*/
|
|
Packit |
b802ec |
init_net_state_privileged(&net_state);
|
|
Packit |
b802ec |
if (drop_elevated_permissions()) {
|
|
Packit |
b802ec |
perror("Unable to drop elevated permissions");
|
|
Packit |
b802ec |
exit(EXIT_FAILURE);
|
|
Packit |
b802ec |
}
|
|
Packit |
b802ec |
init_net_state(&net_state);
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
init_command_buffer(&command_buffer, fileno(stdin));
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
command_pipe_open = true;
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
/*
|
|
Packit |
b802ec |
Dispatch commands and respond to probe replies until the
|
|
Packit |
b802ec |
command stream is closed.
|
|
Packit |
b802ec |
*/
|
|
Packit |
b802ec |
while (true) {
|
|
Packit |
b802ec |
/* Ensure any responses are written before waiting */
|
|
Packit |
b802ec |
fflush(stdout);
|
|
Packit |
b802ec |
wait_for_activity(&command_buffer, &net_state);
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
/*
|
|
Packit |
b802ec |
Receive replies first so that the timestamps are as
|
|
Packit |
b802ec |
close to the response arrival time as possible.
|
|
Packit |
b802ec |
*/
|
|
Packit |
b802ec |
receive_replies(&net_state);
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
if (command_pipe_open) {
|
|
Packit |
b802ec |
if (read_commands(&command_buffer)) {
|
|
Packit |
b802ec |
if (errno == EPIPE) {
|
|
Packit |
b802ec |
command_pipe_open = false;
|
|
Packit |
b802ec |
}
|
|
Packit |
b802ec |
}
|
|
Packit |
b802ec |
}
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
check_probe_timeouts(&net_state);
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
/*
|
|
Packit |
b802ec |
Dispatch commands late so that the window between probe
|
|
Packit |
b802ec |
departure and arriving replies is as small as possible.
|
|
Packit |
b802ec |
*/
|
|
Packit |
b802ec |
dispatch_buffer_commands(&command_buffer, &net_state);
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
/*
|
|
Packit |
b802ec |
If the command pipe has been closed, exit after all
|
|
Packit |
b802ec |
in-flight probes have reported their status.
|
|
Packit |
b802ec |
*/
|
|
Packit |
b802ec |
if (!command_pipe_open) {
|
|
Packit |
b802ec |
if (net_state.outstanding_probe_count == 0) {
|
|
Packit |
b802ec |
break;
|
|
Packit |
b802ec |
}
|
|
Packit |
b802ec |
}
|
|
Packit |
b802ec |
}
|
|
Packit |
b802ec |
|
|
Packit |
b802ec |
return 0;
|
|
Packit |
b802ec |
}
|