ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
im fairly new to raw socket programming,
and now i need a function that fills in the checksum of a header (either tcp or ip) or some way to let the kernel fill it in.
then what do i fill in the checksum field??
i tried several things, also nothing, but i always see when i start tcpdump and launch my program, that the checksum is bad...
When using the raw sockets u can tell the kernel to fill in the check sum field. Moreover if header include option is set then u can directly insert the checksum in the field. The code for calculating internet checksum is easily available on the net.
unsigned short in_cksum(unsigned short *addr,int len)
{
register int sum = 0;
u_short answer = 0;
register u_short *w = addr;
register int nleft = len;
/*
* * Our algorithm is simple, using a 32 bit accumulator (sum), we add
* * sequential 16 bit words to it, and at the end, fold back all the
* * carry bits from the top 16 bits into the lower 16 bits.
* */
while (nleft > 1) {
sum += *w++;
nleft -= 2;
}
/* mop up an odd byte, if necessary */
if (nleft == 1) {
*(u_char *)(&answer) = *(u_char *)w ;
sum += answer;
}
/* add back carry outs from top 16 bits to low 16 bits */
sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
sum += (sum >> 16); /* add carry */
answer = ~sum; /* truncate to 16 bits */
return(answer);
}
i used it like this
Code:
tcp->th_sum = (unsigned short)in_cksum((unsigned short *)iphdr, sizeof(struct ip));
Quote:
Moreover if header include option is set then u can directly insert the checksum in the field.
And if you dont set that IPHDRINCL, does the kernel fill in the checksum?
(btw, i didnt saw it at first, because i didnt used -v with tcpdump....)
Ok, so in_cksum() is no good for the TCP header, now i found this function ( trans_check() ) in the source of Packet Factory(this is a program that lets you send out custom packets), but im not that familiar with that function,
so heres the whole source (including in_cksum and trans_check)
Code:
#define __USE_BSD
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <arpa/inet.h>
#define __FAVOR_BSD
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
unsigned short in_cksum( unsigned short *addr, int len );
unsigned short trans_check(unsigned char proto, char *packet, int length, struct in_addr source_address,
struct in_addr dest_address);
int main()
{
int sockfd, packet_size, sport, dport;
int on = 1, data_len = 0;
struct in_addr srcaddr, dstaddr;
struct sockaddr_in sock_raw;
struct tcphdr *tcp;
struct ip *iphdr;
struct in_addr saddr, daddr;
char *packet;
saddr.s_addr = inet_addr("192.168.168.251");
daddr.s_addr = inet_addr("194.109.192.114");
sport = 23456;
dport = 80;
if(getuid() != 0)
{
printf("YOU MUST BE r00t!!\n");
exit(1);
}
if( ( sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW )) < 0 )
{
perror("socket");
printf("Prob socket\n");
exit(1);
}
if(setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL,(char *)&on,sizeof(on)) < 0)
{
perror("setsockopt");
printf("Prob setsockopt\n");
exit(1);
}
memset(&sock_raw, '\0', sizeof(sock_raw) );
packet_size = (sizeof(struct ip) + sizeof(struct tcphdr));
packet = malloc(packet_size);
/*HIER KOMEN IP EN TCP HEADERS UIT HEADERS.C!!!!*/
iphdr = (struct ip *)packet;
iphdr->ip_v = 4;
iphdr->ip_hl = 5;
iphdr->ip_len = packet_size;
iphdr->ip_off = 0;
iphdr->ip_ttl = IPDEFTTL;
iphdr->ip_p = IPPROTO_TCP;
iphdr->ip_src = saddr;
iphdr->ip_dst = daddr;
iphdr->ip_sum = (unsigned short)in_cksum((unsigned short *)iphdr, sizeof(struct ip));
tcp = (struct tcphdr *)(packet + sizeof ( struct ip ));
memset((char *)tcp,'\0',sizeof(struct tcphdr));
tcp->th_sport = htons(sport);
tcp->th_dport = htons(dport);
tcp->th_seq = htonl(random()%time(NULL));
tcp->th_ack = htonl(random()%time(NULL));
tcp->th_off = 5;
/* We won't use th_x2 (i don't know what it is) */
tcp->th_flags = TH_SYN;
tcp->th_win = htons(12000);
tcp->th_sum = trans_check(IPPROTO_TCP, packet, (sizeof(struct tcphdr) + data_len), saddr, daddr);
sock_raw.sin_family = AF_INET;
sock_raw.sin_port = htons(dport);
sock_raw.sin_addr = daddr;
sendto(sockfd, packet, packet_size, 0x0, (struct sockaddr *)&sock_raw, sizeof(sock_raw));
exit(0);
}
unsigned short in_cksum(unsigned short *addr,int len)
{
register int sum = 0;
u_short answer = 0;
register u_short *w = addr;
register int nleft = len;
/*
* * Our algorithm is simple, using a 32 bit accumulator (sum), we add
* * sequential 16 bit words to it, and at the end, fold back all the
* * carry bits from the top 16 bits into the lower 16 bits.
* */
while (nleft > 1) {
sum += *w++;
nleft -= 2;
}
/* mop up an odd byte, if necessary */
if (nleft == 1) {
*(u_char *)(&answer) = *(u_char *)w ;
sum += answer;
}
/* add back carry outs from top 16 bits to low 16 bits */
sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
sum += (sum >> 16); /* add carry */
answer = ~sum; /* truncate to 16 bits */
return(answer);
}
unsigned short trans_check(unsigned char proto, char *packet, int length, struct in_addr source_address,struct in_addr dest_address)
{
struct psuedohdr {
struct in_addr source_address;
struct in_addr dest_address;
unsigned char place_holder;
unsigned char protocol;
unsigned short length;
} psuedohdr;
char *psuedo_packet;
unsigned short answer;
psuedohdr.protocol = proto;
psuedohdr.length = htons(length);
psuedohdr.place_holder = 0;
psuedohdr.source_address = source_address;
psuedohdr.dest_address = dest_address;
if((psuedo_packet = malloc(sizeof(psuedohdr) + length)) == NULL) {
perror("malloc");
exit(1);
}
memcpy(psuedo_packet,&psuedohdr,sizeof(psuedohdr));
memcpy((psuedo_packet + sizeof(psuedohdr)),
packet,length);
answer = (unsigned short)in_cksum((unsigned short *)psuedo_packet,(length + sizeof(psuedohdr)));
free(psuedo_packet);
return answer;
}
well, i dont know what im doing wrong now, i know the source code of Packet Factory is slightly different from mine, and im gonna search through the source of nmap now, but if someone know allready....
it isnt the IP header or something, cuz thats being filled in beneith there.....
anyway, this really sucks, and in_cksum also doesnt have a man page (or at least i couldnt find one....)
There is nothing wrong with the in_cksum function. I think u are not exactly using it right. The way you used it to calculate the TCP check sum is this
tcp->th_sum = (unsigned short)in_cksum((unsigned short *)iphdr, sizeof(struct ip));
here you are trying to get checksum for TCP header and u are giving in the IP header as argument. This is wrong.. the function call above will return the IP header checksum. Now if you want the TCP header checksum you should give TCP header as the argument of this function.
I think that the checksum field in the TCP header in calculated over the complete TCP packet i.e., the TCP header and the payload. So i think your code should be:
tcp->th_sum = (unsigned short)in_cksum((unsigned short *)tcp, (sizeof(struct tcphdr) + LengthOfTheTcpPayload));
where LengthOfTheTcpPayload is the actual length of the TCP packet payload.
Well i should have worked but i think i am missing out somehting. One thing more that could be wrong is that before calculating the check sum it is compulsary the u set the checksum field in the header to zero i.e., if u want to calculate TCP header checksum then u must do the following:
..... //Fill all the TCP header fields
tcp->th_sum = 0;
tcp->th_sum = (unsigned short)in_cksum((unsigned short *)tcp, (sizeof(struct tcphdr) + LengthOfTheTcpPayload));
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.