netfilterフック

Linuxのnetfilterフック関数の作成

ソースファイル(exp_netfilter1.c)

/*
 * exp_netfilter1.c
 */

#include <linux/types.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/skbuff.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/ip.h>
#include <linux/udp.h>

#define DRIVER_AUTHOR "KWATA"
#define DRIVER_DESC "netfilter experiment"

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 *))
{
  printk(KERN_INFO "[NFE] hook_func");

  return NF_ACCEPT;
}


//----------------------------------
static int __init nfe_init(void)
{
  printk(KERN_INFO "[NFE] nfe_init\n");

  nfho.hook = hook_func;
  nfho.hooknum = NF_INET_PRE_ROUTING;
  nfho.pf = PF_INET;
  nfho.priority = NF_IP_PRI_FIRST;

  nf_register_hook(&nfho);

  return 0;
}


//----------------------------------
static void __exit nfe_exit(void)
{
  printk(KERN_INFO "[NFE] nfe_exit\n");

  nf_unregister_hook(&nfho);
}


module_init(nfe_init);
module_exit(nfe_exit);

MODULE_LICENSE("GPLv3");
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);

makefile

obj-m := exp_netfilter1.o

シェルから以下のように叩く。

$ make -C /usr/src/kernels/linux-3.6.6 M=`pwd` modules

すると、exp_netfilter1.koというカーネルモジュールが出来る。
これをinsmodすればカーネルに組み込まれる。

$ insmod exp_netfilter1.ko

パケットが流れるたびに/var/log/messagesに出力される。
ここでは、単にフックされることの確認のみであり、実際フック関数に渡されるsk_buffの中身を見てどうのこうの処理することまではしていない。
※messagesの監視は
$ tail -f messages
で更新された情報もリアルタイムに表示される。

※ネットでググった例ではフック関数登録時のhooknumにNF_IP_PRE_ROUTING
を設定していたが、/include/linux/netfilter_ipv4.hに定義されているNF_IP_PRE_ROUTINGは#ifndef __KERNEL__で囲まれている。ビルド時に__KERNEL__は定義された状態にあるらしく、この囲まれたブロックは有効になっていない。そのため、ソースにNF_IP_PRE_ROUTINGを書くとコンパイル時に未定義エラーが発生する。
実際にはnetfilter_ipv4.hのNF_IP_PRE_ROUTINGではなく、netfilter.hのNF_INET_PRE_ROUTINGを使えばよいようである。