8

I'm writing ethernet network driver for linux. I want to receive packets, edit and resend them. I know how to edit the packet in packet_interceptor function, but how can I drop incoming packets in this function??

#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, world\n");
}

module_init(hello_init);
module_exit(hello_exit);
Milad Khajavi
  • 2,769
  • 9
  • 41
  • 66
  • Have you tested with my solution? – Atle Oct 22 '13 at 08:54
  • Hi @Atle , I've some problem with my computer in these days. Thanks for your response, I will test it, as soon as I can boot my PC :D. But I remeber befor i ask you, I tested this solution, but it didn't worked. I will tray it again. – Milad Khajavi Oct 23 '13 at 18:05
  • Did get any solution except using netfilter or rx_handler ? – Janith Nov 28 '20 at 07:10

2 Answers2

6

I went through the Kernel networking code (a year since I did anything inside there), and I think you should do be able to do this without leaking anything:

kfree_skb(skb);
return NET_RX_DROP;

Edit

This is done in other protocol handlers like ip_rcv and arp_rcv (last one returns 0 instead of NET_RX_DROP, but I don't think the return value matters very much). Remember not to call any other handlers if you drop the skb.

Look at the code for ip_rcv in ip.c (at the bottom): http://lxr.free-electrons.com/source/net/ipv4/ip_input.c#L375

If everything goes well, it passes the skb to Netfilter which then calls ip_rcv_finish (if it doesn't drop it). If something goes wrong, it frees the skb and returns.

Edit

If more than one protocol handler matches an SKB, the kernel will send it to all of them. When you kfree_skb() in one of the modules, the SKB will still live on in the other handlers.

Atle
  • 1,867
  • 12
  • 10
  • Today I tested, but it didn't worked. What is the problem with it? – Milad Khajavi Oct 29 '13 at 13:02
  • What do you mean with "didn't work"? Was the packet received by the system instead of being droppen? Do the packets even enter your module? – Atle Oct 29 '13 at 16:19
  • 1
    I'm receiving all packets in `packet_interceptor` handler, but all packets received by the system. http://paste.ubuntu.com/6324987/ – Milad Khajavi Oct 29 '13 at 16:51
  • 1
    I did an example with a netfilter module instead. The thing that is going on in your kernel is that since the protocol handler for IP also is registered, the kernel sends the SKB to both your module and IP. When you `kfree_skb()`, you decrement the users counter with one, but IP is also using it so it is not freed and dropped. – Atle Oct 29 '13 at 21:52
  • I think when you are using ETH_P_ALL, it uses ptype_all and copy all the packets...and I think ptype_base want to use(another type instead of ETH_P_ALL).... – Janith Nov 28 '20 at 06:08
6

You are making your module handle all ethernet packets. Linux will send packets to all matching protocol handlers. Since IP is already registered in your kernel, both your module and ip_rcv will receive all SKBs with IP headers.

You cannot change this behaviour without changing the kernel code. One possibility is to create a netfilter module instead. This way, you can intercept the packet after the ip_rcv function and drop it if you want to (in Netfilters PREROUTING hook).

Here is a small Netfilter module which I extracted from some code I had already written. This module is unfinished, but the main stuff are in place.

#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;
}
Atle
  • 1,867
  • 12
  • 10
  • I've tested the netfilter, it works very well, But I need to drop with `dev_add_pack()` hooks. my question is, if the system have two handler (ip_rcv, my_packet_interceptor), when I change the skb in one of my handler, which of them are valid? (assume that I have changed the skb in my_packet_interceptor so I have two skb, `original` and `changed`, which of them go further processing?) – Milad Khajavi Oct 30 '13 at 06:58
  • 1
    The handlers are run after eachother. I would guess that IP is run first since it is probably registered before your module. I don't think the SKB is copied at this stage, so IP will probably be done with it before you change it. – Atle Oct 30 '13 at 08:17
  • So, if the handlers are run after eachother, Why I can't drop the packets? – Milad Khajavi Oct 31 '13 at 06:58
  • 1
    The function which hands the SKBs to all protocol handlers is here: http://lxr.free-electrons.com/source/net/core/dev.c#L3481. As you can see, the return value from `deliver_skb` (which in turn calls the actua handler functions) is ignored. The loops continue anyway. Therefore, you cannot drop an SKB if two protocol handlers gets it. – Atle Oct 31 '13 at 08:28