Как фильтровать и перехватывать пакеты Linux с помощью net dev add () API?


Я пишу сетевой драйвер ethernet для linux. Я хочу получать пакеты, редактировать и отправлять их повторно. Я знаю, как редактировать пакет в функции packet_interceptor, но как я могу отбросить входящие пакеты в этой функции??

#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/ip.h>
#include <net/sock.h>

struct packet_type my_proto;

int packet_interceptor(struct sk_buff *skb,
    struct net_device *dev,
    struct packet_type *pt,
    struct net_device *orig_dev) {

    // I dont want certain packets go to upper in net_devices for further processing.
    // How can I drop sk_buff here?!

  return 0;
}

static int hello_init( void ) {
    printk(KERN_INFO "Hello, world!n");

    my_proto.type = htons(ETH_P_ALL);
    my_proto.dev = NULL;
    my_proto.func = packet_interceptor;

    dev_add_pack(&my_proto);
    return 0;
}    

static void hello_exit(void) {
  dev_remove_pack(&my_proto);
  printk(KERN_INFO "Bye, worldn");
}

module_init(hello_init);
module_exit(hello_exit);
2 7

2 ответа:

Вы заставляете ваш модуль обрабатывать все пакеты ethernet. Linux будет посылать пакеты всем соответствующим обработчикам протоколов. Поскольку IP уже зарегистрирован в вашем ядре, и ваш модуль, и ip_rcv получат все skb с IP-заголовками.

Вы не можете изменить это поведение, не изменив код ядра. Одна из возможностей заключается в создании модуля netfilter. Таким образом, вы можете перехватить пакет после функции ip_rcv и отбросить его, если хотите (в Netfilters PREROUTING крюк).

Вот небольшой модуль Netfilter, который я извлек из некоторого кода, который я уже написал. Этот модуль не закончен, но основные вещи на месте.

#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>

// Handler function
static unsigned int my_handler (
    unsigned int hook,
    struct sk_buff *skb,
    const struct net_device *in,
    const struct net_device *out,
    int (*okfn)(struct sk_buff *))
{
    return NF_ACCEPT;
// or
    return NF_DROP;
}

// Handler registering struct
static struct nf_hook_ops my_hook __read_mostly = {
    .hook = my_handler,
    .pf = NFPROTO_IPV4,
    .hooknum = (1 << NF_INET_PRE_ROUTING),
    .priority = NF_IP_PRI_FIRST // My hook will be run before any other netfilter hook
};

int my_init() {
    int err = nf_register_hook (&my_hook);
    if (err) {
            printk (KERN_ERR "Could not register hook\n");
    }
    return err;
}

Я прошелся по сетевому коду ядра (год с тех пор, как я что-то там делал), и я думаю, что вы должны быть в состоянии сделать это, ничего не утекая:

kfree_skb(skb);
return NET_RX_DROP;

Edit

Это делается в других обработчиках протоколов, таких как ip_rcv и arp_rcv (Последний возвращает 0 вместо NET_RX_DROP, но я не думаю, что возвращаемое значение имеет большое значение). Не забывайте вызывать других обработчиков, если вы бросите skb.

Посмотрите на код для ip_rcv в ip.c (внизу): http://lxr.free-electrons.com/source/net/ipv4/ip_input.c#L375

Если все идет хорошо, он передает skb в Netfilter, который затем вызывает ip_rcv_finish (если он не сбрасывает его). Если что-то идет не так, он освобождает skb и возвращается.

Edit

Если более чем один обработчик протокола соответствует SKB, ядро будет посылать его всем из них. Когда вы kfree_skb() в одном из модулей, SKB все еще будет жить в других обработчиках.