[Winpcap-users] Calculating TCP checksum after altering payload
Vidar Evenrud Seeberg
vseeberg at netcom.no
Tue Feb 7 19:53:21 GMT 2006
Hello experts!
I am lost in my Masters Thesis and I hope some of you gurus can help me.
The issue is about calculating the right TCP checksum after changing payload
of a packet.
The function csum below calculates the checksum correctly for the (IP
header) and the (TCP header + no payload). However it calculates an
incorrect TCP checksum when payload is present. Can anybody help me getting
the checksum calculated correctly?
Here is my code:
#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);
//**********************************************************
// 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 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 think this is
necessary.
// 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);
memset(tcp_hdrcrc, 0, (ntohs(tcplen)+size_payload+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], &tcplen, 2);
memcpy(&tcp_hdrcrc[(ntohs(tcplen)/2)+6], payload_shortarray,
size_payload);
//Calculating the TCP CRC. See function csum below
new_tcp.crc = csum( tcp_hdrcrc,
(ntohs(tcplen)+size_payload+12)/2 );
}
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;
}
//*****************************************************************
// 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;
}
Best regards
Vidar E. Seeberg
More information about the Winpcap-users
mailing list