title: C - IPv6 raw ICMPv6 packet crafting
body: <p>I am currently trying to create raw ICMPv6 packet in C. I only found IPv4 examples that works well and I don't see what I do wrong with IPv6.</p>
  
  <p><strong>What I know so far :</strong></p>
  
  <ul>
  <li><p>I looked over an old <a href="http://www.linux-ipv6.org/ml/usagi-users/msg02249.html" rel="nofollow">mailing-list post</a> to discover I needed to set some variables in in6_addr (→ error 22), but besides they are using :</p>
  
  <pre><code>sock = socket(AF_INET6, SOCK_RAW, IPPROTO_RAW);
  </code></pre></li>
  <li><p>On the <a href="http://spoofer.cmand.org/software.php" rel="nofollow">BCP38 project</a>, they use LIBNET apparently. I prefer avoid librairies if I can do with sockets. In that case, how the calls are made to the "networking API" if not through socket.h.</p></li>
  <li><p>I read <a href="http://www.pdbuchan.com/rawsock/rawsock.html" rel="nofollow">here</a> that <strong>IP_HDRINCL</strong> has no equivalent in IPv6. (but why ?)</p></li>
  </ul>
  
  <p>The following code, is sending an ICMPv6 packet probably due to IPPROTO_ICMPV6 but with kernel-added headers and quite bad packet content... (with a wrong destination address, I didn't fix yet some endianness issue). It worked in IPv6.
  When I use IPPROTO_RAW, the packet is simply not sent...</p>
  
  <p>Any idea ? Thanks in advance</p>
  
  <pre><code>#include &lt;sys/types.h&gt;
  #include &lt;sys/socket.h&gt;
  
  #include &lt;netinet/in.h&gt;
  #include &lt;netinet/ip6.h&gt;
  #include &lt;netinet/icmp6.h&gt;
  #include &lt;arpa/inet.h&gt;
  
  #include &lt;netdb.h&gt;
  #include &lt;unistd.h&gt;
  #include &lt;stdlib.h&gt;
  #include &lt;string.h&gt;
  #include &lt;stdio.h&gt;
  #include &lt;errno.h&gt;
  
  struct ipv6header {
      unsigned char priority:4, version:4;
      unsigned char flow[3];
      unsigned short int length;
      unsigned char nexthdr;
      unsigned char hoplimit;
  
      unsigned int saddr[4];
      unsigned int daddr[4];
  };
  
  struct icmpv6header {
      unsigned char type;
      unsigned char code;
      unsigned short int chk_sum;
      unsigned int body; 
  };
  
  int main()
  {
      char* packet = (char*) malloc(sizeof(struct ipv6header)+sizeof(struct icmpv6header));
      struct ipv6header* ip = (struct ipv6header*) packet;
      struct icmpv6header* icmp = (struct icmpv6header*) (packet+sizeof(struct ipv6header));
  
      icmp-&gt;type = 128;
      icmp-&gt;code = 0;
      icmp-&gt;chk_sum = (0x6a13);
      icmp-&gt;body = htonl(1234);
  
      ip-&gt;version = 6;
      ip-&gt;priority = 0;
      (ip-&gt;flow)[0] = 0;
      (ip-&gt;flow)[1] = 0;
      (ip-&gt;flow)[2] = 0;
      ip-&gt;length = ((unsigned short int) sizeof(struct icmpv6header));
      ip-&gt;nexthdr = 58;
      ip-&gt;hoplimit = 255;
  
      struct sockaddr_in6 remote;
      remote.sin6_family = AF_INET6;
      remote.sin6_port = 0;
      remote.sin6_flowinfo = 0;
      remote.sin6_scope_id = 0;
  
      inet_pton(AF_INET6, "2001:470:x:x:y:y:y:dd7b", &amp;(remote.sin6_addr));
      inet_pton(AF_INET6, "2001:470:x:x:bee:bee:bee:bee", &amp;(ip-&gt;saddr));
      inet_pton(AF_INET6, "2001:470:x:x:y:y:y:dd7b", &amp;(ip-&gt;daddr));
  
      int sock, optval;
      sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
      if(sock == -1)
      {
          printf("Error setting socket\n");
          return -1;
      }
      int ret = setsockopt(sock, IPPROTO_IPV6, IP_HDRINCL, &amp;optval, sizeof(int));
      if(ret != 0) {
          printf("Error setting options %d\n", ret);
          return -1;
      }
      printf("Socket options done\n");
  
      int ret = sendto(sock, packet, ip-&gt;length, 0, (struct sockaddr *) &amp;remote, sizeof(remote));
  
      if(ret != ip-&gt;length) {
          printf("Packet not sent : %d (%d)\n",ret,errno);
          return -1;
      }
      printf("Packet sent\n");
  
      return 0;
  }
  </code></pre>