Writing Loadable Kernel Modules using netfilter hooks (in-depth HOWTO) – Part 1
来源:互联网 发布:淘宝的流量钱包自动领 编辑:程序博客网 时间:2024/06/02 22:17
http://fcns.eu/2010/02/netfilter-hooks/
keyword:write new netfilter module
Note: This article was inspired by the lack of updated documentation on how to write proper netfilter kernel modules. At the time I’m writing this article, the latest stable release was 2.6.32.8. I am also assuming you are familiar with how LKMs (Loadable Kernel Modules) work. If you are not, then you might want to check this article first: tldp.org/HOWTO/Module-HOWTO/
In this article (Part 1) I will present how to create a simple Linux kernel module that implements a netfilter hook for a generic transport protocol (not one of the usual ones).
In Part 2, I plan to connect the module to the iptables rules generated on the userspace side.
What is netfilter?
For those of you who are not familiar with netfilter, all I can say is that it is actually a framework for packet mangling, outside the normal Berkeley socket interface. It’s the engine behind iptables – the popular firewall solution for Linux. It has four parts. Firstly, each protocol defines “hooks” (IPv4 defines 5) which are well-defined points in a packet’s traversal of that protocol stack. At each of these points, the protocol will call the netfilter framework with the packet and the hook number.
Secondly, parts of the kernel can register to listen to the different hooks for each protocol. So when a packet is passed to the netfilter framework, it checks to see if anyone has registered for that protocol and hook; if so, they each get a chance to examine (and possibly alter) the packet in order, then discard the packet (NF_DROP), allow it to pass (NF_ACCEPT), tell netfilter to forget about the packet (NF_STOLEN), or ask netfilter to queue the packet for userspace (NF_QUEUE).
The third part is that packets that have been queued are collected (by the ip_queue driver) for sending to userspace; these packets are handled asynchronously.
Netfilter Hooks in the Linux Kernel.
Netfilter modules can be loaded into the Linux kernel at runtime, so we need hooks in the actual routing code to enable dynamic hooking of functions. An integer identifier is allocated to each of these netfilter hooks. The identifiers of all hooks for each supported protocol are defined in the protocol-specific header file (
- NF_IP_PRE_ROUTING (default value is 0): incoming packets pass this hook in the ip_rcv()(linux/net/ipv4/ip_input.c) function before they are processed by the routing code
- NF_IP_LOCAL_IN (default value is 1): all incoming packets addressed to the local computer pass this hook in the function ip_local_deliver()
- NF_IP_FORWARD (default value is 2): all incoming packets not addressed to the local computer pass this hook in the function ip_forward()
- NF_IP_LOCAL_OUT (default value is 3): all outgoing packets created in the local computer pass this hook in the function ip_build_and_send_pkt()
- NF_IP_POST_ROUTING (default value is 4): this hook in the ip_finish_output() function represents the last chance to access all outgoing (forwarded or locally created) packets before they leave the computer over a network device
Calling the NF_HOOK macro causes the routing code to process the filter functions hooked into a netfilter hook. More specifically, the NF_HOOK macro has the following arguments:
- pf (protocol family): This is the identifier of the protocol family: PF_INET for IP Version 4, PF_INET6for IP Version 6.
- hook: This is the hook identifier. All valid identifiers for each protocol family are defined in a header file (e.g.,
). - skb: This is a pointer to the sk_buff structure with the packet to be handled.
- indev (input device): This is a pointer to the net_device structure of the network device that received the packet. It is set to NULL in the above example, because the packet is an outgoing packet.
- outdev (output device): This is a pointer to the net_device structure of the network device that should be used by the packet to leave the local computer. In the above example, the device used has to be determined first by use of the routing table (rt).
- okfn() (okay function): This function is invoked when all filter functions registered with this hook returned NF_ACCEPT, thereby okaying the packet’s transit.
The packet-filter functions that are actually hooked into the netfilter hooks are so-called hook functions of the type nf_hookfn. The signature of a hook function is defined in
struct sk_buff **skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn) (struct sk_buff *));
The return value of a packet-filter function specifies what should happen to the packet. It is of the typeunsigned int and can take any of the following values, defined in
- NF_DROP (default value is 0): The active rules list processing is stopped, and the packet is dropped
- NF_ACCEPT (default value is 1): The packet is passed to the next packet filter function in the rules list. Once the end of the list has been reached, the packet is released by okfn() for further processing
- NF_STOLEN (default value is 2): The packet filter function withholds the packet for further processing, so that the active rules list processing is stopped. In contrast to NF_DROP, however, the packet does not have to be explicitly dropped
- NF_QUEUE (default value is 3): The function nf_queue() (net/core/netfilter.c) puts the packet in a queue from which it can be removed and processed (e.g., by a user space program). Subsequently, nf_reinject() has to be invoked to return the packet to the Linux kernel for further processing by netfilter
- NF_REPEAT (default value is 4): In contrast to NF_ACCEPT, rather than a continuation of processing at the next packet-filter function, the current filter function is invoked again
nf_register_hook(), nf_unregister_hook() registers and unregisters a packet-filter function with the Linux kernel. The parameter passed is a nf_hook_ops structure, which includes all information required.
To register a new packet-filter function with the Linux kernel, we first have to initialize a structure of the type nf_hook_ops (linux/netfilter.h) with all of the management information required:
struct nf_hook_ops{
struct list_head list;
/* User fills in from here down. */
nf_hookfn *hook;
int pf;
int hooknum;
/* Hooks are ordered in ascending priority. */
int priority;
};
The fields of this structure have the following meaning:
- list: the nf_hook_ops structures are maintained in a linked list within the Linux kernel
- hook(): this is a pointer to the actual packet-filter function of the type nf_hookfn
- pf: the protocol family identifier (e.g., PF_INET or PF_INET6)
- hooknum: the hook identifier (e.g., NF_IP_INPUT) are used to determine the hook for this packet-filter function
- priority: packet-filter functions within the rules list of a hook are sorted by the priority field in ascending order, so that they will be invoked in this order when a packet transits
Now that you’ve got the main idea on how netfilter hooks work, I suggest we check an example. The following code belongs to a personal project involving the design of a little protocol. The source code for the .c file can be found here, while the code for the .h file is here.
The basic idea behind this generic protocol is that it uses a header made of a port number and a type of message, both defined in the header file. My module is supposed to identify the protocol (based on the protocol field of the IP header) and process only packets arriving for this protocol. Once the match is made, the next thing to do is to recover the port number and type of message from our protocol’s header. Once we have all data, we can call our callback function to do whatever we want next.
There have been a couple of important changes since 2.6.22 (which most guides are written for):
- the params of the hook function have changed slightly: struct sk_buff *skb, instead of struct sk_buff **skb
- skb_network_header(const struct sk_buff *skb), skb_transport_header(const struct sk_buff *skb) and skb_mac_header(const struct sk_buff *skb)accessors – instead of nh, h and mac header fields of the sk_buff structure (/include/linux/skbuff.h)
One more important aspect you need to take into consideration is that both skb_network_header andskb_transport_header point to the same memory address. This means that if you want to access the transport header information, you will need to add (skip) to the location of the header in the memory by adding the IP header length (e.g.. rpmp_header = (struct rpmphdr *)(skb_transport_header(sock_buff)+sizeof(struct iphdr));). I don’t know why this happens, but it happens.
Anyway, here is the code:
Source code for my_module.h:
- #include
- #define DRIVER_AUTHOR "Andrei SAMBRA "
- #define DRIVER_DESC "Generic Protocol"
- #define IPPROTO_RPMP 150
- struct rpmphdr {
- __be16 dport;
- __u16 type;
- };
Source code for my_module.c:
- /*
- * Author: andrei.sambra@telecom-sudparis.eu
- * GPLv3 License applies to this code.
- *
- * */
- #include
/* Needed by all modules */ - #include
/* Needed for KERN_INFO */ - #include
/* Needed for the macros */ - #include
- #include
- #include
- #include
- #include
- #include "rpmp.h" /* Needed for our structures */
- #define DEBUG 0
- struct sk_buff *sock_buff;
- struct iphdr *ip_header;
- struct udphdr *udp_header;
- struct rpmphdr *rpmp_header;
- static struct nf_hook_ops nfho;
- static unsigned int hook_func(unsigned int hooknum,
- struct sk_buff *skb,
- const struct net_device *in,
- const struct net_device *out,
- int (*okfn)(struct sk_buff *))
- {
- sock_buff = skb;
- if (!sock_buff) {
- return NF_ACCEPT;
- } else {
- ip_header = (struct iphdr *)skb_network_header(sock_buff);
- if (!ip_header) {
- return NF_ACCEPT;
- } else {
- if (ip_header->protocol == IPPROTO_RPMP) {
- rpmp_header = (struct rpmphdr*)(skb_transport_header(sock_buff)+sizeof(struct iphdr));
- #if DEBUG > 0
- printk(KERN_INFO "[RPMP] DEBUG: th: 0p%p\n", rpmp_header);
- printk(KERN_INFO "[RPMP] DEBUG: nh: 0p%p\n",skb_network_header(sock_buff));
- printk(KERN_INFO "[RPMP] DEBUG: mh: 0p%p\n",skb_mac_header(sock_buff));
- printk(KERN_INFO "[RPMP] DEBUG: Length: rpmp_header=%d | dport=%d | type=%d.\n",
- sizeof(rpmp_header),
- sizeof(rpmp_header->dport),
- sizeof(rpmp_header->type));
- printk(KERN_INFO "[RPMP] DEBUG: From IP address: %d.%d.%d.%dn",
- ip_header-saddr & 0x000000FF,
- (ip_header->saddr & 0x0000FF00) >> 8,
- (ip_header->saddr & 0x00FF0000) >> 16,
- (ip_header->saddr & 0xFF000000) >> 24);
- #endif
- printk(KERN_INFO "[RPMP] Got a RPMP packet for port=%d (type:%d).\n",
- ntohs(rpmp_header->dport),
- ntohs(rpmp_header->type));
- /* Callback function here*/
- return NF_DROP;
- } else {
- return NF_ACCEPT;
- }
- }
- }
- }
- static int __init init_main(void)
- {
- nfho.hook = hook_func;
- nfho.hooknum = 1;
- nfho.pf = PF_INET;
- nfho.priority = NF_IP_PRI_FIRST;
- nf_register_hook(&nfho);
- #if DEBUG > 0
- printk(KERN_INFO "[RPMP] Successfully inserted protocol module into kernel.\n");
- #endif
- return 0;
- }
- static void __exit cleanup_main(void)
- {
- nf_unregister_hook(&nfho);
- #if DEBUG > 0
- printk(KERN_INFO "[RPMP] Successfully unloaded protocol module.\n");
- #endif
- }
- module_init(init_main);
- module_exit(cleanup_main);
- /*
- * Declaring code as GPL.
- */
- MODULE_LICENSE("GPLv3");
- MODULE_AUTHOR(DRIVER_AUTHOR); /* Who wrote this module? */
- MODULE_DESCRIPTION(DRIVER_DESC); /* What does this module do */
上一篇:Linux 网络协议栈纲要
下一篇:[原创]Linux系统中“动态库”和“静态库”那点事儿
- linux 常见服务端口
- xmanager 2.0 for linux配置
- 【ROOTFS搭建】busybox的httpd...
- openwrt中luci学习笔记
- 什么是shell
- linux dhcp peizhi roc
- 关于Unix文件的软链接
- 求教这个命令什么意思,我是新...
- sed -e "/grep/d" 是什么意思...
- 谁能够帮我解决LINUX 2.6 10...
- Writing Loadable Kernel Modules using netfilter hooks (in-depth HOWTO) – Part 1
- Writing Loadable Kernel Modules using netfilter hooks (in-depth HOWTO) – Part 1
- Writing Loadable Kernel Modules using netfilter hooks (in-depth HOWTO) – Part 1
- Loadable Kernel Modules 注射
- Detecting Loadable Kernel Modules (LKM)
- Infecting loadable kernel modules 笔记
- Using Netfilter hooks
- How to Create, Compile, Load Linux LKM Loadable Kernel Modules
- In Depth ASP.NET using ADO.NET: Part I
- HOWTO build additional kernel modules for Android
- Using keyboard hooks in WinCE
- Writing a Linux Kernel Module — Part 1: Introduction
- Debugging the kernel using Ftrace - part 1
- Remote Debugging of Loadable Kernel Modules with kgdb: a Knowledge-based Article for Getting Started
- Using WebSocket in .NET 4.5 (Part 1)
- HOWTO compile kernel modules for the kernel 2.6: (编译linux2.6版本内核)
- Howto - Cross Compiling in Linux using MingW32
- Using jQuery UI in DotNetNuke Modules
- linux内核ipv4网络部分分层结构及涉入源文件
- Linux Netfilter实现机制和扩展技术
- ClippingNodeTest之ScrollViewDemo
- A example of NF_IP_PRE_ROUTING module PART_1(转载)
- Linux 网络协议栈纲要
- Writing Loadable Kernel Modules using netfilter hooks (in-depth HOWTO) – Part 1
- [原创]CentOS6.0系统下安装配置openCV成功
- 全球首款工业物联网芯片渝“芯”一号在渝发布
- SQL 其他问题
- IT男们,先别慌着coding了,看看了中国又发生了什么吧
- 理解js中的闭包
- 认清经济大形势,别让我们辛苦code来的财富一再缩水
- [原创]通过SSH登录Linux服务器很慢,且服务器提示Access Denied时的解决方案
- C++多态性机制初探