IPPROTO_IP和IPPROTO_RAW有什么区别?

时间:2014-07-05 21:45:13

标签: sockets

有人可以解释或给我一个IPPROTO_IP的定义,并帮助我了解IPPROTO_IPIPPROTO_RAW之间的差异吗?

3 个答案:

答案 0 :(得分:21)

这是我在Linux上的/usr/include/netinet.in.h文件的摘录。

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

这是man socket的摘录:

  

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


IPPROTO_IP

in.h文件中,评论说:Dummy protocol for TCP.
这个常量的值为0.它实际上是一个自动选择,具体取决于套接字类型和族 如果您使用它,并且套接字类型为 SOCK_STREAM 且系列为 AF_INET ,则协议将自动为TCP(与您使用IPPROTO_TCP时完全相同) )。 如果您将 IPPROTO_IP AF_INET SOCK_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    |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

考虑阅读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.           │
          └──────────────────────┴────────────────────────────┘

因此,为简单起见,您可以手动编辑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 */
  };

为什么以及何时使用IPPROTO_RAW?

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

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

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

答案 1 :(得分:4)

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

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

答案 2 :(得分:2)

Unix Network Programming, Vol.1有一整套 关于原始套接字的章节。

IPPROTO_IP代码为0,这是默认代码,并创建一个仅接收IP数据包的套接字。

IPPROTO_RAW(代码为255),上面引用的书说Whenever a received datagram is passed to a raw IPv4 socket, the entire datagram, including the IP header, is passed to the process.这个选项的要点是应用程序想要在IP头中添加一些与内核不同的内容会默认输入, 例如一个不同的源地址(这是破解者可以发送欺骗的方式 包)。如果您使用此选项,则您有责任填写大部分内容 IP头的字段(除了头填充之外的校验和) 自动,以及填写的标识字段 如果您将其设置为0,则自动。

相关问题