title: IPv6 raw socket programming with native C
body: <p>I am working on IPv6 and need to craft an IPv6 packet from scratch and put it into a buffer. Unfortunately I do not have much experience with C. From a tutorial I have successfully done the same thing with IPv4 by defining </p>
  
  <pre><code>struct ipheader {
   unsigned char      iph_ihl:5, /* Little-endian */
                  iph_ver:4;
   unsigned char      iph_tos;
   unsigned short int iph_len;
   unsigned short int iph_ident;
   unsigned char      iph_flags;
   unsigned short int iph_offset;
   unsigned char      iph_ttl;
   unsigned char      iph_protocol;
   unsigned short int iph_chksum;
   unsigned int       iph_sourceip;
   unsigned int       iph_destip;
  };
  
  /* Structure of a TCP header */
  struct tcpheader {
   unsigned short int tcph_srcport;
   unsigned short int tcph_destport;
   unsigned int       tcph_seqnum;
   unsigned int       tcph_acknum;
   unsigned char      tcph_reserved:4, tcph_offset:4;
   // unsigned char tcph_flags;
    unsigned int
         tcp_res1:4,       /*little-endian*/
         tcph_hlen:4,      /*length of tcp header in 32-bit words*/
         tcph_fin:1,       /*Finish flag "fin"*/
         tcph_syn:1,       /*Synchronize sequence numbers to start a connection*/
         tcph_rst:1,       /*Reset flag */
         tcph_psh:1,       /*Push, sends data to the application*/
         tcph_ack:1,       /*acknowledge*/
         tcph_urg:1,       /*urgent pointer*/
         tcph_res2:2;
   unsigned short int tcph_win;
   unsigned short int tcph_chksum;
   unsigned short int tcph_urgptr;
  };
  </code></pre>
  
  <p>and fill the packet content in like this:</p>
  
  <pre><code>// IP structure
     ip-&gt;iph_ihl = 5;
     ip-&gt;iph_ver = 6;
     ip-&gt;iph_tos = 16;
     ip-&gt;iph_len = sizeof (struct ipheader) + sizeof (struct tcpheader);
     ip-&gt;iph_ident = htons(54321);
     ip-&gt;iph_offset = 0;
     ip-&gt;iph_ttl = 64;
     ip-&gt;iph_protocol = 6; // TCP
     ip-&gt;iph_chksum = 0; // Done by kernel
  
     // Source IP, modify as needed, spoofed, we accept through command line argument
     ip-&gt;iph_sourceip = inet_addr("1922.168.1.128");
     // Destination IP, modify as needed, but here we accept through command line argument
     ip-&gt;iph_destip = inet_addr(1922.168.1.1);
  
     // The TCP structure. The source port, spoofed, we accept through the command line
     tcp-&gt;tcph_srcport = htons(atoi("1024"));
     // The destination port, we accept through command line
     tcp-&gt;tcph_destport = htons(atoi("4201"));
     tcp-&gt;tcph_seqnum = htons(1);
     tcp-&gt;tcph_acknum = 0;
     tcp-&gt;tcph_offset = 5;
     tcp-&gt;tcph_syn = 1;
     tcp-&gt;tcph_ack = 0;
     tcp-&gt;tcph_win = htons(32767);
     tcp-&gt;tcph_chksum = 0; // Done by kernel
     tcp-&gt;tcph_urgptr = 0;
     // IP checksum calculation
     ip-&gt;iph_chksum = csum((unsigned short *) buffer, (sizeof (struct ipheader) + sizeof (struct tcpheader)));
  </code></pre>
  
  <p>However for IPv6 I have not find a similar way. What I already found is this struct from IETF,</p>
  
  <pre><code>struct ip6_hdr {
  
     union {
  
        struct ip6_hdrctl {
           uint32_t ip6_un1_flow; /* 4 bits version, 8 bits TC, 20 bits
                                        flow-ID */
           uint16_t ip6_un1_plen; /* payload length */
           uint8_t ip6_un1_nxt; /* next header */
           uint8_t ip6_un1_hlim; /* hop limit */
        } ip6_un1;
  
        uint8_t ip6_un2_vfc; /* 4 bits version, top 4 bits
                                        tclass */
     } ip6_ctlun;
     struct in6_addr ip6_src; /* source address */
     struct in6_addr ip6_dst; /* destination address */
  };
  </code></pre>
  
  <p>But I did not know how to fill in the information, for example, how to send a TCP/SYN from  2001:220:806:22:aacc:ff:fe00:1 port 1024 to  2001:220:806:21::4 port 1025? </p>
  
  <p>Could anybody help me or is there any references?</p>
  
  <p>Thank you vere much then.</p>
  
  <p>this is what I have done so far, however there are mismatch between the code  and the real packet captured by Wireshark (as discussed in comments below). I'm not sure it is possible to post a long code in comment section, so I just edit my question.</p>
  
  <p>Anyone can help?</p>
  
  <pre><code>#define PCKT_LEN 2000
  
  int main(void) {
     unsigned char buffer[PCKT_LEN];
     int s;
     struct sockaddr_in6 din;
     struct ipv6_header *ip = (struct ipv6_header *) buffer;
     struct tcpheader *tcp = (struct tcpheader *) (buffer + sizeof (struct ipv6_header));
  
     memset(buffer, 0, PCKT_LEN);
     din.sin6_family = AF_INET6;
     din.sin6_port = htons(0);
     inet_pton(AF_INET6, "::1", &amp;(din.sin6_addr)); // For routing 
  
     ip-&gt;version = 6;
     ip-&gt;traffic_class = 0;
     ip-&gt;flow_label = 0;
     ip-&gt;length = 40;
     ip-&gt;next_header = 6;
     ip-&gt;hop_limit = 64;
     inet_pton(AF_INET6, "::1", &amp;(ip-&gt;dst)); // IPv6 
     inet_pton(AF_INET6, "::1", &amp;(ip-&gt;src)); // IPv6
  
     tcp-&gt;tcph_srcport = htons(atoi("11111"));
     tcp-&gt;tcph_destport = htons(atoi("13"));
     tcp-&gt;tcph_seqnum = htons(0);
     tcp-&gt;tcph_acknum = 0;
     tcp-&gt;tcph_offset = 5;
     tcp-&gt;tcph_syn = 1;
     tcp-&gt;tcph_ack = 0;
     tcp-&gt;tcph_win = htons(32752);
     tcp-&gt;tcph_chksum = 0; // Done by kernel
     tcp-&gt;tcph_urgptr = 0;
  
     s = socket(PF_INET6, SOCK_RAW, IPPROTO_RAW);
     if (s &lt; 0) {
        perror("socket()");
        return 1;
     }
     unsigned short int packet_len = sizeof (struct ipv6_header) + sizeof (struct tcpheader);
     if (sendto(s, buffer, packet_len, 0, (struct sockaddr*) &amp;din, sizeof (din)) == -1) {
        perror("sendto()");
        close(s);
        return 1;
     }
     close(s);
     return 0;
  }
  </code></pre>