我有一个简单的内核模块,本质上是在给定接口的每个数据包上打印一条消息(代码如下)。无论我编译并运行它的内核是什么,我的系统都会在运行时挂起几秒钟。我没有从 Linux 本身收到任何消息,但 VMWare 说来宾操作系统已停止 CPU。模块编译和加载没有错误。有什么想法吗?我将如何调试它? Journalctl 不显示任何内容。任何帮助将不胜感激,我对此很陌生,不知道如何调试它。
虚拟机日志:
2024-02-01T11:57:03.994Z In(05) vcpu-0 MsgHint: msg.monitorevent.halt
2024-02-01T11:57:03.994Z In(05)+ vcpu-0 The CPU has been disabled by the guest operating system. Power off or reset the virtual machine.
2024-02-01T11:57:03.994Z In(05)+ vcpu-0 ---------------------------------------```
内核模块源码:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/ip.h>
#include <linux/inet.h>
static struct nf_hook_ops netfilter_ops;
static char *interface = "ens33";
module_param(interface, charp, 0);
static unsigned int hook_func(void *priv, struct sk_buff *skb, const struct nf_hook_state *state) {
char source[16], dest[16];
if (!skb) {
return NF_ACCEPT;
}
if (strcmp(state->in->name, interface) == 0 || strcmp(state->out->name, interface) == 0) {
struct iphdr *ip_header = ip_hdr(skb);
if (!ip_header) {
return NF_ACCEPT;
}
snprintf(source, 16, "%pI4", &ip_header->saddr);
snprintf(dest, 16, "%pI4", &ip_header->daddr);
printk(KERN_INFO "Packet logged on %s: Source IP: %s, Destination IP: %s\n", interface, source, dest);
}
return NF_ACCEPT;
}
static int __init my_module_init(void) {
netfilter_ops.hook = hook_func;
netfilter_ops.pf = PF_INET;
netfilter_ops.hooknum = NF_INET_PRE_ROUTING;
netfilter_ops.priority = NF_IP_PRI_FIRST;
nf_register_net_hook(&init_net, &netfilter_ops);
printk(KERN_INFO "Kernel module initialized on interface %s\n", interface);
return 0;
}
static void __exit my_module_exit(void) {
nf_unregister_net_hook(&init_net, &netfilter_ops);
printk(KERN_INFO "Kernel module removed\n");
}
module_init(my_module_init);
module_exit(my_module_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("foo bar baz");
MODULE_DESCRIPTION("Netfilter packet logging module");
MODULE_VERSION("0.1");
答案1
好吧,看来我自己找到了答案。问题是钩子方法在调用时只能设置 state->in 或 state->out 之一(显然)。这是更正后的相关行:
if ((state->in && strcmp(state->in->name, interface) == 0) || (state->out && strcmp(state->out->name, interface) == 0)) {