抓包程序的一些分享

昨晚同白总和adden提到抓包的问题。因为写过相关的代码,遇到过抓包的各种各样的坑,此文分享一些相关的经验。

 

1. Linux cooked capture

在用tcpdump或wireshark看数据包时,有时会看到数据链路层的的包头称为Linux cooked capture。这不是一个真实的包头,当用tcpdump指定从所有网络介质 -i any 抓包时,所有抓到的包的数据链路层被换成了Linux cooked capture。在wireshark官方网站对Linux cooked capture的解释中: 这是一个在linux上被libpcap抓包库使用的“假协议”(pseudo-protocal),当从“any”设备在抓包,或者本地的数据链路层包头无效时被使用。更多,见http://wiki.wireshark.org/SLL

 

2. IP over IP tunnel

wikipedia的示例图显示IP tunnel上的包的结构是:

但实战中用libpcap库从我们的线上机的IP隧道抓包时,pcap_loop或pcap_dispatch或pcap_next函数返回的数据包只有Inner IP header + IP payload,没有Outer IP headr,也没链路层的头部。多么幸运啊!

 

3. 混乱的RAW_SOCKET,PF_PACKET协议族

这不是工业标准定义的神秘领域,非常之混乱,谨慎进入。如果要写这方面的socket,可供参考。个人经验,用linux原生的socket抓包时,socket()的三的参数如下组合时的神奇效果.

     

        _recv_fd = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_IP));

        从此socket中读所有的IP包,返回的IP包没有链路层包头,因为第二个参数是SOCK_DGRAM,链路层包头返回时被去掉。第三个参数指定的是IP包。奇怪的是,如果出站的IP包的目的地址不是本机,则出站的IP包不会被抓到。

       

        _recv_fd = socket(AF_PACKET , SOCK_RAW , htons(ETH_P_IP));

        和上一个socket的区别是,这个会返回链路层包头。和上一个socket一样,同样只能装到部分出站的包。

      

            _recv_fd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);

        这行代码只可以读入站的包,抓不到出站的包。

 

            _recv_fd = socket(AF_PACKET , SOCK_RAW , htons(ETH_P_ALL));

        这行代码可以抓到所有出站,入站的包,数据链路层包头也被返回。

 

4. 外网进来的IP包有可能很大。

N多年前一般的路由的MTU只有1K多,意味着4K大小的IP会被切成小IP包。现在的网络环境与几年前确实大大提高。从外网入来的IP包会大过4096,当时写程序时放IP包的buffer大小为4096,觉得应该无压力,结果观察到程序崩溃,后定位到是放IP包的缓冲区溢出。后来改成8192,暂时没问题。

copyright ykyi.net

为什么dump生成core文件大小是0

今天程序崩溃了,但是生成的core文件大小是0.

用ulimit -c 查看生成core文件的大小限制是无限unlimited.

也不是磁盘大小和写入权限的问题。

但究竟是什么问题呢?

捣了半天终于搞明白,原来是文件系统造成的。

我是在vmware的虚拟机的debian linux上运行程序,文件系统用的是从host机windows 7挂载到/mnt/hgfs的windows的NTFS文件系统。

后来我把程序转移动linux自己的文件系统,崩溃的时候就生成正常的core dump文件了。

copyright ykyi.net

CDT调试中的追踪点和断点有什么区别。

追踪点(Tracepoint)被当成断点(breakpoint)的一种,但有两个不同点需要注意:

1. 当一个追踪点在一个调试会话中被创建时,它并不种入到二进制代码中,直到用户显式地开始追踪实验。这意味着,创建/修改/删除追踪点并不影响程序,直到追踪真正开始。

2. 简单的创建一个追踪点并不是非常有价值,因为它默认不会收集任何信息。重要的是,把操作(Actions)添加到Tracepoint,这样tracepoint被触发的时候,前面自定义的Action就大有用处了。

来自CDT官网的原文:

Create Tracepoints

Tracepoints are handled as a type of breakpoint. There are two differences to note:

  1. When a tracepoint is created in a debug session, it is not actually planted in the binary code until the user explicitly starts the tracing experiment. This means that creating/modifying/deleting tracepoints does not affect the program until tracing is actually started.
  2. Simply creating a Tracepoint has very limited value as it won't collect any information by default. It is important to add Actions to the Tracepoint to tell it what to do. This will be explained below.

copyright ykyi.net

让eclipse自动生成的注释的时间显示英文,不用中文.

这几天换成用eclipse在windows机器上编写代码,远程运行在linux上,并且在windows机器上远程调试。

新建一个C++类的时候,eclipse/CDT自动生成注释,注释的时间用了中文,并且用的注释风格也不是我想要的。

但我想全部用英文,这个如何解决了。在stackoverflow上找到了答案,并试验成功。

windows -> preferences -> c/c++ -> code style -> code template

在右边的注释模板中编辑File Comment,改成你想要的模式。比如我的:

/*********************************************
 * ${file_name}
 * Author: ${user}
 * Created on: ${date}
 ********************************************/

再在eclipse的安装目录上找到eclipse.ini文件,加入:-Duser.language=en_US

重启eclipse。现在${date}变量生产的日期就是全英文了。

copyright ykyi.net

CPRP和CPT是什么意思,有什么区别

CPRP是Cost Per rating Point的缩写, CPT是cost per thousand的缩写。

举例来说,某一个电视节目的一个商业广告时间槽位(commercial time slot)的价格是$1000,这个电视节目的收视率是10%(program rating),那么CPRP就是$1000除以10,即$100。

而CPT则是广告到达某一个特定人群的花费。

 

copyright ykyi.net

如何从windows远程调试linux程序。

用gdb在远程linux机器上调试程序实在太不方便了。于是想到用eclipse的GUI调试。下面介绍如何从windows远程调试linux程序。

 

 

 

 

1. 在远程linux上安装gdbserver

 

 

2. windows上安装Cygwin或者MinGW。我用Cygwin编译gdb时遇到问题,用MinGW则通过了。但我想Cygwin应该也是可以的.

 

 

3. sourceforge.net上下载expat工程。这是个分析xml文件的开源库。如果跳过这步,也可以,但是gdb不能分析gdbserver发过来的xml文件。 

 

 

4. expat文件夹, ./configure –enable-shared; make; make install

 

 

5. gdb官网下载gdb源代码,解开后运行: ./configure –with-expat –target=x86_64-linux-gnu  –host=i686-pc-mingw32   注意这里的with-expat使得gdb能用解析xml文件的功能,target使得gdb能调试的目标平台的程序,这个字符串可以从l远程inux中运行gdb时开打印出来的声明处得到。Host指定了gdb运行在什么样的平台,这个字符串可以通过运行 ./config.guess 得到。

 

 

6. 然后是make; make install 三板斧。

 

 

7. 现在试一试是否工作正常。在远程linux机器上随便创建一个程序。遵守程序员世界的传统,建个hello world,注意编译时开启 -g 选项。假设源程序是 hello.c, 可执行文件是 hello

 

 

8. 在远程linux端运行 gdbserver :8383 hello 。 8383前有个冒号,8383是端口号,随便取。

 

9. hello.c 和 hello 拷贝到windows机器。

 

 

10. 在控制台介面中,运行 x86_64-linux-gnu-gdb ./Hello。注意前面的gdb名字要相应替换成第5个步骤中编译出来的gdb文件名。

 

11. gdb的控制台交互介面中输入target remote 192.168.44.129:8383 注意把IP换成远程linux机器的IP地址。

12. 试试常用的gdb命令,continue, break, run 什么的。如果能工作就能进入下一步了。

 

13. 创建一个eclipsec/c++工程,源代码则是远程linux机器的源代码.假设工程名也是hello

13. 这一步的目的是在eclipse中创建一个Remote Application Debug configuration。选Run->Debug Configuration在左边选中c/c++ remote application,再点左上角的+号增加一个configuration。在main选项卡的c/c++ application处填windows机上可执行文件hello的路径。Projecteclipsec/c++工程名。 Connection处新建一个连接,类型选linux,其它选项填ssh。我想其它的协议应该也是可以的,但是我用了ssh。 Remote Absolute File path for c/c++ application要填在远程linux机器上启动hello的路径。是否勾上skip download to target path,表示是否在windows机器编译工程然后把编译好的文件上传到远程机器。因为我选择在远程linuxmake,所以我勾选了此项。因你的需求做调整。

 

 

14. Debugger选项卡中把GDB debugger的路填上windows上前面编译出来的gdb的路径。比如我的路径是:D:\MinGW\bin\x86_64-linux-gnu-gdb.exe

 

 

15. 现在就可以用这个Debug configuration远程调试了。

 

 

因为配置远程调试环境涉及到的配置实在太繁杂,如果写一篇考虑所有细节面面俱到的文章太困难了。这篇文章仅把骨干步骤写出,如果读者在实践中遇到各种千奇百怪的问题,需要运用你自己的判断力解决。hope this article helps.

 

copyright ykyi.net