netfilter

来源:互联网 发布:c语言和c#的区别 编辑:程序博客网 时间:2024/05/19 17:56

netfilter

  通俗的说,netfilter的架构就是在整个网络流程的若干位置放置了一些检测点(HOOK
  ),而在每个检测点上上登记了一些处理函数进行处理(如包过滤,NAT等,甚至可以是
  用户自定义的功能)。
  IP层的五个HOOK点的位置如下图所示(copy from ) :
  --->[1]--->[ROUTE]--->[3]--->[4]--->
  | ^
  | |
  | [ROUTE]
  v |
  [2] [5]
  | ^
  | |
  v |
  [local process]
  [1]:NF_IP_PRE_ROUTING:刚刚进入网络层的数据包通过此点(刚刚进行完版本号,校验
  和等检测), 源地址转换在此点进行;
  [2]:NF_IP_LOCAL_IN:经路由查找后,送往本机的通过此检查点,INPUT包过滤在此点进行;
  [3]:NF_IP_FORWARD:要转发的包通过此检测点,FORWORD包过滤在此点进行;
  [4]:NF_IP_POST_ROUTING:所有马上便要通过网络设备出去的包通过此检测点,内置的目
  的地址转换功能(包括地址伪装)在此点进行;
  [5]:NF_IP_LOCAL_OUT:本机进程发出的包通过此检测点,OUTPUT包过滤在此点进行。
  在IP层代码中,有一些带有NF_HOOK宏的语句,如IP的转发函数中有:
  <-ipforward.c ip_forward()->
  NF_HOOK(PF_INET, NF_IP_FORWARD, skb, skb->dev, dev2,
  ip_forward_finish);
  其中NF_HOOK宏的定义提炼如下:
  <-/include/linux/netfilter.h->
  #ifdef CONFIG_NETFILTER
  #define NF_HOOK(pf, hook, skb, indev, outdev, okfn) /
  (list_empty(&nf_hooks[(pf)][(hook)]) /
  ? (okfn)(skb) /
  : nf_hook_slow((pf), (hook), (skb), (indev), (outdev), (okfn)))
  #else /* !CONFIG_NETFILTER */
  #define NF_HOOK(pf, hook, skb, indev, outdev, okfn) (okfn)(skb)
  #endif /*CONFIG_NETFILTER*/
  如果在编译内核时没有配置netfilter时,就相当于调用最后一个参数,此例中即执行
  ip_forward_finish函数;否则进入HOOK点,执行通过nf_register_hook()登记的功能
  (这句话表达的可能比较含糊,实际是进入nf_hook_slow()函数,再由它执行登记的
  函数)。
  NF_HOOK宏的参数分别为:
  1.pf:协议族名,netfilter架构同样可以用于IP层之外,因此这个变量还可以有诸如
  PF_INET6,PF_DECnet等名字。
  2.hook:HOOK点的名字,对于IP层,就是取上面的五个值;
  3.skb:不用多解释了吧;
  4.indev:进来的设备,以struct net_device结构表示;
  5.outdev:出去的设备,以struct net_device结构表示;
  (后面可以看到,以上五个参数将传到用nf_register_hook登记的处理函数中。)
  6.okfn:是个函数指针,当所有的该HOOK点的所有登记函数调用完后,转而走此流程。
  这些点是已经在内核中定义好的,除非你是这部分内核代码的维护者,否则无权增加
  或修改,而在此检测点进行的处理,则可由用户指定。像packet filter,NAT,connection
  track这些功能,也是以这种方式提供的。正如netfilter的当初的设计目标--提供一
  个完善灵活的框架,为扩展功能提供方便。
  如果我们想加入自己的代码,便要用nf_register_hook函数,其函数原型为:
  int nf_register_hook(struct nf_hook_ops *reg)
  我们考察一下struct nf_hook_ops结构:
  struct nf_hook_ops
  {
  struct list_head list;
  /* User fills in from here down. */
  nf_hookfn *hook;
  int pf;
  int hooknum;
  /* Hooks are ordered in ascending priority. */
  int priority;
  };
  我们的工作便是生成一个struct nf_hook_ops结构的实例,并用nf_register_hook将
  其HOOK上。其中list项我们总要初始化为{NULL,NULL};由于一般在IP层工作,pf总是
  PF_INET;hooknum就是我们选择的HOOK点;一个HOOK点可能挂多个处理函数,谁先谁后
  ,便要看优先级,即priority的指定了。netfilter_ipv4.h中用一个枚举类型指定了内
  置的处理函数的优先级:
  enum nf_ip_hook_priorities {
  NF_IP_PRI_FIRST = INT_MIN,
  NF_IP_PRI_CONNTRACK = -200,
  NF_IP_PRI_MANGLE = -150,
  NF_IP_PRI_NAT_DST = -100,
  NF_IP_PRI_FILTER = 0,
  NF_IP_PRI_NAT_SRC = 100,
  NF_IP_PRI_LAST = INT_MAX,
  };
  hook是提供的处理函数,也就是我们的主要工作,其原型为:
  unsigned int nf_hookfn(unsigned int hooknum,
  struct sk_buff **skb,
  const struct net_device *in,
  const struct net_device *out,
  int (*okfn)(struct sk_buff *));
  它的五个参数将由NFHOOK宏传进去。
  了解了这些,基本上便可以可以写一个lkm出来了。
  三.例子代码
  这段代码是一个例子,其功能实现了一个IDS,检测几个简单攻击(land,winnuke)和特殊
  扫描(nmap),当然,不会有人真把它当严肃的IDS使用吧:-)。可以利用类似结构干点别
  的。。。
  <-example.c begin->
  /*
  * netfilter module example: it`s a kernel IDS(be quie,donot laugh, my friend)
  * yawl@nsfocus.com
  * Compile:gcc -O -c -Wall sample.c ,under linux2.4 kernel,netfilter is needed.
  */
  #define __KERNEL__
  #define MODULE
  #include
  #include
  #include
  #include
  #include
  #include
  #include
  #include
  #define ALERT(fmt,args...) printk("nsfocus: " fmt, ##args)
  /*message will be print to screen(too many~),and logged to /var/log/message*/
  static unsigned int sample(unsigned int hooknum,struct sk_buff **skb,
  const struct net_device *in,
  const struct net_device *out,int (*okfn)(struct sk_buff *))
  {
  struct iphdr *iph;
  struct tcphdr *tcph;
  struct udphdr *udph;
  __u32 sip;
  __u32 dip;
  __u16 sport;
  __u16 dport;
  iph=(*skb)->nh.iph;
  sip=iph->saddr;
  dip=iph->daddr;
  /*play ip packet here
  (note:checksum has been checked,if connection track is enabled,defrag have been done )*/
  if(iph->ihl!=5){
  ALERT("IP packet with packet from %d.%d.%d.%d to %d.%d.%d.%d/n",NIPQUAD(sip),NIPQUAD(dip));
  }
  if(iph->protocol==6){
  tcph=(struct tcphdr*)((__u32 *)iph iph->ihl);
  sport=tcph->source;
  dport=tcph->dest;
  /*play tcp packet here*/
  if((tcph->syn)&&(sport==dport)&&(sip==dip)){
  ALERT("maybe land attack/n");
  }
  if(ntohs(tcph->dest)==139&&tcph->urg){
  ALERT("maybe winnuke a from %d.%d.%d.%d to %d.%d.%d.%d/n",NIPQUAD(sip),NIPQUAD(dip));
  }
  if(tcph->ece&&tcph->cwr){
  ALERT("queso from %d.%d.%d.%d to %d.%d.%d.%d/n",NIPQUAD(sip),NIPQUAD(dip));
  }
  if((tcph->fin)&&(tcph->syn)&&(!tcph->rst)&&(!tcph->psh)&&(!tcph->ack)&&(!tcph->urg)){
  ALERT("SF_scan from %d.%d.%d.%d to %d.%d.%d.%d/n",NIPQUAD(sip),NIPQUAD(dip));
  }
  if((!tcph->fin)&&(!tcph->syn)&&(!tcph->rst)&&(!tcph->psh)&&(!tcph->ack)&&(!tcph->urg)){
  ALERT("NULL_scan from %d.%d.%d.%d to %d.%d.%d.%d/n",NIPQUAD(sip),NIPQUAD(dip));
  }
  if(tcph->fin&&tcph->syn&&tcph->rst&&tcph->psh&&tcph->ack&&tcph->urg){
  ALERT("FULL_Xmas_scan from %d.%d.%d.%d to %d.%d.%d.%d/n",NIPQUAD(sip),NIPQUAD(dip));
  }
  if((tcph->fin)&&(!tcph->syn)&&(!tcph->rst)&&(tcph->psh)&&(!tcph->ack)&&(tcph->urg)){
  ALERT("XMAS_Scan(FPU)from %d.%d.%d.%d to %d.%d.%d.%d/n",NIPQUAD(sip),NIPQUAD(dip));
  }
  }
  else if(iph->protocol==17){
  udph=(struct udphdr *)((__u32 *)iph iph->ihl);
  sport=udph->source;
  dport=udph->dest;
  /*play udp packet here*/
  }
  else if(iph->protocol==1){
  /*play icmp packet here*/
  }
  else if(iph->protocol==2){
  ALERT("igmp packet from %d.%d.%d.%d to %d.%d.%d.%d/n",NIPQUAD(sip),NIPQUAD(dip));
  /*play igmp packet here*/
  }
  else{
  ALERT("unknown protocol%d packet from %d.%d.%d.%d to %d.%d.%d.%d/n",iph->protocol,NIPQUAD(sip),NIPQUAD(dip));
  }
  return NF_ACCEPT;
  /*for it is IDS,we just accept all packet,
  if you really want to drop this skb,just return NF_DROP*/
  }
  static struct nf_hook_ops iplimitfilter
  ={ {NULL,NULL} ,sample,PF_INET,NF_IP_PRE_ROUTING,NF_IP_PRI_FILTER-1};
  int init_module(void)
  {
  return nf_register_hook(&iplimitfilter);
  }
  void cleanup_module(void)
  {
  nf_unregister_hook(&iplimitfilter);
  }
  <-example.c end->
  四.附录:与2.2在应用方面的区别简介
  本来还想详细介绍一下iptables的用法,但如果说的太详细的话,还不如索性将HOWTO
  翻译一下,于是干脆了却了这个念头,只顺便简介一下与以前版本的变化(而且是我认
  为最重要的)。如果ipchains本来便没有在你的脑子中扎根,其实便没有必要看这部分。
  netfilter,又可称为iptables.开发初期准备将packet filter和NAT的配置工具完全
  分开,一个称为iptables,另一个称为ipnatctl,而将整个项目成为netfilter.但后
  来可能是还是习惯2.2内核中用ipchians一个工具干两件事的用法,又
  改为全部用iptables配置了。
  理论上还可以用2.2系列的ipchains和2.0系列的ipfwadm作配置工具,但只是做兼容
  或过渡的考虑了。通过源码看到他们也是通过现有的结构HOOK上去的(主要是net/ipv
  4/netfilter目录下的ip_fw_compat.c,ip_fw_compat_masq.c,ip_fw_compat_redir.c,
  ipchains_core.c,ipfwadm_core.c这几个文件)。
  一个重要的变化是原有的INPUT,OUTPUT(原来是小写的input,ouput)链(现在应称
  为表?)的位置变了,原来的input,output的位置相当于现在的NF_IP_PRE_ROUTING,
  NF_IP_POST_ROUTING 。原有的结构确实不太合理,转发的包要经过三条链,现在INPUT
  专指去往本机的,OUPUT专指从本机发出的,而FOWARD仍旧是转发的包。
  举两个简单的例子:
  1.作地址伪装(场景:对外通过拨号连接internet)注意原来的MASQ变成好长的
  MASQUERATE,而伪装相当于SNAT,因此位置是在POSTROUTING:
  iptables -t nat -A POSTROUTING -o ppp0 -j MASQUERATE
  2.还有一个限制包速率的功能比较好玩,例如如下规则:
  iptables -A FORWARD -p tcp --syn -m limit --limit 1/s -j ACCEPT
  简单的说就是在转发时(-A FORWARD:因为是防火墙嘛),如果是tcp协议,且有syn
  标记(-p tcp --syn),可以限制为每秒一个(-m limit --limit 1/s ),行动项是
  ACCEPT。最后连起来意义就是每秒只允许转发一个tcp连接请求。
  五.后记
  netfilter还提供了许多新功能,如可以将包转发到应用层,由应用程序进行处理等
  ,可目前我还没有分析多少,慢慢抽出点时间看吧。唉,尽管以前看过ipchains的代码
  ,但netfilter实在变动太大了,一切都要从头看起
  参考文献:
  [1.] Linux 2.4 Packet Filtering HOWTO
  Rusty Russell, mailing list netfilter@lists.samba.org
  v1.0.1 Mon May 1 18:09:31 CST 2000
  [2.] Linux IPCHAINS-HOWTO
  Paul Russell, ipchains@rustcorp.com
  v1.0.7, Fri Mar 12 13:46:20 CST 1999
  [3.] Linux 2.4 NAT HOWTO
  Rusty Russell, mailing list netfilter@lists.samba.org
  v1.0.1 Mon May 1 18:38:22 CST 2000
  [4.] Linux netfilter Hacking HOWTO
  Rusty Russell, mailing list netfilter@lists.samba.org
  v1.0.1 Sat Jul 1 18:24:41 EST 2000
  [5.] Writing a Module for netfilter
  by Paul "Rusty" Russell
  Linux Magazine June 2000 http://www.linux-mag.com/2000-06/gear_01.html
  netfilter技术分析
  netfilter是由Rusty Russell提出的Linux2.4内核防火墙框架,该框架既简洁又灵活,可实现安全策略应用中的许多功能,如数据包过滤、数据包处理、地址伪装、透明代理、动态网络地址转换(Network Address Translation,NAT),以及基于用户及媒体访问控制(Media AccessControl,MAC)地址的过滤和基于状态的过滤、包速率限制等。
  1.1 netfilter框架
  netfilter提供了一个抽象、通用化的框架[1],作为中间件,为每种网络协议(IPv4、IPv6等)定义一套钩子函数。Ipv4定义了5个钩子函数,这些钩子函数在数据报流过协议栈的5个关键点被调用,也就是说,IPv4协议栈上定义了5个“允许垂钓点”。在每一个“垂钓点”,都可以让netfilter放置一个“鱼钩”,把经过的网络包(Packet)钓上来,与相应的规则链进行比较,并根据审查的结果,决定包的下一步命运,即是被原封不动地放回IPv4协议栈,继续向上层递交;还是经过一些修改,再放回网络;或者干脆丢弃掉。
  Ipv4中的一个数据包通过netfilter系统的过程如图1所示。
  图1 Netfilter的功能框架
  1.2 netfilter的关键技术
  netfilter主要采用连线跟踪(Connection Tracking)、包过滤(Packet Filtering)、地址转换、包处理(Packet Mangling)4种关键技术。
  1.2.1 连线跟踪
  连线跟踪是包过滤、地址转换的基础,它作为一个独立的模块运行。采用连线跟踪技术在协议栈低层截取数据包,将当前数据包及其状态信息与历史数据包及其状态信息进行比较,从而得到当前数据包的控制信息,根据这些信息决定对网络数据包的操作,达到保护网络的目的。
  当下层网络接收到初始化连接同步(Synchronize,SYN)包,将被netfilter规则库检查。该数据包将在规则链中依次序进行比较。如果该包应被丢弃,发送一个复位(Reset,RST)包到远端主机,否则连接接收。这次连接的信息将被保存在连线跟踪信息表中,并表明该数据包所应有的状态。这个连线跟踪信息表位于内核模式下,其后的网络包就将与此连线跟踪信息表中的内容进行比较,根据信息表中的信息来决定该数据包的操作。因为数据包首先是与连线跟踪信息表进行比较,只有SYN包才与规则库进行比较,数据包与连线跟踪信息表的比较都是在内核模式下进行的,所以速度很快。
  1.2.2 包过滤
  包过滤检查通过的每个数据包的头部,然后决定如何处置它们,可以选择丢弃,让包通过,或者更复杂的操作。
  1.2.3 地址转换
  网络地址转换源(NAT)分为(SourceNAT,SNAT)和目的NAT(Destination NAT,DNAT)2种不同的类型。SNAT是指修改数据包的源地址(改变连接的源IP)。SNAT会在数据包送出之前的最后一刻做好转换工作。地址伪装(Masquerading)是SNAT的一种特殊形式。DNAT 是指修改数据包的目标地址(改变连接的目的IP)。DNAT总是在数据包进入以后立即完成转换。端口转发、负载均衡和透明代理都属于DNAT。
  1.2.4 包处理
  利用包处理可以设置或改变数据包的服务类型(Type of Service, TOS)字段;改变包的生存期(Time to Live, TTL)字段;在包中设置标志值,利用该标志值可以进行带宽限制和分类查询。

百度百科中的词条内容仅供参考,如果您需要解决具体问题
(尤其在法律、医学等领域),建议您咨询相关领域专业人士。
本词条对我有帮助17
扩展阅读:
1.http://www.quickviews.net/data/2006/0124/article_7383_1.htm
2.http://www.elecfans.com/
3.http://www.elecfans.com/article/87/81/2008/2008111817650.html
4.http://www.elecfans.com/soft/study/digital/2008/2008111811823.html
相关词条:
什么是相关词条 我来完善
开放分类:
计算机,防火墙
合作编辑者:
dplion、leigaiting
如果您认为本词条还需进一步完善,百科欢迎您也来参与编辑词条    在开始编辑前,您还可以先学习如何编辑词条

词条统计

浏览次数:约 1605 次
编辑次数:2 次  历史版本
最近更新:2008-11-18
创建者:leigaiting

最新动态

百科活动:校园百科编辑赛
活动快报
各高校大学生火热报名中
首批9所高校百科任务成功发起

© Baidu 权利声明

<script src="http://baike.baidu.com/js/usertracker.js"></script><script type="text/javascript"><!--pageTools.ctrlRelatedLemma=function(){if(!Fe.G("relatedLemmaDown")){return false}var H=Fe.G("word_more_con").getElementsByTagName("A");var C=Fe.G("oneLineSpan");var B=Fe.G("oneLineDiv");var A=Fe.G("word_more");var F=H.length;for(var D=0;D&lt;F;D++){var E=H[0];C.appendChild(E);if(C.offsetWidth&gt;(B.offsetWidth-A.offsetWidth)){if(D&lt;(F-1)){Fe.G("word_more_con").insertBefore(E,H[0]);A.style.visibility="visible"}else{if(D==(F-1)){Fe.G("word_more_con").appendChild(E);A.style.visibility="visible"}}B.style.visibility="visible";return }}B.style.visibility="visible"};function ctrlBKDynamic(){if(typeof bkDynamic!="undefined"){var A=bkDynamic[0];Fe.G("profileTitle").innerHTML=A;if(!!bkDynamic[1][0]){Fe.G("task").innerHTML="&lt;dt&gt;&lt;strong&gt;"+bkDynamic[1][0]+'&lt;/strong&gt;:&lt;a href="'+bkDynamic[1][1][1]+'" target="_blank"&gt;'+bkDynamic[1][1][0]+'&lt;/a&gt;&lt;/dt&gt; &lt;dd&gt;&lt;a href="'+bkDynamic[1][1][1]+'" target="_blank"&gt;&lt;img src="'+bkDynamic[1][1][2]+'" width="160" height="81"&gt;&lt;/a&gt;&lt;/dd&gt;';Fe.G("task").style.display=""}if(!!bkDynamic[2][0]){Fe.G("notice").innerHTML="&lt;dt&gt;&lt;strong&gt;"+bkDynamic[2][0]+"&lt;/strong&gt;:&lt;/dt&gt;"+bkDynamic[2][1];Fe.G("task").style.display=""}Fe.G("bkDynamic").style.display=""}}function ascUpdateData(A){if(A.length==3){Fe.G("vote_num").innerHTML=A[0];Fe.G("viewPV").innerHTML=A[1]}else{if(A.length==1){if(A[0]&gt;=0){Fe.G("vote_num").innerHTML=A[0];Fe.G("vote_txt").innerHTML="您已评价,谢谢!"}else{if(A[0]==-1){Fe.G("vote_txt").innerHTML="您已评价,谢谢!"}}}}}pageTools.scriptElAsc=function(){var C="/view/getLemmaCountAsc/lemmaid=490561&amp;random="+Math.random();if(Fe.isIE){Fe.Ajax.sio(C,pageTools.doDynamicData)}else{var B=document.getElementsByTagName("head")[0];var A=document.createElement("script");A.type="text/javascript";A.src=C;A.onload=pageTools.doDynamicData;B.appendChild(A)}};pageTools.doDynamicData=function(){var A=lemmaCount[2];if(A==1){var B=document.createElement("script");B.src="/template/baikeDynamicData.js?random="+Math.random();document.body.appendChild(B)}};pageTools.vote=function(){var A=Fe.G("vote_btn");A.onmouseover=function(){this.className="text_vote2"};A.onmouseout=function(){this.className="text_vote1";Fe.G("vote_txt").innerHTML="本词条对我有帮助"};A.onclick=function(){if(typeof voteScriptEl!="undefined"){document.body.removeChild(voteScriptEl)}voteScriptEl=document.createElement("script");document.body.appendChild(voteScriptEl);voteScriptEl.src="/view/recommendLemma/lemmaid=490561&amp;random="+Math.random()}};pageTools.getDays=function(C){if(!C){return""}var A=C.match(/(/d{2,4})-(/d{1,2})-(/d{1,2}) (/d{1,2}):(/d{1,2}):(/d{1,2})/);if(!A){C=C.split(" ")[0];return C}A[2]=parseInt(A[2],10)-1;var E=Date.parse(new Date(A[1],A[2],A[3],A[4],A[5],A[6]));var B=new Date();var F=[];for(var D=0;D&lt;4;D++){F[D]=Date.parse(new Date(B.getFullYear(),B.getMonth(),B.getDate()-D))}if(E&gt;=F[0]){return"今天"}if(E&gt;=F[1]){return"昨天"}if(E&gt;=F[2]){return"2天前"}if(E&gt;=F[3]){return"3天前"}var C=C.split(" ")[0];return C};pageTools.formatTime=function(){var A=Fe.G("lastModifyTime");A.innerHTML=pageTools.getDays(A.innerHTML);A.style.display=""};pageTools.formatRelatedRight=function(){if(!Fe.G("relatedContainer")){return false}var B=jsTools.GT("li","relatedContainer");if(!B){return false}var A=B.length;if(A&lt;=10){Fe.show("relatedLemma_right");return false}else{Fe.show("relatedMoreRight");pageTools.ctrlRelatedMore();Fe.show("relatedLemma_right")}};pageTools.ctrlRelatedMore=function(){var C=jsTools.GT("li","relatedContainer");var B=C.length;if(typeof C=="undefined"||B&lt;=10){return false}if(C[10].style.display=="none"){for(var A=10;A&lt;B;A++){C[A].style.display=""}Fe.G("relatedMoreRight").innerHTML="收起"}else{for(var A=10;A&lt;B;A++){C[A].style.display="none"}Fe.G("relatedMoreRight").innerHTML="更多";if(arguments.callee.clickMoreCount&gt;0){window.scrollTo(Fe.G("nav").offsetLeft,Fe.G("nav").offsetTop)}}arguments.callee.clickMoreCount++};pageTools.ctrlRelatedMore.clickMoreCount=0;if(flag==1){document.write("&lt;script src=http://msg.baidu.com/ms?ct=18&amp;cm=3&amp;tn=bmSelfUsrStat&amp;mpn=13227114&amp;un=&gt;&lt;//script&gt;");showMsg()}if(G("cat")){var lItems=G("cat").getElementsByTagName("DD");var lItemnum=lItems.length-1;var catList={dir:G("dir"),cat:G("cat"),temp:G("temp"),data:G("data"),catCon:"",t:null,h:0,tempH:0,items:lItems,itemnum:lItemnum,shownum:8};function hideCat(){if(catList.itemnum&lt;=catList.shownum){return false}catList.cat.className="arr";var B=catList.cat.offsetWidth;catList.cat.style.width=B+"px";catList.data.style.width=B+"px";for(var A=catList.shownum;A&lt;catList.itemnum;A++){catList.catCon+="&lt;li&gt;"+catList.items[A].innerHTML+"&lt;/li&gt;";catList.items[A].style.display="none"}catList.data.innerHTML=catList.catCon;catList.tempH=catList.data.offsetHeight;catList.data.style.marginTop=-catList.tempH+"px"}function maxCat(){if(catList.h&lt;catList.tempH){catList.h+=10;catList.temp.style.height=catList.h+"px";catList.data.style.marginTop=catList.h-catList.tempH+"px";catList.t=setTimeout("maxCat()",10)}if(catList.h==20){catList.temp.style.borderBottom="1px solid #ccc"}}function minCat(){if(catList.h&gt;0){catList.h-=10;catList.temp.style.height=catList.h+"px";catList.data.style.marginTop=-(catList.tempH-catList.h)+"px";catList.t=setTimeout("minCat()",10)}if(catList.h==20){catList.temp.style.borderBottom="none"}}function contains2(B,A){while(A){A=A.parentNode?A.parentNode:A;if(A==B){return true}return false}}catList.dir.onmouseover=function(A){clearTimeout(catList.t);catList.t=setTimeout("maxCat()",100)};catList.dir.onmouseout=function(A){if(document.all){clearTimeout(catList.t)}else{if(A.currentTarget!=A.relatedTarget&amp;&amp;!contains2(A.currentTarget,A.relatedTarget)){clearTimeout(catList.t)}}catList.t=setTimeout("minCat()",100)};hideCat()}jsTools.addLoadEvent(pageTools.scriptElAsc);jsTools.addLoadEvent(pageTools.ctrlRelatedLemma);jsTools.addLoadEvent(pageTools.vote);jsTools.addLoadEvent(pageTools.formatTime);jsTools.addLoadEvent(pageTools.formatRelatedRight);// --></script><script src="http://baike.baidu.com/template/baikeDynamicData.js?random=0.13339689792639886"></script>