Chinaunix首页 | 论坛 | 博客
  • 博客访问: 528698
  • 博文数量: 120
  • 博客积分: 3030
  • 博客等级: 中校
  • 技术积分: 1445
  • 用 户 组: 普通用户
  • 注册时间: 2006-03-05 01:00
文章存档

2011年(1)

2009年(2)

2008年(32)

2007年(33)

2006年(52)

我的朋友

分类: LINUX

2007-03-19 15:28:59


nf_iterate()函数遍历由i给定的链表,并且对于给定的分组调用链表结点中注册函数进行处理。
335 static unsigned int nf_iterate(struct list_head *head,
336 struct sk_buff **skb,
337 int hook,
338 const struct net_device *indev,
339 const struct net_device *outdev,
340 struct list_head **i,
341 int (*okfn)(struct sk_buff *))
342 {
for循环完成遍历操作。当调用结点中的hook函数后,根据返回值进行相应处理。如果hook函数的返回值是NF_QUEUE,NF_STOLEN,NF_DROP时,函数返回该值;如果返回值是NF_REPEAT时,则跳到前一个结点继续处理;如果是其他值,由下一个结点继续处理。如果整条链表处理完毕,返回值不是上面四个值,则返回NF_ACCEPT。
343 for (*i = (*i)->next; *i != head; *i = (*i)->next) {
344 struct nf_hook_ops *elem = (struct nf_hook_ops *)*i;
345 switch (elem->hook(hook, skb, indev, outdev, okfn)) {
346 case NF_QUEUE:
347 return NF_QUEUE;
348
349 case NF_STOLEN:
350 return NF_STOLEN;
351
352 case NF_DROP:
353 return NF_DROP;
354
355 case NF_REPEAT:
356 *i = (*i)->prev;
357 break;
358
359 #ifdef CONFIG_NETFILTER_DEBUG
360 case NF_ACCEPT:
361 break;
362
363 default:
364 NFDEBUG("Evil return from %p(%u).\n",
365 elem->hook, hook);
366 #endif
367 }
368 }
369 return NF_ACCEPT;
370 }
371
为队列注册处理函数。注册的时候是每一个协议族只注册一个处理函数,如果给定的协议族已经注册了处理函数,则返回出错信息。由于queue_handler是全局结构变量,所以注册时和删除时,要进行加锁保护。
372 int nf_register_queue_handler(int pf, nf_queue_outfn_t outfn, void *data)
373 {
374 int ret;
375
376 br_write_lock_bh(BR_NETPROTO_LOCK);
377 if (queue_handler[pf].outfn)
378 ret = -EBUSY;
379 else {
380 queue_handler[pf].outfn = outfn;
381 queue_handler[pf].data = data;
382 ret = 0;
383 }
384 br_write_unlock_bh(BR_NETPROTO_LOCK);
385
386 return ret;
387 }
388
389 /* The caller must flush their queue before this */
删除给定协议族的队列处理函数。
390 int nf_unregister_queue_handler(int pf)
391 {
392 br_write_lock_bh(BR_NETPROTO_LOCK);
393 queue_handler[pf].outfn = NULL;
394 queue_handler[pf].data = NULL;
395 br_write_unlock_bh(BR_NETPROTO_LOCK);
396 return 0;
397 }
398
399 /*
400 * Any packet that leaves via this function must come back
401 * through nf_reinject().
402 */

nf_queue首先检查给定协议族是否有队列处理函数,如果没有,则无法处理分组,只能丢弃之,然后返回。接着给由skb指定的分组 分配并且附加一个netfilter信息头。如果没有空间,则打印出错信息。这两项工作完成后,调用队列的处理函数处理本分组。如果处理过程中出错,则丢弃分组,并且归还已分配的netfilter信息头空间。
403 static void nf_queue(struct sk_buff *skb,
404 struct list_head *elem,
405 int pf, unsigned int hook,
406 struct net_device *indev,
407 struct net_device *outdev,
408 int (*okfn)(struct sk_buff *))
409 {
410 int status;
411 struct nf_info *info;
412
413 if (!queue_handler[pf].outfn) {
414 kfree_skb(skb);
415 return;
416 }
417
418 info = kmalloc(sizeof(*info), GFP_ATOMIC);
419 if (!info) {
420 if (net_ratelimit())
421 printk(KERN_ERR "OOM queueing packet %p\n",
422 skb);
423 kfree_skb(skb);
424 return;
425 }
426
427 *info = (struct nf_info) {
428 (struct nf_hook_ops *)elem, pf, hook, indev, outdev, okfn };
429
430 /* Bump dev refs so they don't vanish while packet is out */
431 if (indev) dev_hold(indev);
432 if (outdev) dev_hold(outdev);
433
434 status = queue_handler[pf].outfn(skb, info, queue_handler[pf].data);
435 if (status < 0) {
436 /* James M doesn't say [censored] enough. */
437 if (indev) dev_put(indev);
438 if (outdev) dev_put(outdev);
439 kfree(info);
440 kfree_skb(skb);
441 return;
442 }
443 }
444
下面这个函数是netfilter面向内核的关键函数,因为每一个hook对分组的处理,都是通过调用本函数完成的。
445 int nf_hook_slow(int pf, unsigned int hook, struct sk_buff *skb,
446 struct net_device *indev,
447 struct net_device *outdev,
448 int (*okfn)(struct sk_buff *))
449 {
450 struct list_head *elem;
451 unsigned int verdict;
452 int ret = 0;
453
454 /* We may already have this, but read-locks nest anyway */
读加锁,如注释所述,这里的对加锁存在着嵌套。
455 br_read_lock_bh(BR_NETPROTO_LOCK);
456
调试信息
457 #ifdef CONFIG_NETFILTER_DEBUG
458 if (skb->nf_debug & (1 << hook)) {
459 printk("nf_hook: hook %i already set.\n", hook);
460 nf_dump_skb(pf, skb);
461 }
462 skb->nf_debug |= (1 << hook);
463 #endif
464
根据给定的协议组参数和hook值选定响应hook链表。
465 elem = &nf_hooks[pf][hook];
遍历链表,并且处理给定分组,返回值决定分组的命运。
466 verdict = nf_iterate(&nf_hooks[pf][hook], &skb, hook, indev,
467 outdev, &elem, okfn);
将分组排队处理
468 if (verdict == NF_QUEUE) {
469 NFDEBUG("nf_hook: Verdict = QUEUE.\n");
470 nf_queue(skb, elem, pf, hook, indev, outdev, okfn);
471 }
472
473 switch (verdict) {
如果分组可以接受,由后续函数处理。至于这一点请参考本人前面关于netfilter的HOOK之间关系的帖子。
474 case NF_ACCEPT:
475 ret = okfn(skb);
476 break;
477
如果分组不能接受,则丢弃分组
478 case NF_DROP:
479 kfree_skb(skb);
480 ret = -EPERM;
481 break;
482 }
483
释放锁
484 br_read_unlock_bh(BR_NETPROTO_LOCK);
485 return ret;
486 }
487
处理排队的分组,每一个由nf_queue处理的分组,最终都要由nf_reinject处理。
488 void nf_reinject(struct sk_buff *skb, struct nf_info *info,
489 unsigned int verdict)
490 {
491 struct list_head *elem = &info->elem->list;
492 struct list_head *i;
493
494 /* We don't have BR_NETPROTO_LOCK here */
读加锁
495 br_read_lock_bh(BR_NETPROTO_LOCK);
检查将分组传递给用户空间的模块是否存在
496 for (i = nf_hooks[info->pf][info->hook].next; i != elem; i = i->next) {
497 if (i == &nf_hooks[info->pf][info->hook]) {
498 /* The module which sent it to userspace is gone. */
若不存在,则丢弃分组。
499 NFDEBUG("%s: module disappeared, dropping packet.\n",
500 __FUNCTION__);
501 verdict = NF_DROP;
502 break;
503 }
504 }
505 如果给定参数verdict说用户空间可以接收分组,则我们继续处理。
506 /* Continue traversal iff userspace said ok... */
507 if (verdict == NF_REPEAT) {
508 elem = elem->prev;
509 verdict = NF_ACCEPT;
510 }
511
512 if (verdict == NF_ACCEPT) {
513 verdict = nf_iterate(&nf_hooks[info->pf][info->hook],
514 &skb, info->hook,
515 info->indev, info->outdev, &elem,
516 info->okfn);
517 }
518
519 switch (verdict) {
如果处理后,接收分组,由后续函数继续处理
520 case NF_ACCEPT:
521 info->okfn(skb);
522 break;
523
如果需要排队分组,以便发送给用户空间
524 case NF_QUEUE:
525 nf_queue(skb, elem, info->pf, info->hook,
526 info->indev, info->outdev, info->okfn);
527 break;
528
如果需要过滤分组,则丢弃分组
529 case NF_DROP:
530 kfree_skb(skb);
531 break;
532 }
533 br_read_unlock_bh(BR_NETPROTO_LOCK);
534
535 /* Release those devices we held, or Alexey will kill me. */
536 if (info->indev) dev_put(info->indev);
537 if (info->outdev) dev_put(info->outdev);
538
539 kfree(info);
540 return;
541 }
542
netfilter的初始化函数
543 void __init netfilter_init(void)
544 {
545 int i, h;
546
在初始化过程中仅仅
初始化HOOK链表
547 for (i = 0; i < NPROTO; i++) {
548 for (h = 0; h < NF_MAX_HOOKS; h++)
549 INIT_LIST_HEAD(&nf_hooks[h]);
550 }
551 }

阅读(1122) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~