Help! Raw Socket CheckSum

A

Astroman

Hi guys and girls. This is my first time posting here so go easy :) .
I was wondering if someone could please interpret how this csum()
function works in the following C code. I know that the function
returns the checksum value but I was wondering How. I only included
the top half of the c code because you probably dont need the other
half and also it is a syn flooding program so I thought I shouldn't
post the whole lot. This is from the raw socket programming tutorial
written by Mixter. Couldn't find anything better. Just FAQ's.

#define __USE_BSD /* use bsd'ish ip header */
#include <sys/socket.h> /* these headers are for a Linux system, but
*/
#include <netinet/in.h> /* the names on other systems are easy to
guess.. */
#include <netinet/ip.h>
#define __FAVOR_BSD /* use bsd'ish tcp header */
#include <netinet/tcp.h>
#include <unistd.h>

#define P 25 /* lets flood the sendmail port */


/*PLEASE EXPLAIN THE BELOW ! */
unsigned short /* this function generates header checksums */
csum (unsigned short *buf, int nwords)
{
unsigned long sum;
for (sum = 0; nwords > 0; nwords--)
sum += *buf++;
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
return ~sum;
}

int
main (void)
{
int s = socket (PF_INET, SOCK_RAW, IPPROTO_TCP); /* open raw socket
*/
char datagram[4096]; /* this buffer will contain ip header, tcp
header,
and payload. we'll point an ip header structure
at its beginning, and a tcp header structure after
that to write the header values into it */
struct ip *iph = (struct ip *) datagram;
struct tcphdr *tcph = (struct tcphdr *) datagram + sizeof (struct
ip);
struct sockaddr_in sin;
/* the sockaddr_in containing the dest. address is used
in sendto() to determine the datagrams path */

sin.sin_family = AF_INET;
sin.sin_port = htons (P);/* you byte-order >1byte header values to
network
byte order (not needed on big endian machines) */
sin.sin_addr.s_addr = inet_addr ("127.0.0.1");

memset (datagram, 0, 4096); /* zero out the buffer */

/* we'll now fill in the ip/tcp header values, see above for
explanations */
iph->ip_hl = 5;
iph->ip_v = 4;
iph->ip_tos = 0;
iph->ip_len = sizeof (struct ip) + sizeof (struct tcphdr); /* no
payload */
iph->ip_id = htonl (54321); /* the value doesn't matter here */
iph->ip_off = 0;
iph->ip_ttl = 255;
iph->ip_p = 6;
iph->ip_sum = 0; /* set it to 0 before computing the actual
checksum later */
iph->ip_src.s_addr = inet_addr ("1.2.3.4");/* SYN's can be blindly
spoofed */
iph->ip_dst.s_addr = sin.sin_addr.s_addr;
tcph->th_sport = htons (1234); /* arbitrary port */
tcph->th_dport = htons (P);
tcph->th_seq = random ();/* in a SYN packet, the sequence is a
random */
tcph->th_ack = 0;/* number, and the ack sequence is 0 in the 1st
packet */
tcph->th_x2 = 0;
tcph->th_off = 0; /* first and only tcp segment */
tcph->th_flags = TH_SYN; /* initial connection request */
tcph->th_win = htonl (65535); /* maximum allowed window size */
tcph->th_sum = 0;/* if you set a checksum to zero, your kernel's IP
stack
should fill in the correct checksum during transmission */
tcph->th_urp = 0;

/* HERE THE FUNCTION IS CALLED */

iph->ip_sum = csum ((unsigned short *) datagram, iph->ip_len >> 1);



Thanks
 
J

Jack Klein

Hi guys and girls. This is my first time posting here so go easy :) .
I was wondering if someone could please interpret how this csum()
function works in the following C code. I know that the function
returns the checksum value but I was wondering How. I only included
the top half of the c code because you probably dont need the other
half and also it is a syn flooding program so I thought I shouldn't
post the whole lot. This is from the raw socket programming tutorial
written by Mixter. Couldn't find anything better. Just FAQ's.

Since standard C has no built-in support for networking at all, such
code is all off-topic here.
#define __USE_BSD /* use bsd'ish ip header */
#include <sys/socket.h> /* these headers are for a Linux system, but
*/
#include <netinet/in.h> /* the names on other systems are easy to
guess.. */
#include <netinet/ip.h>
#define __FAVOR_BSD /* use bsd'ish tcp header */
#include <netinet/tcp.h>
#include <unistd.h>

In fact, each and every one of the headers above is a non-standard
extension, and off-topic here. There are no sockets in C.
/*PLEASE EXPLAIN THE BELOW ! */

Explain what, exactly? What is there about this function that you
don't understand? It using nothing but pointer dereference and
increment to add a number of values, using the '+=' operator. Do you
understand that? If not, what don't you understand about it.
unsigned short /* this function generates header checksums */
csum (unsigned short *buf, int nwords)
{
unsigned long sum;
for (sum = 0; nwords > 0; nwords--)
sum += *buf++;
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
return ~sum;
}

After it has finished adding up the required number of values, it does
some bit wise operations and a few more additions to fold the unsigned
long sum into the lesser rank type unsigned short.

Which of these operators do you have trouble with? '>>', '&', or '~'?

How does it work? By performing the very simple series of operations
defined in the handful of instructions. What does it do? It applies
an algorithm defined for some particular protocol to a data buffer to
generate the check value required by that protocol.

If you want to watch it work, put it in a single source code file with
a main() function. In your main() function define an array of
unsigned shorts and fill it with some data. Pass a pointer and the
length to the function. Then step through it in a debugger or add
printf() statements, and you will see how it works.

As to why this is the algorithm used to generate a check value for
data in this protocol, you will have to ask somebody responsible for
specifying the protocol. It is neither a C language nor a C coding
issue.

[snip the off-topic code]

Note that if your question is about the particular function, all you
needed to do was post the function, which is completely stand-alone
and needs no header files at all. But you certainly need to ask a
more specific question. If you do not understand the operation of the
code, tell us what part you don't understand. If you don't understand
the concept of some sort of verification value, check sum, CRC, or
otherwise, in communication protocols, that's a different matter and
not a C language issue at all.
 
M

Method Man

/*PLEASE EXPLAIN THE BELOW ! */
unsigned short /* this function generates header checksums */
csum (unsigned short *buf, int nwords)
{
unsigned long sum;
for (sum = 0; nwords > 0; nwords--)
sum += *buf++;
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
return ~sum;
}

This is OT and you don't clarify what you don't understand.

I can try explaining the C code itself. The algorithm assumes sizeof(short)
= 2. It sums up the values from the array. It then redefines 'sum' as 2*(16
high order bits of 'sum') + (16 low order bits of 'sum'). There is no
overflow because 'sum' is a long. Finally, it negates the sum (which many
checksum algorithms do) and returns it as a short for future transmission.

To understand more about checksum algos, try a different newsgroup.
 
J

jab3

Method Man finally wrote on Saturday 09 October 2004 03:28 am:
I can try explaining the C code itself. The algorithm assumes
sizeof(short) = 2. It sums up the values from the array. It then redefines
'sum' as 2*(16 high order bits of 'sum') + (16 low order bits of 'sum').

I may be confused, but I don't think that 2*(16 high order bits) + (16 low
order bits) describes what happens. As I read it, it adds the high order
bits to the low order bits, then it adds that result to the high order bits
of the result. For instance, if the number is AE9CF88A,

AE9C + F88A = 0001A726. ( sum = (sum >> 16) + (sum & 0xFFFF) )
0001A726 + 0001 = 0001A727. ( sum += (sum >> 16) )

Note: (various ways of interpreting your description)

2*(AE9C + F88A) = 34E4E
2* AE9C + F88A = 255C2
2* 0001 + A727 = A729
2*(0001 + A727) = 14E50

I'm new at this, so please correct me if I'm wrong, but that is how I
understood what was going on with that algorithm (minus the negation).


Thanks,
jab3
 
A

Astroman

Hi guys, thanks for that. You have answered my question, sorry for not
being more specific. I have also found a few rfc's to explain it for
me as well. Sorry for posting in the wrong newsgroup but thanks for
the help.
 
M

Method Man

jab3 said:
Method Man finally wrote on Saturday 09 October 2004 03:28 am:



I may be confused, but I don't think that 2*(16 high order bits) + (16 low
order bits) describes what happens. As I read it, it adds the high order
bits to the low order bits, then it adds that result to the high order bits
of the result.

Yes, you're correct.
 
J

Jack Klein

This is OT and you don't clarify what you don't understand.

I can try explaining the C code itself. The algorithm assumes sizeof(short)
= 2.

No, it does not make any assumptions at all about sizeof(short). Not
in bits or bytes. In fact this code would work unchanged on
implementations where sizeof(short) is 1 and sizeof(long) is 2. It
would also work unchanged on implementations where sizeof(short) is 1
and sizeof(long) is 1.
It sums up the values from the array.

It sums the values from the array into an unsigned long, which is
possibly wider than unsigned short.
It then redefines 'sum' as 2*(16
high order bits of 'sum') + (16 low order bits of 'sum').

Nonsense, it does not 'redefine' anything. 'sum' was defined as an
unsigned long at the start, and an unsigned long it remains. It
performs a computation on sum.
There is no
overflow because 'sum' is a long.

'sum' is an unsigned long, and hence it subject to modulo wrap around
if a calculation produces an out-of-range value. If it were a signed
long, overflow would be possible, producing undefined behavior.
Finally, it negates the sum (which many
checksum algorithms do) and returns it as a short for future transmission.

No, it returns it as an unsigned short, and that is quite different
since the expression '~sum' could well be outside the range of values
for a short, which would produce an implementation-defined result.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,965
Messages
2,570,148
Members
46,710
Latest member
FredricRen

Latest Threads

Top