<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Libpcap on kamuszhou&#39;s blog</title>
    <link>https://ykyi.net/tags/libpcap/</link>
    <description>Recent content in Libpcap on kamuszhou&#39;s blog</description>
    <generator>Hugo</generator>
    <language>zh-cn</language>
    <lastBuildDate>Thu, 26 Dec 2013 02:13:56 +0000</lastBuildDate>
    <atom:link href="https://ykyi.net/tags/libpcap/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>抓包程序的一些分享</title>
      <link>https://ykyi.net/?p=1102/</link>
      <pubDate>Thu, 26 Dec 2013 02:13:56 +0000</pubDate>
      <guid>https://ykyi.net/?p=1102/</guid>
      <description>&lt;p&gt;&lt;span style=&#34;font-size:14px;&#34;&gt;昨晚同白总和adden提到抓包的问题。因为写过相关的代码，遇到过抓包的各种各样的坑，此文分享一些相关的经验。&lt;/span&gt;&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;font-size:14px;&#34;&gt;&lt;strong&gt;1. Linux cooked capture&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;font-size:14px;&#34;&gt;在用tcpdump或wireshark看数据包时，有时会看到数据链路层的的包头称为Linux cooked capture。这不是一个真实的包头，当用tcpdump指定从所有网络介质 -i any 抓包时，所有抓到的包的数据链路层被换成了Linux cooked capture。在wireshark官方网站对Linux cooked capture的解释中: 这是一个在linux上被libpcap抓包库使用的“假协议”(pseudo-protocal)，当从“any”设备在抓包，或者本地的数据链路层包头无效时被使用。更多，见&lt;a href=&#34;http://wiki.wireshark.org/SLL&#34;&gt;&lt;a href=&#34;http://wiki.wireshark.org/SLL&#34;&gt;http://wiki.wireshark.org/SLL&lt;/a&gt;&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;font-size:14px;&#34;&gt;&lt;strong&gt;2. IP over IP tunnel&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;font-size:14px;&#34;&gt;wikipedia的示例图显示IP tunnel上的包的结构是：&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;font-size:14px;&#34;&gt;&lt;img loading=&#34;lazy&#34; decoding=&#34;async&#34; class=&#34;alignnone&#34; height=&#34;100&#34; src=&#34;http://upload.wikimedia.org/wikipedia/en/thumb/2/2d/IPTunnelDiagram_01-12-07.jpg/300px-IPTunnelDiagram_01-12-07.jpg&#34; width=&#34;300&#34; /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;font-size:14px;&#34;&gt;但实战中用libpcap库从我们的线上机的IP隧道抓包时，pcap_loop或pcap_dispatch或pcap_next函数返回的数据包只有Inner IP header + IP payload，没有Outer IP headr，也没链路层的头部。多么幸运啊！&lt;/span&gt;&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;font-size:14px;&#34;&gt;&lt;strong&gt;3. 混乱的RAW_SOCKET，PF_PACKET协议族&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;font-size:14px;&#34;&gt;这不是工业标准定义的神秘领域，非常之混乱，谨慎进入。如果要写这方面的socket，可供参考。个人经验，用linux原生的socket抓包时，socket()的三的参数如下组合时的神奇效果.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;font-size:14px;&#34;&gt;     &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;font-size:14px;&#34;&gt;        _recv_fd = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_IP));&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;font-size:14px;&#34;&gt;        从此socket中读所有的IP包，返回的IP包没有链路层包头,因为第二个参数是SOCK_DGRAM，链路层包头返回时被去掉。第三个参数指定的是IP包。奇怪的是，如果出站的IP包的目的地址不是本机，则出站的IP包不会被抓到。&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;font-size:14px;&#34;&gt;       &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;font-size:14px;&#34;&gt;        _recv_fd = socket(AF_PACKET , SOCK_RAW , htons(ETH_P_IP));&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;font-size:14px;&#34;&gt;        和上一个socket的区别是，这个会返回链路层包头。和上一个socket一样，同样只能装到部分出站的包。&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;font-size:14px;&#34;&gt;      &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;font-size:14px;&#34;&gt;            _recv_fd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;font-size:14px;&#34;&gt;        这行代码只可以读入站的包，抓不到出站的包。&lt;/span&gt;&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;&lt;span style=&#34;font-size:14px;&#34;&gt;            _recv_fd = socket(AF_PACKET , SOCK_RAW , htons(ETH_P_ALL));&lt;/span&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Linux抓包技术简介</title>
      <link>https://ykyi.net/?p=1006/</link>
      <pubDate>Tue, 10 Sep 2013 05:05:03 +0000</pubDate>
      <guid>https://ykyi.net/?p=1006/</guid>
      <description>&lt;div&gt;
  &lt;p&gt;
    Linux抓包技术简介
  &lt;/p&gt;
  &lt;p&gt;
    Author: zausiu@gmail.com
  &lt;/p&gt;
  &lt;p&gt;
    1.&amp;nbsp;简介
  &lt;/p&gt;
  &lt;p&gt;
    大多数应用常景下，我们在IP层上用AF_INET或AF_INET6作为socket的第一个参数，SOCK_STREAM或SOCK_DGRAM作为socket的第二个参数创建最为常见的IPv4或IPv6的TCP或UDP套接字。这样的套接字满足了绝大多数网络应用常景。
  &lt;/p&gt;
  &lt;p&gt;
    &amp;nbsp;
  &lt;/p&gt;
  &lt;p&gt;
    本文简单介绍三种Linux平台下抓包，截获包的技术。它们提供一些更酷的功能。每种技术的水都很深，作者个人水平有限，按照自己的理解做一般的介绍。仅仅旨在起到科谱的作用。
  &lt;/p&gt;
  &lt;p&gt;
    &amp;nbsp;
  &lt;/p&gt;
  &lt;p&gt;
    2.&amp;nbsp;RAW&amp;nbsp;SOCKET
  &lt;/p&gt;
  &lt;p&gt;
    参数SOCK_RAW可以作为socket函数的第二个参数传入，这样创建的套接字称为原始套接字。设置Socket的第一个参数可以让指定原始套接字开在数据链路层上或者网络层。
  &lt;/p&gt;
  &lt;p&gt;
    &amp;nbsp;
  &lt;/p&gt;
  &lt;p&gt;
    下面的语句创建在数据链路层上的原始socket。
  &lt;/p&gt;
  &lt;p&gt;
    Socket(AF_PACKET,&amp;nbsp;SOCK_RAW,&amp;nbsp;htons(ETH_P_ALL));&amp;nbsp;&amp;nbsp;
  &lt;/p&gt;
  &lt;p&gt;
    在负载不大的情况下，读这个socket可以拿到本机收到的所有数据包。写入这个socket需要程序员负责填充各种包头的数据。
  &lt;/p&gt;
  &lt;p&gt;
    &amp;nbsp;
  &lt;/p&gt;
  &lt;p&gt;
    Socket(AF_INET,&amp;nbsp;SOCK_RAW,&amp;nbsp;xxxxx协议号)；
  &lt;/p&gt;
  &lt;p&gt;
    在IP层上创建IPv4的RAW&amp;nbsp;socket，可以拿到各种经由IPv4的数据包，比如ICMP包，IGMP包等。Steven的&lt;Unix网络编程&gt;第三版第28.4节，第二段：&amp;ldquo;系统收到的UDP包和TCP包不会传给原始套接字&amp;rdquo;。但读tcpcopy的源代码时，确实用了原始套接字在网络层读UDP和TCP包。难道书上写的过时了。见代码，来自tcpcopy：
  &lt;/p&gt;
  &lt;p&gt;
    #if&amp;nbsp;(TCPCOPY_UDP)
  &lt;/p&gt;
  &lt;p&gt;
    &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;fd&amp;nbsp;=&amp;nbsp;socket(AF_INET,&amp;nbsp;SOCK_RAW,&amp;nbsp;IPPROTO_UDP);
  &lt;/p&gt;
  &lt;p&gt;
    #else
  &lt;/p&gt;
  &lt;p&gt;
    &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;fd&amp;nbsp;=&amp;nbsp;socket(AF_INET,&amp;nbsp;SOCK_RAW,&amp;nbsp;IPPROTO_TCP);
  &lt;/p&gt;
  &lt;p&gt;
    #endif
  &lt;/p&gt;
  &lt;p&gt;
    另外，在IP层上创建的原始套接字有一个选项：IP_HDRINCL，它被开启时，则内核帮助填充IP包头。Linux默认没有开启这个选项。
  &lt;/p&gt;
  &lt;p&gt;
    &amp;nbsp;
  &lt;/p&gt;
  &lt;p&gt;
    3.&amp;nbsp;NF_Queue
  &lt;/p&gt;
  &lt;p&gt;
    NF_Queue是用户空间的一个库，需要内核模块NETFILTER_NETLINK_QUEUE的支持。官方网址：&lt;a href=&#34;http://www.netfilter.org/&#34;&gt;http://www.netfilter.org&lt;/a&gt;。通过这个库可以在数据包被发往用户空间处理前截获数据包，或者在数据包被发往网卡前截获数据库。截获后，可以修改数据包的内容，并决定是否丢充这个数据库。
  &lt;/p&gt;
  &lt;p&gt;
    NF_Queue可以用来编写防火墙等安全软件。
  &lt;/p&gt;
  &lt;p&gt;
    Tcpcopy使用NF_Queue丢弃测试中的程序回复给真实客户程序的数据包，使测试中程序回复的报文不影响真实客户程序。
  &lt;/p&gt;
  &lt;p&gt;
    另一个提供类似功能的库是IP_Queue，它已经被废弃。NF_Queue可以完全取代IP_Queue。我们用的tlinux，内核中built-in了NF_Queue模块。
  &lt;/p&gt;
  &lt;p&gt;
    &amp;nbsp;
  &lt;/p&gt;
  &lt;p&gt;
    4.&amp;nbsp;libpcap
  &lt;/p&gt;
  &lt;p&gt;
    大名鼎鼎的Libpcap是一个古老的可以工作在所有Unix-like平台上的抓包库，比linux年纪更大。Tcpdump的广泛使用让libpcap成为事实上的行业标准。它可以很方便的编写抓取数据链路层上的数据包，并可以设置过滤条件在内核级别只复制关心的数据包，而数据链路层上的原始套接字会尽最大努力复制所有的包，所以libpcap的工作效率高。而且，pcap使用方便。下面是一个很简单的使用pcap抓到发往80端口的tcp包并打印源IP，目的IP，和目的端口号的程序。非常短，很容易看，起到介绍libpcap的作用。
  &lt;/p&gt;
  &lt;p&gt;
    &amp;nbsp;int&amp;nbsp;main(int&amp;nbsp;argc,&amp;nbsp;char&amp;nbsp;*argv[])
  &lt;/p&gt;
  &lt;p&gt;
    &amp;nbsp;{
  &lt;/p&gt;
  &lt;p&gt;
    pcap_t&amp;nbsp;*handle; //&amp;nbsp;pcap用的句柄，和其它各种句柄一样。
  &lt;/p&gt;
  &lt;p&gt;
    char&amp;nbsp;*dev; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;网络接口名，如eth0,&amp;nbsp;eth1,&amp;nbsp;tunl0&amp;nbsp;之类
  &lt;/p&gt;
  &lt;p&gt;
    char&amp;nbsp;errbuf[PCAP_ERRBUF_SIZE]; //&amp;nbsp;存描述出错原因的缓冲
  &lt;/p&gt;
  &lt;p&gt;
    struct&amp;nbsp;bpf_program&amp;nbsp;fp; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;pcap用来过滤数据包用
  &lt;/p&gt;
  &lt;p&gt;
    char&amp;nbsp;filter_exp[]&amp;nbsp;=&amp;nbsp;&#34;tcp&amp;nbsp;and&amp;nbsp;dst&amp;nbsp;port&amp;nbsp;80&#34;;&amp;nbsp;//&amp;nbsp;过滤字符串，和tcpdump的写法一样
  &lt;/p&gt;
  &lt;p&gt;
    struct&amp;nbsp;pcap_pkthdr&amp;nbsp;header;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;pcap自己用的包头
  &lt;/p&gt;
  &lt;p&gt;
    const&amp;nbsp;u_char&amp;nbsp;*packet; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;pcap包头后的数据，即抓到的数据
  &lt;/p&gt;
  &lt;p&gt;
    &amp;nbsp;
  &lt;/p&gt;
  &lt;p&gt;
    int&amp;nbsp;len_of_iphdr;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;ip头的长度
  &lt;/p&gt;
  &lt;p&gt;
    struct&amp;nbsp;in_addr&amp;nbsp;src_ip;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;源IP地址
  &lt;/p&gt;
  &lt;p&gt;
    struct&amp;nbsp;in_addr&amp;nbsp;dst_ip;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;目的IP
  &lt;/p&gt;
  &lt;p&gt;
    const&amp;nbsp;u_char&amp;nbsp;*ip_hdr_addr; //&amp;nbsp;IP头的首地址
  &lt;/p&gt;
  &lt;p&gt;
    const&amp;nbsp;u_char&amp;nbsp;*tcp_hdr_addr;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;tcp头的首地址
  &lt;/p&gt;
  &lt;p&gt;
    struct&amp;nbsp;tcphdr&amp;nbsp;*tcp_hdr;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;tcp头结构体
  &lt;/p&gt;
  &lt;p&gt;
    u_short&amp;nbsp;dst_port;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;目的端口
  &lt;/p&gt;
  &lt;p&gt;
    &amp;nbsp;
  &lt;/p&gt;
  &lt;p&gt;
    //&amp;nbsp;如果命令行指定网卡名
  &lt;/p&gt;
  &lt;p&gt;
    if&amp;nbsp;(argv[1])
  &lt;/p&gt;
  &lt;p&gt;
    dev&amp;nbsp;=&amp;nbsp;argv[1];&amp;nbsp;//就用指定的网卡
  &lt;/p&gt;
  &lt;p&gt;
    else
  &lt;/p&gt;
  &lt;p&gt;
    dev&amp;nbsp;=&amp;nbsp;&#34;eth0&#34;;&amp;nbsp;//否则用eth0
  &lt;/p&gt;
  &lt;p&gt;
    &amp;nbsp;
  &lt;/p&gt;
  &lt;p&gt;
    }
  &lt;/p&gt;
  &lt;p&gt;
    &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
  &lt;/p&gt;
  &lt;p&gt;
    &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;用pcap打开这个网卡
  &lt;/p&gt;
  &lt;p&gt;
    handle&amp;nbsp;=&amp;nbsp;pcap_open_live(dev,&amp;nbsp;BUFSIZ,&amp;nbsp;0,&amp;nbsp;1000,&amp;nbsp;errbuf);
  &lt;/p&gt;
  &lt;p&gt;
    if&amp;nbsp;(handle&amp;nbsp;==&amp;nbsp;NULL)&amp;nbsp;{&amp;nbsp;&amp;nbsp;//&amp;nbsp;打开网卡出错
  &lt;/p&gt;
  &lt;p&gt;
    fprintf(stderr,&amp;nbsp;&#34;Couldn&#39;t&amp;nbsp;open&amp;nbsp;device&amp;nbsp;%s:&amp;nbsp;%s\n&#34;,&amp;nbsp;dev,&amp;nbsp;errbuf);
  &lt;/p&gt;
  &lt;p&gt;
    return(2);
  &lt;/p&gt;
  &lt;p&gt;
    }
  &lt;/p&gt;
  &lt;p&gt;
    &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
  &lt;/p&gt;
  &lt;p&gt;
    &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;编译过滤文件
  &lt;/p&gt;
  &lt;p&gt;
    if&amp;nbsp;(pcap_compile(handle,&amp;nbsp;&amp;fp,&amp;nbsp;filter_exp,&amp;nbsp;0,&amp;nbsp;net)&amp;nbsp;==&amp;nbsp;-1)&amp;nbsp;{
  &lt;/p&gt;
  &lt;p&gt;
    fprintf(stderr,&amp;nbsp;&#34;Couldn&#39;t&amp;nbsp;parse&amp;nbsp;filter&amp;nbsp;%s:&amp;nbsp;%s\n&#34;,&amp;nbsp;filter_exp,&amp;nbsp;pcap_geterr(handle));
  &lt;/p&gt;
  &lt;p&gt;
    return(2);
  &lt;/p&gt;
  &lt;p&gt;
    }
  &lt;/p&gt;
  &lt;p&gt;
    &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;设置过滤条件
  &lt;/p&gt;
  &lt;p&gt;
    if&amp;nbsp;(pcap_setfilter(handle,&amp;nbsp;&amp;fp)&amp;nbsp;==&amp;nbsp;-1)&amp;nbsp;{
  &lt;/p&gt;
  &lt;p&gt;
    fprintf(stderr,&amp;nbsp;&#34;Couldn&#39;t&amp;nbsp;install&amp;nbsp;filter&amp;nbsp;%s:&amp;nbsp;%s\n&#34;,&amp;nbsp;filter_exp,&amp;nbsp;pcap_geterr(handle));
  &lt;/p&gt;
  &lt;p&gt;
    return(2);
  &lt;/p&gt;
  &lt;p&gt;
    }
  &lt;/p&gt;
  &lt;p&gt;
    &amp;nbsp;
  &lt;/p&gt;
  &lt;p&gt;
    &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;//&amp;nbsp;抓包
  &lt;/p&gt;
  &lt;p&gt;
    packet&amp;nbsp;=&amp;nbsp;pcap_next(handle,&amp;nbsp;&amp;header);
  &lt;/p&gt;
  &lt;p&gt;
    &amp;nbsp;
  &lt;/p&gt;
  &lt;p&gt;
    //&amp;nbsp;至此packet指向抓到的一个目标端口号是80的数据链路层的包
  &lt;/p&gt;
  &lt;p&gt;
    //&amp;nbsp;它的包结构是&amp;nbsp;14字节以太网包头&amp;nbsp;+&amp;nbsp;可变IPv4包头&amp;nbsp;+&amp;nbsp;TCP包头
  &lt;/p&gt;
  &lt;p&gt;
    ip_hdr_addr&amp;nbsp;=&amp;nbsp;(u_char*)(packet&amp;nbsp;+&amp;nbsp;sizeof(struct&amp;nbsp;ethernet_hdr));
  &lt;/p&gt;
  &lt;p&gt;
    src_ip.s_addr&amp;nbsp;=&amp;nbsp;((struct&amp;nbsp;iphdr*)ip_hdr_addr)-&gt;saddr;
  &lt;/p&gt;
  &lt;p&gt;
    dst_ip.s_addr&amp;nbsp;=&amp;nbsp;((struct&amp;nbsp;iphdr*)ip_hdr_addr)-&gt;daddr;
  &lt;/p&gt;
  &lt;p&gt;
    len_of_iphdr&amp;nbsp;=&amp;nbsp;((struct&amp;nbsp;iphdr*)ip_hdr_addr)-&gt;ihl&amp;nbsp;*&amp;nbsp;4;
  &lt;/p&gt;
  &lt;p&gt;
    tcp_hdr_addr&amp;nbsp;=&amp;nbsp;ip_hdr_addr&amp;nbsp;+&amp;nbsp;len_of_iphdr;
  &lt;/p&gt;
  &lt;p&gt;
    tcp_hdr&amp;nbsp;=&amp;nbsp;(struct&amp;nbsp;tcphdr*)tcp_hdr_addr;
  &lt;/p&gt;
  &lt;p&gt;
    dst_port&amp;nbsp;=&amp;nbsp;tcp_hdr-&gt;dest;
  &lt;/p&gt;
  &lt;p&gt;
    &amp;nbsp;
  &lt;/p&gt;
  &lt;p&gt;
    //&amp;nbsp;经过上面的各种指针偏移，下面打印源IP和目标IP和目标端口.
  &lt;/p&gt;
  &lt;p&gt;
    printf(&#34;src&amp;nbsp;addr&amp;nbsp;%s\n&#34;,&amp;nbsp;inet_ntoa(src_ip));
  &lt;/p&gt;
  &lt;p&gt;
    printf(&#34;dst&amp;nbsp;addr&amp;nbsp;%s\n&#34;,&amp;nbsp;inet_ntoa(dst_ip));
  &lt;/p&gt;
  &lt;p&gt;
    printf(&#34;dst_port&amp;nbsp;%d\n&#34;,&amp;nbsp;ntohs(dst_port));
  &lt;/p&gt;
  &lt;p&gt;
    &amp;nbsp;
  &lt;/p&gt;
  &lt;p&gt;
    /*&amp;nbsp;And&amp;nbsp;close&amp;nbsp;the&amp;nbsp;session&amp;nbsp;*/
  &lt;/p&gt;
  &lt;p&gt;
    pcap_close(handle);
  &lt;/p&gt;
  &lt;p&gt;
    &amp;nbsp;
  &lt;/p&gt;
  &lt;p&gt;
    return(0);
  &lt;/p&gt;
  &lt;p&gt;
    &amp;nbsp;}
  &lt;/p&gt;
  &lt;p&gt;
    &amp;nbsp;
  &lt;/p&gt;
  &lt;p&gt;
    5.&amp;nbsp;总结
  &lt;/p&gt;
  &lt;p&gt;
    本文只是一个非常简单的介绍。如需要进阶学习，Stevens的网络编译有更详细地关于Raw&amp;nbsp;Socket的内容，研究NF_Queue技术则需要读源代码和收集散在社区各个角落的资料了，而讲libpcap有两篇很好的文章：
  &lt;/p&gt;
  &lt;p&gt;
    &#34;&lt;a href=&#34;http://recursos.aldabaknocking.com/libpcapHakin9LuisMartinGarcia.pdf&#34;&gt;Programming&amp;nbsp;with&amp;nbsp;Libpcap&amp;nbsp;&amp;ndash;&amp;nbsp;Sniffing&amp;nbsp;the&amp;nbsp;network&amp;nbsp;from&amp;nbsp;our&amp;nbsp;own&amp;nbsp;application&amp;nbsp;&lt;/a&gt;&#34;用Libpcap编程，在我们的程序中嗅探网络。非常漂亮的pdf文档。
  &lt;/p&gt;
  &lt;p&gt;
    &lt;a href=&#34;http://recursos.aldabaknocking.com/libpcapHakin9LuisMartinGarcia.pdf&#34;&gt;http://recursos.aldabaknocking.com/libpcapHakin9LuisMartinGarcia.pdf&lt;/a&gt;
  &lt;/p&gt;
  &lt;p&gt;
    &lt;a href=&#34;http://yuba.stanford.edu/~casado/pcap/section1.html&#34;&gt;The&amp;nbsp;Sniffer&amp;rsquo;s&amp;nbsp;Guide&amp;nbsp;to&amp;nbsp;Raw&amp;nbsp;Traffic&lt;/a&gt;&amp;nbsp;嗅探器教程。斯坦福大学的Geek于大概2001年写的。
  &lt;/p&gt;
  &lt;p&gt;
    &lt;a href=&#34;http://yuba.stanford.edu/~casado/pcap/section1.html&#34;&gt;http://yuba.stanford.edu/~casado/pcap/section1.html&lt;/a&gt;
  &lt;/p&gt;
  &lt;p&gt;
    copyright ykyi.net
  &lt;/p&gt;
&lt;/div&gt;</description>
    </item>
  </channel>
</rss>
