Comment filtrer et intercepter les paquets Linux en utilisant l’API net_dev_add ()?

J’écris un pilote réseau Ethernet pour Linux. Je veux recevoir des paquets, les éditer et les renvoyer. Je sais comment éditer le paquet dans la fonction packet_interceptor , mais comment puis-je supprimer les paquets entrants dans cette fonction?

 #include  #include  #include  #include  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, world\n"); } module_init(hello_init); module_exit(hello_exit); 

    Vous faites en sorte que votre module gère tous les paquets Ethernet. Linux enverra des paquets à tous les gestionnaires de protocole correspondants. Étant donné qu’IP est déjà enregistré dans votre kernel, votre module et ip_rcv recevront tous les SKB avec en-têtes IP.

    Vous ne pouvez pas changer ce comportement sans changer le code du kernel. Une possibilité consiste à créer un module netfilter à la place. De cette façon, vous pouvez intercepter le paquet après la fonction ip_rcv et le supprimer si vous le souhaitez (dans le hook Netfilters PREROUTING ).

    Voici un petit module Netfilter que j’ai extrait d’un code que j’avais déjà écrit. Ce module est inachevé, mais l’essentiel est en place.

     #include  #include  // 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; } 

    Je suis passé par le code réseau du kernel (un an depuis que j’ai fait quoi que ce soit à l’intérieur), et je pense que vous devriez pouvoir le faire sans rien fuir:

     kfree_skb(skb); return NET_RX_DROP; 

    modifier

    Ceci est fait dans d’autres gestionnaires de protocole tels que ip_rcv et arp_rcv (le dernier renvoie 0 au lieu de NET_RX_DROP, mais je ne pense pas que la valeur de retour compte beaucoup). Rappelez-vous de ne pas appeler d’autres gestionnaires si vous déposez le skb.

    Regardez le code pour ip_rcv dans ip.c (en bas): http://lxr.free-electrons.com/source/net/ipv4/ip_input.c#L375

    Si tout se passe bien, il passe le skb à Netfilter qui appelle ensuite ip_rcv_finish (s’il ne le lâche pas). Si quelque chose ne va pas, cela libère le skb et revient.

    modifier

    Si plus d’un gestionnaire de protocole correspond à un SKB, le kernel l’enverra à tous. Quand vous kfree_skb() dans l’un des modules, le SKB continuera à vivre dans les autres gestionnaires.