linux内核netfilter,linux内核netfilter实现url重定向

原标题:linux内核netfilter实现url重定向

一、NetFilter

NetFilter在2.4.x内核中引入,成为linux平台下进行网络应用的主要扩展,不仅包括防火墙的实现,还包括报文的处理(如报文加密、报文分类统计等)等。

1、NetFilter数据结构:

struct nf_hook_ops {

struct list_head list;

/* User fills in from here down. */

nf_hookfn *hook;

struct module *owner;

u_int8_t pf;

unsigned int hooknum;

/* Hooks are ordered in ascending priority. */

int priority;

};

成员list用于链入全局勾子数组nf_hooks中,它一定在第一位,保证&nf_hook_ops->list的值与&nf_hook_ops相同,稍后在使用时会用到这一技巧;

成员hook即用户定义的勾子函数;owner表示注册这个勾子函数的模块,因为netfilter是内核空间的,所以一般为模块来完成勾子函数注册;pf与hooknum一起索引到特定协议特定编号的勾子函数队列,用于索引nf_hooks;priority决定在同一队列(pf与hooknum相同)的顺序,priority越小则排列越靠前。

struct nf_hook_ops只是存储勾子的数据结构,而真正存储这些勾子供协议栈调用的是nf_hooks,从定义可以看出,它其实就是二维数组的链表。

struct list_head nf_hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS]; [net\filter\core.c]其中NFPROTO_NUMPROTO表示勾子关联的协议,可取值:

enum {

NFPROTO_UNSPEC = 0,

NFPROTO_IPV4 = 2,

NFPROTO_ARP = 3,

NFPROTO_BRIDGE = 7,

NFPROTO_IPV6 = 10,

NFPROTO_DECNET = 12,

NFPROTO_NUMPROTO,

};

NF_MAX_HOOKS表示勾子应用的位置,可选值在每个协议模块内部定义,这些值代表了勾子函数在协议流程中应用的位置(稍后会以bridge为例详细说明),大致上都有以下值:

NF_XXX_PRE_ROUTING,

NF_XXX_LOCAL_IN,

NF_XXX_FORWARD,

NF_XXX_LOCAL_OUT,

NF_XXX_POST_ROUTING,

NF_XXX_NUMHOOKS

2、NetFilter注册

在了解了nf_hook_ops和nf_hooks后,来看下如何操作nf_hooks中的元素。nf_register_hook()将nf_hook_ops注册到nf_hooks中:

int nf_register_hook(struct nf_hook_ops *reg)

{

struct nf_hook_ops *elem;

int err;

err = mutex_lock_interruptible(&nf_hook_mutex);

if (err < 0)

return err;

list_for_each_entry(elem, &nf_hooks[reg->pf][reg->hooknum], list) {

if (reg->priority < elem->priority)

break;

}

list_add_rcu(®->list, elem->list.prev);

mutex_unlock(&nf_hook_mutex);

return 0;

}

这个函数很简单,从指定pf&hooknum的nf_hooks队列遍历,按priority从小到大顺序,将reg插入相应位置,完成勾子函数的注册。

nf_unregister_hook()将nf_hook_ops从nf_hooks中注销掉:

void nf_unregister_hook(struct nf_hook_ops *reg)

{

mutex_lock(&nf_hook_mutex);

list_del_rcu(®->list);

mutex_unlock(&nf_hook_mutex);

synchronize_net();

}

这个函数更简单,从nf_hooks中删除reg。

内核同时还提供了nf_register_hooks()和nf_unregister_hooks(),将reg重复注册n次或将reg从nf_hooks中注销n次。当勾子函数注册完成后,nf_hooks的结构如图所示:

8c0521401c5d35b0092513cf7868b1ea.png

3、NetFilter调用

在报文在内核协议栈传递时,会调用NetFilter模块对报文进行特定的进滤,这样的过滤在代码中随处可见。以上一篇讲过的网桥为例,对于要进行网桥处理的报文,handle_bridge()->br_handle_frame(),如果端口处理于LEARNING或FORWARDING状态,且报文目的地址正确,则会调用br_handle_frame()进行后续处理,而这个函数调用就是:

NF_HOOK(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,

br_handle_frame_finish);

NF_HOOK()->NF_HOOK_THRESH()->nf_hook_thresh()->nf_hook_slow():

int nf_hook_slow(u_int8_t pf, unsigned int hook, struct sk_buff *skb,

struct net_device *indev,

struct net_device *outdev,

int (*okfn)(struct sk_buff *),

int hook_thresh)

{

struct list_head *elem;

unsigned int verdict;

int ret = 0;

/* We may already have this, but read-locks nest anyway */

rcu_read_lock();

elem = &nf_hooks[pf][hook];

next_hook:

verdict = nf_iterate(&nf_hooks[pf][hook], skb, hook, indev,

outdev, &elem, okfn, hook_thresh);

if (verdict == NF_ACCEPT || verdict == NF_STOP) {

ret = 1;

} else if (verdict == NF_DROP) {

kfree_skb(skb);

ret = -EPERM;

} else if ((verdict & NF_VERDICT_MASK) == NF_QUEUE) {

if (!nf_queue(skb, elem, pf, hook, indev, outdev, okfn,

verdict >> NF_VERDICT_BITS))

goto next_hook;

}

rcu_read_unlock();

return ret;

}

相关代码:http://blog.chinaunix.net/uid-23390992-id-3485745.html?page=3返回搜狐,查看更多

责任编辑:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值