Several days ago, I constructed a DNS packet and checked some information. It seems that many of my friends have always had problems with the UDP packet checksum. I tried some sample code and there were also problems. So it took some time to make a successful example. In Linux, GCC passes and verifies the success.
# Include <stdio. h>
# Include <stdlib. h>
# Include <string. h>
# Include <unistd. h>
# Include <sys/socket. h>
# Include <ARPA/inet. h>
# Include <netinet/in. h>
# Include <netinet/IP. h>
# Include <netinet/udp. h>
Unsigned short checksum (unsigned short * buffer, int size)
{
Unsigned long cksum = 0;
While (size> 1)
{
Cksum + = * buffer ++;
Size-= sizeof (unsigned short );
}
If (size)
{
Cksum + = * (unsigned char *) buffer;
}
Cksum = (cksum> 16) + (cksum & 0 xFFFF );
Cksum + = (cksum> 16 );
Return (unsigned short )(~ Cksum );
}
Void calculatechecksum (
Void * iphdr,
Struct udphdr * udphdr,
Char * payload,
Int payloadlen)
{
Struct iphdr * v4hdr = NULL;
Unsigned long zero = 0;
Char Buf [1000],
* PTR = NULL;
Int chksumlen = 0,
I;
PTR = Buf;
V4hdr = (struct iphdr *) iphdr;
// Include the source and destination IP addresses
Memcpy (PTR, & v4hdr-> saddr, sizeof (v4hdr-> saddr ));
PTR + = sizeof (v4hdr-> saddr );
Chksumlen + = sizeof (v4hdr-> saddr );
Memcpy (PTR, & v4hdr-> daddr, sizeof (v4hdr-> daddr ));
PTR + = sizeof (v4hdr-> daddr );
Chksumlen + = sizeof (v4hdr-> daddr );
// Include the 8 bit zero field
Memcpy (PTR, & zero, 1 );
PTR ++;
Chksumlen + = 1;
// Protocol
Memcpy (PTR, & v4hdr-> protocol, sizeof (v4hdr-> protocol ));
PTR + = sizeof (v4hdr-> Protocol );
Chksumlen + = sizeof (v4hdr-> Protocol );
// UDP Length
Memcpy (PTR, & udphdr-> Len, sizeof (udphdr-> Len ));
PTR + = sizeof (udphdr-> Len );
Chksumlen + = sizeof (udphdr-> Len );
// UDP source port
Memcpy (PTR, & udphdr-> source, sizeof (udphdr-> source ));
PTR + = sizeof (udphdr-> source );
Chksumlen + = sizeof (udphdr-> source );
// UDP destination port
Memcpy (PTR, & udphdr-> DEST, sizeof (udphdr-> DEST ));
PTR + = sizeof (udphdr-> DEST );
Chksumlen + = sizeof (udphdr-> DEST );
// UDP length again
Memcpy (PTR, & udphdr-> Len, sizeof (udphdr-> Len ));
PTR + = sizeof (udphdr-> Len );
Chksumlen + = sizeof (udphdr-> Len );
// 16-bit UDP checksum, zero
Memcpy (PTR, & zero, sizeof (unsigned short ));
PTR + = sizeof (unsigned short );
Chksumlen + = sizeof (unsigned short );
// Payload
Memcpy (PTR, payload, payloadlen );
PTR + = payloadlen;
Chksumlen + = payloadlen;
// Pad to next 16-bit Boundary
For (I = 0; I <payloadlen % 2; I ++, PTR ++)
{
Printf ("pad one byte/N ");
* PTR = 0;
PTR ++;
Chksumlen ++;
}
// Compute the checksum and put it in the UDP Header
Udphdr-> check = checksum (unsigned short *) BUF, chksumlen );
Return;
}
Void main ()
{
Int sock;
Unsigned int buffer_size = sizeof (struct iphdr) + sizeof (struct udphdr );
Char dns_data [] = "/x71/x79/x81/X80/x00/x01"
"/X00/x02/x00/x04/x00/x04/x03/x77/x77/x77/x03/x61/x62/x63/x03/x63"
"/X6f/x6d/x00/x00/x01/x00/x01/xc0/x0c/x00/x05/x00/x01/x00/x00/x02"
"/Xe8/x00/x02/xc0/x10/xc0/x10/x00/x01/x00/x00/x00/x02/xe9/x00"
"/X04/x0a/xb5/x84/xfa/xc0/x10/x00/x02/x00/x01/x00/x00/xda/xeb/x00"
"/X0d/x06/x73/X65/x6e/x73/x30/x31/x03/x64/x69/x67/xc0/x14/xc0/x10"
"/X00/x02/x00/x01/x00/x00/xda/xeb/x00/x09/x06/x73/X65/x6e/x73/x30"
"/X32/xc0/x4e/xc0/x10/x00/x02/x00/x01/x00/x00/xda/xeb/x00/x09/x06"
"/X6f/x72/x6e/x73/x30/x31/xc0/x4e/xc0/x10/x00/x02/x00/x01/x00/x00"
"/Xda/xeb/x00/x09/x06/x6f/x72/x6e/x73/x30/x32/xc0/x4e/xc0/x75/x00"
"/X01/x00/x01/x00/x00/x7a/x36/x00/x04/x0a/xbb/xbd/x2c/xc0/x8a/x00"
"/X01/x00/x01/x00/x00/x1b/x96/x00/x04/x0a/xbb/xbe/x2c/xc0/x47/x00"
"/X01/x00/x01/x00/x00/x92/xb1/x00/x04/x0a/xb5/x86/x10/xc0/X60/x00"
"/X01/x00/x01/x00/x00/x92/xb1/x00/x04/x0a/xb5/x87/xc7 ";
Buffer_size + = sizeof (dns_data );
Unsigned char buffer [buffer_size];
Memset (buffer, 0, buffer_size );
Struct iphdr * IP = (struct iphdr *) buffer;
Struct udphdr * UDP = (struct udphdr *) (buffer + sizeof (struct iphdr ));
If (sock = socket (af_inet, sock_raw, ipproto_udp) =-1 ){
Perror ("socket ()");
Exit (exit_failure );
}
Int o = 1;
If (setsockopt (sock, ipproto_ip, ip_hdrincl, & O, sizeof (O) =-1 ){
Perror ("setsockopt ()");
Exit (exit_failure );
}
IP-> Version = 4;
IP-> IHL = 5;
IP-> id = htonl (random ());
IP-> saddr = inet_addr ("1.0.0.1 ");
IP-> daddr = inet_addr ("10.0.0.63 ");
IP-> TTL = 255;
IP-> protocol = ipproto_udp;
IP-> tot_len = buffer_size;
IP-> check = 0;
UDP-> source = htons (53 );
UDP-> DEST = htons (1234 );
UDP-> Len = htons (buffer_size-sizeof (struct iphdr ));
UDP-> check = 0;
Struct sockaddr_in ADDR;
ADDR. sin_family = af_inet;
ADDR. sin_port = UDP-> source;
ADDR. sin_addr.s_addr = IP-> saddr;
Memcpy (buffer + sizeof (struct iphdr) + sizeof (struct udphdr), dns_data, sizeof (dns_data ));
Calculatechecksum (IP, UDP, dns_data, sizeof (dns_data ));
If (sendto (sock, buffer, buffer_size, 0, (struct sockaddr *) & ADDR,
Sizeof (struct sockaddr_in) =-1 ){
Perror ("Send ()");
Exit (1 );
}
Else
Printf ("OK/N ");
}
The above code constructs a DNS response packet. Use the packet capture program to verify the correctness.