分类: LINUX
2015-04-02 21:56:47
原文地址:七、应用层和Netfilter的通信 作者:guanglongxishui
如图所示,netfilter和用户空间进行通信使用的是两个socket的系统调用,把用户空间的地址传给内核,内核使用copy_from_user 和 copy_to_user来进行数据的传递。
我们先来看一下系统调用setsockopt 和getsock_opt的定义。
#include
#include
int getsockopt(int sockfd, int level, int optname,void *optval, socklen_t *optlen);
int setsockopt(int sockfd, int level, int optname,const void *optval, socklen_t optlen);
sockfd指向一个打开的套接口描述符,level一般是标识协议。optname是命令字,optval指向一个地址,通过它来传递/存储数据。optlen是要传递数据的长度.
基于socksetopt和sockgetopt系统调用的机制,Netfilte提供了一个基本框架,允许不同协议的防火墙来自己实现自己和用户空间的通信函数。
struct nf_sockopt_ops
{
struct list_head list;
u_int8_t pf;
/*最小和最大set 命令字*/
int set_optmin;
int set_optmax;
/*处理socksetopt系统调用的函数,由防火墙自己实现*/
int (*set)(struct sock *sk, int optval, void __user *user, unsigned int len);
int (*compat_set)(struct sock *sk, int optval,void __user *user, unsigned int len);
/*最小和最大get 命令字*/
int get_optmin;
int get_optmax;
/*处理sockgetopt系统调用的函数,由防火墙自己实现*/
int (*get)(struct sock *sk, int optval, void __user *user, int *len);
int (*compat_get)(struct sock *sk, int optval,
void __user *user, int *len);
/* Use the module struct to lock set/get code in place */
struct module *owner;
};
Netfilter中每个协议自己初始化一个自己的nf_sockopt_ops实例,把它注册到netfilter管理的链表中。用户空间发起和内核通信时,Netfilter根据各个协议的命令字范围来找到相应的
nf_sockopt_ops实例,调用实例中对应的set/get处理函数,来进行数据的处理。
static LIST_HEAD(nf_sockopts);
int nf_register_sockopt(struct nf_sockopt_ops *reg)
{
struct nf_sockopt_ops *ops;
int ret = 0;
if (mutex_lock_interruptible(&nf_sockopt_mutex) != 0)
return -EINTR;
/*检查要注册的nf_sockopt_ops的命令字范围是否和已注册的重复*/
list_for_each_entry(ops, &nf_sockopts, list) {
if (ops->pf == reg->pf
&& (overlap(ops->set_optmin, ops->set_optmax,
reg->set_optmin, reg->set_optmax)
|| overlap(ops->get_optmin, ops->get_optmax,
reg->get_optmin, reg->get_optmax))) {
NFDEBUG("nf_sock overlap: %u-%u/%u-%u v %u-%u/%u-%u\n",
ops->set_optmin, ops->set_optmax,
ops->get_optmin, ops->get_optmax,
reg->set_optmin, reg->set_optmax,
reg->get_optmin, reg->get_optmax);
ret = -EBUSY;
goto out;
}
}
/*把nf_sockopt_ops实例加入到netfilter管理的全局链表上*/
list_add(?->list, &nf_sockopts);
out:
mutex_unlock(&nf_sockopt_mutex);
return ret;
}
static struct nf_sockopt_ops *nf_sockopt_find(struct sock *sk, u_int8_t pf,int val, int get)
{
struct nf_sockopt_ops *ops;
if (mutex_lock_interruptible(&nf_sockopt_mutex) != 0)
return ERR_PTR(-EINTR);
list_for_each_entry(ops, &nf_sockopts, list) {
/*协议要一样*/
if (ops->pf == pf) {
if (!try_module_get(ops->owner))
goto out_nosup;
/*命令字必须在对应nf_sockopt_ops定义的范围内*/
if (get) {
if (val >= ops->get_optmin &&
val < ops->get_optmax)
goto out;
} else {
if (val >= ops->set_optmin &&
val < ops->set_optmax)
goto out;
}
module_put(ops->owner);
}
}
out_nosup:
ops = ERR_PTR(-ENOPROTOOPT);
out:
mutex_unlock(&nf_sockopt_mutex);
/*返回找到的nf_sockopt_ops*/
return ops;
}
3、Iptable和Netfilter的通信
(1)、初始化nf_sockopt_ops实例
static struct nf_sockopt_ops ipt_sockopts = {
.pf = PF_INET,
.set_optmin = IPT_BASE_CTL,
.set_optmax = IPT_SO_SET_MAX+1,
.set = do_ipt_set_ctl,//后续详细介绍该函数
.get_optmin = IPT_BASE_CTL,
.get_optmax = IPT_SO_GET_MAX+1,
.get = do_ipt_get_ctl,
.owner = THIS_MODULE,
};
(2)、注册nf_sockopt_ops
static int __init ip_tables_init(void)
{
。。。。。。
ret = nf_register_sockopt(&ipt_sockopts);
。。。。。。
}
(未完待续)