2Real 2Real - 1 month ago 16
C Question

How to build a TCP pseudo header and related data for checksum verification in C and libpcap?

I'm trying to build up the proper data structure using a pseudo tcp header, tcp header, and tcp data to be sent to a check sum function to be verified. I cannot figure out what I'm doing wrong in my code.
The following code is my function that builds up the data structure and then sends it to another function to be checked.

void print_inner_ip_header(const u_char* pkt_data, struct ip_header* header)
{
switch(header->protocol)
{
case(ICMP):
{
print_icmp_header((struct icmp_header*)(pkt_data+ETHERNET_HEADER_SIZE+sizeof(struct ip_header)));
break;
}
case(TCP):
{
struct pseudo_tcp_header ps_tcp_header;
ps_tcp_header.source = header->source;
ps_tcp_header.protocol = 6;
ps_tcp_header.dest = header->dest;
ps_tcp_header.reserved = 0;
ps_tcp_header.tcp_size = htons(sizeof(struct tcp_header) + header->total_length - (header->length & 0x0F)*4);

int len = sizeof(struct pseudo_tcp_header) + ps_tcp_header.tcp_size;
u_short ps_tcp[len];

memcpy(ps_tcp, &ps_tcp_header, sizeof(struct pseudo_tcp_header));
memcpy(ps_tcp+sizeof(struct pseudo_tcp_header), (pkt_data+ETHERNET_HEADER_SIZE+sizeof(struct ip_header)), ps_tcp_header.tcp_size);

print_tcp_header(pkt_data, (struct tcp_header*)(pkt_data+ETHERNET_HEADER_SIZE+sizeof(struct ip_header)), ps_tcp, len);
break;
}
case(UDP):
{
print_udp_header((struct udp_header*)(pkt_data+ETHERNET_HEADER_SIZE+sizeof(struct ip_header)));
break;
}
default:
{
break;
}
}
}


void print_tcp_header(const u_char* pkt_data, const struct tcp_header* header, u_short* ps_tcp, int len)
{
u_short checksum = header->checksum;
int check = in_cksum((unsigned short *)ps_tcp, len);
char* checksum_str = "Correct";

printf("CHECK VALUE: %d", check);
if(check)
{
checksum_str = "Incorrect";
}

printf("\n\tTCP Header");
printf("\n\t\tSource Port: %d", ntohs(header->source_port));
printf("\n\t\tDestination Port: %d", ntohs(header->dest_port));
printf("\n\t\tSequence Number: %u", ntohl(header->seq_num));
printf("\n\t\tACK Number: %u", ntohl(header->ack_num));
print_tcp_header_flags(header->flags);
printf("\n\t\tWindow Size: %d", ntohs(header->win_size));
printf("\n\t\tChecksum: %s (%#x)\n", checksum_str, ntohs(checksum));
}


Any help would be appreciated because I've spent numerous hours trying to figure out what I'm doing wrong.

Thanks,

edit: here is my pseudo header

struct pseudo_tcp_header
{
struct in_addr source, dest;
u_char reserved;
u_char protocol;
u_short tcp_size;
};

Answer

The most fundamental problem I can see is the combination of:

     u_short ps_tcp[len];

with

     memcpy(ps_tcp+sizeof(struct pseudo_tcp_header), ...);

Adding to ps_tcp will add units of sizeof(u_short), not bytes.