send packets with kernel routing and without kernel messing with headers
ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
send packets with kernel routing and without kernel messing with headers
Hey everyone. Ok I'm trying to send a packet and have the kernel do the routing for me. I have completely built the specified packet and it could be TCP, UDP, ICMP, etc...just anything on top of IP. All the headers have been created except for the ethernet layer. I want to send this to a socket and have it figure out the routing (if necessary). So if the packet is outbound it'll go to the default gateway and if it's on the internal net it'll just be send directly to the specified machine. Ok so here's what I've been doing.
Code:
if((fs=socket (PF_INET, SOCK_RAW, IPPROTO_TCP))<0)
perror("socket");
int one = 1;
const int *val = &one;
if(setsockopt (fs, IPPROTO_IP, IP_HDRINCL, val, sizeof (one))<0)
perror("iphdrincl");
sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = dest;
int ret=sendto(fs,data,len,0,(struct sockaddr *) &sin,sizeof (sin));
ok so basically that should create a raw socket and tell the kernel that the ip header is already done. then it'll get the previously supplied destination and send the packet. This seems to work from the program, the return value from sendto gives a positive number of the packet length indicating that it has been sent. At the same time I'm monitoring the network from my machine with Ethereal and no packet is in fact sent. If I don't include the setsockopt call I actually do get a packet on the network but it's header has been tampered with. Changing IPPROTO_TCP to IPPROTO_UDP has no same effect. And using IPPROTO_IP gives an error with setsockopt. Does anyone know what's going on here or how to do this? Any help would be appreciated. Also...what is the difference between protocol family and address family. AF_INET PF_INET etc...they seem interchangeable.
I'll try my best to answer some of your questions. I'll start off with the easy one. PF_INET is defined as AF_INET in linux/socket.h so it is in fact the same value. The comment above the PF_* defs is "/* Protocol families, same as address families. */".
I'm a bit confused by the rest... how can you send a packet with missing routing information and expect it to go anywhere? When you get the packet on the network what part of the header did it change?
that's actually the exact tutorial i've been using to get this far. And the problems I've run into are listed above. Ok as for the missing routing information question...the only information I want the kernel to fill in is the immediate destination...the ethernet layer. It has all the other routing information it needs. All IP's and ports are filled in. I just need the kernel to decide if it needs to go to the default gateway or not. So it has all the routing information. If the gateway MAC or the target machines MAC is put in the ethernet header then it will go where it needs to go. It will get dropped on the network and the MAC addr will send it to the gateway which would route it based on the IP or it will be sent immediately to the target system.
When I do get it on the network and I don't use the setsockopt for the IP header it changes a number of fields. Using IPPROTO_UDP for example changes the protocol field in IP to UDP. So the rest of the packet is interpreted as UDP even if it's not really a UDP packet. And then it would go ahead and change some data to fill in the UDP ports as it saw fit.
Yeah I didn't really want to use libnet. I've already reconstructed some of their methods. This is more for a learning exercise. I'd like to learn how to do it without relying on a library like libnet.
hey all. thanks for all the help. Also, thanks for the offer obashir. I found the problem, though. Before I was trying this I was working on the routing myself. So those packets still had an ethernet layer already on them. I bet the socket was sending the packet properly to the kernel (hence the positive value for sendto) but with the extra 14 bytes the IP header would be fubar. So the kernel was dropping the packet on the way out. That's my hypothesis anyways. Stupid mistake. Removing the first 14 bytes (the erroneous eth layer) solved the problem.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.