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 <steven@uplinklabs.net>
pull/173/head
Steven Noonan 5 years ago
parent bc5017b329
commit 1486bf209b
No known key found for this signature in database
GPG Key ID: 408EEB508ED0CD4D

@ -230,11 +230,12 @@ HOST_ENTRY* ev_first;
HOST_ENTRY* ev_last; HOST_ENTRY* ev_last;
char* prog; char* prog;
int ident; /* our pid */ int ident4 = 0; /* our icmp identity field */
int socket4 = -1; int socket4 = -1;
#ifndef IPV6 #ifndef IPV6
int hints_ai_family = AF_INET; int hints_ai_family = AF_INET;
#else #else
int ident6 = 0;
int socket6 = -1; int socket6 = -1;
int hints_ai_family = AF_UNSPEC; int hints_ai_family = AF_UNSPEC;
#endif #endif
@ -368,6 +369,11 @@ int main(int argc, char** argv)
} }
#endif #endif
memset(&src_addr, 0, sizeof(src_addr));
#ifdef IPV6
memset(&src_addr6, 0, sizeof(src_addr6));
#endif
if ((uid = getuid())) { if ((uid = getuid())) {
/* drop privileges */ /* drop privileges */
if (setuid(getuid()) == -1) if (setuid(getuid()) == -1)
@ -375,7 +381,7 @@ int main(int argc, char** argv)
} }
optparse_init(&optparse_state, argv); optparse_init(&optparse_state, argv);
ident = getpid() & 0xFFFF; ident4 = ident6 = getpid() & 0xFFFF;
verbose_flag = 1; verbose_flag = 1;
backoff_flag = 1; backoff_flag = 1;
opterr = 1; opterr = 1;
@ -965,12 +971,12 @@ int main(int argc, char** argv)
exit(num_noaddress ? 2 : 1); exit(num_noaddress ? 2 : 1);
} }
if (src_addr_set && socket4 >= 0) { if (socket4 >= 0) {
socket_set_src_addr_ipv4(socket4, &src_addr); socket_set_src_addr_ipv4(socket4, &src_addr, &ident4);
} }
#ifdef IPV6 #ifdef IPV6
if (src_addr6_set && socket6 >= 0) { if (socket6 >= 0) {
socket_set_src_addr_ipv6(socket6, &src_addr6); socket_set_src_addr_ipv6(socket6, &src_addr6, &ident6);
} }
#endif #endif
@ -1674,11 +1680,11 @@ int send_ping(HOST_ENTRY* h)
#endif /* DEBUG || _DEBUG */ #endif /* DEBUG || _DEBUG */
if (h->saddr.ss_family == AF_INET && socket4 >= 0) { 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 #ifdef IPV6
else if (h->saddr.ss_family == AF_INET6 && socket6 >= 0) { 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 #endif
else { else {
@ -1871,7 +1877,7 @@ int decode_icmp_ipv4(
sent_icmp = (struct icmp*)(reply_buf + hlen + ICMP_MINLEN + sizeof(struct ip)); 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 */ /* not caused by us */
return 0; return 0;
} }
@ -1920,7 +1926,7 @@ int decode_icmp_ipv4(
return 0; return 0;
} }
*id = ntohs(icp->icmp_id); *id = icp->icmp_id;
*seq = ntohs(icp->icmp_seq); *seq = ntohs(icp->icmp_seq);
return 1; return 1;
@ -1963,7 +1969,7 @@ int decode_icmp_ipv6(
sent_icmp = (struct icmp6_hdr*)(reply_buf + sizeof(struct icmp6_hdr) + sizeof(struct ip)); 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 */ /* not caused by us */
return 0; return 0;
} }
@ -2012,7 +2018,7 @@ int decode_icmp_ipv6(
return 0; return 0;
} }
*id = ntohs(icp->icmp6_id); *id = icp->icmp6_id;
*seq = ntohs(icp->icmp6_seq); *seq = ntohs(icp->icmp6_seq);
return 1; return 1;
@ -2082,6 +2088,9 @@ int wait_for_reply(long wait_time)
&seq)) { &seq)) {
return 1; return 1;
} }
if (id != ident4) {
return 1; /* packet received, but not the one we are looking for! */
}
} }
#ifdef IPV6 #ifdef IPV6
else if (response_addr.ss_family == AF_INET6) { else if (response_addr.ss_family == AF_INET6) {
@ -2094,16 +2103,15 @@ int wait_for_reply(long wait_time)
&seq)) { &seq)) {
return 1; return 1;
} }
if (id != ident6) {
return 1; /* packet received, but not the one we are looking for! */
}
} }
#endif #endif
else { else {
return 1; return 1;
} }
if (id != ident) {
return 1; /* packet received, but not the one we are looking for! */
}
seqmap_value = seqmap_fetch(seq, &current_time); seqmap_value = seqmap_fetch(seq, &current_time);
if (seqmap_value == NULL) { if (seqmap_value == NULL) {
return 1; return 1;

@ -16,12 +16,12 @@ extern int random_data_flag;
/* socket.c */ /* socket.c */
int open_ping_socket_ipv4(); int open_ping_socket_ipv4();
void init_ping_buffer_ipv4(size_t ping_data_size); 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); int socket_sendto_ping_ipv4(int s, struct sockaddr *saddr, socklen_t saddr_len, uint16_t icmp_seq, uint16_t icmp_id);
#ifdef IPV6 #ifdef IPV6
int open_ping_socket_ipv6(); int open_ping_socket_ipv6();
void init_ping_buffer_ipv6(size_t ping_data_size); 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); int socket_sendto_ping_ipv6(int s, struct sockaddr *saddr, socklen_t saddr_len, uint16_t icmp_seq, uint16_t icmp_id);
#endif #endif

@ -89,15 +89,23 @@ void init_ping_buffer_ipv4(size_t ping_data_size)
crash_and_burn("can't malloc ping packet"); 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; 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_family = AF_INET;
sa.sin_addr = *src_addr; sa.sin_addr = *src_addr;
if (bind(s, (struct sockaddr*)&sa, len) < 0)
if (bind(s, (struct sockaddr*)&sa, sizeof(sa)) < 0)
errno_crash_and_burn("cannot bind source address"); 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) 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_code = 0;
icp->icmp_cksum = 0; icp->icmp_cksum = 0;
icp->icmp_seq = htons(icmp_seq_nr); icp->icmp_seq = htons(icmp_seq_nr);
icp->icmp_id = htons(icmp_id_nr); icp->icmp_id = icmp_id_nr;
if (random_data_flag) { if (random_data_flag) {
for (n = ((char*)&icp->icmp_data - (char*)icp); n < ping_pkt_size_ipv4; ++n) { for (n = ((char*)&icp->icmp_data - (char*)icp); n < ping_pkt_size_ipv4; ++n) {

@ -88,15 +88,23 @@ void init_ping_buffer_ipv6(size_t ping_data_size)
crash_and_burn("can't malloc ping packet"); 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; struct sockaddr_in6 sa;
socklen_t len = sizeof(sa);
memset(&sa, 0, sizeof(sa)); memset(&sa, 0, sizeof(sa));
sa.sin6_family = AF_INET6; sa.sin6_family = AF_INET6;
sa.sin6_addr = *src_addr; sa.sin6_addr = *src_addr;
if (bind(s, (struct sockaddr*)&sa, sizeof(sa)) < 0) if (bind(s, (struct sockaddr*)&sa, sizeof(sa)) < 0)
errno_crash_and_burn("cannot bind source address"); 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) 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_type = ICMP6_ECHO_REQUEST;
icp->icmp6_code = 0; icp->icmp6_code = 0;
icp->icmp6_seq = htons(icmp_seq_nr); icp->icmp6_seq = htons(icmp_seq_nr);
icp->icmp6_id = htons(icmp_id_nr); icp->icmp6_id = icmp_id_nr;
if (random_data_flag) { if (random_data_flag) {
for (n = sizeof(struct icmp6_hdr); n < ping_pkt_size_ipv6; ++n) { for (n = sizeof(struct icmp6_hdr); n < ping_pkt_size_ipv6; ++n) {

Loading…
Cancel
Save