用Range Adaptor,废弃replace_copy_if之类的函数

看看replace_copy_if的一个简单的例子:

std::vector<int> vec;

boost::push_back(rng, std::back_inserter(vec), pred);

对于这种写法,如果使用Range Adaptor的话,则可以写成:

std::vector<int> vec;

boost::push_back(vec, rng | boost::adaptors::replaced_if(pred, new_value));

第二种写法有什么好处呢,

1. 更高效率。因为std::back_inserter有额外的内存分配开销。

2. 更灵活。因为第二种写法可以应用更多的适配器,比如: boost::push_back(vec, rng | boost::adaptors::replaced_if(pred, new_value) | boost::adaptors::reversed);

3. 更安全。因为第二种写法没有用unbounded output iterator。

抓包程序的一些分享

昨晚同白总和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 blog.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 blog.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 blog.ykyi.net

设置变量GIT_CURL_VERBOSE可以帮助调试git出错

今天操作git的时候又出错了:

error: Failed connect to github.com:8080; No route to host while accessing https://github.com/zausiu/gryphon/info/refs
fatal: HTTP request failed

 

之前用公司的http代理上git, 

#git config -l

http.proxy=http://web-proxy.oa.com:8080

 

设置变量GIT_CURL_VERBOSE可以看到详细的出错情况:

#export GIT_CURL_VERBOSE=1

# git pull
* Couldn't find host github.com in the .netrc file; using defaults
* About to connect() to proxy web-proxy.oa.com port 8080 (#0)
*   Trying 10.14.36.100…
* 0x23d67b0 is at send pipe head!
* STATE: CONNECT => WAITCONNECT handle 0x23df5f0; (connection #0) 
* No route to host
* Failed connect to github.com:8080; No route to host
* Closing connection #0
* Couldn't find host github.com in the .netrc file; using defaults
* About to connect() to proxy web-proxy.oa.com port 8080 (#0)
*   Trying 10.14.36.100…
* 0x23d67b0 is at send pipe head!
* STATE: CONNECT => WAITCONNECT handle 0x23df5f0; (connection #0) 
* No route to host
* Failed connect to github.com:8080; No route to host
* Closing connection #0
error: Failed connect to github.com:8080; No route to host while accessing https://github.com/zausiu/gryphon/info/refs
fatal: HTTP request failed

copyright blog.ykyi.net

 

 

 

用线上机测试tcpcopy基本通过。支持旧模式,Advanced模式失败

测试结果介绍:

 

tcpcopy在编译期配置成使用NFQueue模式,用Raw Socket抓包。线上机的流量被成功复制并导向测试机。经改动的tcpd初期工作正常。

改动版的tcpd(实际上是一个echo服务器)。测试机上的tcpd把收到的报文被打印到日志文件。但日志文件到6M+大小的时候,就停止打印。目前还没有查到原因,可能是改动后的tcpdBug。此时,tcpdump仍然抓到大量从线上机复制来的真实流量到达测试机。tcpcopy应该是工作正常的。

 

tcpcopy被编译成使用libpcap抓包时不能在线上机上正常工作。tcpdump没有抓到预期从线上机复制到测试机的报文。原因是:线上机10.130.68.100上的真实流量从网络接口tunl0:0进入,从网络接口eth1发出。分析tcpd的日志发现,tcpd使用libpcap只拿到tunl0IP,没有发现tunl0:0IP。需要了解IP隧道,和libpcap库的相关知识,有可能解决这个问题。

 

编译成使用Raw Socket抓包,和Advanced模式时,tcpcopy启动失败,错误日志显示Advanced模式只能使用libpcap库抓包。因此,只有在解决libpcap正确识别tunl0:0网络接口后,才能在线上机上运行tcpcopy

 

预备知识:

Tcpcopy可以编译成用libpcap抓包或者使用Raw Socket抓包。Libpcap库是tcpdump使用的抓包库,Raw Socket是操作系统内建的功能。

官方文档建议用libpcap抓包,以获得更高性能和较低丢包率。

 

Tcpcopy在编译期指定工作模式。tcpcopy目前有两种工作模式,一种使用IPQueue技术或者NFQueue技术。NFQueue技术是用来替代IPQueue技术的。我们目前使用的tlinux,内建了NFQueue内核模块,没有开启IPQueue模块。因为NFQueue是内建的即CONF_XXXXXX = y,而不是编译成模块,即CONF_XXXXX = m, 所以我们在环境中不需要使用modprobe 加载IPQueue或者NFQueue模块。忽略官方文档中提到的modprobe ip_queue

 

测试步骤:

 

使用NFQueue模式:

线上机:10.130.68.100

编译tcpcopy时指定使用NFQueue不要指定 –enable-pcap,则默认使用raw socket抓包。用pcap抓包时识别不到网络接口tunl0:0,而tunl0:0是真实流量的入口。

# ./configure –enable-nfqueue

#./make

生成的tcpcopysrc/tcpcopy 目录下。

运行tcpcopy命令,把流量复制到测试机:

# ./tcpcopy -x 80-10.213.243.156

测试机:10.213.243.156

编译tcpcopy时同样指定–enable-nfqueue,不要指定–enable-pcap。然后运行intercept

# ./intercept

 

使用Advanced模式:

因为暂时未能解决用libpcap识别到网络设备tunel0:0的问题,实际上Advanced模式暂时不能工作。根据以前的使用经验,用Advanced模式时需要注意两点:

1. ./configure时指定 –enable-advaned –enable-pcap

2. Advanced模式需要两台测试机,需要设成一条路由把复制后的真实流量导向测试机。需要更改默认路由:删掉当前的默认路由,新的默认路由从正确的网卡指向测试机2IP

# route del default

# route add default gw 10.213.243.156 dev eth1

copyright blog.ykyi.net