Newsgroup: it.comp.lang.c
Titolo: send tcp raw socket (bogus tcp header length)

Hi,
I don't know if I post my request in the correct group.
I try to send a packet with raw socket from a program wrote with c 
langage and compiled on linux os (kernel : 2.4.27-1-386) but I have an 
error with ethereal sniffer on windows xp.
I can't find any solution on the net.   :(     Could anybody help with 
that problem?
my code :
#define __USE_BSD
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#define __FAVOR_BSD
#include <netinet/tcp.h>
#include <unistd.h>
#include <ncurses.h>
#include <stdlib.h>
#include <string.h>
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 (int argc, char *argv[]){
if(argc < 5){
printf("Usage : %s <srcIP> <destIP> <destPORT> <nbDatagram>\n",argv[0]);
printf("Example : %s 192.168.0.140 192.168.0.146 445 5\n",argv[0]);
return -1;
}
char datagram[4096];
struct ip *iph = (struct ip *) datagram;
struct tcphdr *tcph = (struct tcphdr *) datagram + sizeof (struct ip);
struct sockaddr_in sin;
memset (datagram, 0, 4096);    /* zero out the buffer */
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = inet_addr (argv[2]);
sin.sin_port = htons (atoi(argv[3]));
/* we'll now fill in the ip/tcp header values */
   iph->ip_hl = 5;
   iph->ip_v = IPPROTO_IPIP;
   iph->ip_tos = 0;
   iph->ip_len = sizeof (struct ip) + sizeof (struct tcphdr);
   iph->ip_id = htonl (random());
   iph->ip_off = 0;
   iph->ip_ttl = 255;
   iph->ip_p = IPPROTO_TCP;
   iph->ip_sum = 0;
   iph->ip_src.s_addr = inet_addr (argv[1]);
   iph->ip_dst.s_addr = sin.sin_addr.s_addr;
   tcph->th_sport = htons (random());
   tcph->th_dport = sin.sin_port;
   tcph->th_seq = random ();
   tcph->th_ack = 0;
   tcph->th_x2 = 0;
   tcph->th_off = 0; (I tried with tcph->th_off = 5; too)
   tcph->th_flags = TH_SYN;
   tcph->th_win = htonl (65535);
   tcph->th_sum = 0;
   tcph->th_urp = 0;
   iph->ip_sum = csum ((unsigned short *) datagram, iph->ip_len >> 1);
int s = socket (PF_INET, SOCK_RAW, IPPROTO_TCP);    /* open raw socket */
int one = 1;
const int *val = &one;
if (setsockopt (s, IPPROTO_IP, IP_HDRINCL, val, sizeof (one)) < 0)
       printf ("Warning: Cannot set HDRINCL!\n");
int loop = 0;
while (loop<atoi(argv[4]))
{
   loop++;
   if (sendto (s,        /* our socket */
                datagram,    /* the buffer containing headers and data */
          iph->ip_len,    /* total length of our datagram */
          0,        /* routing flags, normally always 0 */
          (struct sockaddr *) &sin,    /* socket addr, just like in */
          sizeof (sin)) < 0)        /* a normal send() */
     printf ("error\n");
    else
     printf (".");
}
return 0;
}
And This is the ethereal's response :
No.     Time        Source                Destination           Protocol 
Info
       1 0.000000    192.168.0.140         192.168.0.146         TCP   0 
 > 0 [] Seq=0 Ack=0 Win=0, bogus TCP header length (0, must be at least 20)
Frame 1 (60 bytes on wire, 60 bytes captured)
Ethernet II, Src: 3com_b6:d6:29 (00:50:da:b6:d6:29), Dst: 
DellComp_d5:be:c6 (00:b0:d0:d5:be:c6)
Internet Protocol, Src: 192.168.0.140 (192.168.0.140), Dst: 
192.168.0.146 (192.168.0.146)
     Version: 4
     Header length: 20 bytes
     Differentiated Services Field: 0x00 (DSCP 0x00: Default; ECN: 0x00)
     Total Length: 40
     Identification: 0x0000 (0)
     Flags: 0x04 (Don't Fragment)
     Fragment offset: 0
     Time to live: 255
     Protocol: TCP (0x06)
     Header checksum: 0xf960 [correct]
     Source: 192.168.0.140 (192.168.0.140)
     Destination: 192.168.0.146 (192.168.0.146)
Transmission Control Protocol, Src Port: 0 (0), Dst Port: 0 (0), Seq: 0
     Source port: 0 (0)
     Destination port: 0 (0)
     Sequence number: 0    (relative sequence number)
     Header length: 0 bytes (bogus, must be at least 20)

You should correct the following lines:
1.  struct tcphdr *tcph = (struct tcphdr *) datagram + sizeof (struct
ip);
   with     struct tcphdr *tcph = (struct tcphdr *)(datagram + sizeof
(struct ip));
2.  tcph->th_off = 0;
   with     tcph->th_off = 5;
You should also calculate the TCP checksum.
Regards,
rbtqwt.

rbt...@gmail.com
 a écrit :

Thank you for your responses.
I can now send a raw packet correctly but I want to send some text in 
"char *data" too.
Have an idee to how to do that or a sample of code ?
this is my new code :
#define __USE_BSD	
#include <sys/socket.h>	
#include <netinet/in.h>	
#include <netinet/ip.h>
#define __FAVOR_BSD	
#include <netinet/tcp.h>
#include <unistd.h>
#include <ncurses.h>
#include <stdlib.h>
#include <string.h>
/*   tcph->th_flags =  TH_FIN, TH_SYN, TH_RST, TH_PUSH, TH_ACK, TH_URG */
unsigned short		/* this function generates header checksums */
csum (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);
}
struct psuedohdr {
struct in_addr source_address;
struct in_addr dest_address;
unsigned char place_holder;
unsigned char protocol;
unsigned short length;
} psuedohdr;
unsigned short trans_check(unsigned char proto,
char *packet,
int length,
struct in_addr source_address,
struct in_addr dest_address)
{
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) csum((unsigned short *)psuedo_packet,
(length + sizeof(psuedohdr)));
free(psuedo_packet);
return answer;
}
int main (int argc, char *argv[]){
struct in_addr saddr, daddr;
unsigned int sport, dport, nbpkt;
saddr.s_addr = inet_addr(argv[1]);
daddr.s_addr = inet_addr(argv[2]);
dport = atoi(argv[3]);
nbpkt = atoi(argv[4]);
if(argc < 5){
printf("Usage : %s <srcIP> <destIP> <destPORT> <nbDatagram>\n",argv[0]);
printf("Example : %s 192.168.0.140 192.168.0.146 445 5\n",argv[0]);
return -1;
}
char *data  = "Connected to server \r\n";
char *datagram;
int packet_size = (sizeof(struct iphdr)+sizeof(struct tcphdr));
datagram = malloc(packet_size);
struct ip *iph = (struct ip *) datagram;
struct tcphdr *tcph = (struct tcphdr *) (iph+1);
struct sockaddr_in sin;
bzero( datagram , packet_size );	/* zero out the buffer */
sin.sin_family = AF_INET;
sin.sin_addr = daddr;
sin.sin_port = htons (dport);
/* we'll now fill in the ip/tcp header values */
   tcph->th_sport = htons (random());
   tcph->th_dport = htons (dport);
   tcph->th_seq = htonl (random());
   tcph->th_ack = htonl (random());
   tcph->th_x2 = 0;
   tcph->th_off = 5;
   tcph->th_flags = TH_SYN;
   tcph->th_win = 65535;
   tcph->th_sum = trans_check(IPPROTO_TCP,(char *)tcph,(sizeof(struct 
tcphdr)), saddr, daddr);
   tcph->th_urp = 0;
   iph->ip_hl = 5;
   iph->ip_v = IPPROTO_IPIP;
   iph->ip_tos = 0;
   iph->ip_len = packet_size ;
   iph->ip_id = htonl (random());
   iph->ip_off = htons(0x4000);
   iph->ip_ttl = 128;
   iph->ip_p = IPPROTO_TCP;
   iph->ip_src = saddr;
   iph->ip_dst = daddr;
   iph->ip_sum = csum ((unsigned short *) datagram, iph->ip_len >> 1);
int s = socket (PF_INET, SOCK_RAW, IPPROTO_TCP);	/* open raw socket */
int one = 1;
const int *val = &one;
if (setsockopt (s, IPPROTO_IP, IP_HDRINCL, val, sizeof (one)) < 0)
       printf ("Warning: Cannot set HDRINCL!\n");
int loop = 0;
while (loop<nbpkt)
{
   loop++;
   if (sendto (s,		/* our socket */
       	     datagram,	/* the buffer containing headers and data */
	     iph->ip_len,	/* total length of our datagram */
	     0,		/* routing flags, normally always 0 */
	     (struct sockaddr *) &sin,	/* socket addr, just like in */
	     sizeof (sin)) < 0)		/* a normal send() */
	printf ("error\n");
    else
	printf (".");
}
printf("\n");
return 0;
}

Simply:
1. Increase the packet_size variable.
2. Append the data to the packet.
3. Increase the number of bytes to check in the TCP checksum.
... [ code ] ...
int packet_size = (sizeof(struct iphdr)+sizeof(struct tcphdr)) +
strlen(data);
... [ code ] ...
bzero(datagram, packet_size );
strcpy(tcph+1, data);
... [ code ] ...
tcph->th_sum = trans_check(IPPROTO_TCP,(char *)tcph,(sizeof(struct
tcphdr)) + strlen(data), saddr, daddr);
... [ code ] ...
Regards,
rbtqwt.