eBPF tc prog

tc

tc_redirect.c

c 复制代码
// tc_redirect.c - TC 程序,无条件将 TCP 包重定向到 111.63.65.103:80
#include <linux/bpf.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_endian.h>

#ifndef IPPROTO_TCP
#define IPPROTO_TCP 6
#endif

#ifndef IP_MF
#define IP_MF 0x2000
#endif

#ifndef IP_OFFSET
#define IP_OFFSET 0x1FFF
#endif

static __inline__ __be16 csum_fold(__u32 csum) {
    csum = (csum & 0xffff) + (csum >> 16);
    csum = (csum & 0xffff) + (csum >> 16);
    return (__be16)~csum;
}

SEC("classifier")
int tc_redirect(struct __sk_buff *skb) {
    void *data_end = (void *)(long)skb->data_end;
    void *data = (void *)(long)skb->data;

    // 解析 IP 头(TUN 模式无以太网头)
    struct iphdr *ip = data;
    if ((void *)(ip + 1) > data_end)
        return 0;  // TC_ACT_OK

    if (ip->version != 4)
        return 0;

    if (ip->protocol != IPPROTO_TCP)
        return 0;

    if (ip->frag_off & bpf_htons(IP_MF | IP_OFFSET))
        return 0;

    unsigned int ip_hdr_len = ip->ihl << 2;
    if (ip_hdr_len < sizeof(struct iphdr))
        return 0;

    struct tcphdr *tcp = (void *)ip + ip_hdr_len;
    if ((void *)(tcp + 1) > data_end)
        return 0;

    // 记录原始目的地址和端口
    __u32 old_daddr = ip->daddr;
    __be16 new_daddr = 0x6F3F4167;   // 111.63.65.103

    __u16 old_dport = tcp->dest;
    __be16 new_dport = 0x0050;       // 80

    // 修改 IP 头
    ip->daddr = new_daddr;

    // 增量更新 IP 校验和
    __wsum sum_ip = 0;
    sum_ip = bpf_csum_diff(&old_daddr, 4, &new_daddr, 4, sum_ip);
    __u32 old_ip_csum = ip->check;
    ip->check = 0;
    ip->check = (__be16)~csum_fold(old_ip_csum + sum_ip);

    // 修改 TCP 头
    tcp->dest = new_dport;

    // 增量更新 TCP 校验和
    __wsum sum = 0;
    sum = bpf_csum_diff(&old_daddr, 4, &new_daddr, 4, sum);
    __be32 old_dport32 = (__be32)old_dport;
    __be32 new_dport32 = (__be32)new_dport;
    sum = bpf_csum_diff(&old_dport32, 4, &new_dport32, 4, sum);
    __u32 old_csum = tcp->check;
    tcp->check = 0;
    __u32 new_csum = old_csum + sum;
    tcp->check = (__be16)~csum_fold(new_csum);

    return 0;  // TC_ACT_OK
}

char _license[] SEC("license") = "GPL";
bash 复制代码
# 编译 TC 程序
clang -target bpf -O2 -g -I/usr/include/x86_64-linux-gnu -I/usr/src/linux-headers-$(uname -r)/include -I/usr/src/linux-headers-$(uname -r)/arch/x86/include -I/usr/include/bpf -c tc_redirect.c -o tc_redirect.o

# 挂载 TC 程序到 tun0 的 egress 方向
# 创建 qdisc(如果不存在)
tc qdisc add dev tun0 clsact

# 挂载程序到 egress(出方向)
tc filter add dev tun0 egress bpf obj tc_redirect.o sec classifier

# 测试
curl --interface 10.0.0.1 --local-port 12345 http://10.0.0.2:8080 -v

# 抓包
tcpdump -i any -n -v

# 清理
tc filter del dev tun0 egress
tc qdisc del dev tun0 clsact
相关推荐
BestOrNothing_201516 小时前
C++零基础到工程实战(4.3.1):数组与vector初识——连续内存与动态数组的本质解析
c++·vector·初始化·内存分配·栈区数组·堆区数组
2401_8734794016 小时前
通过IP地址查询判断网络风险,有哪些具体指标和判断方法?
网络·tcp/ip·网络安全
脱氧核糖核酸__16 小时前
LeetCode热题100——240.搜索二维矩阵 II(题目+题解+答案)
c++·算法·leetcode·矩阵
倔强的石头10616 小时前
NFS网络文件系统下企业级数据库安装排障实战:环境变量失效与权限问题的深度解析
网络·数据库
杰 .16 小时前
Linux 开机 + 进程创建 + fork + exec + 加载器
linux·服务器
极客智造16 小时前
C++ 类模板完全深度指南:泛型编程、特化、分离编译与工程实践
c++
IpdataCloud16 小时前
游戏工作室多开怎么快速识别?用IP查询定位服务三步锁定异常账号
网络协议·tcp/ip·游戏
赤月奇16 小时前
UDP 广播包-SocketTool发送UDP广播包
网络·网络协议·udp
woohu12316 小时前
沃虎网络变压器如何通过共模抑制比(CMR)为设备滤除电磁“杂音”
网络
blackorbird16 小时前
AI工作流自动化平台n8n正被大规模网络武器化
运维·网络·人工智能·自动化