Chinaunix首页 | 论坛 | 博客
  • 博客访问: 263534
  • 博文数量: 52
  • 博客积分: 1379
  • 博客等级: 大尉
  • 技术积分: 525
  • 用 户 组: 普通用户
  • 注册时间: 2006-06-18 17:34
文章分类

全部博文(52)

文章存档

2011年(48)

2010年(4)

分类: LINUX

2011-03-16 17:03:00

没有分析过代码,很多都是猜测
先有一个例子tcpdump如何抓GET包:
sudo tcpdump  -ni eth0 'ip and tcp and dst port 80 and tcp[(tcp[12:1]&0xf0)>>2:4]=1195725856'


tcpdump:

建一个PF_SOCKET 协议的socket
选择一个接口并bind
把filter 表达式翻译成BPF指令(由libpcap完成, BPF的介绍在  bpf.pdf   中介绍)
setsockopt SO_ATTACH_FILTER 安装filter
收包(很可能是通过mmap来进行的, 曾经有用过,Documemtation/networking/packet_mmap.txt 有介绍)
打印或者写入文件


kernel: af_paket.c
packet_create 调用 dev_add_pack添加一个handler到协议栈入口
网卡驱动收包之后调用
int netif_receive_skb(struct sk_buff *skb);
上协议栈



如果指定了socket指定ETH_P_ALL, 那么dev_add_pack把handler放这
  1. list_for_each_entry_rcu(ptype, &ptype_all, list) {
  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.     }

否则在下面按照协议类型处理


  1. type = skb->protocol;
  2.     list_for_each_entry_rcu(ptype,
  3.             &ptype_base[ntohs(type) & PTYPE_HASH_MASK], list) {
  4.         if (ptype->type == type &&
  5.          (ptype->dev == null_or_orig || ptype->dev == skb->dev ||
  6.          ptype->dev == orig_dev)) {
  7.             if (pt_prev)
  8.                 ret = deliver_skb(skb, pt_prev, orig_dev);
  9.             pt_prev = ptype;
  10.         }
  11.     }
比如ip协议或者arp注册的函数就会在这里处理

即使iptables禁止了,tcpdump也能抓到进来的包

ip注册的函数叫ip_rcv, packet注册的叫packet_rcv
packet_rcv调用run_filter过已经设置好的filter, 它的值作为返回给用户的字节数(默认是96)
run_filter解释执行BPF指令,但是通常效率很高, 有关BPF指令的介绍可以参考bpf.pdf



如果想在程序中抓取特定类型的包, 那么不需要使用libpcap,tcpdump直接翻译一下就可以了
#  tcpdump -dd ip and tcp and dst port 80  -ni eth0
{ 0x28, 0, 0, 0x0000000c },
{ 0x15, 0, 8, 0x00000800 },
{ 0x30, 0, 0, 0x00000017 },
{ 0x15, 0, 6, 0x00000006 },
{ 0x28, 0, 0, 0x00000014 },
{ 0x45, 4, 0, 0x00001fff },
{ 0xb1, 0, 0, 0x0000000e },
{ 0x48, 0, 0, 0x00000010 },
{ 0x15, 0, 1, 0x00000050 },
{ 0x6, 0, 0, 0x00000060 },
{ 0x6, 0, 0, 0x00000000 },
把这个写入到C代码中就可以用了
tcpdump -d ip and tcp and dst port 80  -ni eth0可以看出这些指令的细节
(000) ldh      [12] 协议2字节
(001) jeq      #0x800           jt 2    jf 10  // ipv4 下面其它的根据协议头部很容易理解了
(002) ldb      [23]
(003) jeq      #0x6             jt 4    jf 10
(004) ldh      [20]
(005) jset     #0x1fff          jt 10    jf 6
(006) ldxb     4*([14]&0xf)
(007) ldh      [x + 16]
(008) jeq      #0x50            jt 9    jf 10
(009) ret      #96
(010) ret      #0

开头那个例子表明filter expression可以很复杂 参考  expr_bpf.pdf  
ip and tcp and dst port 80 and tcp[(tcp[12:1]&0xf0)>>2:4]=1195725856

ipv4                                            payload tcp[tcp headlen "(>> 4) *4"  == ">>2": 4b] = "GET "

阅读(4924) | 评论(0) | 转发(0) |
0

上一篇:pthread_cancel与取消点

下一篇:咸盐名句

给主人留下些什么吧!~~