netfilter 函数剖析-1

转载 2005年02月27日 17:14:00

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 }
从下一次开始,我将具体分析net/ipv4/netfilter目录下的文件。

西安交通大学 王灏

相关文章推荐

洞悉linux下的Netfilter&iptables:开发自己的hook函数【实战】(下)

从用户空间来操作内核中Netfilter框架里自定义的HOOK函数          本文承上一篇博客。主要是和大家探讨一下如何从用户空间操作我已经注册到Netfilter中的自定义hook函数。有...

(十六)洞悉linux下的Netfilter&iptables:开发自己的hook函数【实战】(下)

从用户空间来操作内核中Netfilter框架里自定义的HOOK函数          本文承上一篇博客。主要是和大家探讨一下如何从用户空间操作我已经注册到Netfilter中的自定义hook函数。有...

netfilter源码分析(5)- ipt_do_table()函数,数据包的过滤

 netfilter源码分析(5)- ipt_do_table()函数,数据包的过滤             五、 ipt_do_table()函数...

(十五)洞悉linux下的Netfilter&iptables:开发自己的hook函数【实战】(上)

原文出处:http://blog.chinaunix.net/uid-23069658-id-3243434.html

netfilter:开发一个hook函数

一、什么是hook函数     netfilter架构其实就是在一个packet流经系统时的多个关键点处设置了钩子,程序员可以为每一个钩子点注册一个监听器(即钩子函数,就是在packet流经这个钩子...

(十六)洞悉linux下的Netfilter&iptables:开发自己的hook函数【实战】(下)

文章来源:http://blog.chinaunix.net/uid-23069658-id-3245853.html 写文章的这个真大神,完美解决了我的所有问题。 从用户空间来操作内核中Netf...

netfilter(1)

本文参考了http://blog.chinaunix.net/uid-23069658-id-3160506.html和http://blog.chinaunix.net/uid-23069658-i...

(十六)洞悉linux下的Netfilter&iptables:开发自己的hook函数【实战】(下)

原文出处:http://blog.chinaunix.net/uid-23069658-id-3245853.html

Linux协议栈-netfilter(1)-框架

1. netfilter框架 Netfilter 是内核中进行数据包过滤,连接跟踪,地址转换等的主要实现框架。当我们希望过滤特定的数据包或者需要修改特定数据包的某些内容再发送出去,这些动作主要都在n...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)