[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