LinuxQuestions.org
Visit Jeremy's Blog.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 04-26-2003, 03:29 PM   #1
Encrypted
LQ Newbie
 
Registered: Jan 2003
Distribution: Red Hat 8.0, Debian 3.0
Posts: 20

Rep: Reputation: 0
Question Raw Sockets, Checksum Function


Hi,

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.

i searched google, with no luck ...

thanks in advance

encrypted
 
Old 04-26-2003, 04:27 PM   #2
nakkaya
LQ Guru
 
Registered: Jan 2003
Location: Turkey&USA
Distribution: Emacs and linux is its device driver(Slackware,redhat)
Posts: 1,398

Rep: Reputation: 45
to my knowlege there no such function.
 
Old 04-27-2003, 04:41 AM   #3
Encrypted
LQ Newbie
 
Registered: Jan 2003
Distribution: Red Hat 8.0, Debian 3.0
Posts: 20

Original Poster
Rep: Reputation: 0
Allright,

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...

there must be someway


encrypted
 
Old 04-27-2003, 06:07 AM   #4
Encrypted
LQ Newbie
 
Registered: Jan 2003
Distribution: Red Hat 8.0, Debian 3.0
Posts: 20

Original Poster
Rep: Reputation: 0
[edit]

ok i found the problem...

[/edit]

Last edited by Encrypted; 04-27-2003 at 04:45 PM.
 
Old 04-28-2003, 02:43 AM   #5
yrraja
Member
 
Registered: Sep 2002
Distribution: RH, FC, Ubuntu, Solaris, AIX
Posts: 114

Rep: Reputation: 15
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.

By the way how did u solve your problem?
 
Old 04-28-2003, 03:46 AM   #6
Encrypted
LQ Newbie
 
Registered: Jan 2003
Distribution: Red Hat 8.0, Debian 3.0
Posts: 20

Original Poster
Rep: Reputation: 0
Yeah, i found a function for it, its called in_cksum() , and it i didnt found it on my linux box, but as you said, the code's widely available,

and my problem was, i did
Code:
tcp = (struct tcphdr *)packet;
That rewrote my IP Header,
then someone told me to do this:
Code:
tcp = (struct tcphdr *)(packet + sizeof ( struct ip ));
And it worked


btw, for anyone interested, heres that in_cksum
Code:
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?

thanks again
encrypted
 
Old 04-28-2003, 04:37 AM   #7
Encrypted
LQ Newbie
 
Registered: Jan 2003
Distribution: Red Hat 8.0, Debian 3.0
Posts: 20

Original Poster
Rep: Reputation: 0
ahh too bad..

i know i just said i thought it worked but i doesnt,
because when i send a packet i found it weird that i didnt got any packet back..... heres why:
Code:
11:03:09.548004 (tos 0x0, ttl 64, length: 40) 192.168.168.***.23456 > beast.dierentuin.com.http: S [bad tcp cksum 5e40 (->5e54)!] 752768794:752768794(0) win 12000
(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....

thanks
encrypted
 
Old 04-28-2003, 05:14 AM   #8
Encrypted
LQ Newbie
 
Registered: Jan 2003
Distribution: Red Hat 8.0, Debian 3.0
Posts: 20

Original Poster
Rep: Reputation: 0
well, interesting thing i found in source of nmap,
Fyodor does use in_cksum for the TCP header,
like this,
Code:
tcp->th_sum = in_cksum((unsigned short *)pseudo, sizeof(struct tcphdr) + 
		       sizeof(struct pseudo_header) + datalen);
Thats great, but i dont get what te function is of this pseudo header....
Code:
struct pseudo_header *pseudo =  (struct pseudo_header *) (packet + sizeof(struct iphdr) - sizeof(struct pseudo_header));

pseudo->s_addr = source->s_addr;
pseudo->d_addr = victim->s_addr;
pseudo->protocol = IPPROTO_TCP;
pseudo->length = htons(sizeof(struct tcphdr) + datalen);
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....)

thanks again,
encrypted
 
Old 04-28-2003, 05:24 AM   #9
yrraja
Member
 
Registered: Sep 2002
Distribution: RH, FC, Ubuntu, Solaris, AIX
Posts: 114

Rep: Reputation: 15
Hi,

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.

Yaser
 
Old 04-28-2003, 06:09 AM   #10
Encrypted
LQ Newbie
 
Registered: Jan 2003
Distribution: Red Hat 8.0, Debian 3.0
Posts: 20

Original Poster
Rep: Reputation: 0
Ok, so i should look like this:
Code:
tcp->th_sum = (unsigned short)in_cksum((unsigned short *)tcp, sizeof(struct tcphdr));
right?
if so, it still gives 'bad checksum'......

encrypted
 
Old 04-28-2003, 07:15 AM   #11
yrraja
Member
 
Registered: Sep 2002
Distribution: RH, FC, Ubuntu, Solaris, AIX
Posts: 114

Rep: Reputation: 15
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.

Try it out!

Yaser
 
Old 04-28-2003, 09:58 AM   #12
Encrypted
LQ Newbie
 
Registered: Jan 2003
Distribution: Red Hat 8.0, Debian 3.0
Posts: 20

Original Poster
Rep: Reputation: 0
But isnt the payload the data of the packet?

because there isnt any data with the handshake.....
so the payload must be zero right?
that wont change a thing i assume.

this is getting pretty annoying,

but thanks anyway

encrypted
 
Old 04-28-2003, 11:04 PM   #13
yrraja
Member
 
Registered: Sep 2002
Distribution: RH, FC, Ubuntu, Solaris, AIX
Posts: 114

Rep: Reputation: 15
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));

Just check if u are setting this field to zero.

Yaser
 
Old 05-03-2003, 03:10 AM   #14
Encrypted
LQ Newbie
 
Registered: Jan 2003
Distribution: Red Hat 8.0, Debian 3.0
Posts: 20

Original Poster
Rep: Reputation: 0
Hi,

i found the problem,
just a little thing that i forget,
instead of
Code:
pseudo->length = htons(sizeof(struct tcphdr) );
i did
Code:
pseudo->length= sizeof(struct tcphdr);
But its working now


thanks,
encrypted
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Pblm in Raw Sockets fpfernando Linux - Software 1 10-08-2005 01:04 AM
Raw Ethernet Sockets alanwolfen Programming 2 01-06-2005 06:51 PM
raw sockets and C wrongman Programming 3 05-04-2004 02:17 PM
can I use mmap with raw sockets? kanth Programming 2 02-28-2004 12:42 PM
raw sockets BashTin Programming 1 06-07-2003 06:34 AM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 04:13 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration