Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the difference between IPPROTO_IP and IPPROTO_RAW?

Tags:

sockets

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 ?

like image 484
Mohamad Haidar Avatar asked Jul 05 '14 21:07

Mohamad Haidar


People also ask

What is the difference between IPPROTO_IP and 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.

What is the IPPROTO_raw protocol in Linux?

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.

Where do I find the IPPROTO_IP socket options?

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.

What is the default value for IPPROTO_IP?

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.


2 Answers

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.


IPPROTO_IP

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.

IPPROTO_RAW

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:

  • checksum ;
  • total length.

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 */
  };

Why and when to use IPPROTO_RAW?

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.

like image 82
Fox Avatar answered Apr 29 '23 12:04

Fox


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.

like image 27
Remy Lebeau Avatar answered Apr 29 '23 13:04

Remy Lebeau