You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

原始套接字BPF过滤失效:TCP 22端口过滤代码不生效

问题分析与解决方案

你的问题核心在于:tcpdump生成的BPF过滤器是针对包含链路层(如以太网)头部的数据包设计的,但你的原始套接字(SOCK_RAW)接收的数据包是从IP头部开始的,导致过滤器偏移量全部错位,无法匹配目标数据包。

具体问题点

  1. BPF过滤器偏移错误:tcpdump生成的BPF第一条指令就会读取以太网头部的EtherType字段(偏移0xc),但你的原始套接字没有链路层头部,这部分检查直接失败,后续逻辑根本不会执行。
  2. 冗余的IP_HDRINCL设置:该选项仅在发送自定义IP头部的数据包时需要,接收数据包时完全不需要,属于无效操作。

修正后的代码

替换原有BPF过滤器为适配IP头部起始的版本,并移除不必要的IP_HDRINCL设置:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <linux/filter.h>
#include <linux/if_ether.h>

#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))

int main()
{
    // BPF过滤器:匹配127.0.0.1且TCP端口为22的数据包(IP头部起始)
    struct sock_filter code[] = {
        // 检查IP协议是否为TCP(0x06)
        {0x30, 0, 0, 0x00000009},
        {0x15, 0, 12, 0x00000006},
        // 检查源IP是否为127.0.0.1
        {0x20, 0, 0, 0x0000000c},
        {0x15, 2, 0, 0x7f000001},
        // 检查目标IP是否为127.0.0.1
        {0x20, 0, 0, 0x00000010},
        {0x15, 0, 8, 0x7f000001},
        // 计算IP头部长度(IHL字段 *4)
        {0x30, 0, 0, 0x00000000},
        {0x54, 0, 0, 0x0000000f},
        {0x48, 0, 0, 0x00000004},
        {0x07, 0, 0, 0x00000000},
        // 检查TCP源端口是否为22(0x16)
        {0xb2, 0, 0, 0x00000000},
        {0x15, 1, 0, 0x00000016},
        // 检查TCP目标端口是否为22
        {0xb2, 0, 0, 0x00000002},
        {0x15, 0, 1, 0x00000016},
        // 匹配成功,返回允许接收的长度
        {0x06, 0, 0, 0x00040000},
        // 匹配失败,丢弃数据包
        {0x06, 0, 0, 0x00000000},
    };

    struct sock_fprog bpf = {
        .len    = ARRAY_SIZE(code),
        .filter = code,
    };

    int sock = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
    if (sock < 0) {
        perror("socket failed");
        exit(-1);
    }

    int ret = setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &bpf, sizeof(bpf));
    if (ret < 0) {
        perror("attach filter failed");
        close(sock);
        exit(-1);
    }

    char buffer[4096];
    while (1) {
        memset(buffer, 0, sizeof(buffer));
        ssize_t recv_len = recv(sock, buffer, sizeof(buffer), 0);
        if (recv_len < 0) {
            perror("recv failed");
            close(sock);
            exit(-1);
        }
        printf("捕获到符合条件的数据包,长度:%zd\n", recv_len);
    }

    close(sock);
    return 0;
}

关键说明

  1. BPF过滤器逻辑:
    • 先验证IP协议为TCP
    • 检查源/目标IP是否为127.0.0.1
    • 根据IP头部的IHL字段计算头部长度,定位到TCP头部起始位置
    • 检查TCP的源/目标端口是否为22
  2. 运行要求:必须以root权限运行(和tcpdump一样),因为原始套接字需要管理员权限。

内容的提问来源于stack exchange,提问作者AFloiris

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 23:19:52