目的:编写linux kernel驱动程序,在挂载点上读取icmp协议数据,打印icmp数据包内容。
//icmp头部结构
struct icmphdr {
__u8 type; //8位类型
__u8 code; //8位代码
__sum16 checksum; //16位校验和
union {
struct {
__be16 id; //16位id
__be16 sequence; //16位序号
} echo;
__be32 gateway;
struct {
__be16 __unused;
__be16 mtu;
} frag;
} un;
};
//驱动代码
#include <linux/module.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/icmp.h>
static struct nf_hook_ops nfho;
static unsigned int ptcp_hook_func(const struct nf_hook_ops *ops,
struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
struct iphdr *iph; /* IPv4 header */
struct icmphdr *icmph; /*icmp header*/
//struct tcphdr *tcph; /* TCP header */
//u16 sport, dport; /* Source and destination ports */
//u32 saddr, daddr; /* Source and destination addresses */
unsigned char *user_data; /* TCP data begin pointer */
unsigned char *tail; /* TCP data end pointer */
unsigned char *it; /* TCP data iterator */
int length;
/* Network packet is empty, seems like some problem occurred. Skip it */
if (!skb)
return NF_ACCEPT;
iph = ip_hdr(skb); /* get IP header */
/* Skip if it's not ICMP packet */
if (iph->protocol != IPPROTO_ICMP)
return NF_ACCEPT;
//tcph = tcp_hdr(skb); /* get TCP header */
icmph = icmp_hdr(skb);
length = sizeof(struct icmphdr);
printk("length:%d\n", length);
/* Calculate pointers for begin and end of TCP packet data */
//user_data = (unsigned char *)((unsigned char *)tcph + (tcph->doff * 4));
user_data = (unsigned char *)((unsigned char *)icmph + length);
tail = skb_tail_pointer(skb);
/* Print ICMP packet data (payload) */
printk("print_tcp: data:\n");
for (it = user_data; it != tail; ++it) {
char c = *(char *)it;
if (c == '\0')
break;
printk("%c", c);
}
printk("\n\n");
return NF_ACCEPT;
}
static int __init ptcp_init(void)
{
int res;
nfho.hook = (nf_hookfn *)ptcp_hook_func; /* hook function */
nfho.hooknum = NF_INET_PRE_ROUTING; /* received packets */
nfho.pf = PF_INET; /* IPv4 */
nfho.priority = NF_IP_PRI_FIRST; /* max hook priority */
res = nf_register_hook(&nfho);
if (res < 0) {
pr_err("print_tcp: error in nf_register_hook()\n");
return res;
}
pr_debug("print_tcp: loaded\n");
return 0;
}
static void __exit ptcp_exit(void)
{
nf_unregister_hook(&nfho);
pr_debug("print_tcp: unloaded\n");
}
module_init(ptcp_init);
module_exit(ptcp_exit);
MODULE_LICENSE("GPL");
//Makefile
ifneq ($(KERNELRELEASE),)
obj-m:=print_tcp.o
else
PWD:=$(shell pwd)
KDIR:=/usr/lib/modules/$(shell uname -r)/build
all:
$(MAKE) -C $(KDIR) M=$(PWD)
clean:
rm -rf *.o *.mod.c *.ko *.symvers *.order *.markers
endif
1、编译:

生成print_tcp.ko驱动文件。
2、挂载驱动
insmod print_tcp.ko
3、测试

图中标红的打印出来的就是ICMP协议传输的数据。

抓包也可以看到,数据部分也是这些数据。
4、卸载驱动
rmmod print_tcp
5、完。
参考:
https://codeday.me/bug/20190325/825084.html
本文介绍了一种在Linux内核中编写驱动程序的方法,该程序能够捕获并解析ICMP协议数据包,实现对数据包内容的打印。通过详细展示驱动代码及编译、挂载步骤,帮助读者理解如何在内核层面处理网络数据。

3416

被折叠的 条评论
为什么被折叠?



