Root/
1 | /* |
2 | Kernel module to match application layer (OSI layer 7) data in connections. |
3 | |
4 | http://l7-filter.sf.net |
5 | |
6 | (C) 2003-2009 Matthew Strait and Ethan Sommer. |
7 | |
8 | This program is free software; you can redistribute it and/or |
9 | modify it under the terms of the GNU General Public License |
10 | as published by the Free Software Foundation; either version |
11 | 2 of the License, or (at your option) any later version. |
12 | http://www.gnu.org/licenses/gpl.txt |
13 | |
14 | Based on ipt_string.c (C) 2000 Emmanuel Roger <winfield@freegates.be>, |
15 | xt_helper.c (C) 2002 Harald Welte and cls_layer7.c (C) 2003 Matthew Strait, |
16 | Ethan Sommer, Justin Levandoski. |
17 | */ |
18 | |
19 | #include <linux/spinlock.h> |
20 | #include <linux/version.h> |
21 | #include <net/ip.h> |
22 | #include <net/tcp.h> |
23 | #include <linux/module.h> |
24 | #include <linux/skbuff.h> |
25 | #include <linux/netfilter.h> |
26 | #include <net/netfilter/nf_conntrack.h> |
27 | #include <net/netfilter/nf_conntrack_core.h> |
28 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) |
29 | #include <net/netfilter/nf_conntrack_extend.h> |
30 | #include <net/netfilter/nf_conntrack_acct.h> |
31 | #endif |
32 | #include <linux/netfilter/x_tables.h> |
33 | #include <linux/netfilter/xt_layer7.h> |
34 | #include <linux/ctype.h> |
35 | #include <linux/proc_fs.h> |
36 | |
37 | #include "regexp/regexp.c" |
38 | |
39 | MODULE_LICENSE("GPL"); |
40 | MODULE_AUTHOR("Matthew Strait <quadong@users.sf.net>, Ethan Sommer <sommere@users.sf.net>"); |
41 | MODULE_DESCRIPTION("iptables application layer match module"); |
42 | MODULE_ALIAS("ipt_layer7"); |
43 | MODULE_VERSION("2.21"); |
44 | |
45 | static int maxdatalen = 2048; // this is the default |
46 | module_param(maxdatalen, int, 0444); |
47 | MODULE_PARM_DESC(maxdatalen, "maximum bytes of data looked at by l7-filter"); |
48 | #ifdef CONFIG_NETFILTER_XT_MATCH_LAYER7_DEBUG |
49 | #define DPRINTK(format,args...) printk(format,##args) |
50 | #else |
51 | #define DPRINTK(format,args...) |
52 | #endif |
53 | |
54 | /* Number of packets whose data we look at. |
55 | This can be modified through /proc/net/layer7_numpackets */ |
56 | static int num_packets = 10; |
57 | |
58 | static struct pattern_cache { |
59 | char * regex_string; |
60 | regexp * pattern; |
61 | struct pattern_cache * next; |
62 | } * first_pattern_cache = NULL; |
63 | |
64 | DEFINE_SPINLOCK(l7_lock); |
65 | |
66 | static int total_acct_packets(struct nf_conn *ct) |
67 | { |
68 | #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 26) |
69 | BUG_ON(ct == NULL); |
70 | return (ct->counters[IP_CT_DIR_ORIGINAL].packets + ct->counters[IP_CT_DIR_REPLY].packets); |
71 | #else |
72 | struct nf_conn_counter *acct; |
73 | |
74 | BUG_ON(ct == NULL); |
75 | acct = nf_conn_acct_find(ct); |
76 | if (!acct) |
77 | return 0; |
78 | return (acct[IP_CT_DIR_ORIGINAL].packets + acct[IP_CT_DIR_REPLY].packets); |
79 | #endif |
80 | } |
81 | |
82 | #ifdef CONFIG_IP_NF_MATCH_LAYER7_DEBUG |
83 | /* Converts an unfriendly string into a friendly one by |
84 | replacing unprintables with periods and all whitespace with " ". */ |
85 | static char * friendly_print(unsigned char * s) |
86 | { |
87 | char * f = kmalloc(strlen(s) + 1, GFP_ATOMIC); |
88 | int i; |
89 | |
90 | if(!f) { |
91 | if (net_ratelimit()) |
92 | printk(KERN_ERR "layer7: out of memory in " |
93 | "friendly_print, bailing.\n"); |
94 | return NULL; |
95 | } |
96 | |
97 | for(i = 0; i < strlen(s); i++){ |
98 | if(isprint(s[i]) && s[i] < 128) f[i] = s[i]; |
99 | else if(isspace(s[i])) f[i] = ' '; |
100 | else f[i] = '.'; |
101 | } |
102 | f[i] = '\0'; |
103 | return f; |
104 | } |
105 | |
106 | static char dec2hex(int i) |
107 | { |
108 | switch (i) { |
109 | case 0 ... 9: |
110 | return (i + '0'); |
111 | break; |
112 | case 10 ... 15: |
113 | return (i - 10 + 'a'); |
114 | break; |
115 | default: |
116 | if (net_ratelimit()) |
117 | printk("layer7: Problem in dec2hex\n"); |
118 | return '\0'; |
119 | } |
120 | } |
121 | |
122 | static char * hex_print(unsigned char * s) |
123 | { |
124 | char * g = kmalloc(strlen(s)*3 + 1, GFP_ATOMIC); |
125 | int i; |
126 | |
127 | if(!g) { |
128 | if (net_ratelimit()) |
129 | printk(KERN_ERR "layer7: out of memory in hex_print, " |
130 | "bailing.\n"); |
131 | return NULL; |
132 | } |
133 | |
134 | for(i = 0; i < strlen(s); i++) { |
135 | g[i*3 ] = dec2hex(s[i]/16); |
136 | g[i*3 + 1] = dec2hex(s[i]%16); |
137 | g[i*3 + 2] = ' '; |
138 | } |
139 | g[i*3] = '\0'; |
140 | |
141 | return g; |
142 | } |
143 | #endif // DEBUG |
144 | |
145 | /* Use instead of regcomp. As we expect to be seeing the same regexps over and |
146 | over again, it make sense to cache the results. */ |
147 | static regexp * compile_and_cache(const char * regex_string, |
148 | const char * protocol) |
149 | { |
150 | struct pattern_cache * node = first_pattern_cache; |
151 | struct pattern_cache * last_pattern_cache = first_pattern_cache; |
152 | struct pattern_cache * tmp; |
153 | unsigned int len; |
154 | |
155 | while (node != NULL) { |
156 | if (!strcmp(node->regex_string, regex_string)) |
157 | return node->pattern; |
158 | |
159 | last_pattern_cache = node;/* points at the last non-NULL node */ |
160 | node = node->next; |
161 | } |
162 | |
163 | /* If we reach the end of the list, then we have not yet cached |
164 | the pattern for this regex. Let's do that now. |
165 | Be paranoid about running out of memory to avoid list corruption. */ |
166 | tmp = kmalloc(sizeof(struct pattern_cache), GFP_ATOMIC); |
167 | |
168 | if(!tmp) { |
169 | if (net_ratelimit()) |
170 | printk(KERN_ERR "layer7: out of memory in " |
171 | "compile_and_cache, bailing.\n"); |
172 | return NULL; |
173 | } |
174 | |
175 | tmp->regex_string = kmalloc(strlen(regex_string) + 1, GFP_ATOMIC); |
176 | tmp->pattern = kmalloc(sizeof(struct regexp), GFP_ATOMIC); |
177 | tmp->next = NULL; |
178 | |
179 | if(!tmp->regex_string || !tmp->pattern) { |
180 | if (net_ratelimit()) |
181 | printk(KERN_ERR "layer7: out of memory in " |
182 | "compile_and_cache, bailing.\n"); |
183 | kfree(tmp->regex_string); |
184 | kfree(tmp->pattern); |
185 | kfree(tmp); |
186 | return NULL; |
187 | } |
188 | |
189 | /* Ok. The new node is all ready now. */ |
190 | node = tmp; |
191 | |
192 | if(first_pattern_cache == NULL) /* list is empty */ |
193 | first_pattern_cache = node; /* make node the beginning */ |
194 | else |
195 | last_pattern_cache->next = node; /* attach node to the end */ |
196 | |
197 | /* copy the string and compile the regex */ |
198 | len = strlen(regex_string); |
199 | DPRINTK("About to compile this: \"%s\"\n", regex_string); |
200 | node->pattern = regcomp((char *)regex_string, &len); |
201 | if ( !node->pattern ) { |
202 | if (net_ratelimit()) |
203 | printk(KERN_ERR "layer7: Error compiling regexp " |
204 | "\"%s\" (%s)\n", |
205 | regex_string, protocol); |
206 | /* pattern is now cached as NULL, so we won't try again. */ |
207 | } |
208 | |
209 | strcpy(node->regex_string, regex_string); |
210 | return node->pattern; |
211 | } |
212 | |
213 | static int can_handle(const struct sk_buff *skb) |
214 | { |
215 | if(!ip_hdr(skb)) /* not IP */ |
216 | return 0; |
217 | if(ip_hdr(skb)->protocol != IPPROTO_TCP && |
218 | ip_hdr(skb)->protocol != IPPROTO_UDP && |
219 | ip_hdr(skb)->protocol != IPPROTO_ICMP) |
220 | return 0; |
221 | return 1; |
222 | } |
223 | |
224 | /* Returns offset the into the skb->data that the application data starts */ |
225 | static int app_data_offset(const struct sk_buff *skb) |
226 | { |
227 | /* In case we are ported somewhere (ebtables?) where ip_hdr(skb) |
228 | isn't set, this can be gotten from 4*(skb->data[0] & 0x0f) as well. */ |
229 | int ip_hl = 4*ip_hdr(skb)->ihl; |
230 | |
231 | if( ip_hdr(skb)->protocol == IPPROTO_TCP ) { |
232 | /* 12 == offset into TCP header for the header length field. |
233 | Can't get this with skb->h.th->doff because the tcphdr |
234 | struct doesn't get set when routing (this is confirmed to be |
235 | true in Netfilter as well as QoS.) */ |
236 | int tcp_hl = 4*(skb->data[ip_hl + 12] >> 4); |
237 | |
238 | return ip_hl + tcp_hl; |
239 | } else if( ip_hdr(skb)->protocol == IPPROTO_UDP ) { |
240 | return ip_hl + 8; /* UDP header is always 8 bytes */ |
241 | } else if( ip_hdr(skb)->protocol == IPPROTO_ICMP ) { |
242 | return ip_hl + 8; /* ICMP header is 8 bytes */ |
243 | } else { |
244 | if (net_ratelimit()) |
245 | printk(KERN_ERR "layer7: tried to handle unknown " |
246 | "protocol!\n"); |
247 | return ip_hl + 8; /* something reasonable */ |
248 | } |
249 | } |
250 | |
251 | /* handles whether there's a match when we aren't appending data anymore */ |
252 | static int match_no_append(struct nf_conn * conntrack, |
253 | struct nf_conn * master_conntrack, |
254 | enum ip_conntrack_info ctinfo, |
255 | enum ip_conntrack_info master_ctinfo, |
256 | const struct xt_layer7_info * info) |
257 | { |
258 | /* If we're in here, throw the app data away */ |
259 | if(master_conntrack->layer7.app_data != NULL) { |
260 | |
261 | #ifdef CONFIG_IP_NF_MATCH_LAYER7_DEBUG |
262 | if(!master_conntrack->layer7.app_proto) { |
263 | char * f = |
264 | friendly_print(master_conntrack->layer7.app_data); |
265 | char * g = |
266 | hex_print(master_conntrack->layer7.app_data); |
267 | DPRINTK("\nl7-filter gave up after %d bytes " |
268 | "(%d packets):\n%s\n", |
269 | strlen(f), total_acct_packets(master_conntrack), f); |
270 | kfree(f); |
271 | DPRINTK("In hex: %s\n", g); |
272 | kfree(g); |
273 | } |
274 | #endif |
275 | |
276 | kfree(master_conntrack->layer7.app_data); |
277 | master_conntrack->layer7.app_data = NULL; /* don't free again */ |
278 | } |
279 | |
280 | if(master_conntrack->layer7.app_proto){ |
281 | /* Here child connections set their .app_proto (for /proc) */ |
282 | if(!conntrack->layer7.app_proto) { |
283 | conntrack->layer7.app_proto = |
284 | kmalloc(strlen(master_conntrack->layer7.app_proto)+1, |
285 | GFP_ATOMIC); |
286 | if(!conntrack->layer7.app_proto){ |
287 | if (net_ratelimit()) |
288 | printk(KERN_ERR "layer7: out of memory " |
289 | "in match_no_append, " |
290 | "bailing.\n"); |
291 | return 1; |
292 | } |
293 | strcpy(conntrack->layer7.app_proto, |
294 | master_conntrack->layer7.app_proto); |
295 | } |
296 | |
297 | return (!strcmp(master_conntrack->layer7.app_proto, |
298 | info->protocol)); |
299 | } |
300 | else { |
301 | /* If not classified, set to "unknown" to distinguish from |
302 | connections that are still being tested. */ |
303 | master_conntrack->layer7.app_proto = |
304 | kmalloc(strlen("unknown")+1, GFP_ATOMIC); |
305 | if(!master_conntrack->layer7.app_proto){ |
306 | if (net_ratelimit()) |
307 | printk(KERN_ERR "layer7: out of memory in " |
308 | "match_no_append, bailing.\n"); |
309 | return 1; |
310 | } |
311 | strcpy(master_conntrack->layer7.app_proto, "unknown"); |
312 | return 0; |
313 | } |
314 | } |
315 | |
316 | /* add the new app data to the conntrack. Return number of bytes added. */ |
317 | static int add_datastr(char *target, int offset, char *app_data, int len) |
318 | { |
319 | int length = 0, i; |
320 | if (!target) return 0; |
321 | |
322 | /* Strip nulls. Make everything lower case (our regex lib doesn't |
323 | do case insensitivity). Add it to the end of the current data. */ |
324 | for(i = 0; i < maxdatalen-offset-1 && i < len; i++) { |
325 | if(app_data[i] != '\0') { |
326 | /* the kernel version of tolower mungs 'upper ascii' */ |
327 | target[length+offset] = |
328 | isascii(app_data[i])? |
329 | tolower(app_data[i]) : app_data[i]; |
330 | length++; |
331 | } |
332 | } |
333 | target[length+offset] = '\0'; |
334 | |
335 | return length; |
336 | } |
337 | |
338 | /* add the new app data to the conntrack. Return number of bytes added. */ |
339 | static int add_data(struct nf_conn * master_conntrack, |
340 | char * app_data, int appdatalen) |
341 | { |
342 | int length; |
343 | |
344 | length = add_datastr(master_conntrack->layer7.app_data, master_conntrack->layer7.app_data_len, app_data, appdatalen); |
345 | master_conntrack->layer7.app_data_len += length; |
346 | |
347 | return length; |
348 | } |
349 | |
350 | /* taken from drivers/video/modedb.c */ |
351 | static int my_atoi(const char *s) |
352 | { |
353 | int val = 0; |
354 | |
355 | for (;; s++) { |
356 | switch (*s) { |
357 | case '0'...'9': |
358 | val = 10*val+(*s-'0'); |
359 | break; |
360 | default: |
361 | return val; |
362 | } |
363 | } |
364 | } |
365 | |
366 | /* write out num_packets to userland. */ |
367 | static int layer7_read_proc(char* page, char ** start, off_t off, int count, |
368 | int* eof, void * data) |
369 | { |
370 | if(num_packets > 99 && net_ratelimit()) |
371 | printk(KERN_ERR "layer7: NOT REACHED. num_packets too big\n"); |
372 | |
373 | page[0] = num_packets/10 + '0'; |
374 | page[1] = num_packets%10 + '0'; |
375 | page[2] = '\n'; |
376 | page[3] = '\0'; |
377 | |
378 | *eof=1; |
379 | |
380 | return 3; |
381 | } |
382 | |
383 | /* Read in num_packets from userland */ |
384 | static int layer7_write_proc(struct file* file, const char* buffer, |
385 | unsigned long count, void *data) |
386 | { |
387 | char * foo = kmalloc(count, GFP_ATOMIC); |
388 | |
389 | if(!foo){ |
390 | if (net_ratelimit()) |
391 | printk(KERN_ERR "layer7: out of memory, bailing. " |
392 | "num_packets unchanged.\n"); |
393 | return count; |
394 | } |
395 | |
396 | if(copy_from_user(foo, buffer, count)) { |
397 | return -EFAULT; |
398 | } |
399 | |
400 | |
401 | num_packets = my_atoi(foo); |
402 | kfree (foo); |
403 | |
404 | /* This has an arbitrary limit to make the math easier. I'm lazy. |
405 | But anyway, 99 is a LOT! If you want more, you're doing it wrong! */ |
406 | if(num_packets > 99) { |
407 | printk(KERN_WARNING "layer7: num_packets can't be > 99.\n"); |
408 | num_packets = 99; |
409 | } else if(num_packets < 1) { |
410 | printk(KERN_WARNING "layer7: num_packets can't be < 1.\n"); |
411 | num_packets = 1; |
412 | } |
413 | |
414 | return count; |
415 | } |
416 | |
417 | static bool |
418 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28) |
419 | match(const struct sk_buff *skbin, const struct xt_match_param *par) |
420 | #else |
421 | match(const struct sk_buff *skbin, |
422 | const struct net_device *in, |
423 | const struct net_device *out, |
424 | const struct xt_match *match, |
425 | const void *matchinfo, |
426 | int offset, |
427 | unsigned int protoff, |
428 | bool *hotdrop) |
429 | #endif |
430 | { |
431 | /* sidestep const without getting a compiler warning... */ |
432 | struct sk_buff * skb = (struct sk_buff *)skbin; |
433 | |
434 | const struct xt_layer7_info * info = |
435 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28) |
436 | par->matchinfo; |
437 | #else |
438 | matchinfo; |
439 | #endif |
440 | |
441 | enum ip_conntrack_info master_ctinfo, ctinfo; |
442 | struct nf_conn *master_conntrack, *conntrack; |
443 | unsigned char *app_data, *tmp_data; |
444 | unsigned int pattern_result, appdatalen; |
445 | regexp * comppattern; |
446 | |
447 | /* Be paranoid/incompetent - lock the entire match function. */ |
448 | spin_lock_bh(&l7_lock); |
449 | |
450 | if(!can_handle(skb)){ |
451 | DPRINTK("layer7: This is some protocol I can't handle.\n"); |
452 | spin_unlock_bh(&l7_lock); |
453 | return info->invert; |
454 | } |
455 | |
456 | /* Treat parent & all its children together as one connection, except |
457 | for the purpose of setting conntrack->layer7.app_proto in the actual |
458 | connection. This makes /proc/net/ip_conntrack more satisfying. */ |
459 | if(!(conntrack = nf_ct_get(skb, &ctinfo)) || |
460 | !(master_conntrack=nf_ct_get(skb,&master_ctinfo))){ |
461 | DPRINTK("layer7: couldn't get conntrack.\n"); |
462 | spin_unlock_bh(&l7_lock); |
463 | return info->invert; |
464 | } |
465 | |
466 | /* Try to get a master conntrack (and its master etc) for FTP, etc. */ |
467 | while (master_ct(master_conntrack) != NULL) |
468 | master_conntrack = master_ct(master_conntrack); |
469 | |
470 | /* if we've classified it or seen too many packets */ |
471 | if(!info->pkt && (total_acct_packets(master_conntrack) > num_packets || |
472 | master_conntrack->layer7.app_proto)) { |
473 | |
474 | pattern_result = match_no_append(conntrack, master_conntrack, |
475 | ctinfo, master_ctinfo, info); |
476 | |
477 | /* skb->cb[0] == seen. Don't do things twice if there are |
478 | multiple l7 rules. I'm not sure that using cb for this purpose |
479 | is correct, even though it says "put your private variables |
480 | there". But it doesn't look like it is being used for anything |
481 | else in the skbs that make it here. */ |
482 | skb->cb[0] = 1; /* marking it seen here's probably irrelevant */ |
483 | |
484 | spin_unlock_bh(&l7_lock); |
485 | return (pattern_result ^ info->invert); |
486 | } |
487 | |
488 | if(skb_is_nonlinear(skb)){ |
489 | if(skb_linearize(skb) != 0){ |
490 | if (net_ratelimit()) |
491 | printk(KERN_ERR "layer7: failed to linearize " |
492 | "packet, bailing.\n"); |
493 | spin_unlock_bh(&l7_lock); |
494 | return info->invert; |
495 | } |
496 | } |
497 | |
498 | /* now that the skb is linearized, it's safe to set these. */ |
499 | app_data = skb->data + app_data_offset(skb); |
500 | appdatalen = skb_tail_pointer(skb) - app_data; |
501 | |
502 | /* the return value gets checked later, when we're ready to use it */ |
503 | comppattern = compile_and_cache(info->pattern, info->protocol); |
504 | |
505 | if (info->pkt) { |
506 | tmp_data = kmalloc(maxdatalen, GFP_ATOMIC); |
507 | if(!tmp_data){ |
508 | if (net_ratelimit()) |
509 | printk(KERN_ERR "layer7: out of memory in match, bailing.\n"); |
510 | return info->invert; |
511 | } |
512 | |
513 | tmp_data[0] = '\0'; |
514 | add_datastr(tmp_data, 0, app_data, appdatalen); |
515 | pattern_result = ((comppattern && regexec(comppattern, tmp_data)) ? 1 : 0); |
516 | |
517 | kfree(tmp_data); |
518 | tmp_data = NULL; |
519 | spin_unlock_bh(&l7_lock); |
520 | |
521 | return (pattern_result ^ info->invert); |
522 | } |
523 | |
524 | /* On the first packet of a connection, allocate space for app data */ |
525 | if(total_acct_packets(master_conntrack) == 1 && !skb->cb[0] && |
526 | !master_conntrack->layer7.app_data){ |
527 | master_conntrack->layer7.app_data = |
528 | kmalloc(maxdatalen, GFP_ATOMIC); |
529 | if(!master_conntrack->layer7.app_data){ |
530 | if (net_ratelimit()) |
531 | printk(KERN_ERR "layer7: out of memory in " |
532 | "match, bailing.\n"); |
533 | spin_unlock_bh(&l7_lock); |
534 | return info->invert; |
535 | } |
536 | |
537 | master_conntrack->layer7.app_data[0] = '\0'; |
538 | } |
539 | |
540 | /* Can be here, but unallocated, if numpackets is increased near |
541 | the beginning of a connection */ |
542 | if(master_conntrack->layer7.app_data == NULL){ |
543 | spin_unlock_bh(&l7_lock); |
544 | return info->invert; /* unmatched */ |
545 | } |
546 | |
547 | if(!skb->cb[0]){ |
548 | int newbytes; |
549 | newbytes = add_data(master_conntrack, app_data, appdatalen); |
550 | |
551 | if(newbytes == 0) { /* didn't add any data */ |
552 | skb->cb[0] = 1; |
553 | /* Didn't match before, not going to match now */ |
554 | spin_unlock_bh(&l7_lock); |
555 | return info->invert; |
556 | } |
557 | } |
558 | |
559 | /* If looking for "unknown", then never match. "Unknown" means that |
560 | we've given up; we're still trying with these packets. */ |
561 | if(!strcmp(info->protocol, "unknown")) { |
562 | pattern_result = 0; |
563 | /* If looking for "unset", then always match. "Unset" means that we |
564 | haven't yet classified the connection. */ |
565 | } else if(!strcmp(info->protocol, "unset")) { |
566 | pattern_result = 2; |
567 | DPRINTK("layer7: matched unset: not yet classified " |
568 | "(%d/%d packets)\n", |
569 | total_acct_packets(master_conntrack), num_packets); |
570 | /* If the regexp failed to compile, don't bother running it */ |
571 | } else if(comppattern && |
572 | regexec(comppattern, master_conntrack->layer7.app_data)){ |
573 | DPRINTK("layer7: matched %s\n", info->protocol); |
574 | pattern_result = 1; |
575 | } else pattern_result = 0; |
576 | |
577 | if(pattern_result == 1) { |
578 | master_conntrack->layer7.app_proto = |
579 | kmalloc(strlen(info->protocol)+1, GFP_ATOMIC); |
580 | if(!master_conntrack->layer7.app_proto){ |
581 | if (net_ratelimit()) |
582 | printk(KERN_ERR "layer7: out of memory in " |
583 | "match, bailing.\n"); |
584 | spin_unlock_bh(&l7_lock); |
585 | return (pattern_result ^ info->invert); |
586 | } |
587 | strcpy(master_conntrack->layer7.app_proto, info->protocol); |
588 | } else if(pattern_result > 1) { /* cleanup from "unset" */ |
589 | pattern_result = 1; |
590 | } |
591 | |
592 | /* mark the packet seen */ |
593 | skb->cb[0] = 1; |
594 | |
595 | spin_unlock_bh(&l7_lock); |
596 | return (pattern_result ^ info->invert); |
597 | } |
598 | |
599 | // load nf_conntrack_ipv4 |
600 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28) |
601 | static bool check(const struct xt_mtchk_param *par) |
602 | { |
603 | if (nf_ct_l3proto_try_module_get(par->match->family) < 0) { |
604 | printk(KERN_WARNING "can't load conntrack support for " |
605 | "proto=%d\n", par->match->family); |
606 | #else |
607 | static bool check(const char *tablename, const void *inf, |
608 | const struct xt_match *match, void *matchinfo, |
609 | unsigned int hook_mask) |
610 | { |
611 | if (nf_ct_l3proto_try_module_get(match->family) < 0) { |
612 | printk(KERN_WARNING "can't load conntrack support for " |
613 | "proto=%d\n", match->family); |
614 | #endif |
615 | return 0; |
616 | } |
617 | return 1; |
618 | } |
619 | |
620 | |
621 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28) |
622 | static void destroy(const struct xt_mtdtor_param *par) |
623 | { |
624 | nf_ct_l3proto_module_put(par->match->family); |
625 | } |
626 | #else |
627 | static void destroy(const struct xt_match *match, void *matchinfo) |
628 | { |
629 | nf_ct_l3proto_module_put(match->family); |
630 | } |
631 | #endif |
632 | |
633 | static struct xt_match xt_layer7_match[] __read_mostly = { |
634 | { |
635 | .name = "layer7", |
636 | .family = AF_INET, |
637 | .checkentry = check, |
638 | .match = match, |
639 | .destroy = destroy, |
640 | .matchsize = sizeof(struct xt_layer7_info), |
641 | .me = THIS_MODULE |
642 | } |
643 | }; |
644 | |
645 | static void layer7_cleanup_proc(void) |
646 | { |
647 | remove_proc_entry("layer7_numpackets", init_net.proc_net); |
648 | } |
649 | |
650 | /* register the proc file */ |
651 | static void layer7_init_proc(void) |
652 | { |
653 | struct proc_dir_entry* entry; |
654 | entry = create_proc_entry("layer7_numpackets", 0644, init_net.proc_net); |
655 | entry->read_proc = layer7_read_proc; |
656 | entry->write_proc = layer7_write_proc; |
657 | } |
658 | |
659 | static int __init xt_layer7_init(void) |
660 | { |
661 | need_conntrack(); |
662 | |
663 | layer7_init_proc(); |
664 | if(maxdatalen < 1) { |
665 | printk(KERN_WARNING "layer7: maxdatalen can't be < 1, " |
666 | "using 1\n"); |
667 | maxdatalen = 1; |
668 | } |
669 | /* This is not a hard limit. It's just here to prevent people from |
670 | bringing their slow machines to a grinding halt. */ |
671 | else if(maxdatalen > 65536) { |
672 | printk(KERN_WARNING "layer7: maxdatalen can't be > 65536, " |
673 | "using 65536\n"); |
674 | maxdatalen = 65536; |
675 | } |
676 | return xt_register_matches(xt_layer7_match, |
677 | ARRAY_SIZE(xt_layer7_match)); |
678 | } |
679 | |
680 | static void __exit xt_layer7_fini(void) |
681 | { |
682 | layer7_cleanup_proc(); |
683 | xt_unregister_matches(xt_layer7_match, ARRAY_SIZE(xt_layer7_match)); |
684 | } |
685 | |
686 | module_init(xt_layer7_init); |
687 | module_exit(xt_layer7_fini); |
688 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9