英文资料:
- https://www.kernel.org/doc/Documentation/networking/filter.txt
- https://github.com/torvalds/linux/blob/master/tools/testing/selftests/net/psock_lib.h#L29-L73
struct sock_filter filter[] = {
{ 0x28, 0, 0, 0x0000000c },
{ 0x15, 0, 8, 0x00000800 },
{ 0x30, 0, 0, 0x00000017 },
{ 0x15, 0, 6, 0x00000011 },
{ 0x80, 0, 0, 0000000000 },
{ 0x35, 0, 4, 0x00000064 },
{ 0x30, 0, 0, 0x00000050 },
{ 0x15, 1, 0, 0x00000061 },
{ 0x15, 0, 1, 0x00000062 },
{ 0x06, 0, 0, 0xffffffff },
{ 0x06, 0, 0, 0000000000 },
};
size_t N = sizeof(filter) / sizeof(filter[0]);
struct sock_fprog filter_prog = {N, &filter};
int fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter_prog, sizeof(struct sock_fprog));
/* The setsockopt(2) call to SO_DETACH_FILTER doesn't need any arguments
and SO_LOCK_FILTER for preventing the filter to be detached, takes an
integer value with 0 or 1. */
setsockopt(sockfd, SOL_SOCKET, SO_DETACH_FILTER, NULL, 0);
int value=1;
setsockopt(sockfd, SOL_SOCKET, SO_LOCK_FILTER, &value, sizeof(value));
/* the filter below checks for all of the following conditions that
* are based on the contents of create_payload()
* ether type 0x800 and
* ip proto udp and
* skb->len == DATA_LEN and
* udp[38] == 'a' or udp[38] == 'b'
* It can be generated from the following bpf_asm input:
* ldh [12]
* jne #0x800, drop ; ETH_P_IP
* ldb [23]
* jneq #17, drop ; IPPROTO_UDP
* ld len ; ld skb->len
* jlt #100, drop ; DATA_LEN
* ldb [80]
* jeq #97, pass ; DATA_CHAR
* jne #98, drop ; DATA_CHAR_1
* pass:
* ret #-1
* drop:
* ret #0
*
*
* 中文说明:
安装内核Linux内核源码包+开发工具
sudo apt-get install \
linux-source-5.0.0 \
kernel-package \
libelf-dev \
binutils-dev \
libreadline-dev
解压内核源码包进入源码树顶层目录
tar xjvf /usr/src/linux-source-5.0.0.tar.bz2
cd linux-5.0.0
拷贝内核config配置文件
cp /boot/config-`uname -r` .config
编译tools子目录下的bpf_asm工具
make headers_install && make -C tools/bpf/
sudo cp tools/bpf/bpf_asm /usr/local/bin/
运行bpf_asm工具, 转换BPF包过滤脚本为C语言结构体:
cat << EOF | /usr/local/bin/bpf_asm -c -i - | tee myfilter.c
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 脚本功能, 检查数据包是否同时满足下列几条过滤条件
; ether type 0x800 and
; ip proto udp and
; skb->len >= 100 and
; udp[38] == 'a' or udp[38] == 'b'
; -----------------------------------
ldh [12]
jne #0x800, drop ; ETH_P_IP
ldb [23]
jneq #17, drop ; IPPROTO_UDP
ld len ; ld skb->len
jlt #100, drop ; 这里DATA_LEN等于int常量#100
ldb [80]
jeq #97, pass ; DATA_CHAR
jne #98, drop ; DATA_CHAR_1
pass:
ret #-1
drop:
ret #0
EOF
输出文件myfilter.c内容如下
{ 0x28, 0, 0, 0x0000000c },
{ 0x15, 0, 8, 0x00000800 },
{ 0x30, 0, 0, 0x00000017 },
{ 0x15, 0, 6, 0x00000011 },
{ 0x80, 0, 0, 0000000000 },
{ 0x35, 0, 4, 0x00000064 },
{ 0x30, 0, 0, 0x00000050 },
{ 0x15, 1, 0, 0x00000061 },
{ 0x15, 0, 1, 0x00000062 },
{ 0x06, 0, 0, 0xffffffff },
{ 0x06, 0, 0, 0000000000 },
*
* 中文说明:
* BPF过滤规则还可以通过tcpdump命令生成相似的结果, (输出BPF汇编代码用-d, 输出C结构体用-dd)
* tcpdump -s 65535 "ip and (udp[38]=0x61 or udp[38]=0x62)" -d
* 或
* tcpdump -s 65535 "ip and udp" -dd
*/
struct sock_filter bpf_filter[] = {
{ 0x28, 0, 0, 0x0000000c },
{ 0x15, 0, 8, 0x00000800 },
{ 0x30, 0, 0, 0x00000017 },
{ 0x15, 0, 6, 0x00000011 },
{ 0x80, 0, 0, 0000000000 },
{ 0x35, 0, 4, 0x00000064 },
{ 0x30, 0, 0, 0x00000050 },
{ 0x15, 1, 0, 0x00000061 },
{ 0x15, 0, 1, 0x00000062 },
{ 0x06, 0, 0, 0xffffffff },
{ 0x06, 0, 0, 0000000000 },
};
struct sock_fprog bpf_prog;
bpf_prog.filter = bpf_filter;
bpf_prog.len = sizeof(bpf_filter) / sizeof(struct sock_filter);
if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &bpf_prog,
sizeof(bpf_prog))) {
perror("setsockopt SO_ATTACH_FILTER");
exit(1);
}
网友评论