libpcap 捕包分析TCP流

来源:互联网 发布:mysql入门很简单 pdf 编辑:程序博客网 时间:2024/04/28 08:50

libpcap捕包,将tcp流插入数据库分析,在libpcap官方代码基础上改动完成。备份之~

/* * checkSeq.cpp * * Sniffer example of TCP/IP packet capture using libpcap. *  **************************************************************************** *  * Example compiler command-line for GCC: *   g++ -Wall -o snifferToSql2.o snifferToSql2.cpp -lpcap *   g++  -o checkSeq.o $(mysql_config --cflags) checkSeq.cpp -lpcap $(mysql_config --libs)  **************************************************************************** * * **************************************************************************** * */#define APP_NAME                "checkSeq.cpp"#define APP_DESC                "Sniffer example using libpcap/Made by cjqhenry"#include <pcap.h>#include <stdio.h>#include <string.h>#include <stdlib.h>#include <ctype.h>#include <errno.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h> ///----------#include <mysql.h>  #include <string>  #include <sstream>   using namespace std;///-----------/* 默认捕获长度 (每个包捕获的最大长度)   default snap length (maximum bytes per packet to capture) */#define SNAP_LEN 1518/* 以太网头部14个字节   ethernet headers are always exactly 14 bytes [1] */#define SIZE_ETHERNET 14/* 以太网地址6个字节   Ethernet addresses are 6 bytes */#define ETHER_ADDR_LEN        6//=========#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 */};///--------------MYSQL *my_conn;int tcp_num_count;  int udp_num_count;  int fin,syn,rst,push,ack,urg,ece,cwr;voidinsert_tcp_hex_mysql(int, string, string, int, int,   unsigned char*, unsigned long, int, int);void connectMysql();///--------------voidgot_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet);voidprint_payload(const u_char *payload, int len);voidprint_hex_ascii_line(const u_char *payload, int len, int offset);voidprint_app_banner(void);voidprint_app_usage(void);/* * app name/banner */ void print_app_banner(void) {  printf("%s - %s\n", APP_NAME, APP_DESC);  printf("\n");  return;}/* * print help text */ void print_app_usage(void) {  printf("Usage: %s [interface]\n", APP_NAME);  printf("\n");  printf("Options:\n");  printf("    interface    Listen on <interface> for packets.\n");  printf("\n");  return;}/* * print data in rows of 16 bytes: offset   hex   ascii * * 00000   47 45 54 20 2f 20 48 54  54 50 2f 31 2e 31 0d 0a   GET / HTTP/1.1.. */ void print_hex_ascii_line(const u_char *payload, int len, int offset) {  int i;  int gap;  const u_char *ch;        /* offset */  printf("%05d   ", offset);        /* hex */  ch = payload;  for(i = 0; i < len; i++) {    printf("%02x ", *ch);    ch++;                /* print extra space after 8th byte for visual aid */    if (i == 7)      printf(" ");  }        /* print space to handle line less than 8 bytes */  if (len < 8)    printf(" ");        /* fill hex gap with spaces if not full line */  if (len < 16) {    gap = 16 - len;    for (i = 0; i < gap; i++) {      printf("   ");    }  }  printf("   ");        /* ascii (if printable) */  ch = payload;  for(i = 0; i < len; i++) {    if (isprint(*ch))      printf("%c", *ch);    else      printf(".");    ch++;  }  printf("\n");  return;}/* * 打印包的有效载荷数据(避免打印二进制数据) * print packet payload data (avoid printing binary data) */ void print_payload(const u_char *payload, int len) {  int len_rem = len;        int line_width = 16;                        /* 每行的字节数 | number of bytes per line */  int line_len;        int offset = 0;                                        /* 从0开始的偏移计数器 | zero-based offset counter */  const u_char *ch = payload;  if (len <= 0)    return;        /* data fits on one line */  if (len <= line_width) {    print_hex_ascii_line(ch, len, offset);    return;  }        /* 数据跨越多行 data spans multiple lines */  for ( ;; ) {                /* 计算当前行的长度 | compute current line length */    line_len = line_width % len_rem;                /* 显示分割线 | print line */    print_hex_ascii_line(ch, line_len, offset);                /* 计算总剩余 | compute total remaining */    len_rem = len_rem - line_len;                /* 转移到打印的剩余字节的指针                   shift pointer to remaining bytes to print */    ch = ch + line_len;                /* 添加偏移 | add offset */    offset = offset + line_width;                /* 检查是否有线宽字符或更少                   check if we have line width chars or less */    if (len_rem <= line_width) {                        /* print last line and get out */      print_hex_ascii_line(ch, len_rem, offset);      break;    }  }  return;}voidinsert_tcp_hex_mysql(int type, string src_ip, string dst_ip, int src_port, int dst_port,   unsigned char *payload, unsigned long seq, int len,int fin){  int i;  std::stringstream   stream;     string  stype, ssrc_port, sdst_port, sseq,slen ,sack;  string insert_sql;string sfin;  stream << type;     stype=stream.str();  stream.str("");  stream << src_port;     ssrc_port=stream.str();  stream.str("");  stream << dst_port;     sdst_port=stream.str();  stream.str("");  stream << seq;     sseq=stream.str();  stream.str("");  stream << len;     slen=stream.str();  stream.str("");  stream << fin;     sfin=stream.str();  stream.str("");  unsigned char *ch;  string str;        /* hex */  ch = payload;  /*for(i = 0; i < len; i++) {    if (isprint(*ch))    {      printf("%c", *ch);      str.push_back(*ch);    }    else      printf(".");    ch++;  }*/  insert_sql ="INSERT INTO netDataTest VALUES( NULL, '"+ stype +"', '"+  src_ip +"', '"+  dst_ip +"', '"+  ssrc_port +"', '"+ sdst_port +"', '"+  str +"', '"+ sseq +"','"+ slen +"','"+ sfin +"');";    int res =mysql_real_query( my_conn , insert_sql.c_str() , insert_sql.length() );   if (!res)   {    tcp_num_count++;    printf("Inserted %lu rows\n", (unsigned long)mysql_affected_rows(my_conn));  }   else   {    fprintf(stderr, "Insert error %d: %s\n", mysql_errno(my_conn),      mysql_error(my_conn));  }  return;}/* * 解析/显示 包 * dissect/print packet */ void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet) {        static int count = 1;                   /* 包计数器                | packet counter */        /* declare pointers to packet headers */          struct sniff_ethernet *ethernet;  /* 以太网头部        | The ethernet header [1] */          struct sniff_ip *ip;              /* IP 头部                | The IP header */          struct sniff_tcp *tcp;            /* TCP 头部                | The TCP header */          unsigned char *payload;                    /* Packet payload */  int size_ip;  int size_tcp;  int size_payload;        //=====        int proto_flag=2;// 0=TCP_FLAG; 1=UDP_FLAG          struct sniff_udp *udp;            /* UDP 头部                | The UDP header */        int size_udp;        //====        /* 显示包总数 */        printf("\nPacket number %d:\n", count);        count++;                /* 定义以太网头部           define ethernet header */        ethernet = (struct sniff_ethernet*)(packet);                /* 定义/计算 IP 头部偏移           define/compute ip header offset */        ip = (struct sniff_ip*)(packet + SIZE_ETHERNET);        size_ip = IP_HL(ip)*4;        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 infoermation        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)   {      /* define/compute tcp header offset */    tcp = (struct sniff_tcp *) (packet + SIZE_ETHERNET + size_ip);    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 */   size_payload = ntohs (ip->ip_len) - (size_ip + size_tcp);   printf ("  TCP size_payload: %d\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);      /*       * Print payload data; it might be binary, so don't just       * treat it as a string.       */       /*if (size_payload > 0)       {        int i;        std::stringstream   stream;           string  ssrc_port, sdst_port;        string insert_sql;        string stype="1";        string sseq="0";        stream << ntohs (udp->sport);           ssrc_port=stream.str();        stream.str("");        stream << ntohs (udp->dport);           sdst_port=stream.str();        stream.str("");        unsigned char *ch;        string str;        printf ("  ******************** \n");        ch = payload;        for(i = 0; i < size_payload; i++) {          if (isprint(*ch))          {            printf("%c", *ch);            str.push_back(*ch);          }          else            printf(".");          ch++;        }        insert_sql ="INSERT INTO netDataTest VALUES( NULL, '"+ stype +"', '"+ inet_ntoa(ip->ip_src) +"', '"+ inet_ntoa(ip->ip_dst) +"', '"+  ssrc_port +"', '"+ sdst_port +"', '"+  str +"', '"+ sseq +"');";        int res =mysql_real_query( my_conn , insert_sql.c_str() , insert_sql.length() );         if (!res)         {          udp_num_count++;          printf("Inserted %lu rows\n", (unsigned long)mysql_affected_rows(my_conn));        }         else         {          fprintf(stderr, "Insert error %d: %s\n", mysql_errno(my_conn),            mysql_error(my_conn));        }              }//end if payload > 0*/    }//end udp    return;  }  void connectMysql()  {   my_conn=mysql_init(NULL);      if(!mysql_real_connect(my_conn,"localhost","root","","MyTest1",0,NULL,0)) //连接test数据库   {    printf("Connect Error!n");    exit(1);  }}int main(int argc, char **argv){  connectMysql();  tcp_num_count = 0;  udp_num_count = 0;  fin=0;  syn=0;rst=0;push=0;ack=0;urg=0;ece=0;cwr=0;        char *dev = NULL;                                        /* 捕获设备的名称 | capture device name */        char errbuf[PCAP_ERRBUF_SIZE];                /* 错误的缓冲区   | error buffer */        pcap_t *handle;                                                /* 数据包捕获句柄 | packet capture handle */        char filter_exp[] = "ip";                        /* 过滤表达示          | filter expression [3] */        struct bpf_program fp;                                /* 编译过滤表达示 | compiled filter program (expression) */        bpf_u_int32 mask;                                        /* 子网掩码                  | subnet mask */        bpf_u_int32 net;                                        /* IP 地址                  | ip */        int num_packets = PACKETS_NUM;                                /* 捕获的数据包数量 | number of packets to capture */        /* 显示程序版本信息 */  print_app_banner();        /* 检查来自命令行参数需要捕获设备的名称           check for capture device name on command-line */  if (argc == 2) {    dev = argv[1];  }  else if (argc > 2) {    fprintf(stderr, "error: unrecognized command-line options\n\n");    print_app_usage();    exit(EXIT_FAILURE);  }  else {                /* 如果命令行参数没有指定, 则自动找到一个设备                   find a capture device if not specified on command-line */    dev = pcap_lookupdev(errbuf);    if (dev == NULL) {      fprintf(stderr, "Couldn't find default device: %s\n",        errbuf);      exit(EXIT_FAILURE);    }  }        /* 获得捕获设备的网络号和掩码           get network number and mask associated with capture device */  if (pcap_lookupnet(dev, &net, &mask, errbuf) == -1) {    fprintf(stderr, "Couldn't get netmask for device %s: %s\n",      dev, errbuf);    net = 0;    mask = 0;  }        /* 显示捕获设备信息           print capture info */  printf("Device: %s\n", dev);   // printf("Number of packets: %d\n", num_packets);  printf("Filter expression: %s\n", filter_exp);        /* 打开捕获设备           @1        捕获的设备           @2        每次捕获数据的最大长度           @3        1 启用混杂模式           @4        捕获时间, 单位ms           @5        错误缓冲区           open capture device */           handle = pcap_open_live(dev, SNAP_LEN, 1, 1000, errbuf);           if (handle == NULL) {            fprintf(stderr, "Couldn't open device %s: %s\n", dev, errbuf);            exit(EXIT_FAILURE);          }        /*        pcap_datalink();                        返回数据链路层类型,例如DLT_EN10MB;           确保我们对以太网设备捕获           make sure we're capturing on an Ethernet device [2] */           if (pcap_datalink(handle) != DLT_EN10MB) {            fprintf(stderr, "%s is not an Ethernet\n", dev);            exit(EXIT_FAILURE);          }        /* 编译过滤表达式           compile the filter expression */          if (pcap_compile(handle, &fp, filter_exp, 0, net) == -1) {            fprintf(stderr, "Couldn't parse filter %s: %s\n",              filter_exp, pcap_geterr(handle));            exit(EXIT_FAILURE);          }        /* 应用过滤规则           apply the compiled filter */          if (pcap_setfilter(handle, &fp) == -1) {            fprintf(stderr, "Couldn't install filter %s: %s\n",              filter_exp, pcap_geterr(handle));            exit(EXIT_FAILURE);          }        /* 设置回高函数并开始捕获包           now we can set our callback function */        ///pcap_loop(handle, num_packets, got_packet, NULL);          pcap_loop(handle, num_packets, got_packet, NULL);        /* cleanup */          pcap_freecode(&fp);          pcap_close(handle);          printf("\nCapture complete.\n");          printf ("   %d TCP PACTETS are completed :\n", tcp_num_count);          printf ("   %d UDP PACTETS are completed :\n", udp_num_count);printf (" fin %d,syn %d,rst %d,push %d,ack %d,urg %d,ece %d,cwr %d:\n", fin,syn,rst,push,ack,urg,ece,cwr);          mysql_close(my_conn);          return 0;        }


0 0
原创粉丝点击