schweikert / fping

High performance ping tool
https://fping.org
Other
998 stars 249 forks source link

Future request : print returned TOS value #68

Open GBert opened 9 years ago

GBert commented 9 years ago

Ping with TOS field is already in the code, but printing the result is missing. I know that you don't like to change the output so I have added tos_flag which is set by the -O flag (https://github.com/GBert/fping/commit/32e266efec137f19437a845c3ed3ce4d77a035c5)

--- a/src/fping.c
+++ b/src/fping.c
@@ -230,6 +230,7 @@ typedef struct host_entry
      int                  min_reply_i;        /* shortest response time */
      int                  total_time_i;       /* sum of response times */
      int                  *resp_times;        /* individual response times */
+     int                  tos;                /* individual tos field */
 #if defined( DEBUG ) || defined( _DEBUG )
      int                  *sent_times;        /* per-sent-ping timestamp */
 #endif /* DEBUG || _DEBUG */
@@ -295,6 +296,7 @@ struct timezone tz;

 /* switches */
 int generate_flag = 0;              /* flag for IP list generation */
+int tos_flag = 0;                        /* flag if tos should be printed */
 int verbose_flag, quiet_flag, stats_flag, unreachable_flag, alive_flag;
 int elapsed_flag, version_flag, count_flag, loop_flag;
 int per_recv_flag, report_all_rtts_flag, name_flag, addr_flag, backoff_flag;
@@ -363,7 +365,7 @@ int main( int argc, char **argv )
     int c, i, n;
     char *buf;
     uid_t uid;
-    int tos = 0;
+    int tos = 0;
     HOST_ENTRY *cursor;

     s = open_ping_socket();
@@ -548,6 +550,7 @@ int main( int argc, char **argv )
                 if ( setsockopt(s, IPPROTO_IP, IP_TOS, &tos, sizeof(tos))) {
                     perror("setting type of service octet IP_TOS");
                 }
+               tos_flag = 1;
             }
             else {
                 usage(1);
@@ -1605,6 +1608,7 @@ int wait_for_reply(long wait_time)
         sum_replies += this_reply;
         h->total_time += this_reply;
         h->total_time_i += this_reply;
+        h->tos = ip->ip_tos;
         total_replies++;
     }

@@ -1664,7 +1668,10 @@ int wait_for_reply(long wait_time)
             printf( "%s", h->host );

             if( verbose_flag )
-                printf( " is alive" );
+                if ( tos_flag )
+                    printf( " is alive (TOS %d)", h->tos );
+                else
+                    printf( " is alive" );

             if( elapsed_flag )
                 printf( " (%s ms)", sprint_tm( this_reply ) );

Here is the output:

% ./fping -A -n server
server (192.168.100.10) is alive

% ./fping -A -n -O 0 server
server (192.168.100.10) is alive (TOS 0)

% ./fping -A -n -O 184 server
server (192.168.100.10) is alive (TOS 184)
gsnw commented 3 weeks ago

The example patch is a bit older, therefore no longer functional. I found something in the function "decode_icmp_ipv4" while searching for tos.

Unfortunately the value with ./fping -A -n -O 184 127.0.0.1 is always 0

gdb output

(gdb) print *icp
$1 = {icmp_type = 0 '\000', icmp_code = 0 '\000', icmp_cksum = 7861, 
  icmp_hun = {ih_pptr = 74 'J', ih_gwaddr = {s_addr = 57674}, ih_idseq = {
      icd_id = 57674, icd_seq = 0}, ih_void = 57674, ih_pmtu = {
      ipm_void = 57674, ipm_nextmtu = 0}, ih_rtradv = {irt_num_addrs = 74 'J', 
      irt_wpa = 225 '\341', irt_lifetime = 0}}, icmp_dun = {id_ts = {
      its_otime = 0, its_rtime = 0, its_ttime = 0}, id_ip = {idi_ip = {
        ip_hl = 0, ip_v = 0, ip_tos = 0 '\000', ip_len = 0, ip_id = 0, 
        ip_off = 0, ip_ttl = 0 '\000', ip_p = 0 '\000', ip_sum = 0, ip_src = {
          s_addr = 0}, ip_dst = {s_addr = 0}}}, id_radv = {ira_addr = 0, 
      ira_preference = 0}, id_mask = 0, id_data = ""}}
auerswal commented 3 weeks ago

On Ubuntu 20.04 LTS I see a reflected TOS byte using tcpdump:

$ jobs
[1]+  Running                 sudo tcpdump -nlv -i lo icmp &
$ ./src/fping -A -n -O184 127.0.0.1
16:12:39.710673 IP (tos 0xb8, ttl 64, id 58111, offset 0, flags [DF], proto ICMP (1), length 84)
localhost (127.0.0.1) is alive
    127.0.0.1 > 127.0.0.1: ICMP echo request, id 13257, seq 0, length 64
16:12:39.710686 IP (tos 0xb8, ttl 64, id 58112, offset 0, flags [none], proto ICMP (1), length 84)
    127.0.0.1 > 127.0.0.1: ICMP echo reply, id 13257, seq 0, length 64

Without -O…, the TOS byte is zero:

$ ./src/fping -A -n 127.0.0.1
localhost (127.0.0.1) is alive
16:16:20.988235 IP (tos 0x0, ttl 64, id 15164, offset 0, flags [DF], proto ICMP (1), length 84)
    127.0.0.1 > 127.0.0.1: ICMP echo request, id 13336, seq 0, length 64
16:16:20.988251 IP (tos 0x0, ttl 64, id 15165, offset 0, flags [none], proto ICMP (1), length 84)
    127.0.0.1 > 127.0.0.1: ICMP echo reply, id 13336, seq 0, length 64

I think it could be useful to print the received TOS byte value. I am still undecided if this should be enabled as a side-effect of -O…, an extension to -O… similar to -Q…,cumulative, via a new option (e.g., --print-tos), or whenever a non-zero TOS byte is received. I am also unsure what to do with the other output modes, e.g., -c….

gsnw commented 3 weeks ago

That's right, I can also reproduce it. However, the struct ip *ip; from the earlier wait_for_reply() function is missing. The whole thing has partially migrated to the decode_icmp_ipv4() function, where there is a struct ip *ip, which is only called with !using_sock_dgram4.

Had hoped it was still there somewhere else. I'll see how I can best restore it so that TOS comes in a variable

gsnw commented 3 weeks ago

I have create a test and the TOS value is only present, when fping execute as root.

Test Patch

diff --git a/src/fping.c b/src/fping.c
index f7fe6a9..7e2633f 100644
--- a/src/fping.c
+++ b/src/fping.c
@@ -2157,6 +2157,7 @@ int decode_icmp_ipv4(
 {
     struct icmp *icp;
     int hlen = 0;
+    struct ip *myip;

     if (!using_sock_dgram4) {
         struct ip *ip = (struct ip *)reply_buf;
@@ -2183,7 +2184,8 @@ int decode_icmp_ipv4(
     }

     icp = (struct icmp *)(reply_buf + hlen);
-
+    myip = (struct ip * )reply_buf;
+    
     if (icp->icmp_type != ICMP_ECHOREPLY) {
         /* Handle other ICMP packets */
         struct icmp *sent_icmp;

GDB Output

(gdb) print *myip
$1 = {ip_hl = 5, ip_v = 4, ip_tos = 184 '\270', ip_len = 21504, ip_id = 54456, 
  ip_off = 0, ip_ttl = 64 '@', ip_p = 1 '\001', ip_sum = 6851, ip_src = {
    s_addr = 16777343}, ip_dst = {s_addr = 16777343}}
(gdb) print *icp
$2 = {icmp_type = 0 '\000', icmp_code = 0 '\000', icmp_cksum = 63151, 
  icmp_hun = {ih_pptr = 80 'P', ih_gwaddr = {s_addr = 2384}, ih_idseq = {
      icd_id = 2384, icd_seq = 0}, ih_void = 2384, ih_pmtu = {ipm_void = 2384, 
      ipm_nextmtu = 0}, ih_rtradv = {irt_num_addrs = 80 'P', irt_wpa = 9 '\t', 
      irt_lifetime = 0}}, icmp_dun = {id_ts = {its_otime = 0, its_rtime = 0, 
      its_ttime = 0}, id_ip = {idi_ip = {ip_hl = 0, ip_v = 0, 
        ip_tos = 0 '\000', ip_len = 0, ip_id = 0, ip_off = 0, 
        ip_ttl = 0 '\000', ip_p = 0 '\000', ip_sum = 0, ip_src = {s_addr = 0}, 
        ip_dst = {s_addr = 0}}}, id_radv = {ira_addr = 0, ira_preference = 0}, 
    id_mask = 0, id_data = ""}}