Could anyone explain or give me a definition for the IPPROTO_IP
and to help me to understand what are the differences between the IPPROTO_IP
and the IPPROTO_RAW
?
IPPROTO_IP code is 0 which is the default and creates a socket that will receive only IP packet. IPPROTO_RAW (code is 255 ), the book referenced above says Whenever a received datagram is passed to a raw IPv4 socket, the entire datagram, including the IP header, is passed to the process.
IPPROTO_RAW = 255, /* Raw IP packets. */ #define IPPROTO_RAW IPPROTO_RAW IPPROTO_MAX }; The protocol specifies a particular protocol to be used with the socket. Normally only a single protocol exists to support a particular socket type within a given protocol family, in which case protocol can be specified as 0.
Some of the IPPROTO_IP socket options are defined in the Ws2ipdef.h header file which is automatically included by the Ws2tcpip.h header file. The remaining IPPROTO_IP socket options are defined in the Wsipv6ok.h header file which is automatically included by the Winsock2.h header file.
Unix Network Programming, Vol.1 has an entire chapter on raw sockets. IPPROTO_IP code is 0 which is the default and creates a socket that will receive only IP packet.
This is an extract from my /usr/include/netinet.in.h
file on Linux.
/* Standard well-defined IP protocols. */
enum
{
IPPROTO_IP = 0, /* Dummy protocol for TCP. */
#define IPPROTO_IP IPPROTO_IP
IPPROTO_ICMP = 1, /* Internet Control Message Protocol. */
#define IPPROTO_ICMP IPPROTO_ICMP
[.......]
IPPROTO_TCP = 6, /* Transmission Control Protocol. */
#define IPPROTO_TCP IPPROTO_TCP
IPPROTO_UDP = 17, /* User Datagram Protocol. */
#define IPPROTO_UDP IPPROTO_UDP
[.......]
IPPROTO_RAW = 255, /* Raw IP packets. */
#define IPPROTO_RAW IPPROTO_RAW
IPPROTO_MAX
};
This is an extract of man socket
:
The protocol specifies a particular protocol to be used with the socket. Normally only a single protocol exists to support a particular socket type within a given protocol family, in which case protocol can be specified as 0. However, it is possible that many protocols may exist, in which case a particular protocol must be specified in this manner. The protocol number to use is specific to the “communication domain” in which communication is to take place; see protocols(5). See getprotoent(3) on how to map protocol name strings to protocol numbers.
In the in.h
file, the comment says: Dummy protocol for TCP.
This constant has the value 0. It's actually an automatic choice depending on socket type and family.
If you use it, and if the socket type is SOCK_STREAM and the family is AF_INET, then the protocol will automatically be TCP (exactly the same as if you'd used IPPROTO_TCP).
Buf if you use IPPROTO_IP together with AF_INET and SOCK_RAW, you will have an error, because the kernel cannot choose a protocol automatically in this case.
Normally, you interact with layer 4 of OSI model (TCP or UDP). If you use IPPROTO_RAW, you will be able to interact directly with layer 3 (IP). This means you are more low level. For example, you can edit the header and payload of your IP packet (normally, the kernel will handle the header in other modes). Edit the payload means that you are free to put what you want directly in the IP payload. There won't be any TCP segment inside or whatever. You are free to do what you want inside!
This shows the memory layout of an IP packet:
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|Version| IHL |Type of Service| Total Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Identification |Flags| Fragment Offset |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Time to Live | Protocol | Header Checksum |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Destination Address |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Options | Padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Consider reading man 7 raw
which contains a lot of information about the use of RAW sockets.
Raw sockets allow new IPv4 protocols to be implemented in user space.
A raw socket receives or sends the raw datagram not including link
level headers.
The IPv4 layer generates an IP header when sending a packet unless the
IP_HDRINCL socket option is enabled on the socket. When it is enabled,
the packet must contain an IP header. For receiving the IP header is
always included in the packet.
Only processes with an effective user ID of 0 or the CAP_NET_RAW capa‐
bility are allowed to open raw sockets.
All packets or errors matching the protocol number specified for the
raw socket are passed to this socket. For a list of the allowed proto‐
cols see RFC 1700 assigned numbers and getprotobyname(3).
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.
┌───────────────────────────────────────────────────┐
│IP Header fields modified on sending by IP_HDRINCL │
├──────────────────────┬────────────────────────────┤
│IP Checksum │Always filled in. │
├──────────────────────┼────────────────────────────┤
│Source Address │Filled in when zero. │
├──────────────────────┼────────────────────────────┤
│Packet Id │Filled in when zero. │
├──────────────────────┼────────────────────────────┤
│Total Length │Always filled in. │
└──────────────────────┴────────────────────────────┘
So, to make it simple, you can edit all fields of the IP headers manually, except following, which will always be filled by the kernel:
You can edit these fields using the struct ip.
Extract from /usr/include/netinet.ip.h
/*
* Structure of an internet header, naked of options.
*/
struct ip
{
#if __BYTE_ORDER == __LITTLE_ENDIAN
unsigned int ip_hl:4; /* header length */
unsigned int ip_v:4; /* version */
#endif
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned int ip_v:4; /* version */
unsigned int ip_hl:4; /* header length */
#endif
u_int8_t ip_tos; /* type of service */
u_short ip_len; /* total length */
u_short ip_id; /* identification */
u_short ip_off; /* fragment offset field */
#define IP_RF 0x8000 /* reserved fragment flag */
#define IP_DF 0x4000 /* dont fragment flag */
#define IP_MF 0x2000 /* more fragments flag */
#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
u_int8_t ip_ttl; /* time to live */
u_int8_t ip_p; /* protocol */
u_short ip_sum; /* checksum */
struct in_addr ip_src, ip_dst; /* source and dest address */
};
Well, it depends on the application you want to make. Some application have very specific needs, and just need to have a great flexibility.
For example, if you want to implement traceroute
, you will want to increment the TTL every time.
You could change the TTL using setsockopt
, but if you have lots of header fields to change by hand, it's better to take over the full control of the IP header!
Another use is if you want to implement your own protocol on top of IP.
IPPROTO_IP creates a socket that sends/receives raw data for IPv4-based protocols (TCP, UDP, etc). It will handle the IP headers for you, but you are responsible for processing/creating additional protocol data inside the IP payload.
IPPROTO_RAW creates a socket that sends/receives raw data for any kind of protocol. It will not handle any headers for you, you are responsible for processing/creating all payload data, including IP and additional headers.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With