Raw sockets – an Introduction

Normally the TCP/UDP sockets provide an abstraction wherein the user of those sockets does not need to concern himself/herself with the TCP/IP or layer 2 headers. The data is provided to the socket with all the lower layer headers removed.

But what if some one wished to tweak the IP headers themselves. If a developer wishes to access the lower layer header or develop his own L4 layer protocol, a RAW socket will allow the developer to achieve just that.

The different communication layers are provided below with example layer protocols.

FIG Courtesy: http://algorithm-wiki.org/wiki2/index.php?title=OSI_Model

Usually the protocol field is kept “0” in all the previous socket code examples as shown below.

                                          socket(AF_INET, type, 0);

The value of ‘0’ maps to IPPROTO_IP – which maps to IPPROTO_TCP when the type field is SOCK_STREAM and maps to IPPROTO_UDP when the type field is SOCK_DGRAM. So the above command is equivalent to the below two socket calls based on type.

                          socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)

                          socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)

The raw socket uses the socket Type as “SOCK_RAW. A sample invocation of the socket API for a raw socket connection is provided below

                          socket(AF_INET, SOCK_RAW, IPPROTO_TCP)

                          socket(AF_INET, SOCK_RAW, IPPROTO_UDP)

However, if the RAW socket is created with IPPROTO_IP, then the socket API would come out with an error message. This is because IPPROTO_IP in Linux automatically maps to TCP and UDP for SOCK_STREAM and SOCK_DGRAM socket types respectively. For SOCK_RAW, it is unable to figure the protocol type and errors out. For a Raw socket connection, the protocol number has to be a number between 1 and 255. 

If we intend the application to add the TCP layer itself, then the protocol is kept as IPPROTO_TCP and the socket type as SOCK_RAW as shown below

                          socket(AF_INET, SOCK_RAW, IPPROTO_TCP)

For a Raw socket, if we intend the application to add the UDP layer itself, then the protocol is kept as IPPROTO_UDP and the socket type as SOCK_RAW as shown below

                          socket(AF_INET, SOCK_RAW, IPPROTO_UDP)

The UDP header has to be added to the packet by the application. The IP header will be added by the network stack. 

If the socket were to be created as below, then the IP header also needs to be incorporated by the application.

                          socket(AF_INET, SOCK_RAW, IPPROTO_RAW)

The above setting will automatically set the IP_HDRINCL flag and the application would need to take care adding the IP header itself.

Also, If the socket is opened with SOCK_RAW as the type and the IPPROTO_TCP as the socket protocol and if IP_HDRINCL flag is set via setsockopt API, the IP header needs to be added by the application.

On the receive side of the socket, the packet will contain the IP header, the TCP header and the data portion in all the above cases. 

Multiple protocols like ICMP/IGMP/SCTP etc use RAW sockets. All IP packets whose protocol number is not understood by the Linux kernel are forwarded to the upper layers via Raw sockets.

Raw sockets can be used to retrieve an L2 (data link layer) packet as well. We delay that discussion to a later article.

Raw Sockets need root privileges to run on a system. It is possible to raise the privileges of a particular application via linux capabilities (CAP_NET_RAW). The below manpage link provides more information. We will see the usage of the same in a later article with an example.

https://linux.die.net/man/7/capabilities

There is a lot of data provided in this introduction which would require a deeper inspection, We will attempt to do that in the coming articles.

Raw Sockets – an introduction (Continued)

Comments

  1. Pingback: Sequenced Socket Packet code example | Hitch Hiker's Guide to Learning

Leave a Reply

Your email address will not be published. Required fields are marked *