Click here to Skip to main content
15,890,690 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Have been stuck in this problem for several days :-(

Can anyone help me please..?

the core code:
IP header
C++
typedef struct ip_hdr 
{
  /*unsigned char	
  			version:4,
  			ihl:4;*/
  unsigned char 	h_ver;
  unsigned char		tos;
  unsigned short	tot_len;
  unsigned short	id;
  unsigned short
  			zero:1,
			frag:1,
			more_frag:1,	
  			frag_off:13; 			
  unsigned char		ttl;
  unsigned char		protocol;
  unsigned short	checkSum;
  unsigned long		saddr;
  unsigned long		daddr;
  /*The options start here. */
}IP_HEADER;

oh and I really worried about the problem of big/small endian,is this header correct?I type it with the reference of RFC791.Internet Protocol
Generate an IP datagram
C++
int IPGen(ip_hdr *hdr,unsigned long srcIP,unsigned long dstIP)
{
	/*hdr->version=4;
	hdr->ihl=5;//= =?*/
	hdr->h_ver=(4<<4 | sizeof(ip_hdr)/sizeof(unsigned int));
	hdr->tos=0;
	hdr->tot_len=sizeof(ip_hdr)+sizeof(tcp_hdr);
	hdr->id=0;
	hdr->zero=0;
	hdr->frag=0;
	hdr->more_frag=0;
	hdr->frag_off=0;
	hdr->ttl=64;
	hdr->protocol=IP_TCP;
	hdr->saddr=srcIP;
	hdr->daddr=dstIP;

	hdr->saddr=htonl(hdr->saddr);
	hdr->daddr=htonl(hdr->daddr);
	hdr->tot_len=htons(hdr->tot_len);

	hdr->checkSum=0;
	hdr->checkSum=checkSum((char*)hdr,sizeof(ip_hdr);
	return 0;
}

the checkSum function
I copied it from the source code of linux thus I assume that the function works properly,but just in case;-)
C++
unsigned short checkSum(unsigned char * buff, int wlen)
{
    unsigned long sum = 0;

    if (wlen) {
    	unsigned long bogus;
	 __asm__("clc\n"
		"1:\t"
		"lodsl\n\t"
		"adcl %3, %0\n\t"
		"decl %2\n\t"
		"jne 1b\n\t"
		"adcl $0, %0\n\t"
		"movl %0, %3\n\t"
		"shrl $16, %3\n\t"
		"addw %w3, %w0\n\t"
		"adcw $0, %w0"
	    : "=r" (sum), "=S" (buff), "=r" (wlen), "=a" (bogus)
	    : "0"  (sum),  "1" (buff),  "2" (wlen));
    }
    return (~sum) & 0xffff;
}

the warning from G++ 4.7.1(MinGW)
In function 'int IPGen(ip_hdr*, long unsigned int, long unsigned int)':
[Warning] invalid conversion from 'char*' to 'unsigned char*' [-fpermissive]
[Warning] initializing argument 1 of 'short unsigned int checkSum(unsigned char*, int)' [-fpermissive]

and than Wireshark told me that all packet I sent has an wrong IP checkSum :-(
but the really weird thing is I save a normal packet's bytes,and calculate its IP checksum with following code:
C++
(ip_hdr*)(pktbytes+sizeof(eth_hdr))->checkSum=0;
unsigned short checkSum2=checkSum(pktbytes+sizeof(eth_hdr),sizeof(ip_hdr));

I FOUND THAT checkSum2 is unequal to the original checksum!!!
Please,help.
Posted
Updated 2-Feb-14 2:42am
v2
Comments
Sergey Alexandrovich Kryukov 2-Feb-14 17:56pm    
To represent raw unstructured data usually used for hashes, encryption, etc., always use unsigned bytes.
—SA
[no name] 2-Feb-14 19:36pm    
I think you need to break this problem down into smaller pieces. A statement like "I copied it from the source code of linux thus I assume that the function works properly" doesn't cut it. You are the one who needs to confirm this. Ideally test the individual pieces in isolation using some standard test data and then put the whole thing together. SA's comment could be prescient.

This might be a problem of unpacked structures. The IP structures must be packed (containing no pad bytes). Most compilers will insert pad bytes into structures to align the adresses of members. So you must tell the compiler to use packed structures. See the packed attribute at http://gcc.gnu.org/onlinedocs/gcc-4.7.3/gcc/Type-Attributes.html[^] for the GCC compiler.

Your structure should be:
C++
typedef struct __attribute__((packed)) ip_hdr
{
  unsigned char     h_ver;
// ...


The warnings shown by the compiler can be omitted by casting the header structure to the correct type unsigned char * instead of char *:
// Wrong
//hdr->checkSum=checkSum((char*)hdr,sizeof(ip_hdr);
// Correct
hdr->checkSum=checkSum((unsigned char*)hdr,sizeof(ip_hdr);
 
Share this answer
 
Solved!!
passing a count of bytes in the second argument to checkSum, but the online assembler treats it as a count of uint32_t
so devide the sizeof by sizeof(long) will do
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900