title: Socket (SOCK_RAW + IPPROTO_ICMP) can't read TTL response
body: <p>I've created a ping utility on Windows. I'm using a raw socket with a ICMP protocol. I'm local administrator of my computer.</p>
  
  <p>As there a lot of code, I don't want to paste it here but I found an example that is really similar to mine <a href="http://www.winsocketdotnetworkprogramming.com/winsock2programming/winsock2advancedrawsocket11b.html" rel="nofollow noreferrer">winsock2advancedrawsocket11b</a><a href="http://www.winsocketdotnetworkprogramming.com/winsock2programming/winsock2advancedrawsocket11b.html" rel="nofollow noreferrer">http://www.winsocketdotnetworkprogramming.com/winsock2programming/winsock2advancedrawsocket11b.html</a></p>
  
  <p>I download it, test I conclude that it has the same problem as mine. I'm not receiving response when TTL expired (in IP header). I though that using RAW socket let me read that ?</p>
  
  <p>Let's say I want to force a "ttl expired" on a ping, so I send a ping to "google.com" with a ttl of 2.</p>
  
  <pre><code>ping -i 2 -n 1 google.com
  </code></pre>
  
  <p>This give me the following result</p>
  
  <pre><code>Reply from 204.80.6.137: TTL expired in transit.
  Reply from 204.80.6.137: TTL expired in transit.
  </code></pre>
  
  <p>Using my application I send the same ping request and see what I received in Wireshark. I got one ICMP packet sent to google and another packet from my router telling me that TTL has expired. So, why a raw socket on Windows is not receiving this message too ? Is there an option to force reading ip header even if the TTL is expired ?</p>
  
  <p>So I presume that Windows <code>ping.exe</code> utility is filtering packet better/different than what we can do with the Winsock API ?</p>
  
  <p>As reference, this is how the socket is created : </p>
  
  <pre><code>#include &lt;winsock2.h&gt; 
  #include &lt;ws2tcpip.h&gt; 
  #include &lt;mstcpip.h&gt;
  #include &lt;windows.h&gt;
  #include &lt;stdint.h&gt;
  #include &lt;vector&gt;
  #include &lt;algorithm&gt;
  
  struct IPV4_HDR
  {
      unsigned char ip_header_len : 4;
      unsigned char ip_version : 4;
      unsigned char ip_tos;
      unsigned short ip_total_length;
      unsigned short ip_id;
  
      unsigned char ip_frag_offset : 5;
  
      unsigned char ip_more_fragment : 1;
      unsigned char ip_dont_fragment : 1;
      unsigned char ip_reserved_zero : 1;
  
      unsigned char ip_frag_offset1;
  
      unsigned char ip_ttl;
      unsigned char ip_protocol;
      unsigned short ip_checksum;
      unsigned int ip_srcaddr;
      unsigned int ip_destaddr;
  };
  
  struct ICMP_HDR
  {
      BYTE type;
      BYTE code;
      USHORT checksum;
      USHORT id;
      USHORT seq;
  };
  
  unsigned short compute_checksum(unsigned short* buffer, int size)
  {
      unsigned long cksum = 0;
      while (size &gt; 1)
      {
          cksum += *buffer++;
          size -= sizeof(unsigned short);
      }
      if (size)
      {
          cksum += *(char*)buffer;
      }
  
      cksum = (cksum &gt;&gt; 16) + (cksum &amp; 0xffff);
      cksum += (cksum &gt;&gt; 16);
      return (unsigned short)(~cksum);
  }
  
  void send_receive_ping(SOCKET icmp_sock)
  {
      std::vector&lt;char&gt; receive_buffer;
      receive_buffer.resize(65536);
      std::fill(receive_buffer.begin(), receive_buffer.end(), 0);
      char *Buffer = receive_buffer.data();
  
      int recv_bytes = 0;
      DWORD start_time = GetTickCount();
      bool first_time_in_loop = true;
      do
      {
          if ( (first_time_in_loop == true 
              || GetTickCount() - start_time &gt; 5000))
          {
              OutputDebugString(L"Sending an ICMP packet....\n");
              send_icmp_packet(icmp_sock);
  
              first_time_in_loop = false;
              start_time = GetTickCount();
          }
  
          recv_bytes = recvfrom(icmp_sock, Buffer, 65536, 0, 0, 0);
          if (recv_bytes &gt; 0)
          {
              // Handle received packet
          }
          else
          {
              break;
          }
      } while (recv_bytes &gt; 0);
  }
  
  void send_icmp_packet(SOCKET icmp_sock)
  {
      sockaddr_in sockaddr_in_dst = {};
      sockaddr_in_dst.sin_family = AF_INET;
      sockaddr_in_dst.sin_port = 0;
      sockaddr_in_dst.sin_addr.s_addr = inet_addr("184.150.168.247"); // google.com
  
      std::vector&lt;char&gt; send_buffer;
      send_buffer.resize(sizeof(IPV4_HDR) + sizeof(ICMP_HDR));
      std::fill(send_buffer.begin(), send_buffer.end(), 0);
  
      IPV4_HDR *ipv4_header = (IPV4_HDR *)send_buffer.data();
      ipv4_header-&gt;ip_header_len = 5;
      ipv4_header-&gt;ip_version = 4;
      ipv4_header-&gt;ip_tos = 16;
      ipv4_header-&gt;ip_total_length = htons( send_buffer.size() );
      ipv4_header-&gt;ip_id = htons(0);
      ipv4_header-&gt;ip_ttl = 64;
      //ipv4_header-&gt;ip_ttl = 2;
      ipv4_header-&gt;ip_protocol = IPPROTO_ICMP;
      ipv4_header-&gt;ip_srcaddr = dest.sin_addr.s_addr;
      ipv4_header-&gt;ip_destaddr = sockaddr_in_dst.sin_addr.s_addr;
      ipv4_header-&gt;ip_checksum = compute_checksum((unsigned short *)ipv4_header, sizeof(IPV4_HDR));
  
      static unsigned short seq = 0;
      ICMP_HDR *icmp_header = (ICMP_HDR *)(send_buffer.data() + sizeof(IPV4_HDR));
      icmp_header-&gt;type = 8;
      icmp_header-&gt;seq = seq++;
      icmp_header-&gt;id = 888;
      icmp_header-&gt;checksum = compute_checksum((unsigned short *)icmp_header, sizeof(ICMP_HDR));
  
      ret = sendto(icmp_sock, (char *)send_buffer.data(), send_buffer.size(),
          0, (sockaddr *)&amp;sockaddr_in_dst, sizeof(sockaddr_in_dst));
  }
  
  
  int main()
  {
      WSADATA ws;
      WSAStartup(MAKEWORD(2, 2), &amp;ws);
  
      SOCKET icmp_sock = socket(AF_INET, SOCK_RAW, IPPROTO_IP);
  
      char hostname[256];
      gethostname(hostname, sizeof(hostname));
  
      hostent *local = gethostbyname(hostname);
  
      sockaddr_in source;
      memset(&amp;source, 0, sizeof(source));
      memcpy(&amp;source.sin_addr.s_addr, local-&gt;h_addr_list[0], sizeof(source.sin_addr.s_addr));
      source.sin_family = AF_INET;
      source.sin_port = 0;
  
      bind(icmp_sock, (sockaddr *)&amp;source, sizeof(source));
  
      int recv_all_opt = 1;
      int ioctl_read = 0;
      WSAIoctl(icmp_sock, SIO_RCVALL, &amp;recv_all_opt, sizeof(recv_all_opt), 0, 0, (LPDWORD)&amp;ioctl_read, 0, 0);
  
      int ip_header_include = 1;
      setsockopt(icmp_sock, IPPROTO_IP, IP_HDRINCL, (char *)&amp;ip_header_include, sizeof(ip_header_include));
  
      send_receive_ping(icmp_sock);
  
      closesocket(icmp_sock);
      WSACleanup();
  
      return 0;
  }    
  </code></pre>
  
  <p>The preceding code seems to work pretty well but I'm still unable to get the expired TLL from IP message. It's like the OS steals the package. I bet is because I ask to read ICMP message and the TLL is in the IP header. So if the IP header is faulty than the OS discard the message and my socket can't read it. So I tried using a socket IPPROTO_IP :  </p>
  
  <pre><code>sock = socket(AF_INET, SOCK_RAW, IPPROTO_IP);
  </code></pre>
  
  <p>I'm still not getting TTL expired message, worst I'm loosing packet sometime. I saw them in Wireshark but I'm not getting them on my socket. Is someone having an idea why ?</p>