Skip to content

Commit

Permalink
use kernel-assigned ping ident value
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
tycho committed Feb 27, 2020
1 parent bc5017b commit 1486bf2
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 26 deletions.
40 changes: 24 additions & 16 deletions src/fping.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -368,14 +369,19 @@ 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)
perror("cannot setuid");
}

optparse_init(&optparse_state, argv);
ident = getpid() & 0xFFFF;
ident4 = ident6 = getpid() & 0xFFFF;
verbose_flag = 1;
backoff_flag = 1;
opterr = 1;
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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) {
Expand All @@ -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;
Expand Down
4 changes: 2 additions & 2 deletions src/fping.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
18 changes: 13 additions & 5 deletions src/socket4.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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) {
Expand Down
14 changes: 11 additions & 3 deletions src/socket6.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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) {
Expand Down

0 comments on commit 1486bf2

Please sign in to comment.