LVS源码分析三---netfilter hook

 

版权:自由转载,说明出处,保留原作者名,保留文章的完整性,需要商业用途,请联系作者me.
韩波 GameProgramHack@yahoo.com.cn  2010.01.02 深圳市龙岗区坂田镇XXX小山村。

 

内核版本linux-2.6.32.2
ipvs是基于netfilter框架的,在这里我们先了解一下ipvs的hook在netfilter系统中的位置。

 

netfilter hook的图。

https://p-blog.youkuaiyun.com/images/p_blog_youkuaiyun.com/GameProgramHack/EntryImages/20100102/linux2.6.32.2netfilter.JPG

 

上图中红色标注的hook是ip_vs注册的。

长期工作在linux2.4.35下,对于图中nf_defrag_ipv4.o, iptable_raw.o,iptable_security.o,selinux.o很陌生。

static struct nf_hook_ops ip_vs_ops[] __read_mostly = {
 /* After packet filtering, forward packet through VS/DR, VS/TUN,
  * or VS/NAT(change destination), so that filtering rules can be
  * applied to IPVS. */
 /××
  × 由上图可见ip_vs的hook是挂在iptable_filter.o模块的钩子后面。
  × 因此应用层iptables对应的-t filter表的规则,可以和ip_vs.o一起工作。
  × 经过LOCAL_IN的连接,也就是需要转发到后端真实服务器的链接。
  ×  因此这里ip_vs.o不会把数据包按协议栈的流程发送到传输层,
  ×  而是根据当前的模式VS/DR或VS/TUN或VS/NAT,经过对应的处理,把包转发给后端真实的服务器。
  ×  由下面ip_vs_out的钩子可以猜到这个函数在VS/NAT模式下需要实现dnat功能。
  ×/
 {
  .hook  = ip_vs_in,
  .owner  = THIS_MODULE,
  .pf  = PF_INET,
  .hooknum        = NF_INET_LOCAL_IN,
  .priority       = 100,
 },
 /* After packet filtering, change source only for VS/NAT */
 /××
  × 由上图可见ip_vs的hook是挂在iptable_filter.o模块的钩子后面。
  × 因此应用层iptables对应的-t filter表的规则,可以和ip_vs.o一起工作。
  × 根据“change source only for VS/NAT”猜想,这个函数的功能是在VS/NAT
  × 模式下,处理真实服务器——>客户端方向的回包,把回包中的源IP,从真实
  ×  服务器的IP修改为本机(LB)的IP。
  × 这里可见判断,NAT实现ip_vs并没有使用netfilter的nat,而是自己实现
  ×  了一套。
  ×/
 {
  .hook  = ip_vs_out,
  .owner  = THIS_MODULE,
  .pf  = PF_INET,
  .hooknum        = NF_INET_FORWARD,
  .priority       = 100,
 },
 /* After packet filtering (but before ip_vs_out_icmp), catch icmp
  * destined for 0.0.0.0/0, which is for incoming IPVS connections */
 /**
  * 猜想做client和真实服务器的ICMP中转。
  */
 {
  .hook  = ip_vs_forward_icmp,
  .owner  = THIS_MODULE,
  .pf  = PF_INET,
  .hooknum        = NF_INET_FORWARD,
  .priority       = 99,
 },
 /* Before the netfilter connection tracking, exit from POST_ROUTING */
 {
  .hook  = ip_vs_post_routing,
  .owner  = THIS_MODULE,
  .pf  = PF_INET,
  .hooknum        = NF_INET_POST_ROUTING,
  .priority       = NF_IP_PRI_NAT_SRC-1,
 },
};

/*
 *      It is hooked before NF_IP_PRI_NAT_SRC at the NF_INET_POST_ROUTING
 *      chain, and is used for VS/NAT.
 *      It detects packets for VS/NAT connections and sends the packets
 *      immediately. This can avoid that iptable_nat mangles the packets
 *      for VS/NAT.
 */
/××
 × 由上图可以看到这个钩子是在iptable_nat,selinux.o,ip_conntrack.o模块的钩子之前。
 × 设置了skb->ipvs_property这个标志的包,将返回NF_STOP,不会继续跑后面的钩子。
 × ip_vs是不能与selinux.o协同工作,启动ip_vs.o后,属于ip_vs的包将不会
 × 经过selinux hook处理,导致功能失效。
 × 至于iptables_nat, 不经过ip_vs处理的连接,还是可以正常使用iptables -t nat下发的规则。
 × 经过ip_vs的包,如果iptables的nat表有对应的规则,那末这个规则将失效。对于经过ip_vs的
 × 自己实现的nat。也就是说当一个连接同时符合iptables -nat规则和ip_vs规则的时候,iptables
 * nat规则失效,ip_vs正常工作。
 ×/
static unsigned int ip_vs_post_routing(unsigned int hooknum,
           struct sk_buff *skb,
           const struct net_device *in,
           const struct net_device *out,
           int (*okfn)(struct sk_buff *))
{
 if (!skb->ipvs_property)
  return NF_ACCEPT;
 /* The packet was sent from IPVS, exit this chain */
 return NF_STOP;
}

 

这里有一个问题:
在LOCAL_IN,优先级为100的钩子钩子有两个ip_vs_in,nf_nat_fn,到底谁在前谁在后?
这种情况,取决于注册钩子的顺序,也是内核模块加载顺序。


既然这样,为什么上图把ip_vs_in画在前,nf_nat_fn画在后?
由于我猜想ip_vs_in要部分接管nat功能,只有ip_vs_in位于nf_nat_fn前面才能实现这个功能。


只有ip_vs_in位于nf_nat_fn前面才能实现这个功能,那就意味这必须先加载ip_vs.o,后加载
iptable_nat.o模块?
对,由于netfilter实现先注册的在前面:
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(&reg->list, elem->list.prev);
 mutex_unlock(&nf_hook_mutex);
 return 0;
}

 

这里个人的看法是设序设计当中应该尽量避免二义性,减少依赖性。
建议ip_vs_in的优先改为(100 > x > 50)范围,最好为75。
最佳的方案最好是能和netfilter项目组联系,在下面添加一个属于自己的优先级。不过可能2个不同的
开源项目操作起来不方便。
enum nf_ip_hook_priorities {
 NF_IP_PRI_FIRST = INT_MIN,
 NF_IP_PRI_CONNTRACK_DEFRAG = -400,
 NF_IP_PRI_RAW = -300,
 NF_IP_PRI_SELINUX_FIRST = -225,
 NF_IP_PRI_CONNTRACK = -200,
 NF_IP_PRI_MANGLE = -150,
 NF_IP_PRI_NAT_DST = -100,
 NF_IP_PRI_FILTER = 0,
 NF_IP_PRI_SECURITY = 50,
 NF_IP_PRI_NAT_SRC = 100,
 NF_IP_PRI_SELINUX_LAST = 225,
 NF_IP_PRI_CONNTRACK_CONFIRM = INT_MAX,
 NF_IP_PRI_LAST = INT_MAX,
};

                                                             广告过后,精彩等着你... ...

 

 

 

 

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值