Reputation: 620
I have the following working function that takes in a socket ready for an ICMP response and reads it into a buffer but I am struggling to understand the flow of the code and wanted someone to correct/confirm my understanding. My understanding is as follows:
It is the 4th point that I dont quite understand. Is the 'icmp' pointer address stacked underneath the 'ip' pointer address and '(buff + sizeof(struct iphdr))' is referencing the point in memory the 'icmp' pointer should point to? Is there anywhere I can read about type casting using this type of offsetting? `
int read_icmp_answer(int *sock){
char buff[1024];
struct iphdr *ip;
struct icmphdr *icmp;
ip = (struct iphdr *)buff;
icmp = (struct icmphdr *) (buff + sizeof(struct iphdr));
if(read(*sock, buff, sizeof(buff)) > 0) {
if(icmp->type == 0 && icmp->code == 0) return 1;
else return -1;
}
return 0;
}
`
Upvotes: 2
Views: 505
Reputation: 385144
There's nothing to read about.
The author has created 1024 bytes. Then they've lied to the compiler, persuading it that there exists a struct iphdr
at the start of that block, and a struct icmphdr
immediately afterwards (using some pretty basic pointer arithmetic and a couple of casts).
That is not true, and the code has undefined behaviour.
You can examine an object of type T
using a char*
; you cannot examine a char[]
as if it were an object of type T
. That violates strict aliasing rules. Unfortunately, since older and simpler compilers were more likely to let this slide in practice, there is a common misconception surrounding code like this and it continues to show up in examples. 😿
The author should instead have declared a struct iphdr
and read sizeof(iphdr)
bytes into it, then declared a struct icmphdr
and read sizeof(icmphdr)
bytes into that.
Upvotes: 2