话不多说,直接上代码。读完这一段代码libpcap库的基础就介绍完了,后续无限的网络数据分析可能任君发挥。。。
1、示例代码
protocal.c
/*
gcc -o protocal protocal.c -I ./../include -I./ -L./../lib -lpcap
*/
#include <pcap.h>
#include <stdio.h>
#include <stdlib.h>
#include "sniff.h"
int pcap_protocal(const struct pcap_pkthdr *pkthdr, const u_char *packet)
{
printf("packet size:%u, data len:%u\n", pkthdr->len, pkthdr->caplen); //数据包实际的长度, 抓到时的数据长度
/*解析数据链路层 以太网头*/
struct sniff_ethernet *ethernet = (struct sniff_ethernet*)packet;
unsigned char* src_mac = ethernet->ether_shost;
unsigned char* dst_mac = ethernet->ether_dhost;
printf("src_mac:%x:%x:%x:%x:%x:%x\n",src_mac[0],src_mac[1],src_mac[2],src_mac[3],src_mac[4],src_mac[5]);
printf("dst_mac:%x:%x:%x:%x:%x:%x\n",dst_mac[0],dst_mac[1],dst_mac[2],dst_mac[3],dst_mac[4],dst_mac[5]);
//printf("ether_type:%u\n",ethernet->ether_type);
int eth_len = sizeof(struct sniff_ethernet); //以太网头的长度
int ip_len; //ip头的长度
int tcp_len = sizeof(struct sniff_tcp); //tcp头的长度
int udp_len = sizeof(struct sniff_udp); //udp头的长度
/*解析网络层 IP头*/
if(ntohs(ethernet->ether_type) == ETHERTYPE_IPV4)
{ //IPV4
printf("It's IPv4!\n");
struct sniff_ip* ip = (struct sniff_ip*)(packet + eth_len);
ip_len = (ip->ip_hl & 0x0f)*4; //ip头的长度
unsigned char *saddr = (unsigned char*)&ip->ip_src.s_addr; //网络字节序转换成主机字节序
unsigned char *daddr = (unsigned char*)&ip->ip_dst.s_addr;
//printf("eth_len:%u ip_len:%u tcp_len:%u udp_len:%u\n", eth_len, ip_len, tcp_len, udp_len);
printf("src_ip:%d.%d.%d.%d\n", saddr[0], saddr[1],saddr[2],saddr[3]/*InttoIpv4str(saddr)*/); //源IP地址
printf("dst_ip:%d.%d.%d.%d\n", daddr[0],daddr[1],daddr[2],daddr[3]/*InttoIpv4str(daddr)*/); //目的IP地址
/*解析传输层 TCP、UDP、ICMP*/
if(ip->ip_p == IPTYPE_TCP)
{ //TCP
printf("ip->proto:TCP\n"); //传输层用的哪一个协议
struct sniff_tcp* tcp = (struct sniff_tcp*)(packet + eth_len + ip_len);
printf("tcp_sport = %u\n", tcp->th_sport);
printf("tcp_dport = %u\n", tcp->th_dport);
/**********(pcaket + eth_len + ip_len + tcp_len)就是TCP协议传输的正文数据了***********/
}
else if(ip->ip_p == IPTYPE_UDP)
{ //UDP
printf("ip->proto:UDP\n"); //传输层用的哪一个协议
struct sniff_udp* udp = (struct sniff_udp*)(packet + eth_len + ip_len);
printf("udp_sport = %u\n", udp->sport);
printf("udp_dport = %u\n", udp->dport);
/**********(pcaket + eth_len + ip_len + udp_len)就是UDP协议传输的正文数据了***********/
}
else if(ip->ip_p == IPTYPE_ICMP)
{ //ICMP
printf("ip->proto:CCMP\n"); //传输层用的哪一个协议
}
}
else if(ntohs(ethernet->ether_type) == ETHERTYPE_IPV6)
{ //IPV6
printf("It's IPv6!\n");
}
printf("============================================\n");
return 0;
}
int main()
{
int ret32 = -1;
pcap_t *handle = NULL; /* 会话的句柄 */
char dev[] = "eth0"; /* 执行嗅探的设备 */
char errbuf[PCAP_ERRBUF_SIZE]; /* 存储错误 信息的字符串 */
struct bpf_program filter; /*已经编译好的过滤表达式*/
char filter_app[] = "port 22"; /* 过滤表达式*/
bpf_u_int32 mask; /* 执行嗅探的设备的网络掩码 */
bpf_u_int32 net; /* 执行嗅探的设备的IP地址 */
const u_char *packet; /* 实际的包 */
struct pcap_pkthdr header; /* 由pcap.h定义 */
ret32 = pcap_lookupnet(dev, &net, &mask, errbuf);
if(ret32 < 0)
{
printf("pcap_lookupnet return %d, errbuf:%s\n", ret32, errbuf);
}
printf("sizeof(mask) = %d, mask:%#x, net:%#x\n",sizeof(mask), mask, net);
handle = pcap_open_live(dev, 10*1024, 1, 0, errbuf);
if(handle == NULL)
{
printf("pcap_open_live return err,errbuf:%s...\n", errbuf);
return -1;
}
#if 0
ret32 = pcap_compile(handle, &filter, filter_app, 0, net);
if(ret32 < 0)
{
printf("pcap_compile return %d, errbuf:%s\n", ret32, errbuf);
return -1;
}
ret32 = pcap_setfilter(handle, &filter);
if(ret32 < 0)
{
printf("pcap_setfilter return %d, errbuf:%s\n", ret32, errbuf);
return -1;
}
#endif
while(1)
{
/* 截获一个包 */
packet = pcap_next(handle, &header);
if(packet)
{
/* 打印它的长度 */
//printf("Jacked a packet with length of [%d]\n", header.len);
//数据包协议解析
pcap_protocal(&header, packet);
}
else
{
printf("pcap_next return err, errbuf:%s\n", errbuf);
break;
}
}
/* 关闭会话 */
pcap_close(handle);
return 0;
}
sniff.h
#ifndef _SNIFF_H_
#if 0
/*pcap头文件定义的,它包括数据包被嗅探的时间、大小等信息*/
struct pcap_pkthdr {
struct timeval ts; /* 时间戳 */
bpf_u_int32 caplen; /* 已捕捉部分的长度,产生分包后的长度 */
bpf_u_int32 len; /* 该包的脱机长度 */
};
#endif
/* 以太网帧头部 */
struct sniff_ethernet {
#define ETHER_ADDR_LEN 6
u_char ether_dhost[ETHER_ADDR_LEN]; /* 目的主机的地址 */
u_char ether_shost[ETHER_ADDR_LEN]; /* 源主机的地址 */
u_short ether_type; /* IP:0x0800;IPV6:0x86DD; ARP:0x0806;RARP:0x8035 */
};
#define ETHERTYPE_IPV4 (0x0800)
#define ETHERTYPE_IPV6 (0x86DD)
#define ETHERTYPE_ARP (0x0806)
#define ETHERTYPE_RARP (0x8035)
/* IP数据包的头部 */
struct sniff_ip {
#if BYTE_ORDER == LITTLE_ENDIAN
u_int ip_hl:4, /* 头部长度 */
ip_v:4; /* 版本号 */
#if BYTE_ORDER == BIG_ENDIAN
u_int ip_v:4, /* 版本号 */
ip_hl:4; /* 头部长度 */
#endif
#endif /* not _IP_VHL */
u_char ip_tos; /* 服务的类型 */
u_short ip_len; /* 总长度 */
u_short ip_id; /*包标志号 */
u_short ip_off; /* 碎片偏移 */
#define IP_RF 0x8000 /* 保留的碎片标志 */
#define IP_DF 0x4000 /* dont fragment flag */
#define IP_MF 0x2000 /* 多碎片标志*/
#define IP_OFFMASK 0x1fff /*分段位 */
u_char ip_ttl; /* 数据包的生存时间 */
u_char ip_p; /* 所使用的协议:1 ICMP;2 IGMP;4 IP;6 TCP;17 UDP;89 OSPF */
u_short ip_sum; /* 校验和 */
struct in_addr ip_src,ip_dst; /* 源地址、目的地址*/
};
#define IPTYPE_ICMP (1)
#define IPTYPE_IGMP (2)
#define IPTYPE_IP (4)
#define IPTYPE_TCP (6)
#define IPTYPE_UDP (17)
#define IPTYPE_OSPF (89)
#if 0
//IPV6 正确性待确认
struct sniff_ipv6{
union
{
struct ip6_hdrctl
{
u_int32_t ip6_unl_flow;/* 4位的版本,8位的传输与分类,20位的流标识符 */
u_int16_t ip6_unl_plen;/* 报头长度 */
u_int8_t ip6_unl_nxt; /* 下一个报头 */
u_int8_t ip6_unl_hlim; /* 跨度限制 */
}ip6_unl ;
u_int8_t ip6_un2_vfc;/* 4位的版本号,跨度为4位的传输分类 */
}ip6_ctlun ;
#define ip6_vfc ip6_ctlun.ip6_un2_vfc
#define ip6_flow ip6_ctlun.ip6_unl.ip6_unl_flow
#define ip6_plen ip6_ctlun.ip6_unl.ip6_unl_plen
#define ip6_nxt ip6_ctlun.ip6_unl.ip6_unl_nxt
#define ip6_hlim ip6_ctlun.ip6_unl.ip6_unl_hlim
#define ip6_hops ip6_ctlun.ip6_unl.ip6_unl_hops
struct in6_addr ip6_src;/* 发送端地址 */
struct in6_addr ip6_dst;/* 接收端地址 */
};
#endif
typedef u_int tcp_seq;
/* TCP 数据包的头部 */
struct sniff_tcp {
u_short th_sport; /* 源端口 */
u_short th_dport; /* 目的端口 */
tcp_seq th_seq; /* 包序号 */
tcp_seq th_ack; /* 确认序号 */
#if BYTE_ORDER == LITTLE_ENDIAN
u_int th_x2:4, /* 还没有用到 */
th_off:4; /* 数据偏移 */
#endif
#if BYTE_ORDER == BIG_ENDIAN
u_int th_off:4, /* 数据偏移*/
th_x2:4; /*还没有用到 */
#endif
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_FINTH_SYNTH_RSTTH_ACKTH_URGTH_ECETH_CWR)
u_short th_win; /* TCP滑动窗口 */
u_short th_sum; /* 头部校验和 */
u_short th_urp; /* 紧急服务位 */
};
/* UDP header */
struct sniff_udp{
uint16_t sport; /* source port */
uint16_t dport; /* destination port */
uint16_t udp_length;
uint16_t udp_sum; /* checksum */
};
#endif
2、调试输出信息如下:
============================================
packet size:182, data len:182
src_mac:4c:ed:fb:93:b:43
dst_mac:18:31:bf:b2:90:53
It's IPv4!
src_ip:192.168.100.3
dst_ip:192.168.100.162
ip->proto:TCP
tcp_sport = 48385
tcp_dport = 64502
============================================
packet size:95, data len:95
src_mac:88:d7:f6:40:ee:52
dst_mac:33:33:0:1:0:3
It's IPv6!
============================================
packet size:95, data len:95
src_mac:94:de:80:5b:85:95
dst_mac:33:33:0:1:0:3
It's IPv6!
============================================
packet size:75, data len:75
src_mac:88:d7:f6:40:ee:52
dst_mac:1:0:5e:0:0:fc
It's IPv4!
src_ip:192.168.100.107
dst_ip:224.0.0.252
ip->proto:UDP
udp_sport = 27635
udp_dport = 60180