如何通过setsockopt的ICMP_FILTER选项安全过滤ICMP数据包?
如何通过ICMP_FILTER过滤ICMP数据包
首先明确:linux/icmp.h是正确的头文件,其中定义的struct icmp_filter就是用于配置ICMP_FILTER套接字选项的结构。
struct icmp_filter 结构说明
这个结构的核心是__u32 data[8]数组,总共8×32=256位,每一位对应一个ICMP消息类型(0-255):
- 位为1:过滤该类型的ICMP包,套接字不会接收这类数据包
- 位为0:允许接收该类型的ICMP包
- 默认状态下所有位都是0,即接收所有ICMP类型的包
常用操作宏
头文件提供了两个便捷宏来快速初始化过滤器:
ICMP_FILTER_SETALL(&filter):将所有位设为1,即过滤所有ICMP类型ICMP_FILTER_CLEARALL(&filter):将所有位设为0,即允许接收所有ICMP类型
实现需求:只接收ICMP_ECHOREPLY(类型0)
你的场景是发送ICMP_ECHO(类型8),只需要接收对应的ICMP_ECHOREPLY(类型0),可以按以下步骤配置:
- 初始化过滤器,先过滤所有类型
- 单独允许类型0的数据包通过
- 调用
setsockopt应用过滤器
完整代码示例:
#include <linux/icmp.h> #include <sys/socket.h> #include <stdio.h> // 假设sockfd是已创建的原始套接字:int sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); struct icmp_filter filter; // 第一步:过滤所有ICMP类型 ICMP_FILTER_SETALL(&filter); // 第二步:清除类型0对应的位,允许接收ICMP_ECHOREPLY // ICMP_ECHOREPLY的值是0,对应data[0]的第0位 filter.data[ICMP_ECHOREPLY / 32] &= ~(1 << (ICMP_ECHOREPLY % 32)); // 第三步:应用过滤器到套接字 if (setsockopt(sockfd, SOL_RAW, ICMP_FILTER, &filter, sizeof(filter)) == -1) { perror("setsockopt ICMP_FILTER failed"); // 这里添加你的错误处理逻辑,比如关闭套接字、退出等 }
其他场景示例
如果你需要过滤特定类型(比如过滤ICMP_ECHO类型8),可以这样写:
struct icmp_filter filter; // 先允许所有类型 ICMP_FILTER_CLEARALL(&filter); // 设置类型8对应的位为1,过滤ICMP_ECHO包 filter.data[ICMP_ECHO / 32] |= (1 << (ICMP_ECHO % 32)); setsockopt(sockfd, SOL_RAW, ICMP_FILTER, &filter, sizeof(filter));
注意事项
- 操作位时要确保类型值在0-255范围内,避免越界访问
data数组 setsockopt调用失败时一定要检查返回值,通过perror获取具体错误信息- 该过滤器仅对接收的ICMP数据包生效,不影响发送操作
内容的提问来源于stack exchange,提问作者MaPo
相关产品推荐
相关产品推荐

