zoukankan      html  css  js  c++  java
  • 使用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;
    }
    

      

  • 相关阅读:
    linux基础-第十八单元_nginx部署
    centos7 启动docker失败--selinux-enabled=false
    crontab 写入文件目录
    kvm : Permission denied
    使用spice连接kvm guest主机
    python中bottle模块的使用
    如何监控开源 Apache Kafka?
    Spring Quartz
    【问题排查】kafka0.10.x过期数据不会自动删除问题
    Apache Kafka监控之Kafka Web Console
  • 原文地址:https://www.cnblogs.com/xzxl/p/8120346.html
Copyright © 2011-2022 走看看