kk Blog —— 通用基础

date [-d @int|str] [+%s|"+%F %T"]

监控skb释放

skb_probe.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/kprobes.h>

#include <linux/net.h>
#include <linux/socket.h>
#include <linux/sockios.h>
#include <linux/in.h>
#include <linux/inet.h>
#include <linux/inetdevice.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>

#include <net/snmp.h>
#include <net/ip.h>
#include <net/protocol.h>
#include <net/route.h>
#include <linux/skbuff.h>
#include <net/sock.h>
#include <net/arp.h>
#include <net/icmp.h>
#include <net/raw.h>
#include <net/checksum.h>
#include <linux/netfilter_ipv4.h>
#include <net/xfrm.h>
#include <linux/mroute.h>
#include <linux/netlink.h>

int count = 0;

struct ctl_table_header *ctl_header = NULL;
static struct ctl_table debug_table[] = { 
	{
		.procname       = "pr_count",
		.data           = &count,
		.maxlen         = sizeof(count),
		.mode           = 0644,
		.proc_handler   = &proc_dointvec, },
	{ },
};

static struct ctl_table ipv4_dir_table[] = {
	{
		.procname    = "ipv4",
		.mode        = 0555,
		.child       = debug_table, },
	{ },
};

static ctl_table net_dir_table[] = {
	{ 
		.procname    = "net",
		.mode        = 0555,
		.child        = ipv4_dir_table, },
	{ },
};

int dump_stack_skb(void)
{
	if (count > 0) {
		dump_stack();
		count--;
	}
	return 0;
}

/*
// ip_rcv call skb_orphan, skb_orphan will reset skb->destructor
int j_ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
{
	skb->destructor = (void*)dump_stack_skb;
	jprobe_return();
	return 0;
}

static struct jprobe jp_ip_rcv = {
	.entry = j_ip_rcv,
	.kp = {
		.symbol_name  = "ip_rcv",
	}
};
*/

int j_ip_rcv_finish(struct sk_buff *skb)
{
	skb->destructor = (void*)dump_stack_skb;
	jprobe_return();
	return 0;
}

static struct jprobe jp_ip_rcv_finish = {
	.entry = j_ip_rcv_finish,
	.kp = {
		.symbol_name  = "ip_rcv_finish",
	}
};


static int __init kprobe_init(void)
{
	int ret;
	ctl_header = register_sysctl_table(net_dir_table);
	if(!ctl_header){
		printk(KERN_ERR"SYNPROXY: sp_sysctl_init() calls failed.");
		return -1;
	}

//    ret = register_jprobe(&jp_ip_rcv);
	ret = register_jprobe(&jp_ip_rcv_finish);
	if (ret < 0) {
		unregister_sysctl_table(ctl_header);
		printk(KERN_INFO "register_jprobe failed, returned %d\n", ret);
		return -1;
	}
//    printk(KERN_INFO "Planted jprobe at %p, handler addr %p\n", jp_ip_rcv.kp.addr, jp_ip_rcv.entry);
	printk(KERN_INFO "Planted jprobe at %p, handler addr %p\n", jp_ip_rcv_finish.kp.addr, jp_ip_rcv_finish.entry);
	return 0;
}

static void __exit kprobe_exit(void)
{
	if (ctl_header)
		unregister_sysctl_table(ctl_header);

//    unregister_jprobe(&jp_ip_rcv);
//    printk(KERN_INFO "kprobe at %p unregistered\n", jp_ip_rcv.kp.addr);
	unregister_jprobe(&jp_ip_rcv_finish);
	printk(KERN_INFO "kprobe at %p unregistered\n", jp_ip_rcv_finish.kp.addr);
}

module_init(kprobe_init)
module_exit(kprobe_exit)
MODULE_LICENSE("GPL");

Makefile

1
2
3
4
5
6
7
8
9
10
11
obj-m := skb_probe.o

KDIR:=/lib/modules/`uname -r`/build
PWD=$(shell pwd)

KBUILD_FLAGS += -w

all:
	make -C $(KDIR) M=$(PWD) modules
clean:
	make -C $(KDIR) M=$(PWD) clean

运行

打印10次释放

1
echo 10 > /proc/sys/net/ipv4/pr_count