]> git.gsnw.org Git - fping.git/commitdiff
Option to show used IP source address in output
authorGerman Service Network <support@gsnw.de>
Sat, 14 Feb 2026 09:33:24 +0000 (10:33 +0100)
committerSebastian <176771227+gsnw-sebast@users.noreply.github.com>
Sat, 8 Aug 2026 06:32:20 +0000 (08:32 +0200)
CHANGELOG.md
ci/test-11-unpriv.pl
ci/test-16-json-output.pl
doc/fping.pod
src/flags.c
src/flags.h
src/fping.c
src/fping.h
src/output.c

index 4b3942ae60aebbd001d75c5b3e1709bb160cd891..b087d40efafda565029a635c569d2704d1d2a5a4 100644 (file)
@@ -3,6 +3,7 @@ Next
 
 ## New features
 
+- New option --print-srcaddr to show used IP source address in output (#461, thanks @gsnw-sebast)
 - New option --oiface for outgoing interface (#463, thanks @gsnw-sebast)
 
 ## Bugfixes and other changes
index aea3e8f235270a852238513c5ead00a8a65eb866..5bd13d54c1168350575813c8532e94b737605ff3 100755 (executable)
@@ -40,7 +40,7 @@ else {
 }
 
 sub test_unprivileged_works {
-    plan tests => 18;
+    plan tests => 21;
 
     {
         my $cmd = Test::Command->new(cmd => "$fping_copy 127.0.0.1");
@@ -48,6 +48,12 @@ sub test_unprivileged_works {
         $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-tos 127.0.0.1");
         $cmd->exit_is_num(0);
index 02e9fc6551ed38c9fbd4159fcd7cc492ccfc3be1..f4add6acc9349fd7cb0669319d43f1e5bad7f769 100644 (file)
@@ -1,6 +1,6 @@
 #!/usr/bin/perl -w
 
-use Test::Command tests => 63;
+use Test::Command tests => 66;
 use Test::More;
 
 # fping -J -c 2 127.0.0.1
@@ -98,6 +98,13 @@ $cmd->stdout_like(qr/^\{"resp":\s\{"timestamp":\s"[\d+-]+\s[\d+:]+",\s"host":\s"
 $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 -q 127.0.0.1
 {
 my $cmd = Test::Command->new(cmd => "fping -J -c 1 -q 127.0.0.1");
index f674b18f2922273a1b85b86bcface2c4262b822b..5b2a07fe37ca0bfbd8d2003a6ddadeb327e7b782 100644 (file)
@@ -259,6 +259,12 @@ 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.
+IPv6 is currently not supported.
+
 =item B<--seqmap-timeout>=I<MSEC>
 
 Timeout for sequence number mappings in milliseconds. Sequence numbers can
index 6b071b34d73d65a0dddc92213692ebc7a3e1c65c..bf2e9aca1bccca10d7c38611f445cef0e3240d7b 100644 (file)
@@ -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;
index 84f345ec593f7263831278a5f484e33711d226f9..84ff8bd633b18f8db4714903d9ca74dc576ff866 100644 (file)
@@ -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;
index 140ce49a4d892721005d4685d4c62ff41a590381..4ada8fd989dbca9dbe8547b618bcfaf55806b25f 100644 (file)
@@ -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;
@@ -534,6 +541,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 },
@@ -597,6 +605,8 @@ int main(int argc, char **argv)
                     }
                 }
 #endif
+            } else if (strstr(optparse_state.optlongname, "print-srcaddr") != NULL) {
+                opt_print_srcaddr_on = 1;
             } else if (strstr(optparse_state.optlongname, "seqmap-timeout") != NULL) {
                 opt_seqmap_timeout = strtod_strict(optparse_state.optarg) * 1000000;
             } else if (strstr(optparse_state.optlongname, "oiface") != NULL) {
@@ -2240,9 +2250,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;
 
@@ -2355,6 +2366,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;
 }
 
@@ -2365,7 +2383,8 @@ 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 icmp6_hdr *icp;
 
@@ -2474,6 +2493,11 @@ int decode_icmp_ipv6(
     *id = icp->icmp6_id;
     *seq = ntohs(icp->icmp6_seq);
 
+    if (opt_print_srcaddr_on) {
+        strncpy(ip_header_res->src_addr, "not supported", sizeof(ip_header_res->src_addr) - 1);
+        ip_header_res->src_addr[sizeof(ip_header_res->src_addr) - 1] = '\0';
+    }
+
     return 1;
 }
 #endif
@@ -2542,7 +2566,8 @@ int wait_for_reply(int64_t wait_time)
                 buffer,
                 sizeof(buffer),
                 &id,
-                &seq)) {
+                &seq,
+                &ip_header_res)) {
             return 1;
         }
         if (id != ident6) {
@@ -3140,5 +3165,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 (IPv6 is currently not supported).\n");
     exit(is_error);
 }
index 36f129106750b2badec04e42861c90dc4afaa9c9..ef2ca79d1e31eb3f907b6b43dbf21090ee6be20f 100644 (file)
@@ -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 {
index c0de11229e09ec302c5013e6e048180b25141bcc..2ce3047fec19ab2aadec1a3cb43776fa5dea6213 100644 (file)
@@ -233,6 +233,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 defined(HAVE_IP_RECVTOS)
     if(opt_print_tos_on) {
         if(ip_header_res->tos != -1) {
@@ -281,6 +285,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 defined(HAVE_IP_RECVTOS)
     if(opt_print_tos_on) {
         if(ip_header_res->tos != -1) {