#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <string.h>
#include <pcap.h>
#include <ctype.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
/* 默认捕获长度 (每个包捕获的最大长度) */
#define SNAP_LEN 1518
/* 以太网头部14个字节 */
#define SIZE_ETHERNET 14
/* 以太网地址6个字节 */
#define ETHER_ADDR_LEN 6
#define NUM_PACKET 5
#define PACKETS_NUM 2000
#define TCP_FLAG 0
#define UDP_FLAG 1
#define MYIP "192.168.1.106"
/* UDP header */
struct sniff_udp {
uint16_t sport; /* source port */
uint16_t dport; /* destination port */
uint16_t udp_length;
uint16_t udp_sum; /* checksum 检验和 */
};
/* 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 unsigned long 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 */
};
int tcp_num_count;
int udp_num_count;
int fin, syn, rst, push, ack, urg, ece, cwr;
void callback(unsigned char*, const struct pcap_pkthdr*, const unsigned char*);
int main()
{
char errBuf[PCAP_ERRBUF_SIZE];
char *dev = NULL; // dev应设置为网卡
/* 获取网络设备接口,即网络设备名 */
dev = pcap_lookupdev(errBuf); // dev应设置为网卡
/* 显示捕获设备信息
* printf("Device: %s\n", dev);
*/
if (dev == NULL) {
printf("%s\n", errBuf);
exit(1);
}
// netp为ip地址, bpf_u_int32为32位无符号整型
bpf_u_int32 netp = 0, maskp = 0;
int ret = 0;
/* 获取网络号和掩码,成功返回0 */
ret = pcap_lookupnet(dev, &netp, &maskp, errBuf);
if (ret == -1) {
printf("%s\n", errBuf);
exit(1);
}
// printf("ip = %d\n", netp); 应转化为点二进制形式
// 打开网络接口
// 参数分别为接口名, 捕获数据包的长度不能超过65535字节
// 混杂模式, 等待的ms数(超过该时间函数立即返回,0表示一直等待)
pcap_t* pcap_handle = pcap_open_live(dev, SNAP_LEN, 1, 0, errBuf);
//实例 pcap_t *pcap_handle = pcap_open_live("eth0", 1024, 1, 0, errBuf);
if (pcap_handle == NULL) {
printf("%s\n", errBuf);
exit(1);
}
/* pcap_datalink();
* 返回数据链路层类型,例如DLT_EN10MB;
* 确保我们对以太网设备捕获
*/
if (pcap_datalink(pcap_handle) != DLT_EN10MB) {
fprintf(stderr, "%s is not an Ethernet\n", dev);
exit(EXIT_FAILURE);
}
// 捕获单个数据包 const u_char *pcap_next(pcap_t *p,struct pcap_pkthdr *h);
// 参数分别为:打开网络接口返回的指针 捕获的数据包头
/*
const unsigned char *packet_addr = NULL; // 捕获的包的地址
struct pcap_pkthdr packet_header; // 抓到的时间 实际长度 原来长度
packet_addr = pcap_next(pcap_handle, &packet_header);
printf("Packet's length is:%d\n", packet_header.len); // 原来长度
printf("Packet's true length is:%d\n", packet_header.caplen);
*/
// 捕获多个数据包 int pcap_loop(pcap_t *p,int cnt,pcap_handler callback,u_char *user);
// 每捕获一个就调用callback指定的回调函数,可在回调函数中处理数据包
// 参数分别为:同pcap_next 指定捕获数据包的个数(设为-1将一直捕获)
// 参数分别为:回调函数(名字自取) 向回调函数中传递的参数
// 回调函数说明 void callback(u_char *userarg,const struct pcap_pkthdr *pkthdr,const u_char *packet)
// 参数:pcap_loop的最后一个参数 捕获的数据包的头(同pcap_next第二个参数)
// 参数:捕获的的数据包数据
/* 设置回掉函数并开始捕获包 */
if (pcap_loop(pcap_handle, NUM_PACKET, callback, NULL) < 0) {
perror("pcap_loop finish!\n");
}
// 捕获多个数据包 int pcap_dispatch(pcap_t *p,int cnt,pcap_handler callback,u_char *user);
// 说明:和pcap_loop类似,只是超过x毫秒后返回(x是pcap_open_live的第四个参数)
// 关闭网络接口
pcap_close(pcap_handle);
}
//void func(unsigned char *argument, const struct pcap_pkthdr *packet_header, const unsigned char *packet_data)
//{
// printf("使用pcap_loop的回调函数,该包长度为%d\n", packet_header->len);
//}
void callback(unsigned char *args, const struct pcap_pkthdr *header, const unsigned char *packet) {
static int count = 1; /* 包计数器,记录捕获多少包 */
/* 显示包总数
* printf("\nPacket number %d:\n", count);
* count++;
*/
/* declare pointers to packet headers */
struct sniff_ethernet *ethernet; /* 以太网头部 */
struct sniff_ip *ip; /* IP 头部 */
struct sniff_tcp *tcp; /* TCP 头部 */
struct sniff_udp *udp; /* UDP 头部 */
unsigned char *payload; /* Packet payload */
int size_ip;
int size_tcp;
int size_udp;
int size_payload;
int proto_flag = 2; // 0=TCP_FLAG; 1=UDP_FLAG
//====
/* 定义以太网头部 */
ethernet = (struct sniff_ethernet*)(packet);
/* 定义/计算 IP 头部偏移 */
ip = (struct sniff_ip*)(packet + SIZE_ETHERNET);
size_ip = IP_HL(ip)*4; // ip头部长度
if (size_ip < 20) {
printf(" * Invalid IP header length: %u bytes\n", size_ip);
return;
}
/* 显示源IP和目的IP print source and destination IP addresses */
// only print internet->me information
if(strcmp(inet_ntoa(ip->ip_src), MYIP) == 0)
return;
/* 确定协议 determine protocol */
switch(ip->ip_p) {
case IPPROTO_TCP: //useful
// printf(" Protocol: TCP\n");
proto_flag=0;
break;
case IPPROTO_UDP: //useful
// printf(" Protocol: UDP\n");
proto_flag=1;
break;
case IPPROTO_ICMP: //useless
// printf(" Protocol: ICMP\n");
return;
case IPPROTO_IP: //useless
// printf(" Protocol: IP\n");
return;
default:
// printf(" Protocol: unknown\n");
return;
}
/*
* This packet is TCP.
*/
if (proto_flag == 0) {
/* 定义/计算 TCP 头部偏移 */
tcp = (struct sniff_tcp *) (packet + SIZE_ETHERNET + size_ip);
/* 计算TCP头部长度 */
size_tcp = TH_OFF(tcp) * 4;
if (size_tcp < 20) {
printf (" * Invalid TCP header length: %u bytes\n", size_tcp);
return;
}
// printf(" From: %s\n", inet_ntoa(ip->ip_src));
// printf(" To: %s\n", inet_ntoa(ip->ip_dst));
printf (" Src port : %d\n", ntohs (tcp->th_sport));
printf (" Dst port : %d\n", ntohs (tcp->th_dport));
printf (" Seq number: %d\n", ntohl (tcp->th_seq));
int fin=0;
if(tcp->th_flags & TH_FIN)
fin=1;
printf (" FIN : %d\n", fin);
/* define/compute tcp payload (segment) offset */
payload = (unsigned char *) (packet + SIZE_ETHERNET + size_ip + size_tcp);
/* compute tcp payload (segment) size , 即TCP报文数据部分字节数 */
size_payload = ntohs (ip->ip_len) - (size_ip + size_tcp);
printf (" TCP size_payload: %d\n", size_payload);
printf (" Payload (%d bytes):\n", size_payload);
/*
if (size_payload > 0) {
//printf (" Payload (%d bytes):\n", size_payload);
// insert_tcp_hex_mysql(0, inet_ntoa(ip->ip_src), inet_ntoa(ip->ip_dst), ntohs (tcp->th_sport), ntohs (tcp->th_dport), payload, ntohl (tcp->th_seq), size_payload,fin );
}
*/
} //end tcp
//=====================================================================================
/*
* This packet is UDP.
*/
else if (proto_flag == 1) {
/* define/compute udp header offset */
udp = (struct sniff_udp *) (packet + SIZE_ETHERNET + size_ip);
// printf(" From: %s\n", inet_ntoa(ip->ip_src));
// printf(" To: %s\n", inet_ntoa(ip->ip_dst));
printf (" Src port: %d\n", ntohs (udp->sport));
printf (" Dst port: %d\n", ntohs (udp->dport));
printf ("udp length:%d\n", ntohs (udp->udp_length));
// printf ("udp sum:%d\n", ntohs (udp->udp_sum));
/* define/compute udp payload (segment) offset */
payload = (unsigned char *) (packet + SIZE_ETHERNET + size_ip + 8);
size_payload = ntohs (ip->ip_len) - (size_ip + 8);
printf (" UDP size_payload: %d\n", size_payload);
}//end udp
return;
}