验证使用TC模块丢弃TCP报文
先看代码,
#include <uapi/linux/bpf.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <linux/in.h>
//#include <linux/pkt_cls.h>
#include <uapi/linux/pkt_cls.h>
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned long long u64;
#define htons(x) __cpu_to_be16(x)
#define SEC(NAME) __attribute__((section(NAME), used))
static int parse_ipv4(void *data, u64 nh_off, void *data_end)
{
struct iphdr *iph = data + nh_off;
if ((void *)(iph + 1) > data_end)
return 0;
return iph->protocol;
}
SEC("tc-tcp")
int tc_drop_tcp(struct __sk_buff *skb) {
void *data_end = (void *)(long)skb->data_end;
void *data = (void *)(long)skb->data;
struct ethhdr *eth = data;
u16 h_proto;
u64 nh_off;
u32 ipproto;
nh_off = sizeof(*eth);
if (data + nh_off > data_end)
return TC_ACT_SHOT;
h_proto = eth->h_proto;
if (h_proto == htons(ETH_P_IP)) {
ipproto = parse_ipv4(data, nh_off, data_end);
if (IPPROTO_TCP == ipproto)
return TC_ACT_SHOT;
}
return TC_ACT_OK;
}
char _license[] SEC("license") = "GPL";
编译
clang -O2 -Wall -target bpf -I /usr/include/x86_64-linux-gnu/ -c tc-drop-tcp.c -o tc-drop-tcp.o
容器访问外部网络
使用netns命令,修改dns域名服务器,详见项目Docker-Practice
sudo ip netns exec test-show curl www.baidu.com
CTYPE html> <html> <head><meta http-equiv=content-type content=text/html;charset=utf-8><meta http-equiv=X-UA-Compatible content=IE=Edge><link rel=stylesheet type=text/css href=http://s1.bdstatic.com/r/www/cache/bdorz/baidu.min.css>
添加队列与过滤器
查看队列
tc qdisc show dev vethd26706b
qdisc noqueue 0: root refcnt 2
添加队列,自带的tc命令添加会失败,用了自己编译的高版本
sudo ~/workspace/iproute2-5.11.0/tc/tc qdisc add dev vethd26706b clsact
tc qdisc show dev vethd26706b
qdisc noqueue 0: root refcnt 2
qdisc clsact ffff: parent ffff:fff1
查看过滤器出口规则
sudo ~/workspace/iproute2-5.11.0/tc/tc filter show dev vethd26706b egress
添加过滤器
sudo ~/workspace/iproute2-5.11.0/tc/tc filter add dev vethd26706b egress bpf da obj tc-drop-tcp.o sec tc-tcp verbose
Continuing without mounted eBPF fs. Too old kernel?
Prog section 'tc-tcp' loaded (5)!
- Type: 3
- Instructions: 19 (0 over limit)
- License: GPL
Verifier analysis:
0: (b7) r0 = 2
1: (61) r2 = *(u32 *)(r1 +80)
2: (61) r1 = *(u32 *)(r1 +76)
3: (bf) r3 = r1
4: (07) r3 += 14
5: (2d) if r3 > r2 goto pc+12
R0=inv2 R1=pkt(id=0,off=0,r=14,imm=0) R2=pkt_end(id=0,off=0,imm=0) R3=pkt(id=0,off=14,r=14,imm=0) R10=fp0
6: (bf) r3 = r1
7: (07) r3 += 34
8: (2d) if r3 > r2 goto pc+8
R0=inv2 R1=pkt(id=0,off=0,r=34,imm=0) R2=pkt_end(id=0,off=0,imm=0) R3=pkt(id=0,off=34,r=34,imm=0) R10=fp0
9: (71) r2 = *(u8 *)(r1 +13)
10: (67) r2 <<= 8
11: (71) r3 = *(u8 *)(r1 +12)
12: (4f) r2 |= r3
13: (57) r2 &= 65535
14: (55) if r2 != 0x8 goto pc+2
R0=inv2 R1=pkt(id=0,off=0,r=34,imm=0) R2=inv8 R3=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R10=fp0
15: (71) r1 = *(u8 *)(r1 +23)
16: (15) if r1 == 0x6 goto pc+1
R0=inv2 R1=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R2=inv8 R3=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R10=fp0
17: (b7) r0 = 0
18: (95) exit
from 16 to 18: R0=inv2 R1=inv6 R2=inv8 R3=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R10=fp0
18: (95) exit
from 14 to 17: safe
from 8 to 17: safe
from 5 to 18: safe
processed 23 insns, stack depth 0
再次查看过滤器出口规则
sudo ~/workspace/iproute2-5.11.0/tc/tc filter show dev vethd26706b egress
filter protocol all pref 49152 bpf chain 0
filter protocol all pref 49152 bpf chain 0 handle 0x1 tc-drop-tcp.o:[tc-tcp] direct-action not_in_hw id 10 tag e4e8d89f5834ec06 jited
此时容器访问外部网络,使用以上的ip netns命令,无输出
然后删除规则
sudo ~/workspace/iproute2-5.11.0/tc/tc filter del dev vethd26706b egress
卡住的curl再次输出信息,查看规则,为空
最后删除添加的队列
sudo ~/workspace/iproute2-5.11.0/tc/tc qdisc del dev vethd26706b clsact
再次查看规则,输出与最初的一致