newprogrammer
newprogrammer

Reputation: 620

Reading an ICMP response using RAW sockets

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:

  1. A 1024 character array pointer called 'buffer' is defined to be used as the buffer.
  2. Two pointers called 'ip' and 'icmp' are created to point to iphdr and icmphdr stucts.
  3. The 'ip' pointer is set to point to the 'buffer' pointer which is now converted to an iphdr struct pointer
  4. The 'icmp' pointer is set to point to the 'buffer' pointer + the size of struct iphdr which is now converted to an icmphdr struct pointer

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

Answers (1)

Lightness Races in Orbit
Lightness Races in Orbit

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

Related Questions