AF_INET和AF_PACKET区别

本文详细阐述了原始套接字的工作原理、特点及使用注意事项,包括如何通过原始套接字直接访问链路层数据,以及在不同场景下的应用实例。重点介绍了原始套接字与标准套接字的区别,以及在实际开发中如何有效利用原始套接字功能。

http://blog.csdn.net/kzm2008/article/details/5372834



man 7 ip

man 7 packet
  

Packet  sockets  are used to receive or send raw packets at the device driver (OSI Layer 2) level.  They allow the user to implement protocol modules in user space on top of the physical layer. 用AF_INET,上层代码无法获取以太头部信息。


1.原始套接字(raw socket)

  1.1 原始套接字工作原理与规则
         原始套接字是一个特殊的套接字类型,它的创建方式跟TCP/UDP创建方法几乎是
一摸一样,例如,通过

       int sockfd;
       sockfd = socktet(AF_INET, SOCK_RAW, IPPROTO_ICMP);

这两句程序你就可以创建一个原始套接字.然而这种类型套接字的功能却与TCP或者UDP类型套接字的功能有很大的不同:TCP/UDP类型的套接字只能够访问传输层以及传输层以上的数据,因为当IP层把数据传递给传输层时,下层的数据包头已经被丢掉了.而原始套接字却可以访问传输层以下的数据,,所以使用 raw套接字你可以实现上至应用层的数据操作,也可以实现下至链路层的数据操作.
         比如:通过

sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP))

方式创建的raw socket就能直接读取链路层的数据.

1)使用原始套接字时应该注意的问题(参考<<unix网络编程>>以及网上的优秀文档)

(1):对于UDP/TCP产生的IP数据包,内核不将它传递给任何原始套接字,而只是将这些数据交给对应的UDP/TCP数据处理句柄(所以,如果你想要通过原始套接字来访问TCP/UDP或者其它类型的数据,调用socket函数创建原始套接字第三个参数应该指定为htons(ETH_P_IP),也就是通过直接访问数据链路层来实现.(我们后面的密码窃取器就是基于这种类型的).

(2):对于ICMP和EGP等使用IP数据包承载数据但又在传输层之下的协议类型的IP数据包,内核不管是否已经有注册了的句柄来处理这些数据,都会将这些IP数据包复制一份传递给协议类型匹配的原始套接字.

(3):对于不能识别协议类型的数据包,内核进行必要的校验,然后会查看是否有类型匹配的原始套接字负责处理这些数据,如果有的话,就会将这些IP数据包复制一份传递给匹配的原始套接字,否则,内核将会丢弃这个IP数据包,并返回一个ICMP主机不可达的消息给源主机.

(4): 如果原始套接字bind绑定了一个地址,核心只将目的地址为本机IP地址的数包传递给原始套接字,如果某个原始套接字没有bind地址,核心就会把收到的所有IP数据包发给这个原始套接字.

(5): 如果原始套接字调用了connect函数,则核心只将源地址为connect连接的IP地址的IP数据包传递给这个原始套接字.

(6):如果原始套接字没有调用bind和connect函数,则核心会将所有协议匹配的IP数据包传递给这个原始套接字.


<think>我们正在讨论的是原始套接字(SOCK_RAW)地址族AF_INET。根据提供的引用,我们可以总结如下: 1. **AF_INET**:这是IPv4协议的地址族。当我们创建一个套接字时,使用AF_INET表示这个套接字将使用IPv4地址格式。 2. **SOCK_RAW**:这是一种套接字类型,提供原始网络访问。它允许程序直接访问底层协议,比如IP层。 结合两者,`socket(AF_INET, SOCK_RAW, protocol)`创建了一个原始套接字,该套接字工作在IPv4层,可以接收或发送原始IP数据包。 根据引用[3][4]: - 参数`protocol`指定了要处理的协议。例如: - 如果`protocol`设置为`IPPROTO_TCP`(值为6),那么该套接字将接收所有协议字段为6(即TCP)的IP数据包。注意,接收到的数据包包含完整的IP头,且已经重组好。 - 如果`protocol`设置为`IPPROTO_RAW`(值为255),则该套接字只能用于发送IP包,不能接收。发送时需要自己构造IP头(包括计算校验)。 - 如果`protocol`设置为`IPPROTO_IP`(值为0),则该套接字可以接收任何IP数据包。此时,校验协议处理需要由应用程序自己完成。 引用[1][2]则比较了AF_PACKETAF_INET两种原始套接字的区别: - **AF_PACKET**:工作在数据链路层(二层),可以接收发送包含MAC头的原始帧。在接收路径上,它通过注册到`ptype_base`或`ptype_all`链表来接收数据包(在`netif_receive_skb`中处理)。接收到的数据包含MAC头。 - **AF_INET (SOCK_RAW)**:工作在网络层(三层)。它通过`inet_create`函数创建,并注册到`inetsw`数组中(具体为`inetsw_array`中类型为`SOCK_RAW`的项)。接收路径上,IP层处理(如`ip_rcv`、`ip_local_deliver`)后,会调用`raw_local_deliver`函数,根据`raw_v4_hashinfo`将数据包传递给对应的原始套接字。接收到的数据包从IP头开始(不包括MAC头)。 总结一下两者的区别: - **AF_PACKET(PF_PACKET)**:二层原始套接字,可以操作以太网帧,包括MAC头。 - **AF_INET SOCK_RAW**:三层原始套接字,操作IP层数据包(包括IP头,但不包括MAC头)。 下面我们将详细展开介绍。 </think> ### SOCK_RAW 与 AF_INET 的详细解析 #### 1. **基本概念** - **`AF_INET`**:IPv4 地址族(Address Family),用于标识使用 IPv4 协议的套接字。它定义数据包在网络层(IP 层)的处理方式。 - **`SOCK_RAW`**:原始套接字类型,允许直接访问底层协议头(如 IP 头、传输层头),绕过操作系统默认的协议栈封装[^1][^3]。 #### 2. **核心区别** 以下对比基于 Linux 内核实现(参考引用[1][2][3]): | **特性** | **`AF_INET + SOCK_RAW`** | **`PF_PACKET + SOCK_RAW`** | |------------------------|----------------------------------------------|-----------------------------------| | **工作层级** | 网络层(IP 层) | 数据链路层(MAC 层) | | **数据包头包含** | 从 IP 头开始(不含 MAC 头)[^2] | 包含完整 MAC 头 | | **接收路径** | 通过 IP 协议栈(`ip_rcv → ip_local_deliver → raw_local_deliver`)[^1] | 通过 `netif_receive_skb` 直接注册到 `ptype_base/ptype_all`[^1] | | **典型应用** | 自定义传输层协议(如实现私有 TCP/UDP)[^3] | 抓取原始以太网帧(如 tcpdump) | | **创建函数** | `inet_create()`(注册到 `inetsw_array`) | `packet_create()`(注册到 `ptype_base`) | #### 3. **`AF_INET + SOCK_RAW` 的协议参数** 创建时的 `protocol` 参数决定行为: - **`IPPROTO_XXX`(如 `IPPROTO_TCP=6`)** 仅接收指定协议的包(如 TCP),内核交付 **重组后的完整 IP 包**(含 IP 头)。 ```c socket(AF_INET, SOCK_RAW, IPPROTO_TCP); // 仅接收 TCP 包 ``` - **`IPPROTO_RAW`(255)** 仅能 **发送自定义 IP 包**(需手动填充 IP 头并计算校验),**无法接收数据**。 - **`IPPROTO_IP`(0)** 接收 **所有 IP 协议包**,校验与协议解析由应用层处理[^4]。 #### 4. **内核实现关键路径** - **`AF_INET` 接收路径**(简化): $$ \text{ip\_rcv} \rightarrow \text{ip\_rcv\_finish} \rightarrow \text{ip\_route\_input} \rightarrow \text{ip\_local\_deliver} \rightarrow \text{raw\_local\_deliver} $$ 数据包通过 `raw_v4_hashinfo` 匹配原始套接字。 - **`PF_PACKET` 接收路径**: $$ \text{netif\_rx} \rightarrow \text{process\_backlog} \rightarrow \text{netif\_receive\_skb} \rightarrow \text{调用 ptype_base/ptype\_all 注册的处理函数} $$ 回调函数如 `packet_rcv()` 将含 MAC 头的原始帧复制到用户空间。 #### 5. **典型使用场景** - **网络嗅探工具**: 使用 `PF_PACKET + SOCK_RAW` 捕获原始以太网帧(如 Wireshark)[^2]。 - **自定义协议栈**: 用 `AF_INET + SOCK_RAW` 实现私有传输协议(如替代 TCP/UDP)。 - **网络测试工具**: 通过 `IPPROTO_RAW` 发送手动构造的 IP 包(如 ping 洪水攻击模拟)[^3]。 #### 6. **注意事项** 1. 权限要求:Linux 中创建原始套接字需要 `CAP_NET_RAW` 能力(或 root 权限)。 2. 数据包处理: - `AF_INET` 原始套接字收到的是重组后的 IP 包(无分片)[^3]。 - `PF_PACKET` 可能收到原始分片(需应用层重组)。 3. 性能影响:原始套接字绕过协议栈优化,高频使用可能降低网络性能。 ---
<think>好的,用户之前问过套接字函数,现在又接着问AF_INET是什么类型,这说明他可能在具体编程时遇到了相关参数选择的问题。首先,我需要确认AF_INET的定义作用。AF_INET是地址族的一种,用于IPv4网络通信。在之前的回答中,我提到过socket()函数的参数里有domain,其中AF_INET作为例子出现,所以用户现在想更深入了解这个常量的具体含义。 接下来,用户可能是在编写网络程序时需要选择正确的地址族,或者遇到了相关的错误,比如使用了错误的地址族导致连接失败。这时候,我需要详细解释AF_INET的作用,并与其他地址族如AF_INET6(IPv6)、AF_UNIX(本地通信)进行对比,帮助用户理解不同场景下的应用。 另外,用户可能对地址族协议族的概念有混淆,比如PF_INETAF_INET区别。虽然现在大多数系统两者等同,但最好还是说明历史背景当前使用情况,避免用户产生误解。 还需要提到结构体sockaddr_in,这是配合AF_INET使用的,里面包含了IPv4地址端口号。用户可能在绑定或连接时需要填充这个结构体,所以举例说明如何设置结构体的字段会更有帮助。 另外,用户可能对网络字节序转换函数如htonl()不太熟悉,可以简要说明为什么需要转换字节序,并给出示例代码,这样用户在实际编程时能正确使用这些函数,避免错误。 最后,考虑到用户可能是网络编程的初学者,应该用简洁明了的语言,避免过多技术术语,同时通过对比示例加深理解。确保回答结构清晰,先定义,再用途,然后与其他地址族对比,最后给出实际应用示例,这样用户能逐步掌握相关知识。</think>**AF_INET** 是网络编程中表示 **IPv4地址族(Address Family)** 的常量,属于套接字编程的核心概念。 --- ### **核心特性** 1. **定义与用途** - 符号常量,值为 **2**(不同系统可能略有差异) - 用于指定使用 **IPv4协议** 进行网络通信 - 常见于套接字函数参数中: ```c int sockfd = socket(AF_INET, SOCK_STREAM, 0); // 创建IPv4 TCP套接字 ``` 2. **关联结构体** - 与 **`struct sockaddr_in`** 配合使用,存储IPv4地址端口: ```c struct sockaddr_in addr; addr.sin_family = AF_INET; // 地址族 addr.sin_port = htons(8080); // 端口号(需网络字节序) addr.sin_addr.s_addr = INADDR_ANY;// 绑定所有本地IP ``` --- ### **与其他地址族对比** | 地址族常量 | 协议类型 | 典型用途 | |-----------------|-----------------------|------------------------------| | **AF_INET** | IPv4 | 互联网通信(主流场景) | | AF_INET6 | IPv6 | 下一代互联网通信 | | AF_UNIX/AF_LOCAL| 本地进程间通信 | 同一主机内的IPC | | AF_PACKET | 底层数据链路层 | 网络抓包/协议分析 | --- ### **关键扩展** 1. **历史背景** - 早期存在 **PF_INET**(Protocol Family),与AF_INET值相同 - 现代系统通常将两者视为等同(如Linux中定义为:$PF\_INET = AF\_INET$) 2. **网络字节序** 使用AF_INET时,IP地址端口号需转换为 **网络字节序(大端模式)**: ```c inet_pton(AF_INET, "192.168.1.1", &addr.sin_addr); // 字符串转二进制IP ``` --- ### **典型场景** ```c // 创建IPv4 TCP服务器 int server_fd = socket(AF_INET, SOCK_STREAM, 0); struct sockaddr_in address = { .sin_family = AF_INET, .sin_port = htons(80), .sin_addr.s_addr = INADDR_ANY }; bind(server_fd, (struct sockaddr*)&address, sizeof(address)); ``` > **注**:若需支持IPv6,应使用 **AF_INET6** 并配合 **`struct sockaddr_in6`**。
### AF_PACKET 与 PF_PACKET区别 AF_PACKET PF_PACKET 是 Linux 系统中与原始套接字(raw socket)相关的两个术语,它们通常用于直接访问链路层的数据包。尽管它们的名称相似,但在使用场景功能上存在一定的区别AF_PACKET 是一种地址族(address family),用于创建原始套接字,允许程序直接访问链路层的数据帧。它可以通过 `socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL))` 的方式创建,能够接收发送以太网帧,绕过 TCP/IP 协议栈的处理。这种方式使得应用程序可以直接处理链路层的数据,适合需要深入分析网络流量的场景。AF_PACKET 的实现位于 `net/packet/af_packet.c`,与 TCP/IP 协议栈的模块(如 `net/ipv4/af_inet.c`)没有直接的代码依赖关系[^1]。 PF_PACKET 是协议族(protocol family)的一部分,通常用于创建原始套接字以捕获链路层的数据包。PF_PACKET 的使用方式与 AF_PACKET 类似,可以通过 `socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP))` 创建,用于仅接收 IPv4 数据包。PF_PACKET 提供了与 AF_PACKET 类似的功能,但其接口设计更偏向于协议族的概念[^4]。 在实际使用中,AF_PACKET PF_PACKET 的主要区别在于它们的使用方式功能细节。AF_PACKET 提供了更广泛的链路层访问能力,能够处理多种类型的以太网帧,而 PF_PACKET 则通常用于特定协议的数据包捕获。AF_PACKET 支持 PACKET_MMAP 机制,通过共享内存的方式减少数据包捕获时的系统调用内存拷贝,从而提高性能。这种机制在 PF_PACKET 中并不常见[^3]。 总结来说,AF_PACKET PF_PACKET 都提供了对链路层数据包的访问能力,但在具体实现使用场景上有所不同。AF_PACKET 更加灵活,适合需要广泛链路层访问的应用,而 PF_PACKET 则适合特定协议的数据包捕获。 ```c // 示例:使用 AF_PACKET 创建原始套接字 #include <sys/socket.h> #include <linux/if_packet.h> #include <net/ethernet.h> int sockfd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); ``` ```c // 示例:使用 PF_PACKET 创建原始套接字 #include <sys/socket.h> #include <linux/if_packet.h> #include <net/ethernet.h> int sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP)); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值