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

如何在SK_MSG钩子中正确打印消息数据?代码无报错但内容为空

问题分析与解决方案

问题现象

运行sk_msg类型的BPF程序时,程序无报错,但通过/sys/kernel/debug/tracing/trace_pipe查看输出,Socket Message:后始终无内容。切换为sk_skb类型程序后,问题同样存在。

原始代码

#include <stdio.h>

#include <linux/bpf.h>
#include <sys/socket.h>

#include <bpf/bpf_helpers.h>

char LICENSE[] SEC("license") = "GPL";

SEC("sk_msg")
int http_state_machine(struct sk_msg_md *msg) {
  int err;
  int *msg_id_ptr;
  long len = (long)msg->data_end - (long)msg->data;
  if (len > 0) {
    bpf_printk("Message length: %ld\n", len);
  } else {
    bpf_printk("ERR: Message length is negative\n");
    return SK_PASS;
  }

  // Try to print the message
  char msg_str[300];
  if (len < 300) {
    bpf_printk("Message length is less than 300\n");
  } else {
    err = bpf_msg_pull_data(msg, 0, 300, 0);
    if (err < 0) {
      bpf_printk("ERR: bpf_msg_pull_data failed\n");
      return SK_PASS;
    }

    err = bpf_probe_read_kernel(msg_str, 300, msg->data);
    if (err < 0) {
      bpf_printk("ERR: bpf_probe_read_kernel failed\n");
      return SK_PASS;
    }
    bpf_printk("Socket Message: %s\n", msg_str);
  }

  return SK_PASS;
}

输出示例

ComposePostServ-1918515 [008] d...1 1322265.977032: bpf_trace_printk: Message length: 1295

ComposePostServ-1918515 [008] d...1 1322265.977039: bpf_trace_printk: Socket Message: 

ComposePostServ-1918516 [004] d...1 1322266.019906: bpf_trace_printk: Message length: 872

ComposePostServ-1918516 [004] d...1 1322266.019914: bpf_trace_printk: Socket Message: 

核心原因与解决办法

1. 字符串未以NULL终止

bpf_printk的%s格式要求字符串必须以\0结尾,但从网络数据中复制的msg_str是原始二进制数据,大概率没有终止符,甚至可能开头就包含\0字节,导致%s无法正常解析输出。

解决方法:手动添加NULL终止符,确保数组最后一位为终止符:

// 在bpf_probe_read_kernel之后添加
msg_str[299] = '\0';

2. 网络数据含非ASCII或不可打印字符

网络报文(比如HTTP)可能包含二进制数据、控制字符,或者编码不是纯ASCII,直接用%s打印会被截断或无法显示。

解决方法:改用十六进制打印,或者过滤可打印字符后输出:

  • 十六进制打印示例:
// 替换原有的bpf_printk("Socket Message: %s\n", msg_str);
for (int i = 0; i < 300; i++) {
    bpf_printk("%02x ", msg_str[i]);
    if ((i+1) % 16 == 0) {
        bpf_printk("\n");
    }
}
  • 过滤可打印字符示例:
char printable_str[300] = {0};
int idx = 0;
for (int i = 0; i < 300; i++) {
    if (msg_str[i] >= 32 && msg_str[i] <= 126) {  // 可打印ASCII范围
        printable_str[idx++] = msg_str[i];
        if (idx >= 299) break;
    }
}
printable_str[idx] = '\0';
bpf_printk("Socket Message: %s\n", printable_str);

3. 验证bpf_msg_pull_data的实际效果

虽然代码检查了err < 0,但可以打印err值确认是否成功拉取了预期长度的数据:

bpf_printk("bpf_msg_pull_data returned: %d\n", err);

如果返回值不等于300,说明拉取的数据长度不足,需进一步排查报文分段等问题。

4. 确认bpf_probe_read_kernel的使用正确性

对于sk_msg程序,msg->data指向内核空间的报文数据,bpf_probe_read_kernel的使用是正确的,但需确保复制长度不超过msg->data_end - msg->data的实际值,避免越界。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 08:47:53