嗨Linux网络专家, 我试图获得一个工具来监控每个进程创建的所有套接字,以及每个进程使用的带宽。我可以从/ proc轮询该信息,但我会想念在轮询周期之间创建和销毁的短期套接字。
我们的想法是创建一个内核模块,用于向网络子系统注册协议处理程序,以便为每个收到的数据包调用我的处理函数。在处理程序中,我想查找与sk_buff关联的套接字以及打开套接字的进程。为了让进程等待套接字,我将通过套接字的等待队列并检查列表中的任务。我写了这个:
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/kdev_t.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/slab.h>
#include <net/datalink.h>
#include <net/inet_hashtables.h>
#include <net/tcp.h>
#include <net/inet_common.h>
#include <linux/list.h>
#include <linux/ip.h>
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("xxx");
MODULE_AUTHOR("xxxx");
int prot_handler(struct sk_buff *, struct net_device *, struct packet_type *, struct net_device *);
static struct packet_type handler_packet_type __read_mostly = {
.type = cpu_to_be16(ETH_P_IP),
.func = prot_handler,
};
int
prot_handler(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
{
const struct iphdr *iph;
const struct tcphdr *th;
struct sock *sk;
struct socket_wq *wq;
wait_queue_head_t *q;
struct task_struct * task;
//printk(KERN_ALERT "Got sk_buff.\n");
iph = ip_hdr(skb);
th = tcp_hdr(skb);
sk = __inet_lookup_established(dev_net(skb->dev), &tcp_hashinfo,
iph->saddr, th->source,
iph->daddr, ntohs(th->dest),
skb->skb_iif);
/* __inet_lookup_skb is crashing. It might be because skb_steal_sock?
*
* __inet_lookup_skb:
* skb_steal_sock
* __inet_lookup
* __inet_lookup_established
* __inet_lookup_listener
*/
if (!sk)
return 0;
//printk(KERN_ALERT "Found active sock.\n");
// code mimics sock_def_readable
rcu_read_lock();
wq = rcu_dereference(sk->sk_wq);
q = &wq->wait;
if (wq_has_sleeper(wq)) {
// code mimics __wake_up_common
wait_queue_t *curr, *next;
list_for_each_entry_safe(curr, next, &q->task_list, task_list) {
task = curr->private;
if (task && task->pid != 0)
printk(KERN_ALERT "Got packet for process ID: %d\n", task->pid);
}
}
}
}
rcu_read_unlock();
return 0;
}
static int __init
dev_init(void) {
printk(KERN_ALERT "Registering protocol handler with network stack.\n");
dev_add_pack(&handler_packet_type);
return 0;
}
static void __exit
dev_exit(void) {
printk(KERN_ALERT "Removing protocol handler.\n");
dev_remove_pack(&handler_packet_type);
}
module_init(dev_init);
module_exit(dev_exit);
当我加载此模块时,启动了一个ssh会话到系统进行测试。当我在远程系统上键入内容时调用处理程序,但打印的PID与我的预期不相关。处理程序并不总是被调用。我认为ip_rcv可能存在竞争条件。
Apr 22 10:20:56 ol71node1 kernel: Got packet for process ID: 13927307
Apr 22 10:20:56 ol71node1 kernel: Got packet for process ID: 13927307
Apr 22 10:20:56 ol71node1 kernel: Got packet for process ID: 13927307
即使用例没有多大意义,有人可以指出我能做到这一点吗?
提前致谢。