7

According to http://linux.die.net/man/7/raw , raw_socket = socket(AF_INET, SOCK_RAW, int protocol); is the way to create a raw socket.

  1. I assume that raw-sockets are created on layer-3 and so protocol shouldn't be IPPROTO_TCP / IPPROTO_UDP but it should be IPPROTO_IP. Is this understanding correct?

  2. But when I create the raw socket with protocol as IPPROTO_IP (*socketFd = socket(AF_INET, SOCK_RAW, IPPROTO_IP);), socket creation fails with the error Protocol not supported

  3. When I create the raw socket with protocol as IPPROTO_RAW (*socketFd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);), my application doesn't receive any of packets

  4. When I create the raw socket with protocol as IPPROTO_TCP (socketFd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);), my application receives the TCP packets, but kernel also responds to these packets (and in my case it RSTs the link). I assume it is because kernel thinks there isn't anybody listening to the port to which that packet is intended to.

My intention is just to send responses to the messages coming to my application with a fake IP and TCP header. Since none of the above tries worked for me, how should I create the raw socket and make kernel TCP layer to be quiet for only that connection?

EDIT: Please skip questions 1-3. They are already answered by Filipe. For ques 4, we do have a workaround. But keeping the question open, if someone out here has an answer and would like to answer it.

Raj Kumar
  • 143
  • 2
  • 11
  • I can create a dummy tcp-socket and mislead kernel to forward the packets to both the sockets (dummy tcp-socket as well as my raw-socket). And the dummy socket will just absorb the packets and do nothing and my raw-socket will do what it is designed to do. But is that the only way? – Raj Kumar Aug 01 '15 at 13:28
  • You can use AF_PACKET and the kernel will do exactly nothing to your packets (all the way down to the MAC layer). But I'm not sure if that's what you want. – Jonathon Reinhart Aug 01 '15 at 13:37
  • when i try to do so by, "socketFd = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW);", socket creation fails saying "Protocol not available" – Raj Kumar Aug 01 '15 at 13:43
  • Are you running your program as root? Normal users cannot open raw sockets. – Jonathon Reinhart Aug 01 '15 at 13:45
  • yes, it is being run by root user "root@xxx:" – Raj Kumar Aug 01 '15 at 13:46

3 Answers3

9

I assume that raw sockets are created on layer-3 and so protocol shouldn't be IPPROTO_TCP / IPPROTO_UDP but it should be IPPROTO_IP. Is this understanding correct?

No. You are right that raw sockets are basically layer 3 packets, but the protocol should not be IPPROTO_IP. The protocol argument in the case of raw sockets indicates what type of packets you are interested in receiving on that socket. Remember that a protocol essentially performs transport-level demultiplexing, so you need to specify what type of protocol your raw socket is interested in. This is made clear in man 7 raw:

All packets or errors matching the protocol number specified for the raw socket are passed to this socket. For a list of the allowed protocols see RFC 1700 assigned numbers and getprotobyname(3).

Since you are interested in receiving IP packets for a TCP connection, you should use IPPROTO_TCP.

But when I create the raw socket with protocol as IPPROTO_IP (*socketFd = socket(AF_INET, SOCK_RAW, IPPROTO_IP);), socket creation fails with the error Protocol not supported.

Yes, that's kind of expectable: the IP protocol is not a layer 4 protocol. As I said, the protocol field is used for transport-layer demultiplexing, so it makes little sense to use IPPROTO_IP.

When I create the raw socket with protocol as IPPROTO_RAW (*socketFd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);), my application doesn't receive any of packets

That's because IPPROTO_RAW means that you are interested in sending all types of protocol packets (TCP, UDP, or any other protocol). But with IPPROTO_RAW you can't do the opposite: IPPROTO_RAW would mean that you could receive any protocol in this raw socket, which is not supported. This is also made clear in man 7 raw:

A protocol of IPPROTO_RAW implies enabled IP_HDRINCL and is able to send any IP protocol that is specified in the passed header. Receiving of all IP protocols via IPPROTO_RAW is not possible using raw sockets.

In other words, IPPROTO_RAW gives you the power to send packets matching any protocol, but at the cost of preventing you from ever getting a reply. You could create other specific raw sockets tied to a protocol to get the replies as a workaround, but this complicates the design because you'd have to manage a pool of raw sockets, and it is most definitely not what you want to do here.

When I create the raw socket with protocol as IPPROTO_TCP (socketFd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);), my application receives the TCP packets, but kernel also responds to these packets (and in my case it RSTs the link). I assume it is because kernel thinks there isn't anybody listening to the port to which that packet is intended to.

You can't prevent the kernel from doing its job. From the raw sockets manpage:

When a packet is received, it is passed to any raw sockets which have been bound to its protocol before it is passed to other protocol handlers (e.g., kernel protocol modules).

So you are right that the kernel sends an RST packet because it has no knowledge of active TCP sockets or connections on the specified port. As I said, you can't stop the kernel from doing its work, but a relatively quick (and perhaps ugly) hack is to drop RST packets with iptables:

iptables -A OUTPUT -p tcp --tcp-flags RST RST -j DROP

Yes, not very elegant, but I think there's not much we can do here.

As suggested in the comments, you might also create a dummy TCP socket bound to the same port and address where you just receive and discard the messages. That way the kernel won't send RST replies, and you don't need to mess with iptables.

Also remember that since you need to specify IPPROTO_TCP for your raw socket, you should set IP_HDRINCL on the socket with setsockopts(2) so that you can build the custom IP header.

Finally, make sure the process running this has an effective user ID of 0 or the CAP_NET_RAW capability (in practice: run it as root).

Filipe Gonçalves
  • 20,783
  • 6
  • 53
  • 70
  • hi thanks for such an elaborate answer. regarding the usage of 'IPPROTO_IP', I thought it says "give me the packets from all protocols". regarding the usage of 'IPPROTO_RAW', I think I didnt read the man page properly :-) regarding your suggestion to make changes in iptables, i suppose that change is going to affect the whole sysytem. But my intention was to block this only for the port that I was interested on. So for now, I'm going to create another dummy-tcp socket, so that kernel can also do its job in parallel to my raw-socket. Thats the best I could think of :-) hope thats fine – Raj Kumar Aug 01 '15 at 14:12
  • @RajKumar Yes, the iptables rule will affect the entire system. You can refine it by specifying a port, but I agree that it's not elegant. Creating a dummy TCP socket is also a great idea - I'd say better than my suggestion. I'm going to add this to my answer. – Filipe Gonçalves Aug 01 '15 at 14:15
  • Thanks for your time Filipe. So should we close this question? I suppose we can keep it open for somebody to have a look and provide an answer apart from the workaround that we are doing. Is that fine? I will update the question, so that only the main problem 4 is looked at, since other things are more of my mistakes. – Raj Kumar Aug 01 '15 at 14:20
  • @RajKumar I don't think we should close it. It's a useful question and it contributes to the knowledge base of stackoverflow. By all means, do not delete it. If you think my answer is useful, you can mark it as accepted (but it's not mandatory) by clicking the check sign next to it. – Filipe Gonçalves Aug 01 '15 at 14:25
  • @RajKumar Also I wouldn't delete the other questions. Other people might be having similar problems. But of course, it's up to you - just my 2 cents :) – Filipe Gonçalves Aug 01 '15 at 14:26
0

[this is a comment to Jonathon Reinhart's comment, but i don't have enough reputation]

regarding AF-PACKET sockets

Creating raw sockets with AF_PACKET is described in man packet. The value for "protocol" variable should be the value of ethertype in network byte order. These values are defined in <linux/if_ether.h> (in host byte order). So to open a raw socket you do

socketFd = socket ( AF_PACKET , SOCK_RAW , htons ( ETH_P_IP ) );

If AF_PACKET sockets are what you need, you can also use libpcap/tcpdump. It will allow you to capture ethernet frames and send raw ethernet frames. For capture you can set a filter on what frames you want (e.g., TCP port X). (basically with libpcap you can do the same things as with AF_PACKET sockets, but easier)

links to guide for capturing and man page for sending

Effie
  • 758
  • 5
  • 15
-2

The following link here http://www.tenouk.com/Module43a.html was retrieved from an answer to this question Simple raw socket server in C/C++ on Linux And it suggests that you must be root or running as setuid0 to use a raw socket

/* Must be root or SUID 0 to open RAW socket */
...
 /* Create RAW socket */

   if((s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)

   {

    perror("socket() error");

    /* If something wrong, just exit */

    exit(1);

   }
Community
  • 1
  • 1
hairy_marmite
  • 129
  • 2
  • 8
  • hi, i'm running my application as root user only – Raj Kumar Aug 01 '15 at 13:49
  • OP already indicated he tried this. Copy and pasting code from somewhere doesn't constitute a good answer, especially when that's the same code the OP is asking about. – Jonathon Reinhart Aug 01 '15 at 13:49
  • Fair enough. Check out the link anyway it seems to detail how to do low level stuff anyway. – hairy_marmite Aug 01 '15 at 13:52
  • Sorry @Jonathan , he hadn't at that time mentioned he was running as root. Secondly this is a quote from the link, which specifically mentions needing root. Other comments to his question did not provide any or links... won't bother in future. – hairy_marmite Aug 01 '15 at 13:56
  • The problem is not the link. The problem is that this does not answer the question. He asked 4 questions, none of which you answered. We certainly appreciate your efforts, but you need to read the question and make sure to understand it before attempting to answer it. This is not an SO-only thing, it's general advice. Don't take the downvote personally (wasn't me). – Filipe Gonçalves Aug 01 '15 at 14:04
  • @hairy, sorry. I should have mentioned this at the very beginning of my question. I will have a look at the link posted by you. Thanks for the time ;-) – Raj Kumar Aug 01 '15 at 14:15