这篇文章分析一下如何利用Netfilter过滤指定的端口,如TCP的80端口。
1、源代码:filterPort.c
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/netdevice.h>
MODULE_LICENSE("GPL");
/* This is the structure we shall use to register our function */
static struct nf_hook_ops nfho;
/* IP address we want to drop packets from, in NB order */
static unsigned char *deny_port = "/x00/x50"; /* port 80 */
/* This is the hook function itself */
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 *))
{
struct sk_buff *sb = skb;
struct iphdr *iph;
struct tcphdr *tcph;
if(!sb) return NF_ACCEPT;
iph = ip_hdr(sb);
if(!iph) return NF_ACCEPT;
/*Make sure this is a TCP packet first*/
if(iph->protocol != IPPROTO_TCP)
{
return NF_ACCEPT;
}
tcph = (struct tcphdr *)(sb->data + iph->ihl * 4);
//tcph = tcp_hdr(sb);
//pr_warning("%d.%d.%d.%d:%u/t%d.%d.%d.%d:%u/n",NIPQUAD(iph->saddr),ntohs(tcph->source),NIPQUAD(iph->daddr),ntohs(tcph->dest));
if(tcph->dest == *(__be16 *)deny_port)
{
pr_warning("Dropped packet to prot %d/n",ntohs(tcph->dest) );
return NF_DROP;
}
return NF_ACCEPT;
}
/* Initialisation routine */
int init_module()
{
/* Fill in our hook structure */
nfho.hook = hook_func; /* Handler function */
nfho.hooknum = NF_INET_PRE_ROUTING; /* First hook for IPv4 */
nfho.pf = PF_INET;
nfho.priority = NF_IP_PRI_FIRST; /* Make our function first */
nf_register_hook(&nfho);
pr_info("filterPort install into kernel!/n");
return 0;
}
/* Cleanup routine */
void cleanup_module()
{
nf_unregister_hook(&nfho);
pr_info("filterPort removed from kernel!/n");
}
2、Makefile:
obj-m +=filterPort.o
all:
make -C /lib/modules/`uname -r`/build M=`pwd`
clean:
make -C /lib/modules/`uname -r`/build M=`pwd` cleaninstall:
/sbin/insmod filterPort.ko
remove:
/sbin/rmmod filterPort
3、编译:
make
4、安装模块:
make install
5、测试:
在安装该内核模块的机器上打开http服务:
service httpd start
从别的机器访问这台机器的http服务。会发现连接不上,并且/var/log/messages中有如下字样:
Dropped packet to prot 80
6、卸载模块:
make remove
7、注意:
本来以为和获得IP头部一样,可以这样
tcph = tcp_hdr(sb);
获得TCP的头部,结果头部信息总是不正确。查看 内核源码:
ip_hdr 定义为:return (struct iphdr *) (skb->head + skb->network_header);
tcp_hdr 定以为:return (struct tcphdr *)(skb->head + skb->transport_header);
终于明白我在处理这个skb 时,内核还在网络层,还没有处理到传输层,所以transport_header 的值与network_header 相同。
于是老老实实用:
tcph = (struct tcphdr *)(sb->data + iph->ihl * 4);