Chinaunix首页 | 论坛 | 博客
  • 博客访问: 250044
  • 博文数量: 88
  • 博客积分: 1429
  • 博客等级:
  • 技术积分: 523
  • 用 户 组: 普通用户
  • 注册时间: 2010-01-18 15:31
文章分类

全部博文(88)

文章存档

2017年(2)

2016年(24)

2013年(1)

2012年(24)

2011年(15)

2010年(22)

我的朋友

分类: LINUX

2017-04-01 08:38:54

原文地址:tcpdump如何获取到包(AF_PACKET) 作者:

strace  tcpdump xx可以看到,最核心的在这里:

socket(PF_PACKET, SOCK_RAW, 768)        = 3

 

从内核中可以看到:

创建PF_PACKET的socket最终会调到packet_create:

  1. // L3 entry的回调函数
  2. po->prot_hook.func = packet_rcv;

  3.        if (proto) { // proto项有设置则添加一个L3 handler entry

  4.                 po->prot_hook.type = proto;

  5.                 dev_add_pack(&po->prot_hook);

  6.                 sock_hold(sk);

  7.                 po->running = 1;

  8.         }

  9.  
  10. // 添加一个L2->l3 entry
  11. void dev_add_pack(struct packet_type *pt)

  12. {

  13.         struct list_head *head = ptype_head(pt);

  14.  

  15.         spin_lock(&ptype_lock);

  16.         list_add_rcu(&pt->list, head);

  17.         spin_unlock(&ptype_lock);

  18. }

  19.  
  20. //根据packet_type中的类型决定放入哪个链表中
  21. static inline struct list_head *ptype_head(const struct packet_type *pt)

  22. {

  23.         if (pt->type == htons(ETH_P_ALL))

  24.                 return &ptype_all;

  25.         else

  26.                 return &ptype_base[ntohs(pt->type) & PTYPE_HASH_MASK];

  27. }

由此可见到:每个AF_PACKET类型的socekt的创建都会在L2->L3的处理表中添加一个handler entry. entry对应的处理函数为packet_rcv.

1)  Protocol类型为ETH_P_ALLntohs后为768, 即所有包,则放入ptype_all链表中

2)  Protocol类型为其他值,则放入ptype_base hash表中。

对于AF_PACKET类型,这里的type就是socekt传入的第三个参数protocolhtons值。

 

L2层向L3层进发。走netif_receive_skb:

会先遍历ptype_all链表,如果入口设备匹配,则每个发一个,然后再走到ptype_base hash表,对匹配的packet_type每个发一个。

  1. list_for_each_entry_rcu(ptype, &ptype_all, list) { //先遍历ptype_all

  2.                 if (ptype->dev == null_or_orig || ptype->dev == skb->dev ||

  3.                     ptype->dev == orig_dev) {

  4.                         if (pt_prev)

  5.                                 ret = deliver_skb(skb, pt_prev, orig_dev);

  6.                         pt_prev = ptype;

  7.                 }

  8.         }

  9.  ….

  10.         list_for_each_entry_rcu(ptype,

  11.                         &ptype_base[ntohs(type) & PTYPE_HASH_MASK], list) {//再遍历ptype_base

  12.                 if (ptype->type == type && (ptype->dev == null_or_orig ||

  13.                      ptype->dev == skb->dev || ptype->dev == orig_dev ||

  14.                      ptype->dev == orig_or_bond)) {

  15.                         if (pt_prev)

  16.                                 ret = deliver_skb(skb, pt_prev, orig_dev);

  17.                         pt_prev = ptype;

  18.                 }

  19.         }

  因此, 如果创建AF_PACKET 套接字, protocol768则抓取所有二层包,如果protocol为指定协议类型(ip or icmp .. ) 则可以只抓取特性L3 protocol的包。

   Tcpdump通过创建AF_PACKET, protocolETH_P_ALLsocket, 可以获取到所有报文,通过sk_filter可以对报文进行过滤。关于sk_filter,详见http://
阅读(1096) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~