libpcap编程:Sniffer

来源:互联网 发布:淘宝网上有卖烟的吗 编辑:程序博客网 时间:2024/05/17 01:15

主要实现运用libpcap(winpcap)的api进行数据链路层的抓包操作,并一层层进行解析,解析TCP, UDP, ICMP等协议。

主要代码及解析如下:

    /*************************************************************************        > File Name: sniffer.c        > Author: PCB        > Mail: pangbin2415@gmai.com        > Created Time: 2016年04月10日 星期日 20时40分52秒     ************************************************************************/    #include<stdio.h>    #include<pcap.h>    #include<string.h>    #include<stdlib.h>    #include<unistd.h>    #include<signal.h>    #include<sys/socket.h>    #include<netinet/in.h>    #include<arpa/inet.h>    #include<netinet/ip.h>    #include<netinet/tcp.h>    #include<netinet/udp.h>    #include<netinet/ip_icmp.h>    pcap_t* pd;    int linkhdrlen; //链路层的长度    /*     * device: 要连接的设备名字     * bpfstr: 要过滤的规则     * */    pcap_t* open_pcap_socket(char* device, const char* bpfstr)    {    char errbuf[PCAP_ERRBUF_SIZE];   //存放出错信息    pcap_t* pd;    uint32_t srcip, netmask; //存放源的ip地址和子网掩码    struct bpf_program bpf; //存取bpf过滤规则的一个结构    //找到一个设备    if(!*device && !(device == pcap_lookupdev(errbuf)))    {    printf("pcap_lookupdev(): %s\n", errbuf);    return NULL;    }    //打开该设备,并且等到一个包到来    if((pd = pcap_open_live(device, BUFSIZ, 1, 0, errbuf)) == NULL)    {    printf("pcap_open_live(): %s\n", errbuf);    return NULL;    }    //得到设备的ip地址和ip的掩码    if(pcap_lookupnet(device, &srcip, &netmask, errbuf) < 0)    {    printf("pcap_lookupnet: %s\n", errbuf);      return NULL;    }    //应用过滤规则    if(pcap_compile(pd, &bpf, (char*)bpfstr, 0, netmask))    {    printf("pcap_compile(): %s\n", pcap_geterr(pd));    return NULL;    }    if(pcap_setfilter(pd, &bpf)<0)    {    printf("pcap_setfilter(): %s\n", pcap_geterr(pd));    return NULL;    }    //printf("Open_pcapSocket()\n");    return pd;    }//end open_pcap_socket(char* device, const char* bpfstr);    void capture_loop(pcap_t* pd, int packets, pcap_handler func)    {    int linktype;    //判断数据链路层的类型    if((linktype = pcap_datalink(pd)) < 0)    {    printf("pcap_datalink(): %s\n", pcap_geterr(pd));    return;    }    switch(linktype)    {    case DLT_NULL://BSD回路封装;链路层协议是一个4字节的域    linkhdrlen = 4;    break;    case DLT_EN10MB: //以太网,链路层协议是一个14字节的域    linkhdrlen = 14;    break;    case DLT_SLIP:     case DLT_PPP:    linkhdrlen = 24;  //链路层长度为24个字节    break;    default:    printf("Unsupport datalink (%d)\n", linktype);    return;    }    //开始抓包    if(pcap_loop(pd, packets, func, 0) < 0)    printf("pcap_loop failed: %s\n", pcap_geterr(pd));    }    /*     * 解析包的程序*/    void parse_packet(u_char *user, struct pcap_pkthdr* packethdr, u_char* packetptr)    {    struct ip* iphdr;  //netinet库的ip结构    struct icmphdr* icmphdr;  //icmp结构    struct tcphdr* tcphdr;//tcp结构    struct udphdr* udphdr;//udp结构    char iphdrInfo[256], srcip[256], dstip[256];    unsigned short id, seq;    packetptr += linkhdrlen; //过滤掉数据链路层的数据    iphdr = (struct ip*)packetptr;    strcpy(srcip, inet_ntoa(iphdr->ip_src));    strcpy(dstip, inet_ntoa(iphdr->ip_dst));    sprintf(iphdrInfo, "ID:%d TOS:0x%x, TTL:%d, Iplen:%d Dglen:%d",       ntohs(iphdr->ip_id), iphdr->ip_tos, iphdr->ip_ttl, 4*iphdr->ip_hl, ntohs(iphdr->ip_len)       );    //将ip的字段跳过去    packetptr += 4*iphdr->ip_hl;    switch(iphdr->ip_p)    {    case IPPROTO_TCP:  //如果是TCP协议    tcphdr = (struct tcphdr*)packetptr;    printf("TCP %s:%d -> %s:%d\n", srcip, ntohs(tcphdr->source), dstip, ntohs(tcphdr->dest));    printf("%s\n", iphdrInfo);    printf("%c%c%c%c%c%c Seq: 0x%x Ack: 0x%x Win: 0x%x TcpLen: %d\n", (tcphdr->urg ? 'U' : '*'),       (tcphdr->ack ? 'A' : '*'),       (tcphdr->psh ? 'P' : '*'),       (tcphdr->rst ? 'R' : '*'),       (tcphdr->syn ? 'S' : '*'),       (tcphdr->fin ? 'F' : '*'),       ntohl(tcphdr->seq), ntohl(tcphdr->ack_seq), ntohs(tcphdr->window), 4*tcphdr->doff      );    break;    case IPPROTO_UDP: //UDP协议    udphdr = (struct udphdr*) packetptr;    printf("UDP %s:%d -> %s:%d\n", srcip, ntohs(udphdr->source),      dstip, ntohs(udphdr->dest)      );    printf("%s\n", iphdrInfo);    break;    case IPPROTO_ICMP: //ICMP协议    icmphdr = (struct icmphdr*)packetptr;    printf("ICMP %s -> %s\n", srcip, dstip);    printf("%s\n", iphdrInfo);    memcpy(&id, (u_char*)icmphdr+4, 2);    memcpy(&seq, (u_char*)icmphdr+6, 2);    printf("Type:%d Code:%d ID:%d Seq:%d\n", icmphdr->type, icmphdr->code, ntohs(id), ntohs(seq));    break;    }    printf("---------------------------------------------\n\n");    }    void quiteOut(int signo)    {    struct pcap_stat stats;    if(pcap_stats(pd, &stats) >= 0)    {    printf("%d packets received\n", stats.ps_recv);    printf("%d packtes dropped\n\n", stats.ps_drop);    }    pcap_close(pd);    exit(0);    }    int main(int argc, char **argv)    {    char interface[256] = "", bpfstr[256] = "";    int packets = 0, c,i;    while((c = getopt(argc, argv, "i:n:") ) != -1)  //读取参数,当为-i时,指定接口,当为-n时,指定读取多少packets    {    switch(c)    {    case 'i':    strcpy(interface, optarg);    break;    case 'n':    packets = atoi(optarg);    break;    }    }    //获取过滤的字符串    for(i = optind; i < argc; i++)    {    strcat(bpfstr, argv[i]);    strcat(bpfstr, " ");    }    //连接接口    if((pd = open_pcap_socket(interface, bpfstr)))    {    /*/     * 绑定中断事件给quiteOut函数*/    signal(SIGINT, quiteOut);    signal(SIGTERM, quiteOut);    signal(SIGQUIT, quiteOut);    capture_loop(pd, packets, (pcap_handler)parse_packet);    quiteOut(0);    }    exit(0);    }

主要使用:

该程序支持监听的接口及一共要接收的数据包的大小,并且提供过滤功能,具体使用如下:

sudo ./sniffer -i eth0 tcp port 80

运行结果如下:

0 0
原创粉丝点击