⬆️ ⬇️

Real sock_raw'thin

image



Raw sockets provide the programmer with more features than the rest of the socket API. Everyone knows about these "broad" possibilities, but their more or less systematized description is rarely found on the Internet. Let's try to fill this gap and understand the purpose of raw sockets and options for their use in network software.



So, raw sockets are a special kind of sockets available when using a type system call:



int socket = socket(AF_INET, SOCK_RAW, IPPROTO_*); 


I won’t hold back and make a small digression about the possible arguments in the socket call and their conceptual meaning. We all know that the socket API was conceived as a generalized programming interface, i.e. an interface through which it will be possible to work with a wide variety of network mechanisms, or even just intra-host interaction. The first argument of the call selects the so-called. communication domain. The creators of the socket API took the communication domain AF_INET under the TCP / IP-based interconnection (IPv4), which we indicate in our call. The second argument specifies the type of the socket — the sockets are typed according to the semantics of the data transfer they provide (SOCK_STREAM — streaming, SOCK_DGRAM — datagram). In our case, the socket type is SOCK_RAW - probably this is the only deviation from the rules, when the second argument means not so much the transfer semantics, as access to a special low-level functionality. Finally, the third argument specifies the protocol. A list of constants, most of which can be used as the third argument in our call, can be found in the file /usr/src/linux-*/include/linux/in.h, where * is the kernel version. The most commonly used constants are IPPROTO_TCP, IPPROTO_UDP, IPPROTO_ICMP, IPPOROTO_IGMP, IPPROTO_RAW.

')

When you start working with raw sockets, you immediately notice at least two of their features - how data is encapsulated and if you have access to IP headers. Data sent using a raw socket is encapsulated directly into the payload field of an IP datagram, bypassing the transport layer. As for the headers, it is convenient to distinguish two situations here - sending and receiving datagrams. A user application that uses raw sockets always receives an entire IP datagram, including its header. At the same time, all necessary checks for validity of fields of the datagram header are still performed by the kernel, and the application will never receive a datagram through the raw socket, which indicates, for example, an invalid version of the IP protocol (that is, a version other than IPv4).



image



When sending data through a raw socket, the programmer has a choice - to shift the task of creating IP headers to the kernel or creating headers himself. The second is possible using the IP_HDRINCL socket option (plus there is a situation in Linux where this option will be enabled automatically if the IPPROTO_RAW constant is used as the third argument in the socket () call). However, even if the IP_HDRINCL option is used, the kernel will still “assist” the programmer. Thus, the header fields of Total Length and Header Checksum datagrams are always automatically filled with the kernel, and the Source Address and Identification fields will be filled with the kernel if the programmer leaves their values ​​equal to zero. The ability to create your own datagram header is mainly used to send packets with a “idle” source IP address.



Raw sockets can be used as a packet capture mechanism that is somewhat limited in its capabilities. It is limited for several reasons. First, through the raw socket, you can only get a copy of the incoming packet, but not generated by this machine and not transit (routed). Secondly, through a raw socket, you can only receive IP datagrams with the specified Protocol ID (the Protocol ID corresponds to the third argument in the socket () system call used to create the socket), and not all IP traffic. Finally, a distinctive feature of raw sockets in FreeBSD (but not Linux) is that we can get an IP datagram only if the kernel does not know how to handle it (the exception is the ICMP and IGMP protocol packets, which we will discuss below). This means that the kernel does not implement code intended for processing an IP datagram with the specified Protocol ID. Also, the following fact is interesting: if more than one raw socket is created with similar parameters, each socket will receive its own copy of the incoming packet.



Raw sockets are indispensable when writing network scanners. For example, we can use a call like:



 int socket = socket(AF_INET, SOCK_RAW, IPPROTO_TCP); 




Next, we just have to construct a TCP segment and send it to send raw to the socket. Do not forget also about the possibility of forgery of the source IP address, which in this context will be very useful. Similarly, it is possible to write programs for fuzzing the kernel’s network stack. For example, constructed transport layer packets may contain obviously invalid values ​​in the fields we need.



When using TCP through a raw socket, you should understand the following thing. We cannot completely recreate the operation of the TCP protocol, and we will not be able to do this, based on the capabilities provided by raw sockets. The maximum that we can do is receive incoming traffic of this type (in Linux) and send individual outgoing TCP segments that are allegedly part of a TCP connection established or established.



Finally, it is worth mentioning another aspect of using raw sockets. There are protocols that are controlled mainly by the kernel itself, such as ICMP and IGMP. In some cases, accessing these protocols from a user application can be quite useful:



 int socket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); int socket = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP); 




Utilities like ping, classic tracert (ICMP), and utilities that allow you to manipulate an IGMP subscription are written this way.



Thus, by putting together all the facts, you can try to conclude about the purpose of raw sockets. This mechanism is useful to us if you need to implement:







It is difficult to imagine that the functionality provided by raw sockets was originally intended to encourage the writing of software for network attacks. Rather, the rationale for the need for this mechanism served quite peaceful goals. However, the capabilities of raw sockets, ultimately, have found application in hacker software.





Links to useful resources on the topic



SOCK_RAW Demystified

http://sock-raw.org/papers/sock_raw



4.2bsd Networking Implementation Notes (Revised July, 1983)

http://www.eecs.berkeley.edu/Pubs/TechRpts/1983/CSD-83-146



Linux man pages, SOCKET (2)

http://man7.org/linux/man-pages/man2/socket.2.html



Linux man pages, SOCKET (7)

ttp: //man7.org/linux/man-pages/man7/socket.7.html



Linux man pages, RAW (7)

http://man7.org/linux/man-pages/man7/raw.7.html

Source: https://habr.com/ru/post/184430/



All Articles