使用libpcab抓包&处理包

#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
", dev);
  	 */ 
    if (dev == NULL) {
        printf("%s
", 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
", errBuf);
        exit(1);
    }
//  printf("ip = %d
", 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
", errBuf);
        exit(1);
    }
    
    /* pcap_datalink();
     * 返回数据链路层类型,例如DLT_EN10MB;
     * 确保我们对以太网设备捕获
	 */
    if (pcap_datalink(pcap_handle) != DLT_EN10MB) {
        fprintf(stderr, "%s is not an Ethernet
", 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
", packet_header.len);   // 原来长度
    printf("Packet's true length is:%d
", 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!
");
    }

    // 捕获多个数据包 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
", packet_header->len);
//}

void callback(unsigned char *args, const struct pcap_pkthdr *header, const unsigned char *packet) {
	static int count = 1;                   /* 包计数器,记录捕获多少包  */
	/* 显示包总数 
     * printf("
Packet number %d:
", 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
", 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
");
            proto_flag=0;
            break;
        case IPPROTO_UDP:		//useful
    //        printf("   Protocol: UDP
");
            proto_flag=1;
	        break;
        case IPPROTO_ICMP:		//useless
    //        printf("   Protocol: ICMP
");
            return;
        case IPPROTO_IP:		//useless
    //        printf("   Protocol: IP
");
            return;
        default:
    //        printf("   Protocol: unknown
");
            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
", size_tcp);
     		return;
   		}
	//  printf("       From: %s
", inet_ntoa(ip->ip_src));
	//	printf("         To: %s
", inet_ntoa(ip->ip_dst));
		printf ("   Src port  : %d
", ntohs (tcp->th_sport));
   		printf ("   Dst port  : %d
", ntohs (tcp->th_dport));
   		printf ("   Seq number: %d
", ntohl (tcp->th_seq));
   		int fin=0;
  		if(tcp->th_flags & TH_FIN) 
    		fin=1;
   		printf ("   FIN       : %d
", 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
", size_payload);
 		printf ("   Payload (%d bytes):
", size_payload);
     	/*
		if (size_payload > 0) {
         	//printf ("   Payload (%d bytes):
", 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
", inet_ntoa(ip->ip_src));
    //	printf("         To: %s
", inet_ntoa(ip->ip_dst));
    	printf ("   Src port: %d
", ntohs (udp->sport));
    	printf ("   Dst port: %d
", ntohs (udp->dport));
    	printf ("udp length:%d
", ntohs (udp->udp_length));
    //	printf ("udp sum:%d
", 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
", size_payload);
    }//end udp
	return;
}

  

原文地址:https://www.cnblogs.com/xzxl/p/8120346.html