#define APP_NAME "sniffex" #define APP_DESC "Sniffer example using libpcap" #define APP_COPYRIGHT "Copyright (c) 2005" #define APP_DISCLAIMER "THERE IS ABSOLUTELY NO WARRANTY FOR THIS PROGRAM."#define HAVE_REMOTE 我的程序是这样写的: #include <pcap.h> #include <stdio.h> #include <stdio.h> #include <string.h> #include <stdlib.h> #ifdef WIN32 #include <winsock2.h> #include <iostream> // 告诉连接器与WS2_32库连接 #pragma comment(lib,"WS2_32.lib") #pragma warning(disable: 4996) #else #include <ctype.h> #include <errno.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #endif using namespace std; /* default snap length (maximum bytes per packet to capture) */ #define SNAP_LEN 1518 /*分析:6字节目的地址+6字节源地址+2字节帧类型+最大1500字上层数据+4字节CRC校验*/ /* ethernet headers are always exactly 14 bytes [1] */ #define SIZE_ETHERNET 14/* 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 */ typedef u_int tcp_seq;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 */ };void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet);void print_payload(const u_char *payload, int len);void print_hex_ascii_line(const u_char *payload, int len, int offset);void print_app_banner(void);void print_app_usage(void); std::string IpToStr(const sockaddr *addr); void PrintAdapterInfo(pcap_if_t* pAdapter);// 将sockaddr*类型的IP转换成字符串类型的IP地址 std::string IpToStr(const sockaddr *addr) { std::string s; s = inet_ntoa((*(sockaddr_in*)addr).sin_addr); return s; } // 输出每个网卡的信息 void PrintAdapterInfo(pcap_if_t* pAdapter) { printf("名字:%s\n", pAdapter->name); if (pAdapter->description) printf("描述:(%s)\n", pAdapter->description); else printf(" (没有相关的描述信息)\n"); pcap_addr *p = pAdapter->addresses; // 得到指向地址结构的指针 // 输出地址信息 while(p != NULL) { printf("IP地址:%s\n", IpToStr(p->addr).c_str()); printf("子网掩码:%s\n", IpToStr(p->netmask).c_str()); printf("广播地址:%s\n", IpToStr(p->broadaddr).c_str()); p = p->next; } printf("\n\n"); } /* * app name/banner */ void print_app_banner(void) { printf("%s - %s\n", APP_NAME, APP_DESC); printf("%s\n", APP_COPYRIGHT); printf("%s\n", APP_DISCLAIMER); printf("\n");return; }/* * print help text */ void print_app_usage(void) { printf("Usage: %s [interface]\n", APP_NAME); printf("\n"); printf("Options:\n"); printf(" interface Listen on <interface> for packets.\n"); printf("\n");return; }/* * print data in rows of 16 bytes: offset hex ascii * * 00000 47 45 54 20 2f 20 48 54 54 50 2f 31 2e 31 0d 0a GET / HTTP/1.1.. */ void print_hex_ascii_line(const u_char *payload, int len, int offset) { int i; int gap; const u_char *ch; /* offset */ printf("%05d ", offset);
/* hex */ ch = payload; for(i = 0; i < len; i++) { printf("%02x ", *ch); ch++; /* print extra space after 8th byte for visual aid */ if (i == 7) printf(" "); } /* print space to handle line less than 8 bytes */ if (len < 8) printf(" ");
/* fill hex gap with spaces if not full line */ if (len < 16) { gap = 16 - len; for (i = 0; i < gap; i++) { printf(" "); } } printf(" ");
/* ascii (if printable) */ ch = payload; for(i = 0; i < len; i++) { if (isprint(*ch)) printf("%c", *ch); else printf("."); ch++; } printf("\n");return; }/* * print packet payload data (avoid printing binary data) */ void print_payload(const u_char *payload, int len) { int len_rem = len; int line_width = 16; /* number of bytes per line */ int line_len; int offset = 0; /* zero-based offset counter */ const u_char *ch = payload; /* data fits on one line */ if (len <= line_width) { print_hex_ascii_line(ch, len, offset); return; } /* data spans multiple lines */ for ( ;; ) { /* compute current line length */ line_len = line_width % len_rem; /* print line */ print_hex_ascii_line(ch, line_len, offset); /* compute total remaining */ len_rem = len_rem - line_len; /* shift pointer to remaining bytes to print */ ch = ch + line_len; /* add offset */ offset = offset + line_width; /* check if we have line width chars or less */ if (len_rem <= line_width) { /* print last line and get out */ print_hex_ascii_line(ch, len_rem, offset); break; } }return; }/* * dissect/print packet */ void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet) { static int count = 1; /* packet counter */
/* declare pointers to packet headers */ const struct sniff_ethernet *ethernet; /* The ethernet header [1] */ const struct sniff_ip *ip; /* The IP header */ const struct sniff_tcp *tcp; /* The TCP header */ const u_char *payload; /* Packet payload */ int size_ip; int size_tcp; int size_payload;
/* * Print payload data; it might be binary, so don't just * treat it as a string. */ printf(" Payload (%d bytes):\n", size_payload); if (size_payload > 0) {
print_payload(payload, size_payload); }return; }
下面是main函数:int main(int argc, char **argv) {
char errbuf[PCAP_ERRBUF_SIZE]; /* error buffer */ pcap_t *handle; /* packet capture handle */ int i=0; int inum; pcap_if_t *alldevs; pcap_if_t *dev; char filter_exp[] = "tcp"; /* filter expression [3] */ struct bpf_program fp; /* compiled filter program (expression) */ bpf_u_int32 mask; /* subnet mask */ bpf_u_int32 net; /* ip */ int num_packets = 10; /* number of packets to capture */ /* 这个API用来获得网卡 的列表 */ if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1) { fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf); exit(1); } /* 显示列表的响应字段的内容 */ for(dev=alldevs;dev;dev=dev->next) { printf("%d. %s", ++i, dev->name); if (dev->description) { printf("\n\t\tDescription: (%s)\n", dev->description); PrintAdapterInfo(dev); // 输出每个网卡信息 } else printf(" (No description available)\n"); } //没有找到相关设备 if(i==0) { printf("\nNo interfaces found! Make sure WinPcap is installed.\n"); return 0; } printf("Enter the interface number (1-%d):",i); scanf("%d", &inum); if(inum < 1 || inum > i) { printf("\nInterface number out of range.\n"); pcap_freealldevs(alldevs); return -1; } for(dev=alldevs, i=0; i< inum-1 ;dev=dev->next, i++); print_app_banner();
/* get network number and mask associated with capture device */ /* *函数:pcap_lookupnet() *函数原型:int pcap_lookupnet(char *device, bpf_u_int32 *netp,bpf_u_int32 *maskp, char *errbuf) ; *函数作用:获得指定网络设备的网络的网络号和掩码。netp和maskp参数都是bpf_u_u_int32指针,用于存储网络设备IP地址与子网掩码。如果函数出错,则返回-1,t同时errbuf中存 *放相关的出错信息 */ if (pcap_lookupnet(dev->name, &net, &mask, errbuf) == -1) { fprintf(stderr, "Couldn't get netmask for device %s: %s\n", dev, errbuf); net = 0; mask = 0; } /* print capture info */ printf("Device: %s\n", dev->name); printf("Number of packets: %d\n", num_packets); printf("Filter expression: %s\n", filter_exp);
/* open capture device */ /* *函数:pcap_open_live *函数原型:pcap_t *pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf) ; *函数作用:获取用于捕获网络数据包的数据包捕获描述字。device参数指定打开的网络设备名,snaplen参数指定捕获数据的最大字节数,promise指定是否将网络接口设置于混杂模式;to_ms *参数指定超时时间(毫秒),通常出于效率考虑,可以将该值的值设置得比较大,但是当对响应时间要求比较高式,应该将该值设置的比较小;ebuf参数则仅仅在pcap_open_live()函数出错式返回NULL时,用于存放出错信息。 *若函数执行成功,则返回可用的数据包捕获描述字,否则返回NULL,同时在ebuf中存放错误的信息。 */ handle = pcap_open_live(dev->name, SNAP_LEN,1, 1000, errbuf); if (handle == NULL) { fprintf(stderr, "Couldn't open device %s: %s\n", dev->name, errbuf); exit(EXIT_FAILURE); } /* make sure we're capturing on an Ethernet device [2] */ /* *函数:pcap_datalink *函数原型:int pcap_datalink(pcap_t *p); *函数作用:返回数据链路层类型,例如DLT_EN10MB。 */ if (pcap_datalink(handle) != DLT_EN10MB) { fprintf(stderr, "%s is not an Ethernet\n", dev->name); exit(EXIT_FAILURE); } /* compile the filter expression */ /* *函数:pcap_compile *函数原型:int pcap_compile(pcap_t *p, struct bpf_program *fp,char *str, int optimize, bpf_u_int32 netmask) ; *函数作用:将指定的规则编译到过滤器中,其中参数p是描述字,fo是一个bpf_program结构的指针,在pcap_compile()函数中被赋值,optimize参数控制结果代码的优化,netmask参数指定 *本地网络的网络掩码。若函数执行失败,会返回-1,成功时返回0。 */ if (pcap_compile(handle, &fp, filter_exp, 0, net) == -1) { fprintf(stderr, "Couldn't parse filter %s: %s\n", filter_exp, pcap_geterr(handle)); exit(EXIT_FAILURE); } /* apply the compiled filter */ /* *函数:pcap_setfilter *函数原型:int pcap_setfilter(pcap_t *p, struct bpf_program *fp); *函数作用:设定一个过滤程序,其中参数p是描述字,fp参数bpf_program结构指针,通常取自pcap_compile()函数调用。 *若函数执行成功,则返回0,失败则返回-1。 */ if (pcap_setfilter(handle, &fp) == -1) { fprintf(stderr, "Couldn't install filter %s: %s\n", filter_exp, pcap_geterr(handle)); exit(EXIT_FAILURE); } /* now we can set our callback function */ /* *函数:pcap_loop *函数原型:int pcap_loop(pcap_t *p, int cnt,pcap_handler callback, u_char *user); *函数作用:捕获并处理数据包,其中参数pp是描述字。 *cnt参数指定函数返回前处理数据包的最大值 *若cnt值为-1,表示在一个缓冲区中处理所有的数据包, *若cnt值为0,表示处理所有的数据包,或者出现错误。 *callback参数指定一个带有三个参数的回调函数,这个函数原型是: *void call_back(u_char *,pcap_pkthdr*,u_char *); *这三个参数一个是从pcap_loop()函数传递过来的u_char指针,一个是pcap_pkthdr结构的指针,另一个是指示数据包大小的u_char指针。 *如果成功则返回读取到的字节数,读取到EOF时则返回零值,出错时则返回-1,此时可以调用pcap_perror()或者pcap_geterr()函数获取错误信息。 */ pcap_loop(handle, num_packets, got_packet, NULL); /* cleanup */ pcap_freecode(&fp); /* *函数:pcap_close(); *函数原型:void pcap_close(pcap_t *p) ; *函数作用:关闭网络设备,并释放资源 */ pcap_close(handle); printf("\nCapture complete.\n"); return 0; }
int main(int argc, char **argv) {
char errbuf[PCAP_ERRBUF_SIZE]; /* error buffer */ pcap_t *handle; /* packet capture handle */ int i=0; int inum; pcap_if_t *alldevs; pcap_if_t *dev; char filter_exp[] = "tcp"; /* filter expression [3] */ struct bpf_program fp; /* compiled filter program (expression) */ bpf_u_int32 mask; /* subnet mask */ bpf_u_int32 net; /* ip */ int num_packets = 10; /* number of packets to capture */ /* 这个API用来获得网卡 的列表 */ if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1) { fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf); exit(1); } /* 显示列表的响应字段的内容 */ for(dev=alldevs;dev;dev=dev->next) { printf("%d. %s", ++i, dev->name); if (dev->description) { printf("\n\t\tDescription: (%s)\n", dev->description); PrintAdapterInfo(dev); // 输出每个网卡信息 } else printf(" (No description available)\n"); } //没有找到相关设备 if(i==0) { printf("\nNo interfaces found! Make sure WinPcap is installed.\n"); return 0; } printf("Enter the interface number (1-%d):",i); scanf("%d", &inum); if(inum < 1 || inum > i) { printf("\nInterface number out of range.\n"); pcap_freealldevs(alldevs); return -1; } for(dev=alldevs, i=0; i< inum-1 ;dev=dev->next, i++); print_app_banner();
/* get network number and mask associated with capture device */ /* *函数:pcap_lookupnet() *函数原型:int pcap_lookupnet(char *device, bpf_u_int32 *netp,bpf_u_int32 *maskp, char *errbuf) ; *函数作用:获得指定网络设备的网络的网络号和掩码。netp和maskp参数都是bpf_u_u_int32指针,用于存储网络设备IP地址与子网掩码。如果函数出错,则返回-1,t同时errbuf中存 *放相关的出错信息 */ if (pcap_lookupnet(dev->name, &net, &mask, errbuf) == -1) { fprintf(stderr, "Couldn't get netmask for device %s: %s\n", dev, errbuf); net = 0; mask = 0; } /* print capture info */ printf("Device: %s\n", dev->name); printf("Number of packets: %d\n", num_packets); printf("Filter expression: %s\n", filter_exp);
/* open capture device */ /* *函数:pcap_open_live *函数原型:pcap_t *pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf) ; *函数作用:获取用于捕获网络数据包的数据包捕获描述字。device参数指定打开的网络设备名,snaplen参数指定捕获数据的最大字节数,promise指定是否将网络接口设置于混杂模式;to_ms *参数指定超时时间(毫秒),通常出于效率考虑,可以将该值的值设置得比较大,但是当对响应时间要求比较高式,应该将该值设置的比较小;ebuf参数则仅仅在pcap_open_live()函数出错式返回NULL时,用于存放出错信息。 *若函数执行成功,则返回可用的数据包捕获描述字,否则返回NULL,同时在ebuf中存放错误的信息。 */ handle = pcap_open_live(dev->name, SNAP_LEN,1, 1000, errbuf); if (handle == NULL) { fprintf(stderr, "Couldn't open device %s: %s\n", dev->name, errbuf); exit(EXIT_FAILURE); } /* make sure we're capturing on an Ethernet device [2] */ /* *函数:pcap_datalink *函数原型:int pcap_datalink(pcap_t *p); *函数作用:返回数据链路层类型,例如DLT_EN10MB。 */ if (pcap_datalink(handle) != DLT_EN10MB) { fprintf(stderr, "%s is not an Ethernet\n", dev->name); exit(EXIT_FAILURE); } /* compile the filter expression */ /* *函数:pcap_compile *函数原型:int pcap_compile(pcap_t *p, struct bpf_program *fp,char *str, int optimize, bpf_u_int32 netmask) ; *函数作用:将指定的规则编译到过滤器中,其中参数p是描述字,fo是一个bpf_program结构的指针,在pcap_compile()函数中被赋值,optimize参数控制结果代码的优化,netmask参数指定 *本地网络的网络掩码。若函数执行失败,会返回-1,成功时返回0。 */ if (pcap_compile(handle, &fp, filter_exp, 0, net) == -1) { fprintf(stderr, "Couldn't parse filter %s: %s\n", filter_exp, pcap_geterr(handle)); exit(EXIT_FAILURE); } /* apply the compiled filter */ /* *函数:pcap_setfilter *函数原型:int pcap_setfilter(pcap_t *p, struct bpf_program *fp); *函数作用:设定一个过滤程序,其中参数p是描述字,fp参数bpf_program结构指针,通常取自pcap_compile()函数调用。 *若函数执行成功,则返回0,失败则返回-1。 */ if (pcap_setfilter(handle, &fp) == -1) { fprintf(stderr, "Couldn't install filter %s: %s\n", filter_exp, pcap_geterr(handle)); exit(EXIT_FAILURE); } /* now we can set our callback function */ /* *函数:pcap_loop *函数原型:int pcap_loop(pcap_t *p, int cnt,pcap_handler callback, u_char *user); *函数作用:捕获并处理数据包,其中参数pp是描述字。 *cnt参数指定函数返回前处理数据包的最大值 *若cnt值为-1,表示在一个缓冲区中处理所有的数据包, *若cnt值为0,表示处理所有的数据包,或者出现错误。 *callback参数指定一个带有三个参数的回调函数,这个函数原型是: *void call_back(u_char *,pcap_pkthdr*,u_char *); *这三个参数一个是从pcap_loop()函数传递过来的u_char指针,一个是pcap_pkthdr结构的指针,另一个是指示数据包大小的u_char指针。 *如果成功则返回读取到的字节数,读取到EOF时则返回零值,出错时则返回-1,此时可以调用pcap_perror()或者pcap_geterr()函数获取错误信息。 */ pcap_loop(handle, num_packets, got_packet, NULL); /* cleanup */ pcap_freecode(&fp); /* *函数:pcap_close(); *函数原型:void pcap_close(pcap_t *p) ; *函数作用:关闭网络设备,并释放资源 */ pcap_close(handle); printf("\nCapture complete.\n"); return 0; }
#define APP_DESC "Sniffer example using libpcap"
#define APP_COPYRIGHT "Copyright (c) 2005"
#define APP_DISCLAIMER "THERE IS ABSOLUTELY NO WARRANTY FOR THIS PROGRAM."#define HAVE_REMOTE
我的程序是这样写的:
#include <pcap.h>
#include <stdio.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#ifdef WIN32
#include <winsock2.h>
#include <iostream>
// 告诉连接器与WS2_32库连接
#pragma comment(lib,"WS2_32.lib")
#pragma warning(disable: 4996)
#else
#include <ctype.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#endif
using namespace std;
/* default snap length (maximum bytes per packet to capture) */
#define SNAP_LEN 1518
/*分析:6字节目的地址+6字节源地址+2字节帧类型+最大1500字上层数据+4字节CRC校验*/
/* ethernet headers are always exactly 14 bytes [1] */
#define SIZE_ETHERNET 14/* 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 */
typedef u_int tcp_seq;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 */
};void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet);void print_payload(const u_char *payload, int len);void print_hex_ascii_line(const u_char *payload, int len, int offset);void print_app_banner(void);void print_app_usage(void);
std::string IpToStr(const sockaddr *addr);
void PrintAdapterInfo(pcap_if_t* pAdapter);// 将sockaddr*类型的IP转换成字符串类型的IP地址
std::string IpToStr(const sockaddr *addr)
{
std::string s;
s = inet_ntoa((*(sockaddr_in*)addr).sin_addr);
return s;
}
// 输出每个网卡的信息
void PrintAdapterInfo(pcap_if_t* pAdapter)
{
printf("名字:%s\n", pAdapter->name);
if (pAdapter->description)
printf("描述:(%s)\n", pAdapter->description);
else
printf(" (没有相关的描述信息)\n"); pcap_addr *p = pAdapter->addresses; // 得到指向地址结构的指针
// 输出地址信息
while(p != NULL)
{
printf("IP地址:%s\n", IpToStr(p->addr).c_str());
printf("子网掩码:%s\n", IpToStr(p->netmask).c_str());
printf("广播地址:%s\n", IpToStr(p->broadaddr).c_str());
p = p->next;
}
printf("\n\n");
}
/*
* app name/banner
*/
void
print_app_banner(void)
{ printf("%s - %s\n", APP_NAME, APP_DESC);
printf("%s\n", APP_COPYRIGHT);
printf("%s\n", APP_DISCLAIMER);
printf("\n");return;
}/*
* print help text
*/
void
print_app_usage(void)
{ printf("Usage: %s [interface]\n", APP_NAME);
printf("\n");
printf("Options:\n");
printf(" interface Listen on <interface> for packets.\n");
printf("\n");return;
}/*
* print data in rows of 16 bytes: offset hex ascii
*
* 00000 47 45 54 20 2f 20 48 54 54 50 2f 31 2e 31 0d 0a GET / HTTP/1.1..
*/
void
print_hex_ascii_line(const u_char *payload, int len, int offset)
{ int i;
int gap;
const u_char *ch; /* offset */
printf("%05d ", offset);
/* hex */
ch = payload;
for(i = 0; i < len; i++) {
printf("%02x ", *ch);
ch++;
/* print extra space after 8th byte for visual aid */
if (i == 7)
printf(" ");
}
/* print space to handle line less than 8 bytes */
if (len < 8)
printf(" ");
/* fill hex gap with spaces if not full line */
if (len < 16) {
gap = 16 - len;
for (i = 0; i < gap; i++) {
printf(" ");
}
}
printf(" ");
/* ascii (if printable) */
ch = payload;
for(i = 0; i < len; i++) {
if (isprint(*ch))
printf("%c", *ch);
else
printf(".");
ch++;
} printf("\n");return;
}/*
* print packet payload data (avoid printing binary data)
*/
void print_payload(const u_char *payload, int len)
{ int len_rem = len;
int line_width = 16; /* number of bytes per line */
int line_len;
int offset = 0; /* zero-based offset counter */
const u_char *ch = payload; /* data fits on one line */
if (len <= line_width) {
print_hex_ascii_line(ch, len, offset);
return;
} /* data spans multiple lines */
for ( ;; ) {
/* compute current line length */
line_len = line_width % len_rem;
/* print line */
print_hex_ascii_line(ch, line_len, offset);
/* compute total remaining */
len_rem = len_rem - line_len;
/* shift pointer to remaining bytes to print */
ch = ch + line_len;
/* add offset */
offset = offset + line_width;
/* check if we have line width chars or less */
if (len_rem <= line_width) {
/* print last line and get out */
print_hex_ascii_line(ch, len_rem, offset);
break;
}
}return;
}/*
* dissect/print packet
*/
void
got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet)
{ static int count = 1; /* packet counter */
/* declare pointers to packet headers */
const struct sniff_ethernet *ethernet; /* The ethernet header [1] */
const struct sniff_ip *ip; /* The IP header */
const struct sniff_tcp *tcp; /* The TCP header */
const u_char *payload; /* Packet payload */ int size_ip;
int size_tcp;
int size_payload;
printf("\nPacket number %d:\n", count);
count++;
printf("打印以太帧!\n");
const u_char *ptr=packet;
int i=0;
for(i=0;i<SIZE_ETHERNET+8;i++)
{
printf("[%02d]:%x ",i,*ptr);
ptr++;
}
/*
IP包头开始部分的第一个字节应该是45,4表示协议版本是IPV4,5表示IP包头部是5个32bit长,也就是20个字节
*/
printf("\n以太帧打印完毕\n");
/* define ethernet header */
ethernet = (struct sniff_ethernet*)(packet);
/* define/compute ip header offset */
ip = (struct sniff_ip*)(packet + SIZE_ETHERNET);//越过以太网首部,得到IP首部
size_ip = IP_HL(ip)*4;/*IP包头长度单位为32Bit*/
if (size_ip < 20) {
printf(" * Invalid IP header length: %u bytes\n", size_ip);
return;
} /* print source and destination IP addresses */
printf(" From: %s\n", inet_ntoa(ip->ip_src));
printf(" To: %s\n", inet_ntoa(ip->ip_dst));
/* determine protocol */
switch(ip->ip_p) {
case IPPROTO_TCP:
printf(" Protocol: TCP\n");
break;
case IPPROTO_UDP:
printf(" Protocol: UDP\n");
return;
case IPPROTO_ICMP:
printf(" Protocol: ICMP\n");
return;
case IPPROTO_IP:
printf(" Protocol: IP\n");
return;
default:
printf(" Protocol: unknown\n");
return;
}
/*
* OK, this packet is TCP.
*/
/* define/compute tcp header offset */
tcp = (struct sniff_tcp*)(packet + SIZE_ETHERNET + size_ip); //越过IP首部,得到TCP首部
size_tcp = TH_OFF(tcp)*4;
if (size_tcp < 20) {
printf(" * Invalid TCP header length: %u bytes\n", size_tcp);
return;
}
printf(" Src port: %d\n", ntohs(tcp->th_sport));
printf(" Dst port: %d\n", ntohs(tcp->th_dport));
/* define/compute tcp payload (segment) offset */
payload = (u_char *)(packet + SIZE_ETHERNET + size_ip + size_tcp);
//越过TCP首部得到净载荷数据
/* compute tcp payload (segment) size */
size_payload = ntohs(ip->ip_len) - (size_ip + size_tcp);
/*
* Print payload data; it might be binary, so don't just
* treat it as a string.
*/
printf(" Payload (%d bytes):\n", size_payload);
if (size_payload > 0) {
print_payload(payload, size_payload);
}return;
}
{
char errbuf[PCAP_ERRBUF_SIZE]; /* error buffer */
pcap_t *handle; /* packet capture handle */
int i=0;
int inum;
pcap_if_t *alldevs;
pcap_if_t *dev;
char filter_exp[] = "tcp"; /* filter expression [3] */
struct bpf_program fp; /* compiled filter program (expression) */
bpf_u_int32 mask; /* subnet mask */
bpf_u_int32 net; /* ip */
int num_packets = 10; /* number of packets to capture */
/* 这个API用来获得网卡 的列表 */
if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1)
{
fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf);
exit(1);
}
/* 显示列表的响应字段的内容 */
for(dev=alldevs;dev;dev=dev->next)
{
printf("%d. %s", ++i, dev->name);
if (dev->description)
{
printf("\n\t\tDescription: (%s)\n", dev->description);
PrintAdapterInfo(dev); // 输出每个网卡信息
}
else printf(" (No description available)\n");
}
//没有找到相关设备
if(i==0)
{
printf("\nNo interfaces found! Make sure WinPcap is installed.\n");
return 0;
} printf("Enter the interface number (1-%d):",i);
scanf("%d", &inum); if(inum < 1 || inum > i)
{
printf("\nInterface number out of range.\n");
pcap_freealldevs(alldevs);
return -1;
}
for(dev=alldevs, i=0; i< inum-1 ;dev=dev->next, i++); print_app_banner();
/* get network number and mask associated with capture device */
/*
*函数:pcap_lookupnet()
*函数原型:int pcap_lookupnet(char *device, bpf_u_int32 *netp,bpf_u_int32 *maskp, char *errbuf) ;
*函数作用:获得指定网络设备的网络的网络号和掩码。netp和maskp参数都是bpf_u_u_int32指针,用于存储网络设备IP地址与子网掩码。如果函数出错,则返回-1,t同时errbuf中存
*放相关的出错信息
*/
if (pcap_lookupnet(dev->name, &net, &mask, errbuf) == -1) {
fprintf(stderr, "Couldn't get netmask for device %s: %s\n",
dev, errbuf);
net = 0;
mask = 0;
} /* print capture info */
printf("Device: %s\n", dev->name);
printf("Number of packets: %d\n", num_packets);
printf("Filter expression: %s\n", filter_exp);
/* open capture device */
/*
*函数:pcap_open_live
*函数原型:pcap_t *pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf) ;
*函数作用:获取用于捕获网络数据包的数据包捕获描述字。device参数指定打开的网络设备名,snaplen参数指定捕获数据的最大字节数,promise指定是否将网络接口设置于混杂模式;to_ms
*参数指定超时时间(毫秒),通常出于效率考虑,可以将该值的值设置得比较大,但是当对响应时间要求比较高式,应该将该值设置的比较小;ebuf参数则仅仅在pcap_open_live()函数出错式返回NULL时,用于存放出错信息。
*若函数执行成功,则返回可用的数据包捕获描述字,否则返回NULL,同时在ebuf中存放错误的信息。
*/
handle = pcap_open_live(dev->name, SNAP_LEN,1, 1000, errbuf);
if (handle == NULL) {
fprintf(stderr, "Couldn't open device %s: %s\n", dev->name, errbuf);
exit(EXIT_FAILURE);
} /* make sure we're capturing on an Ethernet device [2] */
/*
*函数:pcap_datalink
*函数原型:int pcap_datalink(pcap_t *p);
*函数作用:返回数据链路层类型,例如DLT_EN10MB。
*/
if (pcap_datalink(handle) != DLT_EN10MB) {
fprintf(stderr, "%s is not an Ethernet\n", dev->name);
exit(EXIT_FAILURE);
} /* compile the filter expression */
/*
*函数:pcap_compile
*函数原型:int pcap_compile(pcap_t *p, struct bpf_program *fp,char *str, int optimize, bpf_u_int32 netmask) ;
*函数作用:将指定的规则编译到过滤器中,其中参数p是描述字,fo是一个bpf_program结构的指针,在pcap_compile()函数中被赋值,optimize参数控制结果代码的优化,netmask参数指定
*本地网络的网络掩码。若函数执行失败,会返回-1,成功时返回0。
*/
if (pcap_compile(handle, &fp, filter_exp, 0, net) == -1) {
fprintf(stderr, "Couldn't parse filter %s: %s\n",
filter_exp, pcap_geterr(handle));
exit(EXIT_FAILURE);
} /* apply the compiled filter */
/*
*函数:pcap_setfilter
*函数原型:int pcap_setfilter(pcap_t *p, struct bpf_program *fp);
*函数作用:设定一个过滤程序,其中参数p是描述字,fp参数bpf_program结构指针,通常取自pcap_compile()函数调用。
*若函数执行成功,则返回0,失败则返回-1。
*/
if (pcap_setfilter(handle, &fp) == -1) {
fprintf(stderr, "Couldn't install filter %s: %s\n",
filter_exp, pcap_geterr(handle));
exit(EXIT_FAILURE);
} /* now we can set our callback function */
/*
*函数:pcap_loop
*函数原型:int pcap_loop(pcap_t *p, int cnt,pcap_handler callback, u_char *user);
*函数作用:捕获并处理数据包,其中参数pp是描述字。
*cnt参数指定函数返回前处理数据包的最大值
*若cnt值为-1,表示在一个缓冲区中处理所有的数据包,
*若cnt值为0,表示处理所有的数据包,或者出现错误。
*callback参数指定一个带有三个参数的回调函数,这个函数原型是:
*void call_back(u_char *,pcap_pkthdr*,u_char *);
*这三个参数一个是从pcap_loop()函数传递过来的u_char指针,一个是pcap_pkthdr结构的指针,另一个是指示数据包大小的u_char指针。
*如果成功则返回读取到的字节数,读取到EOF时则返回零值,出错时则返回-1,此时可以调用pcap_perror()或者pcap_geterr()函数获取错误信息。
*/
pcap_loop(handle, num_packets, got_packet, NULL); /* cleanup */
pcap_freecode(&fp);
/*
*函数:pcap_close();
*函数原型:void pcap_close(pcap_t *p) ;
*函数作用:关闭网络设备,并释放资源
*/
pcap_close(handle); printf("\nCapture complete.\n"); return 0;
}
{
char errbuf[PCAP_ERRBUF_SIZE]; /* error buffer */
pcap_t *handle; /* packet capture handle */
int i=0;
int inum;
pcap_if_t *alldevs;
pcap_if_t *dev;
char filter_exp[] = "tcp"; /* filter expression [3] */
struct bpf_program fp; /* compiled filter program (expression) */
bpf_u_int32 mask; /* subnet mask */
bpf_u_int32 net; /* ip */
int num_packets = 10; /* number of packets to capture */
/* 这个API用来获得网卡 的列表 */
if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1)
{
fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf);
exit(1);
}
/* 显示列表的响应字段的内容 */
for(dev=alldevs;dev;dev=dev->next)
{
printf("%d. %s", ++i, dev->name);
if (dev->description)
{
printf("\n\t\tDescription: (%s)\n", dev->description);
PrintAdapterInfo(dev); // 输出每个网卡信息
}
else printf(" (No description available)\n");
}
//没有找到相关设备
if(i==0)
{
printf("\nNo interfaces found! Make sure WinPcap is installed.\n");
return 0;
} printf("Enter the interface number (1-%d):",i);
scanf("%d", &inum); if(inum < 1 || inum > i)
{
printf("\nInterface number out of range.\n");
pcap_freealldevs(alldevs);
return -1;
}
for(dev=alldevs, i=0; i< inum-1 ;dev=dev->next, i++); print_app_banner();
/* get network number and mask associated with capture device */
/*
*函数:pcap_lookupnet()
*函数原型:int pcap_lookupnet(char *device, bpf_u_int32 *netp,bpf_u_int32 *maskp, char *errbuf) ;
*函数作用:获得指定网络设备的网络的网络号和掩码。netp和maskp参数都是bpf_u_u_int32指针,用于存储网络设备IP地址与子网掩码。如果函数出错,则返回-1,t同时errbuf中存
*放相关的出错信息
*/
if (pcap_lookupnet(dev->name, &net, &mask, errbuf) == -1) {
fprintf(stderr, "Couldn't get netmask for device %s: %s\n",
dev, errbuf);
net = 0;
mask = 0;
} /* print capture info */
printf("Device: %s\n", dev->name);
printf("Number of packets: %d\n", num_packets);
printf("Filter expression: %s\n", filter_exp);
/* open capture device */
/*
*函数:pcap_open_live
*函数原型:pcap_t *pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf) ;
*函数作用:获取用于捕获网络数据包的数据包捕获描述字。device参数指定打开的网络设备名,snaplen参数指定捕获数据的最大字节数,promise指定是否将网络接口设置于混杂模式;to_ms
*参数指定超时时间(毫秒),通常出于效率考虑,可以将该值的值设置得比较大,但是当对响应时间要求比较高式,应该将该值设置的比较小;ebuf参数则仅仅在pcap_open_live()函数出错式返回NULL时,用于存放出错信息。
*若函数执行成功,则返回可用的数据包捕获描述字,否则返回NULL,同时在ebuf中存放错误的信息。
*/
handle = pcap_open_live(dev->name, SNAP_LEN,1, 1000, errbuf);
if (handle == NULL) {
fprintf(stderr, "Couldn't open device %s: %s\n", dev->name, errbuf);
exit(EXIT_FAILURE);
} /* make sure we're capturing on an Ethernet device [2] */
/*
*函数:pcap_datalink
*函数原型:int pcap_datalink(pcap_t *p);
*函数作用:返回数据链路层类型,例如DLT_EN10MB。
*/
if (pcap_datalink(handle) != DLT_EN10MB) {
fprintf(stderr, "%s is not an Ethernet\n", dev->name);
exit(EXIT_FAILURE);
} /* compile the filter expression */
/*
*函数:pcap_compile
*函数原型:int pcap_compile(pcap_t *p, struct bpf_program *fp,char *str, int optimize, bpf_u_int32 netmask) ;
*函数作用:将指定的规则编译到过滤器中,其中参数p是描述字,fo是一个bpf_program结构的指针,在pcap_compile()函数中被赋值,optimize参数控制结果代码的优化,netmask参数指定
*本地网络的网络掩码。若函数执行失败,会返回-1,成功时返回0。
*/
if (pcap_compile(handle, &fp, filter_exp, 0, net) == -1) {
fprintf(stderr, "Couldn't parse filter %s: %s\n",
filter_exp, pcap_geterr(handle));
exit(EXIT_FAILURE);
} /* apply the compiled filter */
/*
*函数:pcap_setfilter
*函数原型:int pcap_setfilter(pcap_t *p, struct bpf_program *fp);
*函数作用:设定一个过滤程序,其中参数p是描述字,fp参数bpf_program结构指针,通常取自pcap_compile()函数调用。
*若函数执行成功,则返回0,失败则返回-1。
*/
if (pcap_setfilter(handle, &fp) == -1) {
fprintf(stderr, "Couldn't install filter %s: %s\n",
filter_exp, pcap_geterr(handle));
exit(EXIT_FAILURE);
} /* now we can set our callback function */
/*
*函数:pcap_loop
*函数原型:int pcap_loop(pcap_t *p, int cnt,pcap_handler callback, u_char *user);
*函数作用:捕获并处理数据包,其中参数pp是描述字。
*cnt参数指定函数返回前处理数据包的最大值
*若cnt值为-1,表示在一个缓冲区中处理所有的数据包,
*若cnt值为0,表示处理所有的数据包,或者出现错误。
*callback参数指定一个带有三个参数的回调函数,这个函数原型是:
*void call_back(u_char *,pcap_pkthdr*,u_char *);
*这三个参数一个是从pcap_loop()函数传递过来的u_char指针,一个是pcap_pkthdr结构的指针,另一个是指示数据包大小的u_char指针。
*如果成功则返回读取到的字节数,读取到EOF时则返回零值,出错时则返回-1,此时可以调用pcap_perror()或者pcap_geterr()函数获取错误信息。
*/
pcap_loop(handle, num_packets, got_packet, NULL); /* cleanup */
pcap_freecode(&fp);
/*
*函数:pcap_close();
*函数原型:void pcap_close(pcap_t *p) ;
*函数作用:关闭网络设备,并释放资源
*/
pcap_close(handle); printf("\nCapture complete.\n"); return 0;
}