[Winpcap-users] TCP Checksum - Still problem

Vidar Evenrud Seeberg vseeberg at netcom.no
Thu Feb 9 07:44:41 GMT 2006


Hello again!

Thank you Vasily for quick reply.
Sorry David, didn't mean to call you Davis in the last posting :)

Tried to htons when converting payloadstring to short-array. Still wrong TCP
checksum. The TCP checksum is correct when  no payload is present.
I still hope that someone of you gurus can take some time to review my code
to see what fails. I would appreciate that  very much.
The code including the three functions providing checksums in different ways
is presented below.

Many thanks in advance!

Regards
Vidar E. Seeberg


#include <stdio.h> 
#include "string.h"
#include "stdlib.h"

// WinPCAP includes 
#include <pcap.h> 
#include <remote-ext.h> 

//Defines
#define SIZE_ETHERNET 14
#define ETHER_ADDR_LEN 6

//**********************************************************
// STRUCTURES
//**********************************************************

struct ethernet_header {
	u_char ether_dhost[ETHER_ADDR_LEN];    /* destination host address
*/
	u_char ether_shost[ETHER_ADDR_LEN];    /* source host address */
	u_short ether_type;                    /* IP? ARP? RARP? etc */
};

// 6 byte MAC Address 
typedef struct mac_address { 
    u_char byte1; 
    u_char byte2; 
    u_char byte3; 
    u_char byte4; 
    u_char byte5; 
    u_char byte6; 
}mac_address; 


// 4 bytes IP address 
typedef struct ip_address{ 
    u_char byte1; 
    u_char byte2; 
    u_char byte3; 
    u_char byte4; 
}ip_address; 


// 20 bytes IP Header 
typedef struct ip_header{ 
    u_char ver_ihl;		// Version (4 bits) + Internet header length
(4 bits) 
    u_char tos; 		// Type of service 
    u_short tlen; 		// Total length 
    u_short identification; 	// Identification 
    u_short flags_fo; 		// Flags (3 bits) + Fragment offset (13
bits) 
    u_char ttl; 		// Time to live 
    u_char proto; 		// Protocol 
    u_short crc; 		// Header checksum 
    ip_address saddr; 		// Source address 
    ip_address daddr; 		// Destination address 
    // u_int op_pad; 		// Option + Padding -- NOT NEEDED! 
}ip_header; 


typedef struct tcp_header { 
	u_short sport; 	// Source port 
	u_short dport; 	// Destination port 
	u_int seqnum; 	// Sequence Number 
	u_int acknum; 	// Acknowledgement number 
	u_char th_off; 	// Header length 
	u_char flags; 	// packet flags 
	u_short win; 	// Window size 
	u_short crc; 	// Header Checksum 
	u_short urgptr; // Urgent pointer...still don't know what this is...

}tcp_header; 



//**********************************************************
// Function prototypes
//**********************************************************
u_char *anonymizePayload(u_char *pkt_data);
u_short csum (unsigned short *buf, int nwords);
u_short check_tcp_sum(struct ip_header *ip, struct tcp_header *tcp, int
totlen, int tcplen, int paylen, char  *payloads);
u_short in_cksum(u_short *addr, int len);



//**********************************************************
// FUNCTION: anonymizePayload
// Receives raw packets one by one from AnonMain.c
// Alters headerdata and/or payload
//**********************************************************
u_char *anonymizePayload(u_char *pkt_data)
{
	const struct ethernet_header *ethernet;	/* The ethernet header */
	const struct ip_header *ip;		/* The IP header */
	const struct tcp_header *tcp;		/* The TCP header */
	ip_header new_ip; 			/* IP header of new outgoing
packet*/
	tcp_header new_tcp; 			/* TCP header of new
outgoing packet*/

	char *payload;				/* Packet payload from
incoming packet*/
	u_char payloadstring[1530];		/* Payload string for new
packet*/
	int i, j;				/* Counters for loops used
e.g. when converting to short array*/
	u_int size_ip, size_tcp;		/* Size of ip and tcp
headers (without payload)*/
	int size_payload;			/* Size of payload*/
	static char * strpointer;		/* Points to a searched-for
string, part of "payloadstring"*/
	u_short tcplen;				/* Size of tcp header,
calculated*/
	u_short tcptos;				/* This is actually protocol
field in IP header (OK, BAD name...)*/
	u_short *size_tcpandpayload;		/* size_tcp+size_payload for
new packet
	
	u_short tcp_hdrcrc[1700];		/* Array built for
calculating tcp crc*/
	u_short payload_shortarray[1700];	/* This is "payloadstring"
converted to short-array*/
	u_short ip_hdrcrc[10];			/* Array built for
calculating ip crc*/
	u_short ip_tos = htons(0x0800); 	/* IP.protocol field
hardcoded*/
	u_char pkt[1600];			/* The assembled packet
returned to AnonMain.c for dumping to file*/
	u_char a, b;				/* Used to convert
"payloadstring" to a short-array*/
	
	mac_address *srcmac;			/* Source MAC*/
	mac_address *destmac; 			/* Destination MAC*/


	//-----------------------------------------------
	// MACs get values
	//-----------------------------------------------
	srcmac = (mac_address *)pkt_data; 
	destmac = (mac_address *)(pkt_data + 6); 
	
	
	//-----------------------------------------------
	// Fetching ethernet and IP headers from
	// the u_char pkt_data received from AnonMain.c
	//-----------------------------------------------
	ethernet = (struct ethernet_header*)(pkt_data);
	ip = (struct ip_header*)(pkt_data + SIZE_ETHERNET);
	size_ip = (ip->ver_ihl & 0xf) * 4; //Gets length of IP header with
options
	if (size_ip < 20) {
		printf("   * Invalid IP header length: %u bytes\n",
size_ip);
		return NULL;
	}
		

	//-----------------------------------------------
	// Working on TCP only (for now
	//-----------------------------------------------
	if( ip->proto == 0x06 ) 
	{
		//-----------------------------------------------
		// Fetching TCP header and payload
		//-----------------------------------------------
		tcp = (struct tcp_header*)(pkt_data + SIZE_ETHERNET +
size_ip); //TCP header
		size_tcp = tcp->th_off/4;
		if (size_tcp < 20) {
			printf("   * Invalid TCP header length: %u bytes\n",
size_tcp);
			return  NULL;
		}
		payload = (u_char *)(pkt_data + SIZE_ETHERNET + size_ip +
size_tcp); //This is a pointer to the payload
		size_payload = ntohs(ip->tlen) - (size_ip + (size_tcp));


		//-----------------------------------------------
		// Converting *payload to a char string
		// According to Kernighan this should be done
		// for reliable character alterations
		// Results of alterations of *strings are "undefined"
		//-----------------------------------------------
		if (size_payload > 0)
		{
			for(i = 0; i < size_payload; i++)
			{
				if (isprint(*payload))
				{
					payloadstring[i] = *payload;
				}
				else if(iscntrl(*payload))
				{
					if(*payload == 0x0D)
					{
						payloadstring[i] = '\r';
					}
					else if(*payload == 0x0A)
					{
						payloadstring[i] = '\n';
					}
					else
						payloadstring[i] = '.';
				}
				else
				{
					payloadstring[i] = '.';
				}
				payload++;
			}
			payloadstring[i] = '\0'; //Terminating the string
		}
		else
			payloadstring[0] = '\0';

	}
	
	
	//-----------------------------------------------
	// An example of payload alteration
	// "gzip" is substituted by "tull"
	//-----------------------------------------------
	if(strpointer = strstr (payloadstring,"gzip"))
		strncpy(strpointer,"tull",4);
	

	
	//----------------------------------------------------------------
	// Construct packet
	// Repeating header fields from incoming packet
	// TCP and IP CRCs must be set to zero before calculating checksum 
	//----------------------------------------------------------------

	// Setup IP Header 
	new_ip.ver_ihl = ip->ver_ihl; 
	new_ip.tos = ip->tos; 
	new_ip.tlen = ip->tlen; 
	new_ip.identification = ip->identification; 
	new_ip.flags_fo = ip->flags_fo; 
	new_ip.ttl = ip->ttl; 
	new_ip.proto = ip->proto; 
	new_ip.crc = 0x00;
	new_ip.saddr = ip->saddr;
	new_ip.daddr = ip->daddr; 
  
	 // Setup TCP Header 
	new_tcp.sport = tcp->sport;  
	new_tcp.dport = tcp->dport; 
	new_tcp.seqnum = tcp->seqnum; 
	new_tcp.acknum = tcp->acknum;
	new_tcp.th_off = tcp->th_off;
	//new_tcp.flags = 0x07; //Example of alterations. Sets FIN, SYN, RST
	new_tcp.flags = tcp->flags; 
	new_tcp.win = tcp->win; 
	new_tcp.urgptr = tcp->urgptr; 
	new_tcp.crc = 0x00; 
 

	//----------------------------------------------------------------
	// Calculate IP CRC
	// This works as it should
	//----------------------------------------------------------------
	memset(ip_hdrcrc, 0, 20); 
	memcpy(ip_hdrcrc, &new_ip, 20); 
	new_ip.crc = csum( ip_hdrcrc, 10 ); /* OBS: THIS WORKS AS IT SHOULD
*/


	//----------------------------------------------------------------
	// Calculate TCP CRC
	// This works as it should when there's no payload (the "else"-part)
	// Incorrect checksum calculated when payload is present (This is my
	// real problem)
	//----------------------------------------------------------------
	if(size_payload>0)
	{
		//Calculating TCP CRC
		//THIS PART OF THE IF STATEMENT DOES NOT WORK
		//PRODUCES INCORRECT CHECKSUM

	
//----------------------------------------------------------------
		// Convert payloadstring to short-array. I thing this is
necessary.
		// Manages putting two characters into a 2-byte short
	
//----------------------------------------------------------------
		i=j=0;
		while(i<size_payload)
		{
			a = payloadstring[i];
			i++;
			b = payloadstring[i];
			i++;
			payload_shortarray[j] = a*256+b;
			j++;
		}
		

	
//----------------------------------------------------------------
		// Constructs the u_short array for TCP CRC calculations
	
//----------------------------------------------------------------
		tcplen = htons(new_tcp.th_off/4);
		tcptos = htons(new_ip.proto);
		i = (new_tcp.th_off/4)+size_payload;
		size_tcpandpayload = &i;

		memset(tcp_hdrcrc, 0, *size_tcpandpayload+12);
		memcpy(tcp_hdrcrc, &new_tcp, ntohs(tcplen)); 
		memcpy(&tcp_hdrcrc[ntohs(tcplen)/2], &new_ip.saddr, 4); 
		memcpy(&tcp_hdrcrc[(ntohs(tcplen)/2)+2], &new_ip.daddr, 4); 
		memcpy(&tcp_hdrcrc[(ntohs(tcplen)/2)+4], &tcptos, 2); 
		memcpy(&tcp_hdrcrc[(ntohs(tcplen)/2)+5],
&size_tcpandpayload, 2); 
		memcpy(&tcp_hdrcrc[(ntohs(tcplen)/2)+6],
&payload_shortarray, size_payload); 
		
	
//----------------------------------------------------------------
		// Three versions of functions calculating the TCP CRC.
		// See functions below
		// csum and in_cksum produce the same CRC
		// check_tcp_sum a different CRC
	
//----------------------------------------------------------------
		//new_tcp.crc = csum( tcp_hdrcrc, (*size_tcpandpayload+12)/2
); 
		//new_tcp.crc = in_cksum(&tcp_hdrcrc,
*size_tcpandpayload+12);
		new_tcp.crc = check_tcp_sum(&new_ip, &new_tcp,
size_tcpandpayload, size_tcp, size_payload,  &payload_shortarray);
	}
	else
	{
		//This part is triggered when there is no payload
		//THIS PART OF THE IF STATEMENT WORKS AS IT SHOULD
		//PRODUCES CORRECT CHECKSUM

		tcplen = htons(new_tcp.th_off/4);
		tcptos = htons(new_ip.proto);
		
		memset(tcp_hdrcrc, 0, (ntohs(tcplen)+12)); 
		memcpy(tcp_hdrcrc, &new_tcp, ntohs(tcplen)); 
		memcpy(&tcp_hdrcrc[ntohs(tcplen)/2], &new_ip.saddr, 4);
//Fra her
		memcpy(&tcp_hdrcrc[(ntohs(tcplen)/2)+2], &new_ip.daddr, 4); 
		memcpy(&tcp_hdrcrc[(ntohs(tcplen)/2)+4], &tcptos, 2); 
		memcpy(&tcp_hdrcrc[(ntohs(tcplen)/2)+5], &tcplen, 2); 
		new_tcp.crc = csum( tcp_hdrcrc, ((ntohs(tcplen)+12)/2) ); 
	}




	//----------------------------------------------------------------
	// Assembling the new outgoing packet 
	// Returns the new packet to AnonMain.c for dumping into a file
	//----------------------------------------------------------------
	memcpy( pkt, srcmac, 6 ); 
	memcpy( (pkt + 6), destmac, 6 ); 
	memcpy( (pkt + 12), &ip_tos, 2);
	memcpy( (pkt + 14), &new_ip, size_ip ); 
	memcpy( (pkt + 14 + size_ip), &new_tcp, ((new_tcp.th_off)/4) );
	memcpy( (pkt + 14 + size_ip + ((new_tcp.th_off)/4)), payloadstring,
size_payload );
 
	return &pkt;
}



//*****************************************************************
// FUNCTION: csum
// Calculates the TCP Checksum 
//*****************************************************************
u_short csum (unsigned short *buf, int nwords) { 
	unsigned long sum=0; 
  for( sum=0; nwords > 0; nwords-- ) 
                sum += *buf++; 
        sum = (sum >> 16) + (sum & 0xffff); 
        sum += (sum >> 16); 
  return (u_short)~sum; 
} 



//*****************************************************************
// FUNCTION: check_tcp_sum
// Calculates the TCP Checksum
// Changed David Chang's original version
// Returns checksum instead of checking correct/incorrect
// Had to explisitly tell the function where to find the new payload
// since it not necessarily follows the TCP header in memory. This is
// because *payloads pont to a altered payload and not the original one. 
//*****************************************************************

u_short check_tcp_sum(struct ip_header *ip, struct tcp_header *tcp, int
totlen, int tcplen, int paylen, char *payloads)
 {
         unsigned long sum;
         u_char *addr, *p;
 
         /* TCP headers are at least 20 bytes long */
 
         if (tcplen < 20)
                 return(-1);
 
         /* Initialize */
		
         sum = 0;
			printf("Initializing sum: %d\n", sum);
         /* Sum pseudo tcp header */
 
         p = (u_char *) &(ip->saddr);
         sum += ((*p << 8) + *(p+1));
         sum += ((*(p+2) << 8) + *(p+3));
 
			printf("Sum is now: %d\n", sum);
         p = (u_char *) &(ip->daddr);
         sum += ((*p << 8) + *(p+1));
         sum += ((*(p+2) << 8) + *(p+3));
 
         sum += (0 + ip->proto);
 
         sum += totlen;
 
         /*  Sum real tcp header and payload */
 
         addr = (u_char *) tcp;
 
         while (tcplen > 0)
         {
                 sum += ((*addr << 8) + *(addr+1));
                 addr += 2;
                 tcplen -= 2;
         }

		 addr = (u_char *) payloads;
		 while (paylen > 1)
         {
                 sum += ((*addr << 8) + *(addr+1));
                 addr += 2;
                 paylen -= 2;
         }
 
         /*  Add left-over byte, if any */
 
         if (paylen > 0)
                 sum += (*addr << 8);
 
         /*  Fold 32-bit sum to 16 bits */
 
         while (sum>>16)
                 sum = (sum & 0xFFFF) + (sum >> 16);
 
	return sum;
 }



//*****************************************************************
// FUNCTION: in_cksum
// Calculates the TCP Checksum 
// This produces the same checksum as csum, but the checksum is
// still reported as incorrect by Ethereal, and it also differs from
// the CRC of the corresponding packet of the input ethereal/tcpdump file
//*****************************************************************
u_short in_cksum(u_short *addr, int len)
{
	register int nleft = len; 
	register u_short *w = addr; 
	register int sum = 0; 
	u_short answer = 0; 
	while (nleft > 1) 
	{ 
		sum += *w++; 
		nleft -= 2; 
	} 
	if (nleft == 1) 
	{ 
		*(u_char *)(&answer) = *(u_char *) w; 
		sum += answer; 
	} 
	sum = (sum >> 16) + (sum & 0xffff); 
	sum += (sum >> 16); 
	answer = ~sum; return(answer); 
}




Best regards
Vidar evenrud Seeberg



More information about the Winpcap-users mailing list