]> git.gsnw.org Git - fping.git/commitdiff
use kernel-assigned ping ident value
authorSteven Noonan <steven@uplinklabs.net>
Thu, 27 Feb 2020 18:53:25 +0000 (10:53 -0800)
committerSteven Noonan <steven@uplinklabs.net>
Thu, 27 Feb 2020 21:46:38 +0000 (13:46 -0800)
On Linux, when running with an unprivileged process, the kernel does not
respect the assigned "id" field. So in that scenario we need to ask the
kernel what assignment it has given us instead.

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

index d7abe4a813d6000f805d7f6a443ff0c62bf16bd3..029cd30d6a7ea84beee861819b804f0489603801 100644 (file)
@@ -230,11 +230,12 @@ HOST_ENTRY* ev_first;
 HOST_ENTRY* ev_last;
 
 char* prog;
-int ident; /* our pid */
+int ident4 = 0; /* our icmp identity field */
 int socket4 = -1;
 #ifndef IPV6
 int hints_ai_family = AF_INET;
 #else
+int ident6 = 0;
 int socket6 = -1;
 int hints_ai_family = AF_UNSPEC;
 #endif
@@ -368,6 +369,11 @@ int main(int argc, char** argv)
     }
 #endif
 
+    memset(&src_addr, 0, sizeof(src_addr));
+#ifdef IPV6
+    memset(&src_addr6, 0, sizeof(src_addr6));
+#endif
+
     if ((uid = getuid())) {
         /* drop privileges */
         if (setuid(getuid()) == -1)
@@ -375,7 +381,7 @@ int main(int argc, char** argv)
     }
 
     optparse_init(&optparse_state, argv);
-    ident = getpid() & 0xFFFF;
+    ident4 = ident6 = getpid() & 0xFFFF;
     verbose_flag = 1;
     backoff_flag = 1;
     opterr = 1;
@@ -965,12 +971,12 @@ int main(int argc, char** argv)
         exit(num_noaddress ? 2 : 1);
     }
 
-    if (src_addr_set && socket4 >= 0) {
-        socket_set_src_addr_ipv4(socket4, &src_addr);
+    if (socket4 >= 0) {
+        socket_set_src_addr_ipv4(socket4, &src_addr, &ident4);
     }
 #ifdef IPV6
-    if (src_addr6_set && socket6 >= 0) {
-        socket_set_src_addr_ipv6(socket6, &src_addr6);
+    if (socket6 >= 0) {
+        socket_set_src_addr_ipv6(socket6, &src_addr6, &ident6);
     }
 #endif
 
@@ -1674,11 +1680,11 @@ int send_ping(HOST_ENTRY* h)
 #endif /* DEBUG || _DEBUG */
 
     if (h->saddr.ss_family == AF_INET && socket4 >= 0) {
-        n = socket_sendto_ping_ipv4(socket4, (struct sockaddr*)&h->saddr, h->saddr_len, myseq, ident);
+        n = socket_sendto_ping_ipv4(socket4, (struct sockaddr*)&h->saddr, h->saddr_len, myseq, ident4);
     }
 #ifdef IPV6
     else if (h->saddr.ss_family == AF_INET6 && socket6 >= 0) {
-        n = socket_sendto_ping_ipv6(socket6, (struct sockaddr*)&h->saddr, h->saddr_len, myseq, ident);
+        n = socket_sendto_ping_ipv6(socket6, (struct sockaddr*)&h->saddr, h->saddr_len, myseq, ident6);
     }
 #endif
     else {
@@ -1871,7 +1877,7 @@ int decode_icmp_ipv4(
 
         sent_icmp = (struct icmp*)(reply_buf + hlen + ICMP_MINLEN + sizeof(struct ip));
 
-        if (sent_icmp->icmp_type != ICMP_ECHO || ntohs(sent_icmp->icmp_id) != ident) {
+        if (sent_icmp->icmp_type != ICMP_ECHO || sent_icmp->icmp_id != ident4) {
             /* not caused by us */
             return 0;
         }
@@ -1920,7 +1926,7 @@ int decode_icmp_ipv4(
         return 0;
     }
 
-    *id = ntohs(icp->icmp_id);
+    *id = icp->icmp_id;
     *seq = ntohs(icp->icmp_seq);
 
     return 1;
@@ -1963,7 +1969,7 @@ int decode_icmp_ipv6(
 
         sent_icmp = (struct icmp6_hdr*)(reply_buf + sizeof(struct icmp6_hdr) + sizeof(struct ip));
 
-        if (sent_icmp->icmp6_type != ICMP_ECHO || ntohs(sent_icmp->icmp6_id) != ident) {
+        if (sent_icmp->icmp6_type != ICMP_ECHO || sent_icmp->icmp6_id != ident6) {
             /* not caused by us */
             return 0;
         }
@@ -2012,7 +2018,7 @@ int decode_icmp_ipv6(
         return 0;
     }
 
-    *id = ntohs(icp->icmp6_id);
+    *id = icp->icmp6_id;
     *seq = ntohs(icp->icmp6_seq);
 
     return 1;
@@ -2082,6 +2088,9 @@ int wait_for_reply(long wait_time)
                 &seq)) {
             return 1;
         }
+        if (id != ident4) {
+            return 1; /* packet received, but not the one we are looking for! */
+        }
     }
 #ifdef IPV6
     else if (response_addr.ss_family == AF_INET6) {
@@ -2094,16 +2103,15 @@ int wait_for_reply(long wait_time)
                 &seq)) {
             return 1;
         }
+        if (id != ident6) {
+            return 1; /* packet received, but not the one we are looking for! */
+        }
     }
 #endif
     else {
         return 1;
     }
 
-    if (id != ident) {
-        return 1; /* packet received, but not the one we are looking for! */
-    }
-
     seqmap_value = seqmap_fetch(seq, &current_time);
     if (seqmap_value == NULL) {
         return 1;
index 232e7eab0be52c9b8a1bd93e948d62d48bf173d6..3f9875a08f3f9b0d308b169673c76f8ec5b2cb2a 100644 (file)
@@ -16,12 +16,12 @@ extern int random_data_flag;
 /* socket.c */
 int  open_ping_socket_ipv4();
 void init_ping_buffer_ipv4(size_t ping_data_size);
-void socket_set_src_addr_ipv4(int s, struct in_addr *src_addr);
+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);
 #ifdef IPV6
 int  open_ping_socket_ipv6();
 void init_ping_buffer_ipv6(size_t ping_data_size);
-void socket_set_src_addr_ipv6(int s, struct in6_addr *src_addr);
+void socket_set_src_addr_ipv6(int s, struct in6_addr *src_addr, int *ident);
 int  socket_sendto_ping_ipv6(int s, struct sockaddr *saddr, socklen_t saddr_len, uint16_t icmp_seq, uint16_t icmp_id);
 #endif
 
index e65440a1299ec0a63ee37ad7f83bf8f973053734..87e6545261812a8eb9923a3390be3cf0ea2dd007 100644 (file)
@@ -89,15 +89,23 @@ void init_ping_buffer_ipv4(size_t ping_data_size)
         crash_and_burn("can't malloc ping packet");
 }
 
-void socket_set_src_addr_ipv4(int s, struct in_addr* src_addr)
+void socket_set_src_addr_ipv4(int s, struct in_addr* src_addr, int *ident)
 {
     struct sockaddr_in sa;
-    memset(&sa, 0, sizeof(sa));
+    socklen_t len = sizeof(sa);
+
+    memset(&sa, 0, len);
     sa.sin_family = AF_INET;
     sa.sin_addr = *src_addr;
-
-    if (bind(s, (struct sockaddr*)&sa, sizeof(sa)) < 0)
+    if (bind(s, (struct sockaddr*)&sa, len) < 0)
         errno_crash_and_burn("cannot bind source address");
+
+    memset(&sa, 0, len);
+    if (getsockname(s, (struct sockaddr *)&sa, &len) < 0)
+        errno_crash_and_burn("can't get ICMP socket identity");
+
+    if (sa.sin_port)
+        *ident = sa.sin_port;
 }
 
 unsigned short calcsum(unsigned short* buffer, int length)
@@ -128,7 +136,7 @@ int socket_sendto_ping_ipv4(int s, struct sockaddr* saddr, socklen_t saddr_len,
     icp->icmp_code = 0;
     icp->icmp_cksum = 0;
     icp->icmp_seq = htons(icmp_seq_nr);
-    icp->icmp_id = htons(icmp_id_nr);
+    icp->icmp_id = icmp_id_nr;
 
     if (random_data_flag) {
         for (n = ((char*)&icp->icmp_data - (char*)icp); n < ping_pkt_size_ipv4; ++n) {
index c576b0ee1b2b1878780d3a6422bfc5be833796c5..433e0e0eb1eded318c379eb5582dc5bb91e3c3ed 100644 (file)
@@ -88,15 +88,23 @@ void init_ping_buffer_ipv6(size_t ping_data_size)
         crash_and_burn("can't malloc ping packet");
 }
 
-void socket_set_src_addr_ipv6(int s, struct in6_addr* src_addr)
+void socket_set_src_addr_ipv6(int s, struct in6_addr* src_addr, int *ident)
 {
     struct sockaddr_in6 sa;
+    socklen_t len = sizeof(sa);
+
     memset(&sa, 0, sizeof(sa));
     sa.sin6_family = AF_INET6;
     sa.sin6_addr = *src_addr;
-
     if (bind(s, (struct sockaddr*)&sa, sizeof(sa)) < 0)
         errno_crash_and_burn("cannot bind source address");
+
+    memset(&sa, 0, len);
+    if (getsockname(s, (struct sockaddr *)&sa, &len) < 0)
+        errno_crash_and_burn("can't get ICMP socket identity");
+
+    if (sa.sin6_port)
+        *ident = sa.sin6_port;
 }
 
 int socket_sendto_ping_ipv6(int s, struct sockaddr* saddr, socklen_t saddr_len, uint16_t icmp_seq_nr, uint16_t icmp_id_nr)
@@ -108,7 +116,7 @@ int socket_sendto_ping_ipv6(int s, struct sockaddr* saddr, socklen_t saddr_len,
     icp->icmp6_type = ICMP6_ECHO_REQUEST;
     icp->icmp6_code = 0;
     icp->icmp6_seq = htons(icmp_seq_nr);
-    icp->icmp6_id = htons(icmp_id_nr);
+    icp->icmp6_id = icmp_id_nr;
 
     if (random_data_flag) {
         for (n = sizeof(struct icmp6_hdr); n < ping_pkt_size_ipv6; ++n) {