Chinaunix

标题: layer7-filter实现简析 [打印本页]

作者: 独孤九贱    时间: 2011-03-04 17:53
标题: layer7-filter实现简析
好久没有来发贴,今天看了一下l7filter过滤的实现,发上来讨论一下:
模版初始化,注册proc和netfilter match:
  1. static int __init xt_layer7_init(void)
  2. {
  3.         need_conntrack();

  4.         layer7_init_proc();
  5.         if(maxdatalen < 1) {
  6.                 printk(KERN_WARNING "layer7: maxdatalen can't be < 1, "
  7.                         "using 1\n");
  8.                 maxdatalen = 1;
  9.         }
  10.         /* This is not a hard limit.  It's just here to prevent people from
  11.         bringing their slow machines to a grinding halt. */
  12.         else if(maxdatalen > 65536) {
  13.                 printk(KERN_WARNING "layer7: maxdatalen can't be > 65536, "
  14.                         "using 65536\n");
  15.                 maxdatalen = 65536;
  16.         }
  17.         return xt_register_matches(xt_layer7_match,
  18.                                    ARRAY_SIZE(xt_layer7_match));
  19. }
复制代码
maxdatalen是最大的数据流长度。layer7使用数据流检测,若干个报文被组装到一个长度为maxdatalen的数据流中。其值默认为2048。

相应的模块注销,完成proc清理和netfilter match的注销:
  1. static void __exit xt_layer7_fini(void)
  2. {
  3.         layer7_cleanup_proc();
  4.         xt_unregister_matches(xt_layer7_match, ARRAY_SIZE(xt_layer7_match));
  5. }
复制代码
layer7_match是核心的匹备函数,layer7扩展了nf_conn结构,引入了协议名称,数据缓冲区和数据长度。当一个报文被匹备时,协议名称将记录这个协议,
以方便该会话的后续报文匹备检测:
  1. static bool
  2. layer7_match(const struct sk_buff *skbin, const struct xt_match_param *mt_para)
  3. {
  4.         /* sidestep const without getting a compiler warning... */
  5.         struct sk_buff * skb = (struct sk_buff *)skbin;

  6.         const struct xt_layer7_info * info = mt_para->matchinfo;
  7.         enum ip_conntrack_info master_ctinfo, ctinfo;
  8.         struct nf_conn *master_conntrack, *conntrack;
  9.         unsigned char * app_data;
  10.         unsigned int pattern_result, appdatalen;
  11.         regexp * comppattern;

  12.         /* Be paranoid/incompetent - lock the entire match function. */
  13.         //加全局锁
  14.         spin_lock_bh(&l7_lock);

  15.         //确认是能够处理的数据报文
  16.         if(!can_handle(skb)){
  17.                 DPRINTK("layer7: This is some protocol I can't handle.\n");
  18.                 spin_unlock_bh(&l7_lock);
  19.                 return info->invert;
  20.         }

  21.         /* Treat parent & all its children together as one connection, except
  22.         for the purpose of setting conntrack->layer7.app_proto in the actual
  23.         connection. This makes /proc/net/ip_conntrack more satisfying. */
  24.         //获取数据包的连接
  25.         if(!(conntrack = nf_ct_get(skb, &ctinfo)) ||
  26.            !(master_conntrack=nf_ct_get(skb,&master_ctinfo))){
  27.                 DPRINTK("layer7: couldn't get conntrack.\n");
  28.                 spin_unlock_bh(&l7_lock);
  29.                 return info->invert;
  30.         }

  31.         /* Try to get a master conntrack (and its master etc) for FTP, etc. */
  32.         /**
  33.          * 如果连接存在主连接,master_conntrack指向连接的主连接,
  34.          * 这样,如果一个连接不存在master,则conntrack/master_conntrack都指向该连接,
  35.          * 如果存在,则conntrack指向子连接自己,而master_conntrack指向其父连接
  36.         */
  37.         while (master_ct(master_conntrack) != NULL)
  38.                 master_conntrack = master_ct(master_conntrack);

  39.         /* if we've classified it or seen too many packets */
  40.         //如果对当前连接的处理超过最大报文上限,默认阀值为10,或者是主连接中已经有了协议名称
  41.         if(TOTAL_PACKETS > num_packets ||
  42.            master_conntrack->layer7.app_proto) {

  43.                 //如果主连接协议名已经标识,而子连接没有,则使用它覆盖所有子连接协议名称,
  44.                 //并且匹备协议名称。否则将主连接协议名设为"Unkown"
  45.                 //对于没有子连接的来说,两个指针都指向自己,这意味着后续的报文直接通过协议名称,
  46.                 //可以快速处理。
  47.                 pattern_result = match_no_append(conntrack, master_conntrack,
  48.                                                  ctinfo, master_ctinfo, info);

  49.                 /* skb->cb[0] == seen. Don't do things twice if there are
  50.                 multiple l7 rules. I'm not sure that using cb for this purpose
  51.                 is correct, even though it says "put your private variables
  52.                 there". But it doesn't look like it is being used for anything
  53.                 else in the skbs that make it here. */
  54.                 skb->cb[0] = 1; /* marking it seen here's probably irrelevant */

  55.                 spin_unlock_bh(&l7_lock);
  56.                 //返回匹备结果
  57.                 return (pattern_result ^ info->invert);
  58.         }

  59.         //需要一个完整的报文做检测
  60.         if(skb_is_nonlinear(skb)){
  61.                 if(skb_linearize(skb) != 0){
  62.                         if (net_ratelimit())
  63.                                 printk(KERN_ERR "layer7: failed to linearize "
  64.                                                 "packet, bailing.\n");
  65.                         spin_unlock_bh(&l7_lock);
  66.                         return info->invert;
  67.                 }
  68.         }

  69.         /* now that the skb is linearized, it's safe to set these. */
  70.         //app_data指向报文数据载荷位
  71.         app_data = skb->data + app_data_offset(skb);
  72.         //appdatalen记录数据载荷长度
  73.         appdatalen = skb_tail_pointer(skb) - app_data;

  74.         /* the return value gets checked later, when we're ready to use it */
  75.         //初始化正则表达式
  76.         comppattern = compile_and_cache(info->pattern, info->protocol);

  77.         /* On the first packet of a connection, allocate space for app data */
  78.         //如果是第一个报文,为连接会话中的app_data指针分配空间
  79.         if(TOTAL_PACKETS == 1 && !skb->cb[0] &&
  80.            !master_conntrack->layer7.app_data){
  81.                 master_conntrack->layer7.app_data =
  82.                         kmalloc(maxdatalen, GFP_ATOMIC);
  83.                 //分配空间
  84.                 if(!master_conntrack->layer7.app_data){
  85.                         if (net_ratelimit())
  86.                                 printk(KERN_ERR "layer7: out of memory in "
  87.                                                 "match, bailing.\n");
  88.                         spin_unlock_bh(&l7_lock);
  89.                         return info->invert;
  90.                 }

  91.                 master_conntrack->layer7.app_data[0] = '\0';
  92.         }

  93.         /* Can be here, but unallocated, if numpackets is increased near
  94.         the beginning of a connection */
  95.         //有这样的可能,当会话已经建立了,l7filter模块才被插入。
  96.         if(master_conntrack->layer7.app_data == NULL){
  97.                 spin_unlock_bh(&l7_lock);
  98.                 return (info->invert); /* unmatched */
  99.         }

  100.         if(!skb->cb[0]){
  101.                 int newbytes;
  102.                 //将报文载荷拷贝到会话中,连接会话中的app_data记录连接的所有数据,最大不超过maxdatalen,
  103.                 //其阀值默认为2048。
  104.                 //感觉将追加的长度判断放在add_data之前更好,这样,大多数不被匹配的报文将减少一次函数调用开销
  105.                 newbytes = add_data(master_conntrack, app_data, appdatalen);

  106.                 //连接的数据缓冲已经满了
  107.                 if(newbytes == 0) { /* didn't add any data */
  108.                         skb->cb[0] = 1;
  109.                         /* Didn't match before, not going to match now */
  110.                         spin_unlock_bh(&l7_lock);
  111.                         return info->invert;
  112.                 }
  113.         }

  114.         //协议匹备,unkown/unset做为逃生的协议名标识,前者标识不进行匹备,后者表示匹备所有
  115.         /* If looking for "unknown", then never match.  "Unknown" means that
  116.         we've given up; we're still trying with these packets. */
  117.         if(!strcmp(info->protocol, "unknown")) {
  118.                 pattern_result = 0;
  119.         /* If looking for "unset", then always match. "Unset" means that we
  120.         haven't yet classified the connection. */
  121.         } else if(!strcmp(info->protocol, "unset")) {
  122.                 pattern_result = 2;
  123.                 DPRINTK("layer7: matched unset: not yet classified "
  124.                         "(%d/%d packets)\n", TOTAL_PACKETS, num_packets);
  125.         /* If the regexp failed to compile, don't bother running it */
  126.         } else if(comppattern &&
  127.                   regexec(comppattern, master_conntrack->layer7.app_data)){
  128.                   //regexec成功则返回1,失败返回0,这里表示匹备成功。
  129.                   //每一次匹备,都使用的是连接的数据进行,数据缓冲区的释放,是放在destroy_conntrack中进行的。
  130.                 DPRINTK("layer7: matched %s\n", info->protocol);
  131.                 pattern_result = 1;
  132.         } else pattern_result = 0;

  133.         if(pattern_result == 1) {
  134.                 //匹备成功,记录协议名称。
  135.                 master_conntrack->layer7.app_proto =
  136.                         kmalloc(strlen(info->protocol)+1, GFP_ATOMIC);
  137.                 if(!master_conntrack->layer7.app_proto){
  138.                         if (net_ratelimit())
  139.                                 printk(KERN_ERR "layer7: out of memory in "
  140.                                                 "match, bailing.\n");
  141.                         spin_unlock_bh(&l7_lock);
  142.                         return (pattern_result ^ info->invert);
  143.                 }
  144.                 strcpy(master_conntrack->layer7.app_proto, info->protocol);
  145.         } else if(pattern_result > 1) { /* cleanup from "unset" */
  146.                 //专门为unset准备的
  147.                 pattern_result = 1;
  148.         }

  149.         /* mark the packet seen */
  150.         //标识数据报文已经被处理过
  151.         skb->cb[0] = 1;

  152.         spin_unlock_bh(&l7_lock);
  153.                 //返回匹备结果
  154.         return (pattern_result ^ info->invert);
  155. }
复制代码
can_handle返回l7filter支持处理的协议,包括tcp/udp/icmp:
  1. static int can_handle(const struct sk_buff *skb)
  2. {
  3.         if(!ip_hdr(skb)) /* not IP */
  4.                 return 0;
  5.         if(ip_hdr(skb)->protocol != IPPROTO_TCP &&
  6.            ip_hdr(skb)->protocol != IPPROTO_UDP &&
  7.            ip_hdr(skb)->protocol != IPPROTO_ICMP)
  8.                 return 0;
  9.         return 1;
  10. }
复制代码
compile_and_cache函数初始化正则表达式,将用户空间的表达式转换为内核可识别的形式
为了加速正则表达式的转换——不可能每个报文都要转换一次。函数引入了缓存机制,不过这个缓存是一维链表形式的。这意味着加了若干条规则后,
这个链将变得很长。
  1. static regexp * compile_and_cache(const char * regex_string,
  2.                                   const char * protocol)
  3. {
  4.         struct pattern_cache * node               = first_pattern_cache;
  5.         struct pattern_cache * last_pattern_cache = first_pattern_cache;
  6.         struct pattern_cache * tmp;
  7.         unsigned int len;

  8.         //遍历表达式缓存表,试图找到缓存节点
  9.         while (node != NULL) {
  10.                 if (!strcmp(node->regex_string, regex_string))
  11.                 return node->pattern;

  12.                 last_pattern_cache = node;/* points at the last non-NULL node */
  13.                 node = node->next;
  14.         }

  15.         /* If we reach the end of the list, then we have not yet cached
  16.            the pattern for this regex. Let's do that now.
  17.            Be paranoid about running out of memory to avoid list corruption. */
  18.         //为新的表达式分配空间
  19.         tmp = kmalloc(sizeof(struct pattern_cache), GFP_ATOMIC);

  20.         //分配失败
  21.         if(!tmp) {
  22.                 if (net_ratelimit())
  23.                         printk(KERN_ERR "layer7: out of memory in "
  24.                                         "compile_and_cache, bailing.\n");
  25.                 return NULL;
  26.         }

  27.         //初始化各成员
  28.         tmp->regex_string  = kmalloc(strlen(regex_string) + 1, GFP_ATOMIC);
  29.         tmp->pattern       = kmalloc(sizeof(struct regexp),    GFP_ATOMIC);
  30.         tmp->next = NULL;

  31.         if(!tmp->regex_string || !tmp->pattern) {
  32.                 if (net_ratelimit())
  33.                         printk(KERN_ERR "layer7: out of memory in "
  34.                                         "compile_and_cache, bailing.\n");
  35.                 kfree(tmp->regex_string);
  36.                 kfree(tmp->pattern);
  37.                 kfree(tmp);
  38.                 return NULL;
  39.         }

  40.         /* Ok.  The new node is all ready now. */
  41.         node = tmp;

  42.         //更新表达式节点缓存
  43.         if(first_pattern_cache == NULL) /* list is empty */
  44.                 first_pattern_cache = node; /* make node the beginning */
  45.         else
  46.                 last_pattern_cache->next = node; /* attach node to the end */

  47.         //编译正则表达式
  48.         /* copy the string and compile the regex */
  49.         len = strlen(regex_string);
  50.         DPRINTK("About to compile this: \"%s\"\n", regex_string);
  51.         node->pattern = regcomp((char *)regex_string, &len);
  52.         if ( !node->pattern ) {
  53.                 if (net_ratelimit())
  54.                         printk(KERN_ERR "layer7: Error compiling regexp "
  55.                                         "\"%s\" (%s)\n",
  56.                                         regex_string, protocol);
  57.                 /* pattern is now cached as NULL, so we won't try again. */
  58.         }

  59.         strcpy(node->regex_string, regex_string);
  60.         return node->pattern;
  61. }
复制代码
match_no_append函数用于匹备已经标识存在协议名的连接,或者是超过最大检测数据包限制的会话:
  1. static int match_no_append(struct nf_conn * conntrack,
  2.                            struct nf_conn * master_conntrack,
  3.                            enum ip_conntrack_info ctinfo,
  4.                            enum ip_conntrack_info master_ctinfo,
  5.                            const struct xt_layer7_info * info)
  6. {
  7.         /* If we're in here, throw the app data away */
  8.         //会话数据缓冲区已经用不着了,释放内存,置空
  9.         if(master_conntrack->layer7.app_data != NULL) {

  10.         #ifdef CONFIG_IP_NF_MATCH_LAYER7_DEBUG
  11.                 if(!master_conntrack->layer7.app_proto) {
  12.                         char * f =
  13.                           friendly_print(master_conntrack->layer7.app_data);
  14.                         char * g =
  15.                           hex_print(master_conntrack->layer7.app_data);
  16.                         DPRINTK("\nl7-filter gave up after %d bytes "
  17.                                 "(%d packets):\n%s\n",
  18.                                 strlen(f), TOTAL_PACKETS, f);
  19.                         kfree(f);
  20.                         DPRINTK("In hex: %s\n", g);
  21.                         kfree(g);
  22.                 }
  23.         #endif

  24.                 kfree(master_conntrack->layer7.app_data);
  25.                 master_conntrack->layer7.app_data = NULL; /* don't free again */
  26.         }

  27.         //主连接已经标识了协议名称了
  28.         if(master_conntrack->layer7.app_proto){
  29.                 //如果连接还没有标识,则使用主连接的覆盖之
  30.                 /* Here child connections set their .app_proto (for /proc) */
  31.                 if(!conntrack->layer7.app_proto) {
  32.                         conntrack->layer7.app_proto =
  33.                           kmalloc(strlen(master_conntrack->layer7.app_proto)+1,
  34.                             GFP_ATOMIC);
  35.                         if(!conntrack->layer7.app_proto){
  36.                                 if (net_ratelimit())
  37.                                         printk(KERN_ERR "layer7: out of memory "
  38.                                                         "in match_no_append, "
  39.                                                         "bailing.\n");
  40.                                 return 1;
  41.                         }
  42.                         strcpy(conntrack->layer7.app_proto,
  43.                                 master_conntrack->layer7.app_proto);
  44.                 }

  45.                 //匹备协议名
  46.                 return (!strcmp(master_conntrack->layer7.app_proto,
  47.                                 info->protocol));
  48.         }
  49.         else {
  50.                 /* If not classified, set to "unknown" to distinguish from
  51.                 connections that are still being tested. */
  52.                 //否则将协议标识为unkown,则为不可识别,这也意味着,每一个unkown的连接,都会进入
  53.                 //这个函数进行匹备协议名
  54.                 master_conntrack->layer7.app_proto =
  55.                         kmalloc(strlen("unknown")+1, GFP_ATOMIC);
  56.                 if(!master_conntrack->layer7.app_proto){
  57.                         if (net_ratelimit())
  58.                                 printk(KERN_ERR "layer7: out of memory in "
  59.                                                 "match_no_append, bailing.\n");
  60.                         return 1;
  61.                 }
  62.                 strcpy(master_conntrack->layer7.app_proto, "unknown");
  63.                 return 0;
  64.         }
  65. }
复制代码
app_data_offset计算载荷的偏移位置,跳过传输层首部:
  1. /* Returns offset the into the skb->data that the application data starts */
  2. static int app_data_offset(const struct sk_buff *skb)
  3. {
  4.         /* In case we are ported somewhere (ebtables?) where ip_hdr(skb)
  5.         isn't set, this can be gotten from 4*(skb->data[0] & 0x0f) as well. */
  6.         int ip_hl = 4*ip_hdr(skb)->ihl;

  7.         if( ip_hdr(skb)->protocol == IPPROTO_TCP ) {
  8.                 /* 12 == offset into TCP header for the header length field.
  9.                 Can't get this with skb->h.th->doff because the tcphdr
  10.                 struct doesn't get set when routing (this is confirmed to be
  11.                 true in Netfilter as well as QoS.) */
  12.                 int tcp_hl = 4*(skb->data[ip_hl + 12] >> 4);

  13.                 return ip_hl + tcp_hl;
  14.         } else if( ip_hdr(skb)->protocol == IPPROTO_UDP  ) {
  15.                 return ip_hl + 8; /* UDP header is always 8 bytes */
  16.         } else if( ip_hdr(skb)->protocol == IPPROTO_ICMP ) {
  17.                 return ip_hl + 8; /* ICMP header is 8 bytes */
  18.         } else {
  19.                 if (net_ratelimit())
  20.                         printk(KERN_ERR "layer7: tried to handle unknown "
  21.                                         "protocol!\n");
  22.                 return ip_hl + 8; /* something reasonable */
  23.         }
  24. }
复制代码
add_data函数用于构建待检测的数据流,它将数据报文追加到连接会话的数据缓冲区中,令人疑惑的是,为什么没有区分数据流方向呢?

  1. /* add the new app data to the conntrack.  Return number of bytes added. */
  2. static int add_data(struct nf_conn * master_conntrack,
  3.                     char * app_data, int appdatalen)
  4. {
  5.         int length = 0, i;
  6.         int oldlength = master_conntrack->layer7.app_data_len;

  7.         /* This is a fix for a race condition by Deti Fliegl. However, I'm not
  8.            clear on whether the race condition exists or whether this really
  9.            fixes it.  I might just be being dense... Anyway, if it's not really
  10.            a fix, all it does is waste a very small amount of time. */
  11.         if(!master_conntrack->layer7.app_data) return 0;

  12.         /* Strip nulls. Make everything lower case (our regex lib doesn't
  13.         do case insensitivity).  Add it to the end of the current data. */
  14.         //追加数据进入连接会话中
  15.         for(i = 0; i < maxdatalen-oldlength-1 &&
  16.                    i < appdatalen; i++) {
  17.                 if(app_data[i] != '\0') {
  18.                         /* the kernel version of tolower mungs 'upper ascii' */
  19.                         master_conntrack->layer7.app_data[length+oldlength] =
  20.                                 isascii(app_data[i])?
  21.                                         tolower(app_data[i]) : app_data[i];
  22.                         length++;
  23.                 }
  24.         }
  25.         //置结束标记
  26.         master_conntrack->layer7.app_data[length+oldlength] = '\0';
  27.         //重新计算长度
  28.         master_conntrack->layer7.app_data_len = length + oldlength;

  29.         return length;
  30. }
复制代码
个人认为,layer7的性能低,是各个方面造成的,不知道优化匹备模式,能不能提高其效率——类似snort规则,引用更多的检测项。
作者: tuibo    时间: 2011-03-04 18:16
它这个太简单了 ,要是用来做防火墙还是不要算了,我是自己重新一个,  正则表达式也用了强悍的pcre。
   

pcre 移植到内核,可以参阅下面我写的:

http://blogold.chinaunix.net/u3/116699/showart_2314530.html
作者: Godbach    时间: 2011-03-04 18:36
回复 1# 独孤九贱


    赞一下九贱兄的无私分享。
作者: Godbach    时间: 2011-03-04 18:36
它这个太简单了 ,要是用来做防火墙还是不要算了,我是自己重新一个,  正则表达式也用了强悍的pcre。
    ...
tuibo 发表于 2011-03-04 18:16


l7 这个框架还是有不少借鉴价值的。

BTW,你的 Blog 的代码是可以直接在内核编译的吗?
作者: tuibo    时间: 2011-03-04 19:10
直接在内核编译
作者: bekars    时间: 2011-03-04 21:41
我也是在内核做的IPS,用户态下规则,但是不能下太多
作者: zhainx    时间: 2011-03-04 22:46
谢谢分享!!
作者: accessory    时间: 2011-03-05 02:59
http://l7-filter.sourceforge.net/

L7-filter is a classifier for Linux's Netfilter that identifies packets based on application layer data. It can classify packets as Kazaa, HTTP, Jabber, Citrix, Bittorrent, FTP, Gnucleus, eDonkey2000, etc., regardless of port. It complements existing classifiers that match on IP address, port numbers and so on.

Our intent is for l7-filter to be used in conjunction with Linux QoS to do bandwith arbitration ("packet shaping") or traffic accounting.

PS:这个是在用户层还是在内核里面实现的?
作者: dreamice    时间: 2011-03-05 11:32
L7-filter is a classifier for Linux's Netfilter that identifies packets based on application lay ...
accessory 发表于 2011-03-05 02:59



    内核层做L7的过滤
作者: dreamice    时间: 2011-03-05 11:33
它这个太简单了 ,要是用来做防火墙还是不要算了,我是自己重新一个,  正则表达式也用了强悍的pcre。
    ...
tuibo 发表于 2011-03-04 18:16



    内核做正则,效率、误报、稳定性是很重要的因素
作者: 独孤九贱    时间: 2011-03-05 12:19
它这个太简单了 ,要是用来做防火墙还是不要算了,我是自己重新一个,  正则表达式也用了强悍的pcre。
    ...
tuibo 发表于 2011-03-04 18:16



顶二楼!

你实际测试,pcre的性能和稳定性更好吗?能否大致给个对比结果呢???
作者: Godbach    时间: 2011-03-05 12:48
我也是在内核做的IPS,用户态下规则,但是不能下太多
bekars 发表于 2011-03-04 21:41

你指的不能太多是多少少啊?
我测试过几千条规则,是没问题的
作者: tuibo    时间: 2011-03-05 15:09
正则表达式有个缺点,不能表示在某些字段值为包长度。
性能还可以吧。  基本上做识别功能没有太好的方法。

用些小技巧可以提高一下,区分协议号,常见的识别放前面匹配,cache。
作者: dreamice    时间: 2011-03-05 16:40
正则表达式有个缺点,不能表示在某些字段值为包长度。
性能还可以吧。  基本上做识别功能没有太好的方法。 ...
tuibo 发表于 2011-03-05 15:09



    能说得更详细点吗?
作者: 独孤九贱    时间: 2011-03-05 19:29
正则表达式有个缺点,不能表示在某些字段值为包长度。
性能还可以吧。  基本上做识别功能没有太好的方法。 ...
tuibo 发表于 2011-03-05 15:09


我主要是关心,它比layer7的好在哪儿得???
作者: tuibo    时间: 2011-03-05 19:34
layer7 每配一条识别一条,100个应用的话,就要跑100个规则。 而且识别码更新也不方面,需要删除添加规则。
作者: shank941    时间: 2011-03-05 23:37
正则表达式有个缺点,不能表示在某些字段值为包长度。
性能还可以吧。  基本上做识别功能没有太好的方法。 ...
tuibo 发表于 2011-03-05 15:09



    觉得做应用层识别还是snort更方便一点,因为snort会增加一个固定字符串的选项,固定字符串的匹配算法是多模的,只有匹配了固定字符串才会再去和对应的pcre规则进行比较,这样可以节省时间。而且snort相对而言,移植到内核态也不是很麻烦,只要把skb和snort里的packet做个映射就行了,以前单位工作时移植过,大概1个月吧差不多可以把整个snort 移植到内核里。
作者: 独孤九贱    时间: 2011-03-06 16:27
layer7 每配一条识别一条,100个应用的话,就要跑100个规则。 而且识别码更新也不方面,需要删除添加规则。
tuibo 发表于 2011-03-05 19:34


嗯, 不过我问的是说用pcre来做有什么优势,因为我想pcre做也应该有这些问题吧????
作者: Godbach    时间: 2011-03-07 10:53
回复 17# shank941


   
  觉得做应用层识别还是snort更方便一点,因为snort会增加一个固定字符串的选项,固定字符串的匹配算法是多模的,只有匹配了固定字符串才会再去和对应的pcre规则进行比较,这样可以节省时间。而且snort相对而言,移植到内核态也不是很麻烦,只要把skb和snort里的packet做个映射就行了,以前单位工作时移植过,大概1个月吧差不多可以把整个snort 移植到内核里。

嗯,把 snort 移植到内核确实是可以实现的,难度不是特别大。
作者: Godbach    时间: 2011-03-07 10:57
但是,写成规则也有写成规则的弊端。有些特征,不是特别容易用规则表示出来,除非自己开发相关的插件。
硬编码的话,可控性搞一些,而且比较复杂的特征也能表示处理。
作者: Godbach    时间: 2011-03-07 10:59
回复 18# 独孤九贱


   
嗯, 不过我问的是说用pcre来做有什么优势,因为我想pcre做也应该有这些问题吧????

嗯,我的理解,如果就仅仅使用 pcre 是同样存在这个的问题,只是变换了规则的呈现方式而已。
但是,如果再结合着引擎的话,可能就会有很大的方便了。比如 snort 中使用了 pcre,同时把 snort 一直到内核,这样的引擎,应该比 layer7 高效一些。
作者: 独孤九贱    时间: 2011-03-07 11:15
回复  独孤九贱


   
嗯,我的理解,如果就仅仅使用 pcre 是同样存在这个的问题,只是变换了规则的呈 ...
Godbach 发表于 2011-03-07 10:59



那是额外的东东了,超出了两个正式表达式实现的范筹了。snort引入了更多的检测项,性能更高应该是理所当然的了。只是要完全移值,好累哟,佩服你们呀!!
作者: Godbach    时间: 2011-03-07 11:25
那是额外的东东了,超出了两个正式表达式实现的范筹了。snort引入了更多的检测项,性能更高应该是理所 ...
独孤九贱 发表于 2011-03-07 11:15

还可以了,主要是一些内存分配函数的处理,以及框架的裁剪。其余的大部分都是 snort 自己实现的
作者: platinum    时间: 2011-03-07 12:40
内核层做L7的过滤
dreamice 发表于 2011-03-05 11:32


现在有了 userspace 版,据说可以把多线程用起来
作者: dreamice    时间: 2011-03-07 12:46
本帖最后由 Godbach 于 2011-03-07 12:51 编辑
回复  shank941


   
嗯,把 snort 移植到内核确实是可以实现的,难度不是特别大。
Godbach 发表于 2011-03-07 10:53



    Godbach 做过这方面的?可否详细写个帖子讲讲
作者: Godbach    时间: 2011-03-07 12:51
Godbach做过这方面的?可否详细写个帖子讲讲
dreamice 发表于 2011-03-07 12:46


多少做过一些,过去有一段时间了。最近比较忙,没时间整理啊。

你有什么问题,大家可以一起交流啊
作者: peimichael    时间: 2011-03-07 13:20
先Mark一下,貌似以后会用到。不知道CU有帖子收藏功能么?
作者: Godbach    时间: 2011-03-07 13:36
回复 27# peimichael
帖子的最上面有:

[打印] [收藏] [本帖文本页] [推荐此主题给朋友]
作者: peimichael    时间: 2011-03-07 14:22
回复 28# Godbach


    找到了,谢谢。眼睛不太好使了
作者: tuibo    时间: 2011-03-07 16:15
对于加密类型的应用,正则不好使了,有的倒是可以侦测,有的协议同时支持加密不加密类型,用不加密的去侦察。 不过对于只支持加密的应用,识别就难了,snort也不顶用
作者: Godbach    时间: 2011-03-07 16:39
有的特征还是分散在一个连接的几个数据包中,这种检测也比较麻烦
作者: smalloc    时间: 2011-03-07 18:37
九贱兄找到工作没?看你好象挂了一年多了
作者: Godbach    时间: 2011-03-07 19:00
回复 32# smalloc
他的签名应该需要修改了。 :wink:
作者: 极北之北    时间: 2011-03-09 09:07
提示: 作者被禁止或删除 内容自动屏蔽
作者: send_linux    时间: 2011-03-09 09:50
九贱兄找到工作没?看你好象挂了一年多了
smalloc 发表于 2011-03-07 18:37



    听说已经找到了啊,呵呵
作者: ouyangyufu    时间: 2011-03-09 12:30
{:2_177:}
作者: dolphin1987    时间: 2011-03-09 18:15
回复 8# accessory


    l7的核心代码是在内核下完成的,用户态只是做简单的规则判断的解析。
作者: dolphin1987    时间: 2011-03-09 18:23
回复 21# Godbach


    godbach兄,看来是这方面的高手,现在对应用(协议)的识别,从应用层来着手,感觉是越来越没有出路了,应该现在的应用都会聪明了,不但会频繁的更新通信协议,有的甚至直接加密传输,这样应用层就没得办法了。不知道godbach兄,你们现在有没有什么新的思路?还望开导开导。
作者: Godbach    时间: 2011-03-09 18:29
回复 38# dolphin1987
开导不敢当。我只是以前也多少做过这方面的工作,因此了解一些。
现在很多应用都是多种协议一起使用的,比如迅雷,它有自己的协议,但是同时它还会用普通的 HTTP 下载,它还支持 Emule 协议等。这样就增加了识别的难度。

基本的方法是做特征分析,简单的是抓包分析。如果有比较好的技术能力,比如可能进行逆向工程,或者用 WinDBG 等进行调试,可以深层次的分析某个应用的行为。
作者: amyyoki    时间: 2011-03-11 13:53
正在做这方面的东西,太感谢了
作者: david224    时间: 2011-03-26 18:03
L7就是效率低了一点,稳定性等各方面还是不错的。:wink:
作者: Anzyfly    时间: 2011-03-28 19:50
九贱兄不发则已,一发就是精品贴,感谢分享,赞一个!{:2_172:}
作者: onlyff608    时间: 2011-04-25 21:13
把layer7的netfilter-layer7-v2.21下下来看了下,现在有几个问题,就是在kernel-2.6.25-2.6.28-layer7-2.21.patch的里面使用了pattern匹配,像node->pattern = regcomp((char *)regex_string, &len);在module_init(xt_layer7_init);module_exit(xt_layer7_fini)注册了模块后,接下来的
--- linux-2.6.28-stock/net/netfilter/regexp/regexp.c        1969-12-31 18:00:00.000000000 -0600
+++ linux-2.6.28/net/netfilter/regexp/regexp.c        2009-01-07 16:07:31.000000000 -0600
@@ -0,0 +1,1197 @@
+/*
+ * regcomp and regexec -- regsub and regerror are elsewhere
+ * @(#)regexp.c        1.3 of 18 April 87
。。。。此处省略n行
是表示把实现正则表达式匹配功能的函数也通过打补丁的方式编译进内核了吗?
还有就是如果我想自己写个对数据包过滤的模块,是不是也可以像layer7这样把实现匹配功能的函数加到我的代码里就可以使用正则表达式了?
作者: anjing83830    时间: 2011-05-27 17:06
谢谢楼主分享,那那将pcre移植到内核具体应该如何实现呢?
作者: phoxia    时间: 2011-05-28 09:10
回复 1# 独孤九贱


    精品啊,学习中
作者: 1hello2    时间: 2012-05-30 17:00
回复 1# 独孤九贱
有个问题:
l7-filter,regexec(regexp *prog, char *string);
第二个参数指:要匹配的字符串,即packets中的payload;
我的问题是,payload中有很多'\0',此处怎么保证 string不是到中间某一个'\0'结束,而是整个payload;
一般方法应该是,加一个payload长度的参数,但是,此处没有。想知道l7-filter中怎么解决的,请九贱兄指导。谢谢啦!


   
作者: Arthur_    时间: 2012-05-31 08:54
本帖最后由 Arthur_ 于 2012-05-31 08:55 编辑

请教搂住 现在thunder 通过峰资源可以封住么? 现在无论怎么封总是有多线程下载的影子.
作者: 独孤九贱    时间: 2012-05-31 10:37
单纯的正则表达式也力有不逮,白金我兄站内发过一篇ppt,专门说这个。




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2