From 6bc29919d38b39c259d698b4c27561d9c589c852 Mon Sep 17 00:00:00 2001 From: Steven Noonan Date: Thu, 27 Feb 2020 12:16:21 -0800 Subject: [PATCH] linux: account for missing IP header block when using SOCK_DGRAM Linux doesn't include an IP header in the payload when using an unprivileged SOCK_DGRAM socket. Signed-off-by: Steven Noonan --- src/fping.c | 24 ++++++++++++++++-------- src/fping.h | 2 +- src/socket4.c | 11 ++++++++++- 3 files changed, 27 insertions(+), 10 deletions(-) diff --git a/src/fping.c b/src/fping.c index 029cd30..a48dfe7 100644 --- a/src/fping.c +++ b/src/fping.c @@ -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) { diff --git a/src/fping.h b/src/fping.h index 3f9875a..6c2a84b 100644 --- a/src/fping.h +++ b/src/fping.h @@ -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); diff --git a/src/socket4.c b/src/socket4.c index 87e6545..9787a9f 100644 --- a/src/socket4.c +++ b/src/socket4.c @@ -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 */