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

@ -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) {

@ -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);

@ -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 */

Loading…
Cancel
Save