Problem with Raw Sockets

This is a discussion on Problem with Raw Sockets within the Linux Programming forums, part of the Platform Specific Boards category; Hi, im pretty new to raw sockets and, obviously, im having a problem, take a look at this Heres what ...

  1. #1
    Registered User
    Join Date
    Nov 2002
    Posts
    24

    Problem with Raw Sockets

    Hi,

    im pretty new to raw sockets and, obviously, im having a problem, take a look at this

    Heres what tcpdump says
    Code:
    23:51:31.971322 (tos 0x0, ttl 64, length: 40) 192.168.***.***.23456 > beast.dierentuin.com.http: S [bad tcp cksum ff09 (->126b)!] 752722692:752722692(0) win 12000
    and heres the code
    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 );
    
    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);
    
    	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 = (unsigned short)in_cksum((unsigned short *)tcp, (sizeof(struct tcphdr)));
    
    	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);
    }
    As you noticed, the TCP checksum is incorrect, but i have no idea how it is incorrect,
    any help is appreciated,

    i allready got some help on other forums, but i couldnt get the program working.....

    thanks
    encrypted

  2. #2
    Registered User
    Join Date
    Apr 2002
    Posts
    110
    Now it is time to shamelessly plug another forum for no apearant reason.

    Unix Socket FAQ

    Good place really is, and you will undoutably have better luck finding an answer to your problem by searching through that forum.

    As far as my interpretation of it goes
    Code:
    iphdr->ip_sum = (unsigned short)in_cksum((unsigned short *)iphdr, sizeof(struct ip));
    You do not need to cast the return value from in_cksum as an unsigned short as that is the value that is being returned.

    As far as the actual checksum goes, I have no real idea. But they are all 16bits, and the code that you are using is used by many programs, including those that I write.

    Some interesting reading include
    Comuting Internet Checksums

    Hope this helps in your programming.

    Later,
    WebmasterMattD
    WebmasterMattD.NET

  3. #3
    Registered User
    Join Date
    Nov 2002
    Posts
    24
    Hey thanks for the links, they were really helpfull
    i got the error now.

    For anyone interested:
    You need a pseudo header in order to calculate the checksum properly.
    That header contains 5 members;
    protocol (IPPROTO_TCP)
    length ( htons( sizeof(struct tcphdr)) )
    saddr ( just source address, as returned with inet_addr() )
    daddr ( same as above only destination address)
    zero ( has to be set to zero )
    now, you dont sent this header along with the packet (hence PSEUDO).
    You have to calculate the TCP checksum over the pseudo header and the TCP header, but it is not send with the packet, you can do that like this: (This is a quote from RobSeace from that UNIX Socket Faq forum MattD gave me)
    No, the pseudo-header is just that: a PSEUDO-header... It's
    not actually transmitted at all... It's a purely conceptual construct
    designed solely for computing the TCP checksum... In concept,
    it comes immediately before the TCP header; but, in reality, it
    just doesn't exist, at all... (Confused yet? ;-))

    In that nmap code you posted, it's just using the buffer space
    immediately prior to the TCP header (actually part of the IP
    header) for temporarily holding the pseudo-header info, while
    it performs the checksum... If you notice in later bits of the code,
    it can get away with that, because it FIRST fills in the TCP
    header and pseudo-header, THEN moves onto the IP header
    (thereby overwriting the pseudo-header junk that was occupying
    the last 12 bytes)...
    I know this is just a primer to pseudo headers and stuff, but its nice to know you need a pseudo header

    And heres the code (it sends a SYN packet to beast.dierentuin.com on port 80)
    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>
    
    struct pseudo_header
    {
          /*for computing TCP checksum, see TCP/IP Illustrated p. 145 */
          unsigned long s_addr;
          unsigned long d_addr;
          char zer0;
          unsigned char protocol;
          unsigned short length;
    };
    
    unsigned short in_cksum( unsigned short *addr, int len );
    
    int main()
    {
       int sockfd, packet_size, sport, dport;
       int on = 1, data_len = 0;
       char *packet;
    
       packet_size = (sizeof(struct ip) + sizeof(struct tcphdr));
       packet = malloc(packet_size);
    
       struct in_addr srcaddr, dstaddr;
       struct sockaddr_in sock_raw;
       struct ip *iphdr = (struct ip *)packet;
       struct in_addr saddr, daddr;
       struct pseudo_header *psuedo = (struct pseudo_header *) (packet + sizeof(struct iphdr) - sizeof(struct pseudo_header));
       struct tcphdr *tcp = (struct tcphdr *)(packet + sizeof( struct ip));
       
       bzero(packet, sizeof(struct iphdr) + sizeof(struct tcphdr));
       
       saddr.s_addr = inet_addr("192.168.168.251");
       daddr.s_addr = inet_addr("194.109.192.114");
    
       
       psuedo->protocol = IPPROTO_TCP;
       psuedo->length = htons(sizeof(struct tcphdr));
       psuedo->s_addr = inet_addr("192.168.168.251");
       psuedo->d_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) );
    
       
            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_FIN;
            tcp->th_win = htons(12000);
       tcp->th_sum = 0;
       tcp->th_sum = in_cksum((unsigned short *)psuedo, sizeof(struct tcphdr) + sizeof(struct pseudo_header));
    
            bzero(packet, sizeof(struct iphdr));
       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));
    
       
       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);
    }
    (btw, i didnt made that in_cksum, because that function is not available in linux (as far as i know) this is a way so i can still use it )

    later,
    encrypted

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Sockets and UDP problem
    By ally153 in forum C Programming
    Replies: 5
    Last Post: 03-20-2006, 04:19 AM
  2. Laptop Problem
    By Boomba in forum Tech Board
    Replies: 1
    Last Post: 03-07-2006, 05:24 PM
  3. multiple UDP sockets with select()
    By nkhambal in forum Networking/Device Communication
    Replies: 2
    Last Post: 01-17-2006, 06:36 PM
  4. Replies: 5
    Last Post: 11-07-2005, 10:34 PM
  5. searching problem
    By DaMenge in forum C Programming
    Replies: 9
    Last Post: 09-12-2005, 01:04 AM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21