-
February 10th, 2005, 04:48 PM
#1
Junior Member
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->check = 0x87e1;
tcp->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!
-
February 10th, 2005, 05:22 PM
#2
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
-
February 10th, 2005, 09:02 PM
#3
Junior Member
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->check=0xe9a8
tcp->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 <stdio.h>
#include <linux/ip.h>
#include <netinet/tcp.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
unsigned short 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 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("43.12.65.1");
ip->daddr = inet_addr("127.0.0.1");
ip->check = csum ((unsigned short *) packet, ip->tot_len >> 1);
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=csum ((unsigned short *) packet, ip->tot_len >> 1);
printf("ip->check=0x%x\n",ip->check);
printf("tcp->check=0x%x\n",tcp->check);
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;
}
-
February 10th, 2005, 10:18 PM
#4
"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
-
February 12th, 2005, 01:24 PM
#5
Junior Member
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!
-
February 13th, 2005, 02:34 AM
#6
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 > 1) {
sum += *w++;
nleft -= 2;
}
if (nleft == 1) {
*(u_char *) (&answer) = *(u_char *) w;
sum += answer;
}
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 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->saddr = ip->saddr;
fake->daddr = ip->daddr;
fake->protocol = IPPROTO_TCP;
fake->len = htons(sizeof(struct tcphdr));
fake->tcp = *tcp;
Finally, the checksum is calculated as follows:
Code:
tcp->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)
-
February 13th, 2005, 11:29 PM
#7
Junior Member
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->member..
But if the all the packet's data is stored into this buffer, when I writte printf("%i", ip->ttl); how does struct ip know where in the buffer the data ttl is stored?
-
February 14th, 2005, 12:26 AM
#8
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)
-
February 14th, 2005, 12:08 PM
#9
Junior Member
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!
-
February 15th, 2005, 03:14 PM
#10
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
-
Forum Rules
|
|