Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ Next

## New features

- New option --print-srcaddr to show used IP source address in output (#461, thanks @gsnw-sebast)
- Add IPv6 support to --print-srcaddr (#462, thanks @gsnw-sebast)

## Bugfixes and other changes

- ci: Removed travis-ci (#446, thanks @gsnw-sebast)
Expand Down
14 changes: 13 additions & 1 deletion ci/test-11-unpriv.pl
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,26 @@ sub get_ping_gid_range {
}

sub test_unprivileged_works {
plan tests => 18;
plan tests => 24;

{
my $cmd = Test::Command->new(cmd => "$fping_copy 127.0.0.1");
$cmd->exit_is_num(0);
$cmd->stdout_is_eq("127.0.0.1 is alive\n");
$cmd->stderr_is_eq("");
}
{
my $cmd = Test::Command->new(cmd => "$fping_copy --print-srcaddr 127.0.0.1");
$cmd->exit_is_num(0);
$cmd->stdout_like(qr{127\.0\.0\.1 is alive \(SRC (?:\d+\.\d+\.\d+\.\d+|unknown)\)\n});
$cmd->stderr_is_eq("");
}
{
my $cmd = Test::Command->new(cmd => "$fping_copy --print-srcaddr ::1");
$cmd->exit_is_num(0);
$cmd->stdout_like(qr{::1 is alive \(SRC (?:::1|unknown)\)\n});
$cmd->stderr_is_eq("");
}
{
my $cmd = Test::Command->new(cmd => "$fping_copy --print-tos 127.0.0.1");
$cmd->exit_is_num(0);
Expand Down
20 changes: 19 additions & 1 deletion ci/test-16-json-output.pl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/perl -w

use Test::Command tests => 63;
use Test::Command tests => 69;
use Test::More;

# fping -J -c 2 127.0.0.1
Expand Down Expand Up @@ -98,6 +98,24 @@
$cmd->stderr_is_eq("");
}

# fping -J -c 1 --print-srcaddr 127.0.0.1
{
my $cmd = Test::Command->new(cmd => "fping -J -c 1 --print-srcaddr 127.0.0.1");
$cmd->exit_is_num(0);
$cmd->stdout_like(qr/^\{"resp":\s\{"host":\s"127\.0\.0\.1",\s"seq":\s0,\s"size":\s\d+,\s"rtt":\s\d+\.\d+,\s"src":\s"\d+\.\d+\.\d+\.\d+"\}\}
\{"summary":\s\{"host":\s"127\.0\.0\.1",\s"xmt":\s\d+,\s"rcv":\s\d+,\s"loss":\s\d+,\s"rttMin":\s\d+\.\d+,\s"rttAvg":\s\d+\.\d+,\s"rttMax":\s\d+\.\d+\}\}\n?$/);
$cmd->stderr_is_eq("");
}

# fping -J -c 1 --print-srcaddr ::1
{
my $cmd = Test::Command->new(cmd => "fping -J -c 1 --print-srcaddr ::1");
$cmd->exit_is_num(0);
$cmd->stdout_like(qr/^\{"resp":\s\{"host":\s"::1",\s"seq":\s0,\s"size":\s\d+,\s"rtt":\s\d+\.\d+,\s"src":\s"::1"\}\}
\{"summary":\s\{"host":\s"::1",\s"xmt":\s\d+,\s"rcv":\s\d+,\s"loss":\s\d+,\s"rttMin":\s\d+\.\d+,\s"rttAvg":\s\d+\.\d+,\s"rttMax":\s\d+\.\d+\}\}\n?$/);
$cmd->stderr_is_eq("");
}

# fping -J -c 1 -q 127.0.0.1
{
my $cmd = Test::Command->new(cmd => "fping -J -c 1 -q 127.0.0.1");
Expand Down
5 changes: 5 additions & 0 deletions doc/fping.pod
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,11 @@ Print cumulative statistics upon exit.

Set source address.

=item B<--print-srcaddr>

Displays the used IP source address in the output. If B<fping> cannot read the source address,
"(SRC unknown)" is returned.

=item B<--seqmap-timeout>=I<MSEC>

Timeout for sequence number mappings in milliseconds. Sequence numbers can
Expand Down
1 change: 1 addition & 0 deletions src/flags.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ int opt_print_netdata_on = 0;
int opt_print_json_on = 0;
int opt_print_tos_on = 0;
int opt_print_ttl_on = 0;
int opt_print_srcaddr_on = 0;
int opt_per_recv_on = 0;
int opt_report_all_rtts_on = 0;
int opt_name_on = 0;
Expand Down
1 change: 1 addition & 0 deletions src/flags.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ extern int opt_print_netdata_on;
extern int opt_print_json_on;
extern int opt_print_tos_on;
extern int opt_print_ttl_on;
extern int opt_print_srcaddr_on;
extern int opt_per_recv_on;
extern int opt_report_all_rtts_on;
extern int opt_name_on;
Expand Down
70 changes: 64 additions & 6 deletions src/fping.c
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,14 @@ char *icmp6_param_prob_str[ICMP6_PARAM_PROB_MAXCODE + 1] = {
#endif

IP_HEADER_RESULT default_ip_header_result() {
return (IP_HEADER_RESULT){-1, -1, 0x80000000U, 0x80000000U, 0x80000000U};
IP_HEADER_RESULT res;
res.tos = -1;
res.ttl = -1;
res.otime_ms = 0x80000000U;
res.rtime_ms = 0x80000000U;
res.ttime_ms = 0x80000000U;
res.src_addr[0] = '\0';
return res;
}

int event_storage_count;
Expand Down Expand Up @@ -533,6 +540,7 @@ int main(int argc, char **argv)
{ "check-source", 0, OPTPARSE_NONE },
{ "print-tos", 0, OPTPARSE_NONE },
{ "print-ttl", 0, OPTPARSE_NONE },
{ "print-srcaddr", 0, OPTPARSE_NONE },
{ "seqmap-timeout", 0, OPTPARSE_REQUIRED },
#if defined(DEBUG) || defined(_DEBUG)
{ NULL, 'z', OPTPARSE_REQUIRED },
Expand Down Expand Up @@ -595,6 +603,15 @@ int main(int argc, char **argv)
perror("setsockopt IPV6_RECVHOPLIMIT");
}
}
#endif
} else if (strstr(optparse_state.optlongname, "print-srcaddr") != NULL) {
opt_print_srcaddr_on = 1;
#if defined(IPV6) && defined(IPV6_RECVPKTINFO)
if (socket6 >= 0) {
if (setsockopt(socket6, IPPROTO_IPV6, IPV6_RECVPKTINFO, &sock_opt_on, sizeof(sock_opt_on))) {
perror("setsockopt IPV6_RECVPKTINFO");
}
}
#endif
} else if (strstr(optparse_state.optlongname, "seqmap-timeout") != NULL) {
opt_seqmap_timeout = strtod_strict(optparse_state.optarg) * 1000000;
Expand Down Expand Up @@ -2045,7 +2062,13 @@ int receive_packet(int64_t wait_time,
char *reply_buf,
size_t reply_buf_len,
int *ip_header_tos,
int *ip_header_ttl)
int *ip_header_ttl,
#ifdef IPV6
struct in6_addr *recv_dst_addr_ipv6
#else
void *recv_dst_addr_ipv6
#endif
)
{
struct timeval to;
int s = 0;
Expand Down Expand Up @@ -2127,6 +2150,11 @@ int receive_packet(int64_t wait_time,
if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_HOPLIMIT) {
memcpy(ip_header_ttl, CMSG_DATA(cmsg), sizeof(*ip_header_ttl));
}
if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) {
struct in6_pktinfo *pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsg);
if (recv_dst_addr_ipv6)
memcpy(recv_dst_addr_ipv6, &pktinfo->ipi6_addr, sizeof(*recv_dst_addr_ipv6));
}
#endif
}
}
Expand Down Expand Up @@ -2216,9 +2244,10 @@ int decode_icmp_ipv4(
{
struct icmp *icp;
int hlen = 0;
struct ip *ip = NULL;

if (!using_sock_dgram4) {
struct ip *ip = (struct ip *)reply_buf;
ip = (struct ip *)reply_buf;
ip_header_res->tos = ip->ip_tos;
ip_header_res->ttl = ip->ip_ttl;

Expand Down Expand Up @@ -2331,6 +2360,13 @@ int decode_icmp_ipv4(
ip_header_res->ttime_ms = ntohl(icp->icmp_dun.id_ts.its_ttime);
}

if (opt_print_srcaddr_on) {
if (ip == NULL || inet_ntop(AF_INET, &ip->ip_dst, ip_header_res->src_addr, sizeof(ip_header_res->src_addr)) == NULL) {
strncpy(ip_header_res->src_addr, "unknown", sizeof(ip_header_res->src_addr) - 1);
ip_header_res->src_addr[sizeof(ip_header_res->src_addr) - 1] = '\0';
}
}

return hlen;
}

Expand All @@ -2341,7 +2377,9 @@ int decode_icmp_ipv6(
char *reply_buf,
size_t reply_buf_len,
unsigned short *id,
unsigned short *seq)
unsigned short *seq,
IP_HEADER_RESULT *ip_header_res,
struct in6_addr *local_addr)
{
struct icmp6_hdr *icp;

Expand Down Expand Up @@ -2450,6 +2488,13 @@ int decode_icmp_ipv6(
*id = icp->icmp6_id;
*seq = ntohs(icp->icmp6_seq);

if (opt_print_srcaddr_on) {
if (local_addr == NULL || IN6_IS_ADDR_UNSPECIFIED(local_addr) || inet_ntop(AF_INET6, local_addr, ip_header_res->src_addr, sizeof(ip_header_res->src_addr)) == NULL) {
strncpy(ip_header_res->src_addr, "unknown", sizeof(ip_header_res->src_addr) - 1);
ip_header_res->src_addr[sizeof(ip_header_res->src_addr) - 1] = '\0';
}
}

return 1;
}
#endif
Expand All @@ -2469,6 +2514,11 @@ int wait_for_reply(int64_t wait_time)
unsigned short seq;
IP_HEADER_RESULT ip_header_res = default_ip_header_result();

#ifdef IPV6
struct in6_addr recv_dst_addr_ipv6;
memset(&recv_dst_addr_ipv6, 0, sizeof(recv_dst_addr_ipv6));
#endif

/* Receive packet */
result = receive_packet(wait_time, /* max. wait time, in ns */
&recv_time, /* reply_timestamp */
Expand All @@ -2477,7 +2527,12 @@ int wait_for_reply(int64_t wait_time)
buffer, /* reply_buf */
sizeof(buffer), /* reply_buf_len */
&ip_header_res.tos, /* TOS resp. TC byte */
&ip_header_res.ttl /* TTL resp. hop limit */
&ip_header_res.ttl, /* TTL resp. hop limit */
#ifdef IPV6
&recv_dst_addr_ipv6
#else
NULL
#endif
);

if (result <= 0) {
Expand Down Expand Up @@ -2518,7 +2573,9 @@ int wait_for_reply(int64_t wait_time)
buffer,
sizeof(buffer),
&id,
&seq)) {
&seq,
&ip_header_res,
&recv_dst_addr_ipv6)) {
return 1;
}
if (id != ident6) {
Expand Down Expand Up @@ -3113,5 +3170,6 @@ void usage(int is_error)
fprintf(out, " -X, --fast-reachable=N exits true immediately when N hosts are found\n");
fprintf(out, " --print-tos show received TOS value\n");
fprintf(out, " --print-ttl show IP TTL value\n");
fprintf(out, " --print-srcaddr show used IP source address\n");
exit(is_error);
}
1 change: 1 addition & 0 deletions src/fping.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ typedef struct ip_header_result {
uint32_t otime_ms;
uint32_t rtime_ms;
uint32_t ttime_ms;
char src_addr[INET6_ADDRSTRLEN];
} IP_HEADER_RESULT;

typedef struct host_entry {
Expand Down
8 changes: 8 additions & 0 deletions src/output.c
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,10 @@ void print_recv_ext(IP_HEADER_RESULT *ip_header_res, int64_t recv_time, int64_t
ms_since_midnight_utc(recv_time));
}

if (ip_header_res->src_addr[0]) {
printf(" (SRC %s)", ip_header_res->src_addr);
}

if(opt_print_tos_on) {
if(ip_header_res->tos != -1) {
printf(" (TOS %d)", ip_header_res->tos);
Expand Down Expand Up @@ -278,6 +282,10 @@ void print_recv_ext_json(IP_HEADER_RESULT *ip_header_res, int64_t recv_time, int
printf("\"localreceive\": %u}", ms_since_midnight_utc(recv_time));
}

if (ip_header_res->src_addr[0]) {
printf(", \"src\": \"%s\"", ip_header_res->src_addr);
}

if(opt_print_tos_on) {
if(ip_header_res->tos != -1) {
printf(", \"tos\": %d", ip_header_res->tos);
Expand Down