Raw socket programming Q.
Results 1 to 10 of 10

Thread: Raw socket programming Q.

  1. #1
    Junior Member
    Join Date
    Feb 2005
    Posts
    8

    Question Raw socket programming Q.

    Hello everybody!

    I'm very interested in networking. I'm learning socket programming on Linux. I know that exists RAW sockets. I have searched for tutorials, but didn't find anything very useful. Then I searched in google for sock_raw filetype:c and found so much useful information. I'm new to C, so I didn't understand much things, but I have basic understand of socket programming. I hope you guys will help me a little.

    I'm trying to make my code to send the first packet of the three-way hand shake. Here is the code that I got so far, unfortunetly it send's a socket, but it dosn't work!

    #include <stdio.h>
    #include <linux/ip.h>
    #include <netinet/tcp.h>
    #include <netinet/in.h>
    #include <sys/types.h>
    #include <sys/socket.h>

    int main(){

    int sock, optval;
    char *packet;

    struct sockaddr_in server;
    struct iphdr *ip;
    struct tcphdr *tcp;

    server.sin_family = AF_INET;
    server.sin_addr.s_addr = inet_addr("127.0.0.1");
    server.sin_port = htons(80);

    ip = (struct iphdr *) malloc(sizeof(struct iphdr));
    tcp = (struct tcphdr *) malloc(sizeof(struct tcphdr));
    packet = (char *) malloc(sizeof(struct iphdr) + sizeof(struct tcphdr));

    ip = (struct iphdr *) packet;
    tcp = (struct tcphdr *) (packet + sizeof(struct iphdr));

    ip->ihl = 5;
    ip->version = 4;
    ip->tos = 0;
    ip->tot_len = sizeof(struct iphdr) + sizeof(struct tcphdr);
    ip->id = htons(getuid());
    ip->ttl = 255;
    ip->protocol = IPPROTO_TCP;
    ip->saddr = inet_addr("127.0.0.1");
    ip->daddr = inet_addr("127.0.0.1");
    ip->check = 0x87e1;

    tcp->source=htons(80);
    tcp->dest=htons(80);
    tcp->seq=htonl(rand()%time(NULL));
    tcp->ack_seq=htonl(0);
    tcp->doff=5;
    tcp->fin=0;
    tcp->syn =1;
    tcp->rst=0;
    tcp->psh=0;
    tcp->ack=0;
    tcp->urg=0;
    tcp->window=htons(4000);
    tcp->urg_ptr=htons(0);
    tcp->check=0x4fe2;

    sock = socket(AF_INET,SOCK_RAW,IPPROTO_TCP);
    setsockopt(sock,IPPROTO_IP,IP_HDRINCL,&optval,sizeof(int));
    sendto(sock,packet,ip->tot_len,0,(struct sockaddr *)&server,sizeof(struct sockaddr));
    close(sock);
    return 0;
    }
    First of all these lines allocate memory, can these lines be writted more simply? I don't realy understand them! Why can't I just create pointer to structure?
    ip = (struct iphdr *) malloc(sizeof(struct iphdr));
    tcp = (struct tcphdr *) malloc(sizeof(struct tcphdr));
    packet = (char *) malloc(sizeof(struct iphdr) + sizeof(struct tcphdr));
    And here are the next two lines:

    ip = (struct iphdr *) packet;
    tcp = (struct tcphdr *) (packet + sizeof(struct iphdr));
    I think it means that ip will be pointer to struct iphdr, but what does packet mean?

    ip-&gt;check = 0x87e1;
    tcp-&gt;check=0x4fe2;
    I know that I need to write some cind of function to calcolate the checksum, but I realy have no idea how to do it! Does anyone know how any tutorial how to do this? I know that I can just use other people functions, but I want to create my own! Allso I use ethereal to monitor my packet, but the strangest thing is that even if I write a checksum in IP header, ethereal shows me different checksum for IP header, but it shows that this checksum is correct!

    I started Apache, and send my packet to Apache, but it didn't reply! I think its because the TCP wrong checksum!

    I know I'm asking much, but I really want to understand how it works, so I want to get this code as simple as posible! Thank you!

  2. #2
    Senior Member Maestr0's Avatar
    Join Date
    May 2003
    Posts
    604
    Chekusms arent too bad once you figure them out.
    http://www.linuxworld.com/story/34589.htm?DE=1

    Once you figure it out you might look into libnet by Daemon9 aka Route aka M.Schiffman.
    http://www.packetfactory.net/projects/libnet/


    -Maestr0
    \"If computers are to become smart enough to design their own successors, initiating a process that will lead to God-like omniscience after a number of ever swifter passages from one generation of computers to the next, someone is going to have to write the software that gets the process going, and humans have given absolutely no evidence of being able to write such software.\" -Jaron Lanier

  3. #3
    Junior Member
    Join Date
    Feb 2005
    Posts
    8
    Thank you!
    I added the checksum function into my code, but still the TCP checksum is incorect! I ran ethereal and here are the results:

    my code prints out IP and TCP checksums:
    ip-&gt;check=0xe9a8
    tcp-&gt;check=0x2ffb

    These are the results from ethereal:
    IP checksum: 0x790a (correct)
    TCP checksum: 0xfb2f (incorrect, should be 0x1007)

    And take a look at tcp's checksum in my code output and in ethereal:
    ethereal: 0x2ffb
    my code: 0xfb2f
    It like flips 0xab to 0xba! Does it has to be this way?

    I don't get it! Why is my TCP checksum incorrect? Here is my modified code:
    #include &lt;stdio.h&gt;
    #include &lt;linux/ip.h&gt;
    #include &lt;netinet/tcp.h&gt;
    #include &lt;netinet/in.h&gt;
    #include &lt;sys/types.h&gt;
    #include &lt;sys/socket.h&gt;

    unsigned short csum (unsigned short *buf, int nwords){
    unsigned long sum;
    for (sum = 0; nwords &gt; 0; nwords--)
    sum += *buf++;
    sum = (sum &gt;&gt; 16) + (sum & 0xffff);
    sum += (sum &gt;&gt; 16);
    return ~sum;
    }

    int main(){

    int sock, optval;
    char *packet;

    struct sockaddr_in server;
    struct iphdr *ip;
    struct tcphdr *tcp;

    server.sin_family = AF_INET;
    server.sin_addr.s_addr = inet_addr("127.0.0.1");
    server.sin_port = htons(80);

    ip = (struct iphdr *) malloc(sizeof(struct iphdr));
    tcp = (struct tcphdr *) malloc(sizeof(struct tcphdr));
    packet = (char *) malloc(sizeof(struct iphdr) + sizeof(struct tcphdr));

    ip = (struct iphdr *) packet;
    tcp = (struct tcphdr *) (packet + sizeof(struct iphdr));

    ip-&gt;ihl = 5;
    ip-&gt;version = 4;
    ip-&gt;tos = 0;
    ip-&gt;tot_len = sizeof(struct iphdr) + sizeof(struct tcphdr);
    ip-&gt;id = htons(getuid());
    ip-&gt;ttl = 255;
    ip-&gt;protocol = IPPROTO_TCP;
    ip-&gt;saddr = inet_addr("43.12.65.1");
    ip-&gt;daddr = inet_addr("127.0.0.1");
    ip-&gt;check = csum ((unsigned short *) packet, ip-&gt;tot_len &gt;&gt; 1);

    tcp-&gt;source=htons(80);
    tcp-&gt;dest=htons(80);
    tcp-&gt;seq=htonl(rand()%time(NULL));
    tcp-&gt;ack_seq=htonl(0);
    tcp-&gt;doff=5;
    tcp-&gt;fin=0;
    tcp-&gt;syn =1;
    tcp-&gt;rst=0;
    tcp-&gt;psh=0;
    tcp-&gt;ack=0;
    tcp-&gt;urg=0;
    tcp-&gt;window=htons(4000);
    tcp-&gt;urg_ptr=htons(0);

    tcp-&gt;check=csum ((unsigned short *) packet, ip-&gt;tot_len &gt;&gt; 1);


    printf("ip-&gt;check=0x%x\n",ip-&gt;check);
    printf("tcp-&gt;check=0x%x\n",tcp-&gt;check);

    sock = socket(AF_INET,SOCK_RAW,IPPROTO_TCP);
    setsockopt(sock,IPPROTO_IP,IP_HDRINCL,&optval,sizeof(int));
    sendto(sock,packet,ip-&gt;tot_len,0,(struct sockaddr *)&server,sizeof(struct sockaddr));
    close(sock);
    return 0;
    }

  4. #4
    Senior Member Maestr0's Avatar
    Join Date
    May 2003
    Posts
    604
    "And take a look at tcp's checksum in my code output and in ethereal:
    ethereal: 0x2ffb
    my code: 0xfb2f
    It like flips 0xab to 0xba! Does it has to be this way?"

    Read about libnet it will do some of this nasty stuff for you. You have to take into account network byte order is big-endian, x86 is little-endian, so yes, they will be in reverse order until you flip'em.

    -Maestr0

    http://wwwwbs.cs.tu-berlin.de/user-t...yte_Order.html
    \"If computers are to become smart enough to design their own successors, initiating a process that will lead to God-like omniscience after a number of ever swifter passages from one generation of computers to the next, someone is going to have to write the software that gets the process going, and humans have given absolutely no evidence of being able to write such software.\" -Jaron Lanier

  5. #5
    Junior Member
    Join Date
    Feb 2005
    Posts
    8
    Thanks!
    I would like to do it without libnet! I used that checksum function from http://www.linuxworld.com/story/34589.htm?DE=1 but the checksum is still wrong! Please look at the code! Thank you!

  6. #6
    Senior Member
    Join Date
    Mar 2004
    Posts
    557
    Hi

    The function which calculates the TCP checksum is the following:
    Code:
    unsigned short tcp_checksum(u_short * addr, int len){
    
        register int nleft = len;
        register u_short *w = addr;
        register int sum = 0;
        u_short answer = 0;
    
        while (nleft &gt; 1) {
    	sum += *w++;
    	nleft -= 2;
        }
    
        if (nleft == 1) {
    	*(u_char *) (&answer) = *(u_char *) w;
    	sum += answer;
        }
    
        sum = (sum &gt;&gt; 16) + (sum & 0xffff);
        sum += (sum &gt;&gt; 16);
        answer = ~sum;
    
        return (answer);
    }
    However, it is not so simple to use it as you try. The TCP Checksum is
    a mixture of the IP and the TCP header, namely

    Code:
    // fake header
    
    struct fake_header
    {
    	unsigned long saddr;
    	unsigned long daddr;
    	char dummy;
    	unsigned char protocol;
    	unsigned short len;
    	struct tcphdr tcp;
    };
    struct fake_header *fake;
    (...)
    	///////////////// calculate the tcp checksum
    
    
    	fake = (struct fake_header *)malloc(sizeof(struct fake_header));
    	memset(fake, 0, sizeof(struct fake_header)); 
    	fake-&gt;saddr    = ip-&gt;saddr; 
    	fake-&gt;daddr    = ip-&gt;daddr; 
    	fake-&gt;protocol = IPPROTO_TCP;	  
    	fake-&gt;len   = htons(sizeof(struct tcphdr)); 
    	fake-&gt;tcp      = *tcp;
    Finally, the checksum is calculated as follows:
    Code:
    	tcp-&gt;check = tcp_checksum((unsigned short *)fake, sizeof(struct fake_header));
    You realise, that the header to calculate the tcp checksum consists of
    - IP: source and destination address
    - a delimiter 0x00 (dummy)
    - TCP: size of tcphdr, followed by the tcpheader.

    Find attached the working code.

    Cheers
    If the only tool you have is a hammer, you tend to see every problem as a nail.
    (Abraham Maslow, Psychologist, 1908-70)

  7. #7
    Junior Member
    Join Date
    Feb 2005
    Posts
    8
    Thank you very much sec_ware!
    Finaly a working checksum!

    I still got two questions! I hope you don't mind!

    fake = (struct fake_header *)malloc(sizeof(struct fake_header));
    Does this code allocates only memory or does something more?

    I found a simple source code for sniffer. The thing that confuses me is that there was this line on the code:
    ip = (struct ip *)buffer;
    buffer is just an char array. All the incoming data are stored into buffer, and I can access it with ip-&gt;member..
    But if the all the packet's data is stored into this buffer, when I writte printf("%i", ip-&gt;ttl); how does struct ip know where in the buffer the data ttl is stored?

  8. #8
    Senior Member
    Join Date
    Mar 2004
    Posts
    557
    Hi hyaku_

    The fake-malloc command only allocates memory. The only thing to mention
    here is that malloc by default returns a pointer to the allocated memory region
    of type "void". Because we want this region to be of type "struct fake_header",
    we perform a little type-casting in order to be able to store the address in "fake".

    And that's exactly how this magic works. With
    Code:
    ip = (struct ip *)buffer;
    you "structure" the char array "buffer", which essentially is just another
    allocated space in memory.

    Cheers.
    If the only tool you have is a hammer, you tend to see every problem as a nail.
    (Abraham Maslow, Psychologist, 1908-70)

  9. #9
    Junior Member
    Join Date
    Feb 2005
    Posts
    8
    Thank you!
    I dont seem to understand that casting! For example bind function takes argument for example (struct sockaddr *)&server. I don't get it! What is the point of this? Why so much casting?

    In raw socket programming why do I need to create an ip and tcp pointer instead of an regular object?

    Do you know any c tutorial about this object, pointer casting? I don't get it!

    When I chacke packet varibles size to something bigger than 1024, why is the checksum invalid?
    And where did you learn raw socket programming? Thanx!

  10. #10
    Senior Member
    Join Date
    Mar 2004
    Posts
    557
    Hi hyaku_

    Casting is a very interesting and important concept.

    In this example of bind, you are not passing the whole object "server", but the pointer
    to the address, where this object is. Since c/c++ is pretty well defined (in contrast to
    fortran), a function should properly define the type of object it is expecting.
    Hence, in bind, due to compatibility with older Winsock-Versions, the expected structure
    is sockaddr.

    This is one example - in general, casting allows you to pass structured memory to a function
    that is not suited for that structure. For example, you can pass the complicated sockaddr
    memory to a function, which prints the memory to the console - for example expecting
    some char buffer[1024] type of object.

    Unfortunately I don't know a decent tutorial about this stuff. But try google for
    "c c++ advanced type casting tutorial" or something like that.

    Code:
    In raw socket programming why do I need to create an ip and tcp pointer instead of an regular object?
    There is a reason if you receive packets.
    In my example, I allocated some buffer (1024 bytes), which was enough for the object
    (I don't know why the function fails for >1024-buffers - I should check, once I find the
    time, because there should be no such an interference.).
    In your example, you allocated what was needed (malloc).
    If you send packets, you know what you are going to send, hence you could instantiate
    "real objects".
    But if you receive packets, you primarily do not know what you are receiving - hence,
    you store those packets in some buffer (or otherwise allocated memory region), and then
    start to analyse it.

    Cheers
    If the only tool you have is a hammer, you tend to see every problem as a nail.
    (Abraham Maslow, Psychologist, 1908-70)

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •