IPPROTO_IP和IPPROTO_RAW有什么区别?

Moh*_*mad 13 sockets

谁能解释或给我一个定义,IPPROTO_IP并帮助我理解IPPROTO_IP和之间有什么区别IPPROTO_RAW

Fox*_*Fox 23

这是我/usr/include/netinet.in.h在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
  };
Run Code Online (Sandbox Code Playgroud)

这是以下内容的摘录man socket:

该协议指定了与套接字一起使用的特定协议.通常,仅存在单个协议来支持给定协议族中的特定套接字类型,在这种情况下,协议可以指定为0.但是,可能存在许多协议,在这种情况下,必须以这种方式指定特定协议.要使用的协议号特定于进行通信的"通信域"; 见协议(5).有关如何将协议名称字符串映射到协议号,请参阅getprotoent(3).


IPPROTO_IP

in.h文件中,注释说:Dummy protocol for TCP.
此常量的值为0.它实际上是一个自动选择,具体取决于套接字类型和系列.
如果您使用它,并且套接字类型是SOCK_STREAM且系列是AF_INET,则协议将自动为TCP(与您使用IPPROTO_TCP时完全相同).如果你将IPPROTO_IPAF_INETSOCK_RAW一起使用,则会出现错误,因为在这种情况下内核无法自动选择协议.

IPPROTO_RAW

通常,您与OSI模型(TCP或UDP)的第4层交互.如果您使用IPPROTO_RAW,您将能够直接与第3层(IP)交互.这意味着你更低级别.例如,您可以编辑IP数据包的标头和有效负载(通常,内核将在其他模式下处理标头).编辑有效负载意味着您​​可以直接将所需内容放入IP有效负载中.内部或其他任何TCP段都不会.你可以自由地做你想做的事!

这显示了IP数据包的内存布局:

 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    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Run Code Online (Sandbox Code Playgroud)

考虑阅读man 7 raw包含有关RAW套接字使用的大量信息.

   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.           ?
          ?????????????????????????????????????????????????????
Run Code Online (Sandbox Code Playgroud)

因此,为简单起见,您可以手动编辑IP标头的所有字段,但以下情况除外,它将始终由内核填充:

  • 校验和;
  • 总长度.

您可以使用struct ip编辑这些字段.

摘录自 /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 */
  };
Run Code Online (Sandbox Code Playgroud)

为什么以及何时使用IPPROTO_RAW?

嗯,这取决于你想要的应用程序.某些应用程序有非常特殊的需求,只需要具有很大的灵活性.例如,如果要实现traceroute,则需要每次都增加TTL.

您可以使用更改TTL setsockopt,但如果您手动更改了许多标题字段,则最好接管IP标头的完全控制!

另一个用途是如果您想在IP之上实现自己的协议.


Rem*_*eau 6

IPPROTO_IP 创建一个套接字,用于发送/接收基于 IPv4 的协议(TCP、UDP 等)的原始数据。它将为您处理 IP 标头,但您负责在 IP 有效负载内处理/创建其他协议数据。

IPPROTO_RAW 创建一个可以发送/接收任何类型协议的原始数据的套接字。它不会为您处理任何标头,您负责处理/创建所有有效负载数据,包括 IP 和其他标头。