Programming with pcap编程参考资料
c语言参考书

c语言参考书
C语言是一门重要的编程语言,有很多优秀的参考书籍可以帮助学习者更好地掌握它。
以下是一些推荐的C语言参考书籍:
1. 《C Primer Plus》(第6版):这是一本非常经典的C语言入门教材,详细介绍了C语言的基础知识和编程技巧,并通过大量实例让读者更好地掌握如何应用这些知识进行程序设计。
此外,书中还涵盖了C99标准和C11标准的新特性,让读者了解最新的C语言开发技术。
2. 《The C Programming Language》(第2版):这本书是由C语言的创始人Dennis M. Ritchie和著名计算机科学家Brian W. Kernighan合作编写的,是一本经典的C语言教材。
书中详细介绍了C语言的基础知识和编程技巧,并通过大量实例让读者更好地掌握如何应用这些知识进行程序设计。
此外,书中还介绍了C语言标准库函数和系统调用等内容。
3. 《手把手教你学C语言》:这本书主要针对学习C语言的初学者,即使完全没有编程基础,也能够通过阅读本书快速掌握C语言的核心知识。
4. 《C和指针》:这本书通过讲述指针来让初学者更好地理解C语言。
5. 《C专家编程》:这本书的特色诙谐幽默,把C上升到一个更高的层次,更容易让初学者接纳。
6. 《C标准库》:这本书是一本圣经,全面阐释了函数的应用,是程序员必备的参考书籍。
7. 《计算机算法设计与分析(第3版)》:这本书是学习数据结构和算法的进阶教材,为后面进阶做了铺垫。
此外,《C陷阱与缺陷》、《计算机算法设计与分析(第3版)》也是不错的参考书。
总之,学习C语言需要多读多实践,只有不断地练习才能更好地掌握它。
基于libcap、winpcap的网络编程

第五章基于libpcap的网络编程技术5. 1常见的包捕获机制简介包捕获就是利用以太网的介质共享的特性,通过将网络适配器设置为混杂模式的方法,接收到所有网络上的以太网帧。
包捕获的机制大致可以分为两类:一类是由操作系统内核提供的捕获机制。
另一类是由应用软件或系统开发包捕获驱动程序提供的捕获机制。
常见的包捕获机制如表5-1所示。
其中最主要的是下列4种:BPF ( Berkeley Packet Filter )DLPI ( Data Link Provider In terface )NIT ( Network In terface Tap ) SOCK-PACKET 类型套接口。
BPF由基于BSD的Unix系统内核所实现。
DLPI是Solaris (和其他System V UNIX ) 系统的内嵌子系统。
NIT是SUN OS4 系统的一部分,但在Solaris /SUN OS5 中被DLPI 所取代。
Linux核心则实现了SOCK-PACKET 的包捕获机制。
从性能上看,BPF比DLPI 和NIT 好得多,SOCK-PACKET 最弱。
表5-1常用的包捕获机制由于现在很多局域网为NT网,其网络传输方式大多采用以太网标准,所以涉及的编程也是在Windows 环境下实现的。
Windows 操作系统没有提供包捕获机制,只提供了数量很少并且功能有限的API调用。
在Windows 环境下由于其自身的封装性,很难对其底层进行编程。
本章将对BSD系列的libpcap进行深入地介绍。
5.2 Libpcap 与 BPF(1) libpcap 概述libpcap(Packet Capturelibrary),即数据包捕获函数库。
该库提供的 C 函数接口可用于捕获经过网络接口 (只要经过该接口,目标地址不一定为本机)的数据包。
它是由洛仑兹 伯克利试验室的研究人员 Steven McCanne 和Van Jacobson 于1993 年在Usenix'93 会议上正式提出的一种用于 Unix 内核数据包过滤体制。
programming and problem solving with c++ 中文版

《Programming and Problem Solving with C++》(中文版《C++程序设计教程》)是一本由美国作家Bjarne Stroustrup所著的教材。
以下是这本书的主要内容:
1.程序设计的基本元素:数据类型、控制结构和变量等基本概念,以及如何
使用它们来编写程序。
2.函数和程序结构:介绍如何使用函数来组织程序,包括函数的定义、声明
和调用,以及如何处理函数参数和返回值。
3.面向对象编程:介绍如何使用类和对象来组织程序,包括类的定义、对象
的创建和使用,以及如何使用继承和多态等面向对象编程技术。
4.泛型编程:介绍如何使用模板来编写泛型程序,包括模板函数的定义和使
用,以及如何使用标准模板库(STL)中的容器和算法等。
5.异常处理:介绍如何使用异常处理技术来处理程序中的错误和异常情况,
包括异常的抛出、捕获和处理。
6.文件和流:介绍如何使用文件和流来读写数据,包括文件的打开、读取、
写入和关闭等操作。
7.高级主题:介绍一些高级主题,包括多线程编程、网络编程和并发编程等。
总的来说,这本书是一本全面介绍C++编程语言的教材,适合初学者和有一定经验的程序员阅读。
SharpPcap开发全攻略(英文版)【范本模板】

CONTENTSIntroduction (2)Background (2)About SharpPcap (3)Packet。
Net architecture and usage (4)SharpPcap tutorial: A step by step guide to using SharpPcap (6)Obtaining the device list (Example 1 in the source package) (6)Opening an adapter and capturing packets (Example 3 in the source package) (8)Capturing packets without the event handler (Example 4 in the source package) (10)Filtering the traffic (Example 5 in the source package) (11)Interpreting the packets (Example 6 in the source package) (12)Handling offline dump files (Example 8 in the source package) (14)Sending packets (Example 9 in the source package) (17)Gathering statistics on the network traffic - WinPcap only (Example 11 in the source package) (21)References (23)History (23)Eg: (24)[A 。
NET sniffer application written with SharpPcap]IntroductionPacket capturing (or packet sniffing)is the process of collecting all packets of data that pass through a given network interface. Capturing network packets in our applications is a powerful capability which lets us write network monitoring, packet analyzers and security tools. The libpcap library for UNIX based systems and WinPcap for Windows are the most widely used packet capture drivers that provide API for low—level network monitoring. Among the applications that use libpcap/WinPcap as its packet capture subsystem are the famous tcpdump and Wireshark.In this article, we will introduce the SharpPcap。
计算机科学与技术专业编程考试复习资料推荐

计算机科学与技术专业编程考试复习资料推荐计算机科学与技术专业的编程考试对学生来说是一项重要的挑战。
为了帮助同学们更好地备考,本文将推荐一些优质的复习资料,希望能够为大家提供一些参考和指导。
一、教材推荐1.《C++ Primer》《C++ Primer》是一本经典的C++教材,适合初学者和有一定基础的同学。
该书全面介绍了C++的语法和常用编程技巧,并通过大量的实例帮助读者理解和掌握知识点。
同时,书中还包含了一些编程练习题,有助于巩固所学知识。
2.《算法导论》《算法导论》是一本经典的算法教材,对计算机科学与技术专业的学生来说是必备的参考书之一。
该书详细介绍了各种常用算法和数据结构,并提供了相应的伪代码和实现方法。
通过学习和理解这本书,同学们可以提高编程能力和解决实际问题的能力。
二、在线资源推荐1.leetcodeleetcode是一个在线的编程练习平台,提供了大量的编程题目和解答。
同学们可以通过在leetcode上刷题,提高自己的编程能力和解题思维。
该平台还提供了讨论区,可以与其他同学交流和分享解题思路,对于理解和掌握算法和数据结构非常有帮助。
2.GitHubGitHub是一个全球最大的代码托管平台,上面有大量的开源项目和代码资源。
同学们可以通过搜索相关的项目,找到一些优秀的编程示例和实践经验。
此外,GitHub还提供了版本控制和协作开发的功能,可以帮助同学们更好地组织和管理自己的代码。
三、学习方法推荐1.理论与实践相结合编程考试不仅要求掌握理论知识,还需要具备实际操作的能力。
因此,同学们在复习过程中应该注重理论与实践相结合。
可以通过编写小项目或者参与开源项目的方式,将所学知识应用到实际中,提高自己的编程能力。
2.刷题与总结编程考试中经常会涉及到一些经典的算法和数据结构。
同学们可以通过刷题的方式来加深对这些知识点的理解和掌握。
在刷题的过程中,可以总结一些常用的解题思路和技巧,形成自己的思维导图或者笔记,方便复习和回顾。
pcap 物理层协议

pcap 物理层协议
物理层协议是计算机网络中最重要的一部分,它是数据从源端发送到目的端的基础。
最常用的物理层协议是 Packet Capture(PCAP)协议,它可以捕捉从网络中传输的数据报文,并将其存储在收集的数据帧中。
PCAP是一种硬件协议,又是一种软件协议,它的功能包括在网络中联系网络层协议和应用层协议,使它们可以合作传输数据,以及提供对网络状态的观察和检测,帮助管理网络性能。
特别是,PCAP 议主要用来提供有效的数据帧捕获,分析和保存网络流量。
PCAP议可以提供有效的数据帧捕获,分析和保存网络流量,因此在许多网络安全相关的应用中,它被广泛使用。
在实际的网络流量记录中,它的主要作用是监控网络流量并发现安全漏洞,从而帮助网络管理人员决定未来的网络安全策略。
PCAP 也被用来确定网络中恶意流量的来源和特征,比如网络攻击、蠕虫病毒和木马等。
此外,PCAP议还可以用来监控网络性能,包括网络的吞吐量、延迟和可用性。
它可以帮助系统管理员识别网络问题的根源,并进行诊断和调优,以提高网络性能。
总之,PCAP理层协议是计算机网络的重要组成部分,它的功能包括数据帧捕获、网络安全监测和网络性能监控等。
它的出现,大大改善了网络管理者的工作效率,为网络安全带来了广泛的应用。
- 1 -。
pcap使用手册

让我们从看看这篇文章写给谁开始。
显而易见的,需要一些C语言基础知识,除非你只想了解基本的理论。
你不必是一个编码专家,因为这个领域只有经验丰富的程序员涉足,而我将尽可能详细的描述这些概念。
另外,考虑到这是有关一个包嗅探器的,所以对网络基础知识的理解是有帮助的。
所有在此出现的代码示例都已在FreeBSD 4.3平台上测试通过。
开始:pcap应用程序的格式我们所要理解的第一件事情是一个基于pcap的嗅探器程序的总体布局。
流程如下:1.我们从决定用哪一个接口进行嗅探开始。
在Linux中,这可能是eth0,而在BSD系统中则可能是xl1等等。
我们也可以用一个字符串来定义这个设备,或者采用pcap提供的接口名来工作。
2.初始化pcap。
在这里我们要告诉pcap对什么设备进行嗅探。
假如愿意的话,我们还可以嗅探多个设备。
怎样区分它们呢?使用文件句柄。
就像打开一个文件进行读写一样,必须命名我们的嗅探“会话”,以此使它们各自区别开来。
3.如果我们只想嗅探特定的传输(如TCP/IP包,发往端口23的包等等),我们必须创建一个规则集合,编译并且使用它。
这个过程分为三个相互紧密关联的阶段。
规则集合被置于一个字符串内,并且被转换成能被pcap读的格式(因此编译它)。
编译实际上就是在我们的程序里调用一个不被外部程序使用的函数。
接下来我们要告诉pcap使用它来过滤出我们想要的那一个会话。
4.最后,我们告诉pcap进入它的主体执行循环。
在这个阶段内pcap一直工作到它接收了所有我们想要的包为止。
每当它收到一个包就调用另一个已经定义好的函数,这个函数可以做我们想要的任何工作,它可以剖析所部获的包并给用户打印出结果,它可以将结果保存为一个文件,或者什么也不作。
5.在嗅探到所需的数据后,我们要关闭会话并结束。
这是实际上一个很简单的过程。
一共五个步骤,其中一个(第3个)是可选的。
我们为什么不看一看是怎样实现每一个步骤呢?设置设备这是很简单的。
WinPcap编程

W i n P c a p编程WinPcap是一个开源的、运行于Win32平台下的体系结构,它的主要功能是进行数据包捕获和网络分析。
它允许应用程序通过协议栈捕获和传输网络数据包,也包括内核级别的数据包过滤、网络静态引擎和支持远程数据包捕获等有用的功能。
WinPcap由两部分组成:1. 驱动程序: 扩展操作系统功能提供低层次的网络访问2. 动态链接库:运行在Win32平台上的应用程序可以非常方便地访问网络低层次的数据。
Ethereal是大名鼎鼎的捕获数据包专业软件,它的运行是在WinPcap的支持之下的,如果没有安装WinPcap,Ethereal也无法正常捕获数据包。
在正式WinPcap编程之前,要配置运行环境。
Win32 平台下WinPcap应用程序需要以下四个动态链接库才能正常运行:这四个动态链接库在WinPcap驱动程序里。
如果应用程序出现一下提示,那就是没有安装驱动程序的原因了。
被过滤广告也可以不安装WinPcap驱动程序。
但是需要把上面提到的四个动态链接库文件拷贝到系统分区/WINDOWS/system32目录下或者接下来配置编程环境。
如果一个源文件使用了WinPcap提供的库函数,那么就需要在该文件开始的位置添加包含文件(或者在引用的文件中),即#include “”也许会出现下面的错误:fatal error C1083: 无法打开包括文件:“”: No such file or directory这个错误表明找不到文件这个头文件在驱动程序安装完成后也是没有的,它是开发包里面的一个头文件所以,如果要运行程序还需要到官方网站上去下载WinPcap SDK―WpdPackWinPcap SDk里面包含库文件,头文件,文档文件和一些例子。
解压缩后把Include目录添加到IDE的包含文件中(Tools->Option->Directory; VS 2003/2005 工具->选项->项目和解决方案/项目->VC++目录)error LNK2019: 无法解析的外部符号_pcap_findalldevs_ex,该符号在函数XXX 中被引用如果发生上面的错误就表明缺少库文件,需要添加到工程中Project->Settings->Link->Object/library modules; VS 2003/2005 项目->添加现有项->所有文件)error C2065: “PCAP_SRC_IF_STRING”: 未声明的标识符error C3861: “pcap_findalldevs_ex”: 找不到标识符error C2065: “PCAP_OPENFLAG_PROMISCUOUS”: 未声明的标识符error C3861: “pcap_open”: 找不到标识符新的版本里WinPcap支持远程数据包获取,发生上面的错误很有可能是新的版本导致不兼容的问题,所以还应当添加一个头文件,即#include ""如果还有问题,可以到WinPcaP官方网站上找FAQ。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Programming with pcapTim Carstenstimcarst at yahoo dot comFurther editing and development by Guy Harrisguy at alum dot mit dot eduOk, let's begin by defining who this document is written for. Obviously, some basic knowledge of C is required, unless you only wish to know the basic theory. You do not need to be a code ninja; for the areas likely to be understood only by more experienced programmers, I'll be sure to describe concepts in greater detail. Additionally, some basic understanding of networking might help, given that this is a packet sniffer and all. All of the code examples presented here have been tested on FreeBSD 4.3 with a default kernel.Getting Started: The format of a pcap applicationThe first thing to understand is the general layout of a pcap sniffer. The flow of code is as follows:1.We begin by determining which interface we want to sniff on. In Linux this may be something like eth0, in BSD it may be xl1, etc. We can either define this device ina string, or we can ask pcap to provide us with the name of an interface that will do the job.2.Initialize pcap. This is where we actually tell pcap what device we are sniffing on. We can, if we want to, sniff on multiple devices. How do we differentiate betweenthem? Using file handles. Just like opening a file for reading or writing, we must name our sniffing "session" so we can tell it apart from other such sessions.3.In the event that we only want to sniff specific traffic (e.g.: only TCP/IP packets, only packets going to port 23, etc) we must create a rule set, "compile" it, andapply it. This is a three phase process, all of which is closely related. The rule set is kept in a string, and is converted into a format that pcap can read (hence compiling it.) The compilation is actually just done by calling a function within our program; it does not involve the use of an external application. Then we tell pcap to apply it to whichever session we wish for it to filter.4.Finally, we tell pcap to enter it's primary execution loop. In this state, pcap waits until it has received however many packets we want it to. Every time it gets a newpacket in, it calls another function that we have already defined. The function that it calls can do anything we want; it can dissect the packet and print it to the user, it can save it in a file, or it can do nothing at all.5.After our sniffing needs are satisfied, we close our session and are complete.This is actually a very simple process. Five steps total, one of which is optional (step 3, in case you were wondering.) Let's take a look at each of the steps and how to implement them.Setting the deviceThis is terribly simple. There are two techniques for setting the device that we wish to sniff on.The first is that we can simply have the user tell us. Consider the following program:#include <stdio.h>#include <pcap.h>int main(int argc, char *argv[]){char *dev = argv[1];printf("Device: %s\n", dev);return(0);}The user specifies the device by passing the name of it as the first argument to the program. Now the string "dev" holds the name of the interface that we will sniff on in a format that pcap can understand (assuming, of course, the user gave us a real interface).The other technique is equally simple. Look at this program:#include <stdio.h>#include <pcap.h>int main(int argc, char *argv[]){char *dev, errbuf[PCAP_ERRBUF_SIZE];dev = pcap_lookupdev(errbuf);if (dev == NULL) {fprintf(stderr, "Couldn't find default device: %s\n", errbuf);return(2);}printf("Device: %s\n", dev);return(0);}In this case, pcap just sets the device on its own. "But wait, Tim," you say. "What is the deal with the errbuf string?" Most of the pcap commands allow us to pass them a string as an argument. The purpose of this string? In the event that the command fails, it will populate the string with a description of the error. In this case, ifpcap_lookupdev() fails, it will store an error message in errbuf. Nifty, isn't it? And that's how we set our device.Opening the device for sniffingThe task of creating a sniffing session is really quite simple. For this, we use pcap_open_live(). The prototype of this function (from the pcap man page) is as follows: pcap_t *pcap_open_live(char *device, int snaplen, int promisc, int to_ms,pcap_t *pcap_open_live(char *device, int snaplen, int promisc, int to_ms,char *ebuf)The first argument is the device that we specified in the previous section. snaplen is an integer which defines the maximum number of bytes to be captured by pcap. promisc, when set to true, brings the interface into promiscuous mode (however, even if it is set to false, it is possible under specific cases for the interface to be in promiscuous mode, anyway). to_ms is the read time out in milliseconds (a value of 0 means no time out; on at least some platforms, this means that you may wait until a sufficient number of packets arrive before seeing any packets, so you should use a non-zero timeout). Lastly, ebuf is a string we can store any error messages within (as we did above with errbuf). The function returns our session handler.To demonstrate, consider this code snippet:#include <pcap.h>...pcap_t *handle;handle = pcap_open_live(somedev, BUFSIZ, 1, 1000, errbuf);if (handle == NULL) {fprintf(stderr, "Couldn't open device %s: %s\n", somedev, errbuf);return(2);}This code fragment opens the device stored in the strong "somedev", tells it to read however many bytes are specified in BUFSIZ (which is defined in pcap.h). We are telling it to put the device into promiscuous mode, to sniff until an error occurs, and if there is an error, store it in the string errbuf; it uses that string to print an error message.A note about promiscuous vs. non-promiscuous sniffing: The two techniques are very different in style. In standard, non-promiscuous sniffing, a host is sniffing only traffic that is directly related to it. Only traffic to, from, or routed through the host will be picked up by the sniffer. Promiscuous mode, on the other hand, sniffs all traffic on the wire. In a non-switched environment, this could be all network traffic. The obvious advantage to this is that it provides more packets for sniffing, which may or may not be helpful depending on the reason you are sniffing the network. However, there are regressions. Promiscuous mode sniffing is detectable; a host can test with strong reliability to determine if another host is doing promiscuous sniffing. Second, it only works in a non-switched environment (such as a hub, or a switch that is being ARP flooded). Third, on high traffic networks, the host can become quite taxed for system resources.Filtering trafficOften times our sniffer may only be interested in specific traffic. For instance, there may be times when all we want is to sniff on port 23 (telnet) in search of passwords. Or perhaps we want to highjack a file being sent over port 21 (FTP). Maybe we only want DNS traffic (port 53 UDP). Whatever the case, rarely do we just want to blindly sniff all network traffic. Enter pcap_compile() and pcap_setfilter().The process is quite simple. After we have already called pcap_open_live() and have a working sniffing session, we can apply our filter. Why not just use our own if/else if statements? Two reasons. First, pcap's filter is far more efficient, because it does it directly with the BPF filter; we eliminate numerous steps by having the BPF driver do it directly. Second, this is a lot easier :)Before applying our filter, we must "compile" it. The filter expression is kept in a regular string (char array). The syntax is documented quite well in the man page for tcpdump; I leave you to read it on your own. However, we will use simple test expressions, so perhaps you are sharp enough to figure it out from my examples.To compile the program we call pcap_compile(). The prototype defines it as:int pcap_compile(pcap_t *p, struct bpf_program *fp, char *str, int optimize,bpf_u_int32 netmask)The first argument is our session handle (pcap_t *handle in our previous example). Following that is a reference to the place we will store the compiled version of our filter. Then comes the expression itself, in regular string format. Next is an integer that decides if the expression should be "optimized" or not (0 is false, 1 is true. Standard stuff.) Finally, we must specify the net mask of the network the filter applies to. The function returns -1 on failure; all other values imply success.After the expression has been compiled, it is time to apply it. Enter pcap_setfilter(). Following our format of explaining pcap, we shall look at the pcap_setfilter() prototype:int pcap_setfilter(pcap_t *p, struct bpf_program *fp)This is very straightforward. The first argument is our session handler, the second is a reference to the compiled version of the expression (presumably the same variable as the second argument to pcap_compile()).Perhaps another code sample would help to better understand:#include <pcap.h>...pcap_t *handle; /* Session handle */char dev[] = "rl0"; /* Device to sniff on */char errbuf[PCAP_ERRBUF_SIZE]; /* Error string */struct bpf_program fp; /* The compiled filter expression */char filter_exp[] = "port 23"; /* The filter expression */bpf_u_int32 mask; /* The netmask of our sniffing device */bpf_u_int32 net; /* The IP of our sniffing device */if (pcap_lookupnet(dev, &net, &mask, errbuf) == -1) {fprintf(stderr, "Can't get netmask for device %s\n", dev);net = 0;mask = 0;}handle = pcap_open_live(dev, BUFSIZ, 1, 1000, errbuf);if (handle == NULL) {fprintf(stderr, "Couldn't open device %s: %s\n", somedev, errbuf);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);}This program preps the sniffer to sniff all traffic coming from or going to port 23, in promiscuous mode, on the device rl0.You may notice that the previous example contains a function that we have not yet discussed. pcap_lookupnet() is a function that, given the name of a device, returns its IP and net mask. This was essential because we needed to know the net mask in order to apply the filter. This function is described in the Miscellaneous section at the end of the document.It has been my experience that this filter does not work across all operating systems. In my test environment, I found that OpenBSD 2.9 with a default kernel does support this type of filter, but FreeBSD 4.3 with a default kernel does not. Your mileage may vary.The actual sniffingAt this point we have learned how to define a device, prepare it for sniffing, and apply filters about what we should and should not sniff for. Now it is time to actually capture some packets.There are two main techniques for capturing packets. We can either capture a single packet at a time, or we can enter a loop that waits for n number of packets to be sniffed before being done. We will begin by looking at how to capture a single packet, then look at methods of using loops. For this we use pcap_next().The prototype for pcap_next() is fairly simple:u_char *pcap_next(pcap_t *p, struct pcap_pkthdr *h)The first argument is our session handler. The second argument is a pointer to a structure that holds general information about the packet, specifically the time in which it was sniffed, the length of this packet, and the length of his specific portion (incase it is fragmented, for example.) pcap_next() returns a u_char pointer to the packet that is described by this structure. We'll discuss the technique for actually reading the packet itself later.Here is a simple demonstration of using pcap_next() to sniff a packet.#include <pcap.h>#include <stdio.h>int main(int argc, char *argv[]){pcap_t *handle; /* Session handle */char *dev; /* The device to sniff on */char errbuf[PCAP_ERRBUF_SIZE]; /* Error string */struct bpf_program fp; /* The compiled filter */char filter_exp[] = "port 23"; /* The filter expression */bpf_u_int32 mask; /* Our netmask */bpf_u_int32 net; /* Our IP */struct pcap_pkthdr header; /* The header that pcap gives us */const u_char *packet; /* The actual packet *//* Define the device */dev = pcap_lookupdev(errbuf);if (dev == NULL) {fprintf(stderr, "Couldn't find default device: %s\n", errbuf);return(2);}/* Find the properties for the device */if (pcap_lookupnet(dev, &net, &mask, errbuf) == -1) {fprintf(stderr, "Couldn't get netmask for device %s: %s\n", dev, errbuf);net = 0;mask = 0;}/* Open the session in promiscuous mode */handle = pcap_open_live(dev, BUFSIZ, 1, 1000, errbuf);if (handle == NULL) {fprintf(stderr, "Couldn't open device %s: %s\n", somedev, errbuf);return(2);}/* Compile and apply the filter */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);}/* Grab a packet */packet = pcap_next(handle, &header);/* Print its length */printf("Jacked a packet with length of [%d]\n", header.len);/* And close the session */pcap_close(handle);This application sniffs on whatever device is returned by pcap_lookupdev() by putting it into promiscuous mode. It finds the first packet to come across port 23 (telnet) and tells the user the size of the packet (in bytes). Again, this program includes a new call, pcap_close(), which we will discuss later (although it really is quite self explanatory).The other technique we can use is more complicated, and probably more useful. Few sniffers (if any) actually use pcap_next(). More often than not, they use pcap_loop() or pcap_dispatch() (which then themselves use pcap_loop()). To understand the use of these two functions, you must understand the idea of a callback function. Callback functions are not anything new, and are very common in many API's. The concept behind a callback function is fairly simple. Suppose I have a program that is waiting for an event of some sort. For the purpose of this example, let's pretend that my program wants a user to press a key on the keyboard. Every time they press a key, I want to call a function which then will determine that to do. The function I am utilizing is a callback function. Every time the user presses a key, my program will call the callback function. Callbacks are used in pcap, but instead of being called when a user presses a key, they are called when pcap sniffs a packet. The two functions that one can use to define their callback is pcap_loop() and pcap_dispatch(). pcap_loop() and pcap_dispatch() are very similar in their usage of callbacks. Both of them call a callback function every time a packet is sniffed that meets our filter requirements (if any filter exists, of course. If not, then all packets that are sniffed are sent to the callback.)The prototype for pcap_loop() is below:int pcap_loop(pcap_t *p, int cnt, pcap_handler callback, u_char *user)The first argument is our session handle. Following that is an integer that tells pcap_loop() how many packets it should sniff for before returning (a negative value means it should sniff until an error occurs). The third argument is the name of the callback function (just its identifier, no parentheses). The last argument is useful in some applications, but many times is simply set as NULL. Suppose we have arguments of our own that we wish to send to our callback function, in addition to the arguments that pcap_loop() sends. This is where we do it. Obviously, you must typecast to a u_char pointer to ensure the results make it there correctly; as we will see later, pcap makes use of some very interesting means of passing information in the form of a u_char pointer. After we show an example of how pcap does it, it should be obvious how to do it here. If not, consult your local C reference text, as an explanation of pointers is beyond the scope of this document. pcap_dispatch() is almost identical in usage. The only difference between pcap_dispatch() and pcap_loop() is that pcap_dispatch() will only process the first batch of packets that it receives from the system, while pcap_loop() will continue processing packets or batches of packets until the count of packets runs out. For a more in depth discussion of their differences, see the pcap man page.Before we can provide an example of using pcap_loop(), we must examine the format of our callback function. We cannot arbitrarily define our callback's prototype; otherwise, pcap_loop() would not know how to use the function. So we use this format as the prototype for our callback function:void got_packet(u_char *args, const struct pcap_pkthdr *header,const u_char *packet);Let's examine this in more detail. First, you'll notice that the function has a void return type. This is logical, because pcap_loop() wouldn't know how to handle a return value anyway. The first argument corresponds to the last argument of pcap_loop(). Whatever value is passed as the last argument to pcap_loop() is passed to the first argument of our callback function every time the function is called. The second argument is the pcap header, which contains information about when the packet was sniffed, how large it is, etc. The pcap_pkthdr structure is defined in pcap.h as:struct pcap_pkthdr {struct timeval ts; /* time stamp */bpf_u_int32 caplen; /* length of portion present */bpf_u_int32 len; /* length this packet (off wire) */};These values should be fairly self explanatory. The last argument is the most interesting of them all, and the most confusing to the average novice pcap programmer. It is another pointer to a u_char, and it points to the first byte of a chunk of data containing the entire packet, as sniffed by pcap_loop().But how do you make use of this variable (named "packet" in our prototype)? A packet contains many attributes, so as you can imagine, it is not really a string, but actually a collection of structures (for instance, a TCP/IP packet would have an Ethernet header, an IP header, a TCP header, and lastly, the packet's payload). Thisu_char pointer points to the serialized version of these structures. To make any use of it, we must do some interesting typecasting.First, we must have the actual structures define before we can typecast to them. The following are the structure definitions that I use to describe a TCP/IP packet over Ethernet./* Ethernet addresses are 6 bytes */#define ETHER_ADDR_LEN 6/* Ethernet header */struct sniff_ethernet {u_char ether_dhost[ETHER_ADDR_LEN]; /* Destination host address */u_char ether_shost[ETHER_ADDR_LEN]; /* Source host address */u_short ether_type; /* IP? ARP? RARP? etc */};/* IP header */struct sniff_ip {u_char ip_vhl; /* version << 4 | header length >> 2 */u_char ip_tos; /* type of service */u_short ip_len; /* total length */u_short ip_id; /* identification */u_short ip_off; /* fragment offset field */#define IP_RF 0x8000 /* reserved fragment flag */#define IP_DF 0x4000 /* dont fragment flag */#define IP_MF 0x2000 /* more fragments flag */#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */u_char ip_ttl; /* time to live */u_char ip_p; /* protocol */u_short ip_sum; /* checksum */struct in_addr ip_src,ip_dst; /* source and dest address */};#define IP_HL(ip) (((ip)->ip_vhl) & 0x0f)#define IP_V(ip) (((ip)->ip_vhl) >> 4)/* TCP header */struct sniff_tcp {u_short th_sport; /* source port */u_short th_dport; /* destination port */tcp_seq th_seq; /* sequence number */tcp_seq th_ack; /* acknowledgement number */u_char th_offx2; /* data offset, rsvd */#define TH_OFF(th) (((th)->th_offx2 & 0xf0) >> 4)u_char th_flags;#define TH_FIN 0x01#define TH_SYN 0x02#define TH_RST 0x04#define TH_PUSH 0x08#define TH_ACK 0x10#define TH_URG 0x20#define TH_ECE 0x40#define TH_CWR 0x80#define TH_FLAGS (TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG|TH_ECE|TH_CWR)u_short th_win; /* window */u_short th_sum; /* checksum */u_short th_urp; /* urgent pointer */};Note: On my Slackware Linux 8 box (stock kernel 2.2.19) I found that code using the above structures would not compile. The problem, as it turns out, was in include/features.h, which implements a POSIX interface unless _BSD_SOURCE is defined. If it was not defined, then I had to use a different structure definition for the TCP header. The more universal solution, that does not prevent the code from working on FreeBSD or OpenBSD (where it had previously worked fine), is simply to do the following:#define _BSD_SOURCE 1prior to including any of your header files. This will ensure that a BSD style API is being used. Again, if you don't wish to do this, then you can simply use the alternative TCP header structure, which I've linked to here, along with some quick notes about using it.So how does all of this relate to pcap and our mysterious u_char pointer? Well, those structures define the headers that appear in the data for the packet. So how can we break it apart? Be prepared to witness one of the most practical uses of pointers (for all of those new C programmers who insist that pointers are useless, I smite you).Again, we're going to assume that we are dealing with a TCP/IP packet over Ethernet. This same technique applies to any packet; the only difference is the structure types that you actually use. So let's begin by defining the variables and compile-time definitions we will need to deconstruct the packet data./* ethernet headers are always exactly 14 bytes */#define SIZE_ETHERNET 14const struct sniff_ethernet *ethernet; /* The ethernet header */const struct sniff_ip *ip; /* The IP header */const struct sniff_tcp *tcp; /* The TCP header */const char *payload; /* Packet payload */u_int size_ip;u_int size_tcp;And now we do our magical typecasting:ethernet = (struct sniff_ethernet*)(packet);ip = (struct sniff_ip*)(packet + SIZE_ETHERNET);size_ip = IP_HL(ip)*4;if (size_ip < 20) {printf(" * Invalid IP header length: %u bytes\n", size_ip);return;}tcp = (struct sniff_tcp*)(packet + SIZE_ETHERNET + size_ip);size_tcp = TH_OFF(tcp)*4;if (size_tcp < 20) {printf(" * Invalid TCP header length: %u bytes\n", size_tcp);return;}payload = (u_char *)(packet + SIZE_ETHERNET + size_ip + size_tcp);How does this work? Consider the layout of the packet data in memory. The u_char pointer is really just a variable containing an address in memory. That's what a pointer is; it points to a location in memory.For the sake of simplicity, we'll say that the address this pointer is set to is the value X. Well, if our three structures are just sitting in line, the first of them (sniff_ethernet) being located in memory at the address X, then we can easily find the address of the structure after it; that address is X plus the length of the Ethernet header, which is 14, or SIZE_ETHERNET.Similarly if we have the address of that header, the address of the structure after it is the address of that header plus the length of that header. The IP header, unlike the Ethernet header, does not have a fixed length; its length is given, as a count of 4-byte words, by the header length field of the IP header. As it's a count of 4-byte words, it must be multiplied by 4 to give the size in bytes. The minimum length of that header is 20 bytes.The TCP header also has a variable length; its length is given, as a number of 4-byte words, by the "data offset" field of the TCP header, and its minimum length is also 20 bytes.。