Libpcap四 libpcap基础应用实例

话不多说,直接上代码。读完这一段代码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

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值