让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

 

 

设置变量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 ykyi.net

 

 

 

packet captured和packet received by filter到底有什么区别

我用的是linux. 结论是 packet received by filter是tcpdump从内核中拿到的且匹配命令上行指定的过滤条件的包, packet captured是经由pcap_loop, 或 pcap_dispatch 或 pcap_next,把包交给回调处理过的包的数量。这两个数字的差值是tcpdump抓到的,还来不及处理的包。

下面是讨论的一些细节:

/////////////

tcpdump的最后输出. 592个包captured,  1184个包received by filter。。这个差值是不是表示有多少包tcpdump没来得及处理.

man tcpdump上写得好复杂,received by filter的数字取决于OS… 1. 包匹配不匹配命令行上指定的filter都算,如果匹配,有没有被tcpdump读出都算..   2. 只有匹配命令行上指定的filter的包才算,有没有被tcpdump读出都算.   3. 只有匹配filter才算,只有被tcpdump读出才算.

我的理解是:如果是第3种,那captured的数字和received by filter的数字就是一样的。 第2种的差值表示tcpdump来不及处理的包数量,理想状态上差值能为0.   第1种情况,基本上总是有差值。

我猜测我用的linux上应该是第2种情况. 

wangbin579() 10:18:54 
应该是匹配的才算received by filter,但奇怪的是,为啥你的系统,captured怎么少?
wangbin579() 10:19:30 
[root@hz0-12-157 ~]# tcpdump -i any tcp and port 36524 or 3306 -w all.pcap
tcpdump: listening on any, link-type LINUX_SLL (Linux cooked), capture size 65535 bytes
10757 packets captured
11171 packets received by filter
334 packets dropped by kernel
wangbin579() 10:20:07 
我们这边系统,基本可以认为packets received by filter=packets captured + packets dropped by kernel

siu¹ººººººº() 10:23:38 
/homemus/tmp # time time tcpdump -i tunl0:1  -w tmp
tcpdump: listening on tunl0:1, link-type RAW (Raw IP), capture size 96 bytes
19508 packets captured
39021 packets received by filter
0 packets dropped by kernel
0.01user 0.02system 0:17.04elapsed 0%CPU (0avgtext+0avgdata 0maxresident)k
0inputs+0outputs (0major+506minor)pagefaults 0swaps

real    0m17.139s
user    0m0.012s
sys     0m0.028s
wangbin579() 10:26:03 
如果是差是丢包,那么通过查看抓包文件,应该能看出很多不完整的session
siu¹ººººººº() 10:28:46 
我觉得差值是来不及写入磁盘的包.
siu¹ººººººº() 10:29:04 
再研究看看了。。谢谢啦/..
wangbin579() 10:30:03 
packets captured是pcap_loop所设置的回调函数所调用的,一旦调用回调函数,就用统计
wangbin579() 10:30:37 
有可能内核态部分和用户态部分,速度上不匹配,有延迟导致的?
siu¹ººººººº() 10:32:33 
我现在理解, received by filter是pcap库从内核中拿到的又匹配命令行上filter的包的数量, packets captured是经由pcap_loop, pcap_dispatch之类通过callback交付出去的包数量. 差值就是还没来得及处理的.
wangbin579() 10:32:48 
17s,每秒也就2000多个,不算多,用户态程序应该来得及处理

wangbin579() 10:33:58 
我这边系统很破,处理速度也比这个快,也没有来不及处理
wangbin579() 10:34:45 
看看我的:
wangbin579() 10:34:47 
[root@hz0-12-157 ~]# time tcpdump -i any tcp and port 36524 or 3306 -w 3306.pcap         
tcpdump: listening on any, link-type LINUX_SLL (Linux cooked), capture size 65535 bytes
294663 packets captured
295432 packets received by filter
693 packets dropped by kernel

real    0m17.676s
user    0m0.897s
sys     0m3.502s
wangbin579() 10:35:52 
量比你大7倍多,也没有出现来不及处理啊,当然我的是物理机,3G内存,
siu¹ººººººº() 10:36:59 
 那你觉得这个差值不是来不及处理的包么?。我觉得应该还是来不及处理的。我在想,可能是写到的磁盘文件系统是NFS之类的 ….我继续排查一下。
wangbin579() 10:37:43 
有可能,我的是写入本地磁盘。
wangbin579() 10:37:58 
你这种情况,我还是第一次碰到
siu¹ººººººº() 10:39:05 
我先去运维那边了解下情况…多谢啦 
wangbin579() 10:39:18 
算涨见识了,还以为一般dropped by kernel为0就代表不丢包呢,居然还有你这种情况。
你可以看看抓包文件,session是不是很多不完整,如果不完整,你的推测是对的
siu¹ººººººº() 10:39:58 
嗯。呵呵~~ 做IT,每天都会碰到挑战宇宙规律的现象。
siu¹ººººººº() 10:40:07 

мe(~ o мe(632813052) 10:41:09 
呵呵
wangbin579() 10:41:24 
其实,网络方面的问题,最复杂了。
我现在已经陷入到网络的汪洋大海之中了,各种各样的问题都会有,而且没有尽头。
早知道如此,3年前我就不搞这一块了
siu¹ººººººº() 10:42:30 
同感。写一点点代码,都非常难以调试。各种认为理所当然的假设,通通是bug的温床

@wangbin579  麻烦你在tcpdump前加个time,。。把输出贴出来。我好像看出问题来了。

[root@hz0-12-157 ~]# time tcpdump -i any tcp and port 36524 or 3306 -w 3306.pcap         
tcpdump: listening on any, link-type LINUX_SLL (Linux cooked), capture size 65535 bytes
294663 packets captured
295432 packets received by filter
693 packets dropped by kernel

real    0m17.676s
user    0m0.897s
sys     0m3.502s
wangbin579() 10:56:03 
不是加了time了吗?
wangbin579() 10:57:15 
[root@hz0-12-157 ~]# time time tcpdump -i any tcp and port 36524 or 3306 -w 3306.pcap
tcpdump: listening on any, link-type LINUX_SLL (Linux cooked), capture size 65535 bytes
^C202061 packets captured
202523 packets received by filter
369 packets dropped by kernel
0.66user 2.50system 0:11.99elapsed 26%CPU (0avgtext+0avgdata 24208maxresident)k
0inputs+105656outputs (0major+660minor)pagefaults 0swaps

real    0m11.999s
user    0m0.661s
sys     0m2.506s
wangbin579() 10:57:26 
加两个,结果如上
siu¹ººººººº() 10:59:29 
问题找到的。我这边运行的tcpdump,根本就没有抢到cpu时间来处理.
wangbin579() 11:00:05 

siu¹ººººººº() 11:00:06 

Real  0m3.914s

User  0m0.008s

Sys   0m0.000s

跑了4秒钟,用户空间才抢到0.008秒,内核态几乎是0 ….
siu¹ººººººº() 11:00:25 
那个差值确实是没有来得及处理的包的数量。
wangbin579() 11:00:41 
奥,那你系统这么繁忙啊

siu¹ººººººº() 11:02:22 
所以,解决了一个问题又会有新的颠覆宇宙规律的问题…系统负载很高,但cpu使用率很低。。

copyright ykyi.net

 

昨天解决了tcpcopy的一个小却很重要的bug.

tcpcopy的基础函数有个bug,流量比较大的时候,内核buffer满了。send系统调用发不完用户缓冲中的数据才会出现。然后加入了tcpcopy的QQ群,和作者稍稍讨论了一点时间。问了关于写论文和tc_session.c过于复杂的问题。

(wangb) 10:00:55 
https://github.com//tcpcopy/pull/162
(wangb) 10:01:04 
The bug arises when send system call returns with part of data transfered
and part of data still need to be sent again.
(wangb) 10:01:13 
常见于压力比较大的场合
(wangb) 10:02:14 
当然如果系统参数设置好的话,这样的情况不常见。这也是为啥我这边无法重现的原因所在
(wangb) 10:02:46 
当然昨天在开发gryphon,貌似遇到过一次
(wangb) 10:03:06 
gryphon给的压力,有时候真不是一般快和大
siu1ooooooo(16236914) 10:03:14 
我在tcpcopy上作二次开发。碰到了个bug,最后追踪到了 tc_socket_send函数。
siu1ooooooo(16236914) 10:03:52 
流量比较大的时候,内核buffer满了。send系统调用发不完用户缓冲中的数据才会出现。
siu1ooooooo(16236914) 10:05:21 
希望能贡献更多代码的。。但是tc_session.c这个模拟tcp状态机的代码太难看懂了。
(wangb) 10:05:49 
有些bug,程序员自身很难发现,往往需要依赖于用户的反馈,当然有上面的bug提出,就更好了
tc_session.c这个模拟tcp状态机,其实不仅模拟tcp状态机,而为复杂的是模拟上层应用交互
光模拟tcp状态机,是远远不够的
siu1ooooooo(16236914) 10:07:27 
有个想法, 把TCP的11个标准状态加入到tc_session中。可不可以做的。.
(wangb) 10:09:13 
数据是死的,但测试服务器是活的。应该可以吧,但加入可能会更复杂。tc_session.c这个会进一步改进的,代码需简化和功能需独立,使其易懂
siu1ooooooo(16236914) 10:09:31 
🙂
(wangb) 10:10:33 
2010~2012.5月,初步探索阶段;2012.5~2014.5,为进一步探索阶段 2014.5~以后,进一步优化
因为tcpcopy刚开始,开发人员是无法知道复杂的互联网的各种应用的特性的,只有积累到一定程度,才能进一步优化。与其说是开发,不如说是探索
siu1ooooooo(16236914) 10:12:10 
期待工程paper  
siu1ooooooo(16236914) 10:12:43 
tcpcopy稳定到了一个版本。先别加功能了。写paper吧  
siu1ooooooo(16236914) 10:13:01 
投中EI应该问题不大。
siu1ooooooo(16236914) 10:13:55 
中了paper,贡献者会迅速增多。
wangb() 10:15:43 
其实写过sigcomm论文,但被拒,说应该投USENIX ATC
wangb() 10:16:18 
I don't think that the research contribution of the paper is a good match for Sigcomm. Perhaps it would be a better match for 
a more practice-oriented conference like USENIX ATC. 
siu1ooooooo(16236914) 10:16:50 
后来呢
wangb() 10:17:05 
确实,tcpcopy是基于实践的,从实践中摸索爬行的。后来我就先不写论文了
siu1ooooooo(16236914) 10:17:22 
嗯。这是个工程实践性很强的探索啊
wangb() 10:17:27 
要写论文,必须要有条件
siu1ooooooo(16236914) 10:17:45 
喔。
wangb() 10:18:06 
从交换机或者其它设备。镜像过来,这样测试系统和在线系统就没有关联,这样的论文是能够中USENIX ATC

wangb() 10:19:13 
tcpcopy最高端的应用,就是在交换机,利用分光镜或者其它镜像设备,利用高性能硬件,把用户的请求数据包复制给测试系统,可惜我没有这样的条件
wangb() 10:19:38 
要是有这样的条件,我肯定要写论文了
siu1ooooooo(16236914) 10:19:55 
呃。。没怎么看懂  
siu1ooooooo(16236914) 10:21:49 
是说复制的流量要非常非常大才能中论文么
siu1ooooooo(16236914) 10:21:59 
而非常大的流量需求硬件支持
wangb() 10:22:02 
twitter梦想的测试环境,其实完全可以用我们的tcpcopy来实现。交换机上面不是有来来往往的数据包吗?在那上面把请求数据包镜像到测试系统,测试系统搭一个跟在线类似的完整系统,这样测试系统跟在线系统承受类似的压力
wangb() 10:22:17 
高端大气,才能中论文
wangb() 10:22:48 
屌丝环境,写论文,还不被批啊
siu1ooooooo(16236914) 10:23:14 
呃。是 。。。明白了。。想起以前学校的事情,懂了。
wangb() 10:24:38 
总之,tcpcopy值得你去研究,期望有更多接班人把思想传承下去,代码可以推掉重来
wangb() 10:25:10 
只要tcp协议还存在,这个思想,应该是最先进的,无法再先进了
siu1ooooooo(16236914) 10:26:11 
需要好多的开发时间啊。..嗯。先上班了啊。多谢wangbin….
wangb() 10:27:16 
慢慢来,这方面反正国外没有人做

copyright ykyi.net

为什么我的名字没有出现在github的contributor列表中.

为什么我没有出现在github.com的contributor列表中.

我提交了commit,但为什么我没有出现在贡献者列表中呢。有三个原因:

1. 检查你的commit中的邮箱信息,这个邮箱必须和你的github.com账号关联。怎么关联邮箱账号呢。先选择Account Setting, 在左边先Emails,于是就看到可以verify邮箱地址的页面了。关联邮箱地址后还有过一段时间,贡献者列表才会更新。

2. 如果工程的贡献者名单列表超过了100个。就不会显示100个以后的贡献者了。官方HELP中说这是为了性能的考量。我觉得是码农偷懒,必竟这个需求太小了。绝大多数工程不会超过100个贡献者,于是码农不想解决这个小问题。

3. 你的commit必须被提交到工程的默认分支上。如果提交到其它的分支上,你的名字就不会被显示。

 

为什么我没有出现在github.com的contributor列表中.

我提交了commit,但为什么我没有出现在贡献者列表中呢。有三个原因:

1. 检查你的commit中的邮箱信息,这个邮箱必须和你的github.com账号关联。怎么关联邮箱账号呢。先选择Account Setting, 在左边先Emails,于是就看到可以verify邮箱地址的页面了。关联邮箱地址后还有过一段时间,贡献者列表才会更新。

2. 如果工程的贡献者名单列表超过了100个。就不会显示100个以后的贡献者了。官方HELP中说这是为了性能的考量。我觉得是码农偷懒,必竟这个需求太小了。绝大多数工程不会超过100个贡献者,于是码农不想解决这个小问题。

3. 你的commit必须被提交到工程的默认分支上。如果提交到其它的分支上,你的名字就不会被显示。

 

copyright ykyi.net

 

 

 

如何删掉github上的master分枝.

假设,代码已经被clone到了本地。第一步要做的就是创建一个新的分支,比如placeholder,然后用-D从本地删除master分支。

git branch placeholder
git checkout placeholder
git branch -D master

如果现在删除github上的master,会报错:

git push origin :master

报错结果大概是这样:

remote: error: refusing to delete the current branch: refs/heads/master
To git@github.com:matthew-brett/datarray.git
! [remote rejected] master (deletion of the current branch prohibited)
error: failed to push some refs to 'git@github.com:matthew-brett/datarray.git'

正确地做法是先checkout到新建的placeholder分支。然后把placeholder推送到github上。

git checkout placeholder # if not on placeholder already
git push origin placeholder

从github的web端入到工程的setting界面,有个地方可以更改默认的分支,用另一个分支做默认分支,而不是master。现在就可以从删掉master了

git push origin :master

另,怎么给github上一个tag更名等:

1) 删除本地的一个tag: git tag -d v0.4
2) 删除GitHub上一个tag (这会删除掉下载链接): git push origin :v0.4
3) 给当前branch打标签: git tag -a v0.5 -m "Version 0.5 Stable"
4) 把所有tag推上github(two dashes): git push --tags

copyright ykyi.net

tcpcopy在视频广告组的二次开发

1.

流量筛选中的 “只导入某频道的流量”功能已经实现了。

技术层面上,实际上是通过指定正则式的方法匹配HTTP请求中的GET方法中的URL来达到过滤的目的。

所以,也可以用ty,ad_type, pf, coverid, oadid, v,plugin等出现在GET方法中的参数编写正则式来过滤流量。

 

2.

流量筛选中的“地域纬度筛选”暂时没有实现。

因为地域纬度的信息不是以参数形式出现在GET方法的URL中,需要通过IP地址或者cookie的中QQ号信息来判断。

还没最终决定是否实现这个功能。

 

3.

tcpcopy官方版本主要的应用场景是复制实时流量。所以部署的时候至少两台机器,一台线上机,另一台测试用机。为了方便压力测试,还引入了至少三台机器的高级模式。

部署起来比较麻烦。

如果“视频CPM广告的模拟投放,以及订单效果预估“只是从磁盘中读入以往的流量,针对这种场景,可以探索tcpcopy的单机离线模式,做到方便部署和使用。

 

4. 部分同学有一个误解.

"将线上的实际访问流量,复制一份保存到本地服务器,用于后续使用"

目前,tcpcopy的官方的版本没有把流量保存下来的功能,保存流量这个目前是用tcpdump的-w选项来做的。

 

另外,技术上,tcpdump只能在IP层和TCP层指定过滤条件,不能用业务的逻辑过滤流量。第1点提到的流量筛选工作在tcpcopy读入实时流量时,或者从tcpdump存下的文件中读入流量时,在应用层指定过滤条件。

copyright ykyi.net

Linux抓包技术简介

Linux抓包技术简介

Author: zausiu@gmail.com

1. 简介

大多数应用常景下,我们在IP层上用AF_INET或AF_INET6作为socket的第一个参数,SOCK_STREAM或SOCK_DGRAM作为socket的第二个参数创建最为常见的IPv4或IPv6的TCP或UDP套接字。这样的套接字满足了绝大多数网络应用常景。

 

本文简单介绍三种Linux平台下抓包,截获包的技术。它们提供一些更酷的功能。每种技术的水都很深,作者个人水平有限,按照自己的理解做一般的介绍。仅仅旨在起到科谱的作用。

 

2. RAW SOCKET

参数SOCK_RAW可以作为socket函数的第二个参数传入,这样创建的套接字称为原始套接字。设置Socket的第一个参数可以让指定原始套接字开在数据链路层上或者网络层。

 

下面的语句创建在数据链路层上的原始socket。

Socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));  

在负载不大的情况下,读这个socket可以拿到本机收到的所有数据包。写入这个socket需要程序员负责填充各种包头的数据。

 

Socket(AF_INET, SOCK_RAW, xxxxx协议号);

在IP层上创建IPv4的RAW socket,可以拿到各种经由IPv4的数据包,比如ICMP包,IGMP包等。Steven的<Unix网络编程>第三版第28.4节,第二段:“系统收到的UDP包和TCP包不会传给原始套接字”。但读tcpcopy的源代码时,确实用了原始套接字在网络层读UDP和TCP包。难道书上写的过时了。见代码,来自tcpcopy:

#if (TCPCOPY_UDP)

        fd = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);

#else

        fd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);

#endif

另外,在IP层上创建的原始套接字有一个选项:IP_HDRINCL,它被开启时,则内核帮助填充IP包头。Linux默认没有开启这个选项。

 

3. NF_Queue

NF_Queue是用户空间的一个库,需要内核模块NETFILTER_NETLINK_QUEUE的支持。官方网址:http://www.netfilter.org。通过这个库可以在数据包被发往用户空间处理前截获数据包,或者在数据包被发往网卡前截获数据库。截获后,可以修改数据包的内容,并决定是否丢充这个数据库。

NF_Queue可以用来编写防火墙等安全软件。

Tcpcopy使用NF_Queue丢弃测试中的程序回复给真实客户程序的数据包,使测试中程序回复的报文不影响真实客户程序。

另一个提供类似功能的库是IP_Queue,它已经被废弃。NF_Queue可以完全取代IP_Queue。我们用的tlinux,内核中built-in了NF_Queue模块。

 

4. libpcap

大名鼎鼎的Libpcap是一个古老的可以工作在所有Unix-like平台上的抓包库,比linux年纪更大。Tcpdump的广泛使用让libpcap成为事实上的行业标准。它可以很方便的编写抓取数据链路层上的数据包,并可以设置过滤条件在内核级别只复制关心的数据包,而数据链路层上的原始套接字会尽最大努力复制所有的包,所以libpcap的工作效率高。而且,pcap使用方便。下面是一个很简单的使用pcap抓到发往80端口的tcp包并打印源IP,目的IP,和目的端口号的程序。非常短,很容易看,起到介绍libpcap的作用。

 int main(int argc, char *argv[])

 {

pcap_t *handle; // pcap用的句柄,和其它各种句柄一样。

char *dev;         // 网络接口名,如eth0, eth1, tunl0 之类

char errbuf[PCAP_ERRBUF_SIZE]; // 存描述出错原因的缓冲

struct bpf_program fp;         // pcap用来过滤数据包用

char filter_exp[] = "tcp and dst port 80"; // 过滤字符串,和tcpdump的写法一样

struct pcap_pkthdr header;      // pcap自己用的包头

const u_char *packet;         // pcap包头后的数据,即抓到的数据

 

int len_of_iphdr;         // ip头的长度

struct in_addr src_ip;    // 源IP地址

struct in_addr dst_ip;    // 目的IP

const u_char *ip_hdr_addr; // IP头的首地址

const u_char *tcp_hdr_addr;     // tcp头的首地址

struct tcphdr *tcp_hdr;         // tcp头结构体

u_short dst_port;             // 目的端口

 

// 如果命令行指定网卡名

if (argv[1])

dev = argv[1]; //就用指定的网卡

else

dev = "eth0"; //否则用eth0

 

}

        

        // 用pcap打开这个网卡

handle = pcap_open_live(dev, BUFSIZ, 0, 1000, errbuf);

if (handle == NULL) {  // 打开网卡出错

fprintf(stderr, "Couldn't open device %s: %s\n", dev, errbuf);

return(2);

}

      

        // 编译过滤文件

if (pcap_compile(handle, &fp, filter_exp, 0, net) == -1) {

fprintf(stderr, "Couldn't parse filter %s: %s\n", filter_exp, pcap_geterr(handle));

return(2);

}

        // 设置过滤条件

if (pcap_setfilter(handle, &fp) == -1) {

fprintf(stderr, "Couldn't install filter %s: %s\n", filter_exp, pcap_geterr(handle));

return(2);

}

 

        // 抓包

packet = pcap_next(handle, &header);

 

// 至此packet指向抓到的一个目标端口号是80的数据链路层的包

// 它的包结构是 14字节以太网包头 + 可变IPv4包头 + TCP包头

ip_hdr_addr = (u_char*)(packet + sizeof(struct ethernet_hdr));

src_ip.s_addr = ((struct iphdr*)ip_hdr_addr)->saddr;

dst_ip.s_addr = ((struct iphdr*)ip_hdr_addr)->daddr;

len_of_iphdr = ((struct iphdr*)ip_hdr_addr)->ihl * 4;

tcp_hdr_addr = ip_hdr_addr + len_of_iphdr;

tcp_hdr = (struct tcphdr*)tcp_hdr_addr;

dst_port = tcp_hdr->dest;

 

// 经过上面的各种指针偏移,下面打印源IP和目标IP和目标端口.

printf("src addr %s\n", inet_ntoa(src_ip));

printf("dst addr %s\n", inet_ntoa(dst_ip));

printf("dst_port %d\n", ntohs(dst_port));

 

/* And close the session */

pcap_close(handle);

 

return(0);

 }

 

5. 总结

本文只是一个非常简单的介绍。如需要进阶学习,Stevens的网络编译有更详细地关于Raw Socket的内容,研究NF_Queue技术则需要读源代码和收集散在社区各个角落的资料了,而讲libpcap有两篇很好的文章:

"Programming with Libpcap – Sniffing the network from our own application "用Libpcap编程,在我们的程序中嗅探网络。非常漂亮的pdf文档。

http://recursos.aldabaknocking.com/libpcapHakin9LuisMartinGarcia.pdf

The Sniffer’s Guide to Raw Traffic 嗅探器教程。斯坦福大学的Geek于大概2001年写的。

http://yuba.stanford.edu/~casado/pcap/section1.html

copyright ykyi.net