Linux协议处理程序,用于获取与其关联的数据包和进程

时间:2016-04-22 01:43:24

标签: sockets linux-kernel

嗨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

即使用例没有多大意义,有人可以指出我能做到这一点吗?

提前致谢。

0 个答案:

没有答案