抓取DNS查询报文并写入数据库(Linux平台C语言版)


之前写的shell脚本有一些致命的缺陷,比如重定向tcpdump的输出到文件,一定要等到tcpdump的进程结束,关闭文件流以后,输出的内容才可以被读出来,而且脚本处理文件的过程非常慢,效率低,这样就会导致丢包,试了N种方法,始终无法解决,这两天一狠心,使用libpcap抓包处理,效率高不说,日后还可以很灵活的增加对其他种类报文的处理,以下是代码:

6月17日: 加入 写入数据到mysql库的功能

#include <pcap.h>
#include <mysql.h>
typedef u_int32_t in_addr_t;
struct in_addr
{
        in_addr_t s_addr;
};

struct ether_header
{
        u_int8_t ether_dhost[6];
        u_int8_t ether_shost[6];
        u_int16_t ether_type;
};

struct ip_header
{
#if defined(WORDS_BIGENDIAN)
        u_int8_t ip_version:4,ip_header_length:4;
#else
        u_int8_t ip_header_length:4,ip_version:4;
#endif
u_int8_t ip_tos;
u_int16_t ip_length;
u_int16_t ip_id;
u_int16_t ip_off;
u_int8_t ip_ttl;
u_int8_t ip_protocol;
u_int16_t ip_checksum;
struct in_addr ip_source_address;
struct in_addr ip_destination_address;
};

struct udp_header
{
        u_int16_t udp_source_port;
        u_int16_t udp_destination_port;
        u_int16_t udp_length;
        u_int16_t udp_checksum;
};

struct dns_packet
{
        u_int16_t dns_trans_id;
        u_int16_t dns_flag;
        u_int16_t dns_question;
        u_int16_t dns_answer;
        u_int16_t dns_authority;
        u_int16_t dns_additional;
        u_int8_t *dns_data;

};


/*Mysql */
MYSQL mysql,*sock;
MYSQL_RES *res;
MYSQL_FIELD *fd;
MYSQL_ROW row;
u_char sqlString[300];


/*queryType
1=select
2=insert
packetType
1=dns
*/
u_int8_t execQuery(MYSQL *sock,u_char sqlQuery[300],int queryType,int packetType)
{
        u_char sqlString[300];
        sprintf(sqlString,sqlQuery,1);
        if(mysql_query(sock,sqlString))
        {
                fprintf(stderr,"Query failed (%s)\n",mysql_error(sock));
                printf("testquery");
                return 0;
        }

        if(queryType!=1)
                return 1;
        if (!(res=mysql_store_result(sock)))
        {
                fprintf(stderr,"Couldn't get result from %s\n", mysql_error(sock));
                return 0;
        }


        while (row = mysql_fetch_row(res))
        {
                switch(packetType){
                case 1:
                        printf("Ther userid #%d 's username is: %s\n", 1,(((row[1]==NULL)&&(!strlen(row[1]))) ? "NULL" : row[1]));
                }
        }

        mysql_free_result(res);
        return 1;
}


void dns_protocol_packet_callback(u_char *argument,const struct pcap_pkthdr* packet_header,const u_char* packet_content)
{
        struct udp_header *udp_protocol;
        struct ip_header *ip_protocol;
        struct dns_packet *dns_protocol;
        ip_protocol=(struct ip *)(packet_content+14);
        u_short source_port;
        u_short destination_port;
        u_short length;
        u_char flag;
        udp_protocol=(struct udp_header *)(packet_content+14+20);
        u_char *dns_querydomain;
        source_port=ntohs(udp_protocol->udp_source_port);
        destination_port=ntohs(udp_protocol->udp_destination_port);
        length=ntohs(udp_protocol->udp_length);
        dns_protocol=(struct dns_packet *)(packet_content+14+20+8);
        if(ntohs(dns_protocol->dns_flag) == 256)
        {
                printf("--------------------------------UDP Protocol------------------------------\n");
                u_char sourceIP[20];
                u_char destIP[20];
                sprintf(sourceIP,"%s",inet_ntoa(ip_protocol->ip_source_address));
                sprintf(destIP,"%s",inet_ntoa(ip_protocol->ip_destination_address));
                printf("%s\n",sourceIP);
                printf("%s\n",destIP);
                u_int8_t *query=&(dns_protocol->dns_data);
                printf("QueryDomain=");
                u_int8_t domainname[100]={0};
                u_int8_t i=0;
                while(*query)
                {
                        domainname[i]=*query;
                        if(*query < 0x30)
                        {
                                printf("%c",'.');
                                domainname[i]='.';
                        }
                        else
                        {
                                printf("%c",*query);
                                domainname[i]=*query;
                        }
                        query++;
                        i++;
                }
                printf("\n");
                printf("%s\n",domainname);
                u_int16_t *dns_query_type=query+2;
 
                u_char sqlstr[300];

                sprintf(sqlstr,"insert into dnsPackets(sourceIP,destIP,url,queryType) VALUES('%s','%s','%s',%d)",sourceIP,destIP,domainname,*dns_query_type);
execQuery(sock,sqlstr,2,1);

                printf("%s\n",sqlstr);
                switch(*dns_query_type)
                {
                        case 1:
                                printf("QueryType=A\n");break;
                        case 12:
                                printf("QueryType=PTR\n");break;
                        default:
                                printf("%d\n",*dns_query_type);
                }
        }
}

void udp_protocol_packet_callback(u_char *argument,const struct pcap_pkthdr* packet_header,const u_char* packet_content)
{
        struct udp_header *udp_protocol;
        struct ip_header *ip_protocol;
        struct dns_packet *dns_protocol;
        u_short source_port;
        u_short destination_port;
        udp_protocol=(struct udp_header *)(packet_content+14+20);
        source_port=ntohs(udp_protocol->udp_source_port);
        destination_port=ntohs(udp_protocol->udp_destination_port);
        switch(destination_port)
        {
                case 53:
                        dns_protocol_packet_callback(argument,packet_header,packet_content);
                        break;
                default:
                        break;
        }
}

void ip_protocol_packet_callback(u_char *argument,const struct pcap_pkthdr* packet_header,const u_char* packet_content)
{
        struct ip_header *ip_protocol;
        u_int header_length;
        u_int offset;
        u_char tos;
        u_int16_t checksum;
        ip_protocol=(struct ip *)(packet_content+14);
        checksum=ntohs(ip_protocol->ip_checksum);
        header_length=ip_protocol->ip_header_length*4;
        tos=ip_protocol->ip_tos;
        offset=ntohs(ip_protocol->ip_off);
        u_char *ip_destination_address=inet_ntoa(ip_protocol->ip_destination_address);
        switch(ip_protocol->ip_protocol)
        {
                case 17:
                        udp_protocol_packet_callback(argument,packet_header,packet_content);
                        break;
                default:break;
        }
}


void ethernet_protocol_packet_callback(u_char *argument,const struct pcap_pkthdr* packet_header,const u_char* packet_content)
{
        u_short ethernet_type;
        struct ether_header *ethernet_protocol;
        u_char *mac_string;
        static int packet_number=1;
        ethernet_protocol=(struct ether_header *)packet_content;
        ethernet_type=ntohs(ethernet_protocol->ether_type);
        switch(ethernet_type)
        {
                case 0x0800:
                        ip_protocol_packet_callback(argument,packet_header,packet_content);
                        break;
                default:break;
        }
                packet_number++;
}

main()
{
/*Init Mysql*/
mysql_init(&mysql);

/*Connecting mysql*/
if(!(sock = mysql_real_connect(&mysql,"localhost","root","","PACKETS",0,NULL,0)))
{
        fprintf(stderr,"Couldn't connect to engine!\n%s\n\n",mysql_error(&mysql));
        perror("");
        exit(1);
}else
        printf("Mysql Connected.\n");

/*Get Packet*/
        pcap_t* pcap_handle;
        char error_content[PCAP_ERRBUF_SIZE];
        char *net_interface;
        struct bpf_program bpf_filter;
        char bpf_filter_string[]="udp";

        bpf_u_int32 net_mask;
        bpf_u_int32 net_ip;
        net_interface=pcap_lookupdev(error_content);
        pcap_lookupnet(net_interface,&net_ip,&net_mask,error_content);
        pcap_handle=pcap_open_live(net_interface,BUFSIZ,1,0,error_content);
        pcap_compile(pcap_handle,&bpf_filter,bpf_filter_string,0,net_ip);
        pcap_setfilter(pcap_handle,&bpf_filter);
        pcap_loop(pcap_handle,-1,ethernet_protocol_packet_callback,NULL);
        pcap_close(pcap_handle);

/*Closing Mysql*/
mysql_close(sock);
}

相关内容