From 1486bf209baa49724c7f776463d2ba5858fa0ff4 Mon Sep 17 00:00:00 2001 From: Steven Noonan Date: Thu, 27 Feb 2020 10:53:25 -0800 Subject: [PATCH] use kernel-assigned ping ident value 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 --- src/fping.c | 40 ++++++++++++++++++++++++---------------- src/fping.h | 4 ++-- src/socket4.c | 18 +++++++++++++----- src/socket6.c | 14 +++++++++++--- 4 files changed, 50 insertions(+), 26 deletions(-) diff --git a/src/fping.c b/src/fping.c index d7abe4a..029cd30 100644 --- a/src/fping.c +++ b/src/fping.c @@ -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, ¤t_time); if (seqmap_value == NULL) { return 1; diff --git a/src/fping.h b/src/fping.h index 232e7ea..3f9875a 100644 --- a/src/fping.h +++ b/src/fping.h @@ -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 diff --git a/src/socket4.c b/src/socket4.c index e65440a..87e6545 100644 --- a/src/socket4.c +++ b/src/socket4.c @@ -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) { diff --git a/src/socket6.c b/src/socket6.c index c576b0e..433e0e0 100644 --- a/src/socket6.c +++ b/src/socket6.c @@ -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) {