]> git.gsnw.org Git - fping.git/commitdiff
linux: account for missing IP header block when using SOCK_DGRAM
authorSteven Noonan <steven@uplinklabs.net>
Thu, 27 Feb 2020 20:16:21 +0000 (12:16 -0800)
committerSteven Noonan <steven@uplinklabs.net>
Thu, 27 Feb 2020 21:46:38 +0000 (13:46 -0800)
Linux doesn't include an IP header in the payload when using an
unprivileged SOCK_DGRAM socket.

Signed-off-by: Steven Noonan <steven@uplinklabs.net>
src/fping.c
src/fping.h
src/socket4.c

index 029cd30d6a7ea84beee861819b804f0489603801..a48dfe703564153cd18ac14308b2f4167bc147ee 100644 (file)
@@ -232,6 +232,7 @@ HOST_ENTRY* ev_last;
 char* prog;
 int ident4 = 0; /* our icmp identity field */
 int socket4 = -1;
+int using_sock_dgram4 = 0;
 #ifndef IPV6
 int hints_ai_family = AF_INET;
 #else
@@ -359,7 +360,7 @@ int main(int argc, char** argv)
         usage(0);
     }
 
-    socket4 = open_ping_socket_ipv4();
+    socket4 = open_ping_socket_ipv4(&using_sock_dgram4);
 #ifdef IPV6
     socket6 = open_ping_socket_ipv6();
     /* if called (sym-linked) via 'fping6', imply '-6'
@@ -1836,19 +1837,22 @@ int decode_icmp_ipv4(
     unsigned short* id,
     unsigned short* seq)
 {
-    struct ip* ip = (struct ip*)reply_buf;
     struct icmp* icp;
     int hlen = 0;
 
+    if (!using_sock_dgram4) {
+        struct ip* ip = (struct ip*)reply_buf;
+
 #if defined(__alpha__) && __STDC__ && !defined(__GLIBC__)
-    /* The alpha headers are decidedly broken.
-     * Using an ANSI compiler, it provides ip_vhl instead of ip_hl and
-     * ip_v.  So, to get ip_hl, we mask off the bottom four bits.
-     */
-    hlen = (ip->ip_vhl & 0x0F) << 2;
+        /* The alpha headers are decidedly broken.
+         * Using an ANSI compiler, it provides ip_vhl instead of ip_hl and
+         * ip_v.  So, to get ip_hl, we mask off the bottom four bits.
+         */
+        hlen = (ip->ip_vhl & 0x0F) << 2;
 #else
-    hlen = ip->ip_hl << 2;
+        hlen = ip->ip_hl << 2;
 #endif
+    }
 
     if (reply_buf_len < hlen + ICMP_MINLEN) {
         /* too short */
@@ -2091,6 +2095,10 @@ int wait_for_reply(long wait_time)
         if (id != ident4) {
             return 1; /* packet received, but not the one we are looking for! */
         }
+        if (using_sock_dgram4) {
+            /* IP header is not included in read SOCK_DGRAM ICMP responses */
+            result += sizeof(struct ip);
+        }
     }
 #ifdef IPV6
     else if (response_addr.ss_family == AF_INET6) {
index 3f9875a08f3f9b0d308b169673c76f8ec5b2cb2a..6c2a84bd53c076a6a9218df025f552a6e9f8a17e 100644 (file)
@@ -14,7 +14,7 @@ int in_cksum( unsigned short *p, int n );
 extern int random_data_flag;
 
 /* socket.c */
-int  open_ping_socket_ipv4();
+int  open_ping_socket_ipv4(int *using_sock_dgram);
 void init_ping_buffer_ipv4(size_t ping_data_size);
 void socket_set_src_addr_ipv4(int s, struct in_addr *src_addr, int *ident);
 int  socket_sendto_ping_ipv4(int s, struct sockaddr *saddr, socklen_t saddr_len, uint16_t icmp_seq, uint16_t icmp_id);
index 87e6545261812a8eb9923a3390be3cf0ea2dd007..9787a9fa6310c3a5bfba45b229e28cdf8a1acada 100644 (file)
@@ -47,7 +47,7 @@
 char* ping_buffer_ipv4 = 0;
 size_t ping_pkt_size_ipv4;
 
-int open_ping_socket_ipv4()
+int open_ping_socket_ipv4(int *using_sock_dgram)
 {
     struct protoent* proto;
     int s;
@@ -56,6 +56,8 @@ int open_ping_socket_ipv4()
     if ((proto = getprotobyname("icmp")) == NULL)
         crash_and_burn("icmp: unknown protocol");
 
+    *using_sock_dgram = 0;
+
     /* create raw socket for ICMP calls (ping) */
     s = socket(AF_INET, SOCK_RAW, proto->p_proto);
     if (s < 0) {
@@ -64,6 +66,13 @@ int open_ping_socket_ipv4()
         if (s < 0) {
             return -1;
         }
+
+#ifdef __linux__
+        /* We only treat SOCK_DGRAM differently on Linux, where the IPv4 header
+         * structure is missing in the message.
+         */
+        *using_sock_dgram = 1;
+#endif
     }
 
     /* Make sure that we use non-blocking IO */