论坛风格切换切换到宽版
  • 703阅读
  • 3回复

[问题求助][img]http://linux.chinaunix.net/bbs/images/default/src_jh.gif[/img]Netfilter日志记录的实现分析 [复制链接]

上一主题 下一主题
离线haliao8.
 
发帖
2227
C币
-60440
威望
385
贡献值
1
银元
-2
铜钱
4841
人人网人气币
0
只看楼主 倒序阅读 使用道具 楼主  发表于: 2009-05-01
好久不灌水,来水一贴。
最近在用ulogd时,遇到一个小.问题,就是经常用户空间收到的数据没有二层帧。.不知是何原因,于是来看了一个Netfilter中ulogd模块(不是应用程序)的实现,虽然仍旧没有找到原因,也顺.便把代码分析的笔记放上来共享一下。.
注意:
1、看的是很老的ulogd 1.2.4的内核实现,.不是最新的2.0,最新的好像用的libnetlink接口,偶还没有时间玩这.个东东;服务器
2、内核版本2.6.12

首先是初始化全局变量,创建netlink套接字,注册netli.nk targe.t:虚拟主机

static int __init init(..void)教育

{

        int i;



        DEBU.GP(".ipt_ULOG: init module\n");           鲜花



        if (nlbu.fsiz >= .128*1024) {             汽车

                printk("Netlink buffer has to be <.= 128.kB\n");          婚庆

                retu.rn. -EINVAL;虚拟主机

        }



      .  /* ulog_buffers  这个数据很重要,它的下标对.应的ulogd使用的netlink group。ulog_b.uffers 用来缓存数据,可以存放一个或多个记录的skb*/健康

        for (i = 0;. i < ULOG_MAXNLGROU.PS; i++) {域名

.               init._timer(&ulog_buffers.timer);.

                ulog_buffers.timer.function = ulog_timer;  /./这个定时器后.面会分析到健康

    .            ulog_buffers.t.imer.data = i;服务器

        }



      .  nflognl = netlink_kernel_create(NETLINK_NFLOG., NULL);              乙肝

        if (.!nflognl)    外汇

          .      return -ENOME.M;    美容



        if (ipt_regist.er_target(&.ipt_ulog_reg) != 0) {电脑

                sock_release(.nflognl->sk_socke.t);投资

   .             ret.urn -EINVAL;          婚庆

        }

  .      if (nflog)             汽车

   .             nf_log_register(PF_INE.T, &ipt_logfn);.

        

        return 0.;             汽车

}
复制代码
target函数ipt_ulog_target是个包裹.函数,转向至i.pt_ulog_packet:外贸

static unsig.ned int ipt_.ulog_target(struct sk_buff **pskb,投资

                                    const struct net_dev.ice *i.n,.

                                    .const str.uct net_device *out,服务器

                .            .        unsigned int hooknum,--- 印刷

                                    const .void *targinfo, void. *userinfo).

{

        s.truct ipt_ulog_info *loginfo = (struct ipt_ulog_info *) .targinfo;.



        .ipt_ulog_packet(hooknum, *pskb, in, out, loginfo, .NULL);.



    .    retu.rn IPT_CONTINUE;            杀毒

}
复制代码
ipt_ulog_packet实现了数据的记录,需要.两点准.备知识:电影
1、用户态各个参数的作.用,看一下帮助:--- 印刷
--ulog-nlgroup nlgroup.         NET.LINK group used for logging    外汇

--ulog-cpra.nge si.ze            Bytes of each packet to be passed(        游戏          )

--ulog-qt.hreshol.d              Threshold of in-kernel queue投资

-.-ulog-prefix prefix           Prefix log messag.es with this prefix.电脑
复制代码
这样才能理解对应的结构:
struct ipt_ulog_in.fo {外贸

       . unsigned int. nl_group;.

     .   si.ze_t copy_range;.

        s.ize_t qth.reshold;.

        char prefix[.ULOG_P.REFIX_LEN];.

};
复制代码
各个成员的含义

2、Linux Ne.tlink的一些基本知识,以前偶在论坛.上写过一贴关于此的,可以找一下,仅供参考;           女人

来看ipt_ulog._packet函数:投资
static void ipt_ulog_pac.ket(unsigned int ho.oknum,域名

                            const struct .sk_buff *.skb,           鲜花

       .                     const struct net._device *in,投资

                            const struct net_devi..ce *out,健康

                       .     const struct ipt_ulog_.info *loginfo,虚拟主机

             .               const char *.prefix)    外汇

{

    .    ulog_buff_t *ub;服务器

   . .    ulog_packet_msg_t *pm;.

        size_.t s.ize, copy_len;域名

        struct .nlmsghdr *nl.h;电脑



       . /* ffs ==. find first bit set, necessary because userspace服务器

         * is already. shifti.ng groupnumber, but we need unshifted.           女人

         * ffs() returns [1..32], we need [0..31].. */域名

        un.signed int g.roupnum = ffs(loginfo->nl_group) - 1;    外汇



        /*

         * 计算需要拷贝的skb长度,如果未设置或者设置的值大.于包的长.度,则len为包长,否则取用户设置值.

         */

        if ((loginf.o-.>copy_range == 0) ||          婚庆

            (.loginfo->.copy_range > skb->len)) {电脑

                copy._len = sk.b->len;.

        } .else {投资

.               copy_len = loginfo->copy_range;.(广告)

        }



    .    ./* 计算总长度:Netlink报头长度+ulog报头长度+数据包长度 */    美容

        size = NLMSG.._SPACE(sizeof(*pm) + copy_len);--------------彩票



.       /* 取得对应Netlink grou.p号的ulog数据包缓存 */[成人用品]

   .   .  ub = &ulog_buffers[groupnum];--- 印刷

        

     .   /* 暂时还没有理会,为什么非要这么大一个锁? .*/--- 印刷

  .      LOCK_B.H(&ulog_lock);.



        .if (!ub->skb) {<性病>

                /.* 如果没.有,则分配之 */(广告)

        .        if (!(ub->sk.b = ulog_alloc_skb(size)))服务器

    .                    goto al.loc_failure;    外汇

        } else if .(ub->qle.n >= loginfo->qthreshold ||           女人

       .            size > skb_tailroo.m(ub->skb)) {.

             .   /*     外汇

        .         * 如果队列已满,或者当前缓存的剩余空间已经不足已装下当.前包,投资

                . * 则把原来的发.送至用户空间,然后再为当前包重新分配.

     .            */.



    .            ulog_se.nd(groupnum);.



  .              if (!(ub->skb = ulog_alloc_skb(size).))--- 印刷

       .                 goto alloc_.failure;.

        }



     .   DEBUGP("ipt_ULOG.: qlen %d, qthreshold %d\n", ub->qlen,              电子

                loginfo->.q.threshold);           女人



        ./* 初始化Ne.tlink 消息首部 */    美容

        nlh = NLMS.G_PUT(ub->skb, 0, ub->ql.en, ULOG_NL_EVENT, 电脑

           .             sizeof(*.pm)+copy_len);投资

        ub->qlen.++;           鲜花



        /* 跳过.消息首部,指向数据区. */          婚庆

        pm .= NLMSG_D.ATA(nlh);.



  .      /* 设置时间戳,如.果没有的话 */           鲜花

        i.f (skb->stamp.t.v_sec == 0)教育

      ..          do_gettimeofday((struct timeval *)&skb->stamp);.



       . /* 填充Netlink数据区中.的ulog数据首部 */学习

.       pm->data_len = co.py_len;教育

        pm->timestamp._sec = skb->st.amp.tv_sec;外贸

        pm->timestamp_usec = skb.->stamp.tv_u.sec;            杀毒

    .    pm.->mark = skb->nfmark;             汽车

.       pm->hook = hookn.um;          婚庆

        

        /* 如果用户.指定了一.个前缀,设置之 */.

  .      i.f (prefix != NULL).

        .        strn.cpy(pm->prefix, prefix, sizeof(pm->prefix));.

        else if (logi.nfo-.>prefix[0] != '\0')(广告)

                strncpy.(pm.->prefix, loginfo->prefix, sizeof(pm->prefix));--------------彩票

        else

              .  *(pm->prefix) = '\0';.--- 印刷

        

        /*

         * 要记录二层的帧,需要满.足以下几个条件.:

   .      * 1、存在一个输.出设备(从本机发出的包,还没有二层帧);虚拟主机

         *.. 2、设备对应的二层的帧头部长度应大于0;             汽车

         * 3、………………………………………….………………………………小地ulog的规.则;域名

         */

        if (in &.&. in->hard_header_len > 0    外汇

            && skb->mac.raw != (v.oid *) skb->.nh.iph电脑

   .         && in->hard_header_len <= ULOG._MAC_LEN) {           建材

                .memcpy(pm->mac,. skb->mac.raw, in->hard_header_len);投资

       .         pm->mac_len. = in->hard_header_len;.

        } else

      .          pm->ma.c_len = 0;          婚庆

        

    .   . /* 拷贝进入接口,如果有的话 */             汽车

        if .(in)              乙肝

        .        strncpy(pm->indev_name, i.n->name, sizeof(pm->indev_name));           鲜花

        else

         .       pm->ind.ev_name[0] = '\0';    外汇

        

        /* 拷贝流出接口,如.果有的.话 */电脑

.       if (out)              乙肝

                strncpy(pm->outdev_name, out->.name, sizeof(pm->ou.tdev_name));..

        else

  .   .           pm->outdev_name[0] = '\0';.



      .  /* 拷贝skb中的数据. */外贸

       . if (skb_copy_bits(skb, 0, pm-.>payload, copy_len) < 0)投资

                BUG(.);           鲜花

        

        /* 如果队列大于1,即缓存了多个包,设置一个多重标.志位,这个标志位在.发送时清除 */[成人用品]

      .  if (ub.->qlen > 1) {.

   .             ub->lastnlh->nlmsg_flags |= NLM._F_MULTI;.

        }



        /.* lastnlh指向当前队列中.的最后一个包,即当前包 */[成人用品]

        ub.->lastnlh = nlh;.[成人用品]



        /*

         *. 定时器期的功能函数在ul.og模块初始化时指向了ulog_timer(),它用于在指定的时间内,清空缓存,    外汇

    .     * 即除了队列长度达到指定要求、或者缓存空间不足之.外,还有一个定时向用户空间发送的机制。投资

         */

        if (!timer._pending(&ub->ti.mer)) {[成人用品]

                ub->timer.expi.res = jiffies + flus.htimeout * HZ / 100;    美容

     .           add_time.r(&ub->timer);.

        }



        /*

         * ub->qlen是当前ne.tlink group下的已经收聚的队列的长度,qthresh.old是用户指定的,需要收集的阀值,当达到这个值.时,将其发送至用户空间    健康

         */

        if (ub->qlen >= lo.ginfo->qthr.eshold) {健康

            .    if (loginfo.->qthreshold > 1).

                   .     nlh->nlmsg_type = .NLMSG_DONE;电影

         .       ulog_send(g.roupnum);.

        }



        U.NLOCK_BH(&ulog_lock).;学习



        return;..



nlmsg_failure:

        PRI.NTR("ipt._ULOG: error during NLMSG_PUT\n");           建材



alloc_failure:

        PRINT.R("ipt_ULOG: Error building netlink mes.sage\n");电脑



.       UNLOCK_BH(&ulog_l.ock);外贸

}
复制代码
这个.函数中,涉及两个重要的函数,一个是分配ulog的skb,用于存储记录的数据,另一个是发送函数.。先来看发送。(广告)
netlink的发送数.据包,是通过调用API netlink_broadcast函数实现的,这里还要完成其它一些工作,比如删除定时器,因为数据已经发出去了,不需要它了,还有就是清除标志变量,修改一.些起控制作用的成员的.值,等等:投资
/* send one ulog_.buff_t to. userspace */外贸

stati.c void ulog_send(unsigned .int nlgroupnum)投资

{

        ulog_buff_t *ub .= &ulog_buf.fers[nlgroupnum];.



        if (timer_pen.ding(&ub->t.imer)) {    外汇

            .    DEBU.GP("ipt_ULOG: ulog_send: timer was pending, de.leting\n");.

               . del_timer(&ub->timer).;[成人用品]

        }



        /*. last nlmsg needs NLMSG_DONE *./    外汇

        if (ub-.>qlen > 1)    美容

              .  ub->l.astnlh->nlmsg_type = NLMSG_DONE;.



        NETLIN.K_CB(ub->skb).dst_gro.ups = (1 << nlgroupnum);.

        DEBUGP("ipt_ULOG.: throwin.g %d packets to netlink mask %u\n",--------------彩票

    .            ub->qlen, nlgroupn.um);.

        netlink_broadcas.t(nflogn.l, ub->skb., 0, (1 << nlgroupnum), GFP_ATOMIC);电脑



        ub->qlen = 0.;          婚庆

        ub->skb .= NULL;电脑

        ub->lastnlh =. NULL.;[成人用品]



}
复制代码
另一个是分配函数:
static struct sk_b.uff *ulog_alloc_sk.b(unsigned int size).

{

        struct sk_.buff *skb.;教育



        /* al.loc skb which should be big. enough for a whole             汽车

     .    *. multipart message. WARNING: has to be <= 131000投资

       .  * due to slab allocator restrictions */.(        游戏          )



        sk.b = a.lloc_skb(nlbufsiz, GFP_ATOMIC);.

.       if (!skb) {(        游戏          )

      .          PRINTR("i.pt_ULOG: can't alloc whole buffer %ub!\n",            杀毒

                        nl.bufs.iz);--- 印刷



                /.* t.ry to allocate only as much as we need for     美容

                 * .curren.t packet */外贸



                .skb .= alloc_skb(size, GFP_ATOMIC);.

                i.f (!skb)虚拟主机

             .           PRINTR("ipt_ULOG: can't ev.en al.locate %ub\n", size);--- 印刷

        }



       . return skb;--------------彩票

}
复制代码分配skb,就是调用alloc_sk.b函数,不过这个分配函数需要注意的一点就是分配的包的大小的问题.,它是先尝试分配(广告)
static unsigned. int .nlbufsiz = 4096;    美容
这么大的空间,如果失败了,才按需分配。这样做的原因还是在于,一个缓存可能要.存放多.个数据包。.


忽忽浏览了一下,错误之.处,大家帮偶指正。
OK,收工,继续..去看为什么偶的系统记录下来的包,应该有而没有二层帧了……           鲜花

评价一下你浏览此帖子的感受

精彩

感动

搞笑

开心

愤怒

无聊

灌水
离线qidu2000.
发帖
2108
C币
-193192
威望
398
贡献值
1
银元
-4
铜钱
4860
人人网人气币
0
只看该作者 沙发  发表于: 2010-04-13
这个帖竟然没人顶!!顶一下!!满关注九贱大侠的帖子

[ 本帖最后由 songpure520 于 2008-1-23 22:39 编辑 ]

离线yszkm.
发帖
2099
C币
-152659
威望
380
贡献值
1
银元
-3
铜钱
4664
人人网人气币
0
只看该作者 板凳  发表于: 2010-04-13
赞!顶!再好好的顶!

离线jarodlee.
发帖
2082
C币
-60363
威望
395
贡献值
1
银元
-4
铜钱
4651
人人网人气币
0
只看该作者 地板  发表于: 2010-04-13


QUOTE:原帖由 独孤九贱 于 2007-11-21 14:47 发表
好久不灌水,来水一贴。
最近在用ulogd时,遇到一个小问题,就是经常用户空间收到的数据没有二层帧。不知是何原因,于是来看了一个Netfilter中ulogd模块(不是应用程序)的实现,虽然仍旧没有找到原因,也顺便 ...


我没有看那些代码,瞎猜的:

因为skb->data已经偏移到了IP层头部,所以没有二层帧。
快速回复
限100 字节
如果您提交过一次失败了,可以用”恢复数据”来恢复帖子内容
 
上一个 下一个