Python3上BPF学习-读取DNS事件

原文链接地址 https://mp.weixin.qq.com/s/xclWzPrAWQ0cxe7Md-c5_g

BPF的逻辑如下图:

原文中源代码如下:

#!/usr/bin/env python3

import dnslib
import fcntl
import os
import sys

from bcc import BPF

BPF_APP = r'''
#include <linux/if_ether.h>
#include <linux/in.h>
#include <bcc/proto.h>
int dns_matching(struct __sk_buff *skb) {
    u8 *cursor = 0;
     // Checking the IP protocol:
    struct ethernet_t *ethernet = cursor_advance(cursor, sizeof(*ethernet));
    if (ethernet->type == ETH_P_IP) {
         // Checking the UDP protocol:
        struct ip_t *ip = cursor_advance(cursor, sizeof(*ip));
        if (ip->nextp == IPPROTO_UDP) {
             // Check the port 53:
            struct udp_t *udp = cursor_advance(cursor, sizeof(*udp));
            if (udp->dport == 53 || udp->sport == 53) {
                return -1;
            }
        }
    }
    return 0;
}
'''


bpf = BPF(text=BPF_APP)
function_dns_matching = bpf.load_func("dns_matching", BPF.SOCKET_FILTER)
BPF.attach_raw_socket(function_dns_matching, '')

socket_fd = function_dns_matching.sock
fl = fcntl.fcntl(socket_fd, fcntl.F_GETFL)
fcntl.fcntl(socket_fd, fcntl.F_SETFL, fl & ~os.O_NONBLOCK)

while True:
    try:
        packet_str = os.read(socket_fd, 2048)
    except KeyboardInterrupt:
        sys.exit(0)

    packet_bytearray = bytearray(packet_str)

    ETH_HLEN = 14
    UDP_HLEN = 8

    # IP header length
    ip_header_length = packet_bytearray[ETH_HLEN]
    ip_header_length = ip_header_length & 0x0F
    ip_header_length = ip_header_length << 2

    # Starting the DNS packet
    payload_offset = ETH_HLEN + ip_header_length + UDP_HLEN

    payload = packet_bytearray[payload_offset:]

    dnsrec = dnslib.DNSRecord.parse(payload)

    # If it’s the response:
    if dnsrec.rr:
        print(f'Resp: {dnsrec.rr[0].rname} {dnslib.QTYPE.get(dnsrec.rr[0].rtype)} {", ".join([repr(dnsrec.rr[i].rdata) for i in range(0, len(dnsrec.rr))])}')
    # If it’s the request:
    else:
        print(f'Request: {dnsrec.questions[0].qname} {dnslib.QTYPE.get(dnsrec.questions[0].qtype)}')

BPF_APP定义了【BPF Program】,该【BPF Program】程序段中定义了int dns_matching(struct __sk_buff *skb);函数,该函数是说检测到UDP源端口或目的端口为53,即DNS的request或response数据包时,【BPF Program】return -1。

【BPF Program】里cursor_advance的解释如下:

cursor_advance宏可以在包的范围内移动光标(指针),返回其当前位置并移动到指定位置。

Python3里的BPF函数帮助信息

>>> from bcc import BPF
>>> help(BPF)
Help on class BPF in module bcc:

class BPF(builtins.object)
 |  BPF(src_file=b'', hdr_file=b'', text=None, debug=0, cflags=[], usdt_contexts=[], allow_rlimit=True, device=None)
 |
 |  Methods defined here:
 |
 |  Table(bpf, map_id, map_fd, keytype, leaftype, name, **kwargs)
 |      Table(bpf, map_id, map_fd, keytype, leaftype, **kwargs)
 |
 |      Create a python object out of a reference to a bpf table handle
 |
 |
 |  __init__(self, src_file=b'', hdr_file=b'', text=None, debug=0, cflags=[], usdt_contexts=[], allow_rlimit=True, device=None)
 |      Create a new BPF module with the given source code.
 |
 |      Note:
 |          All fields are marked as optional, but either `src_file` or `text`
 |          must be supplied, and not both.
 |
 |      Args:
 |          src_file (Optional[str]): Path to a source file for the module
 |          hdr_file (Optional[str]): Path to a helper header file for the `src_file`
 |          text (Optional[str]): Contents of a source file for the module
 |          debug (Optional[int]): Flags used for debug prints, can be |'d together
 |                                 See "Debug flags" for explanation
 |  load_func(self, func_name, prog_type, device=None)
 |
 |  load_funcs(self, prog_type=2)
 |      load_funcs(prog_type=KPROBE)
 |
 |      Load all functions in this BPF module with the given type.
 |      Returns a list of the function handles.
 |
.......

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值