zoukankan      html  css  js  c++  java
  • Linux下一个简单sniffer的实现

          Sniffer(嗅探器)是一种基于被动侦听原理的网络分析方式。将网络接口设置在监听模式,便可以将网上传输的源源不断的信息截获。对于网络监听的基本原理我们不在赘述,我们也不开启网卡的混杂模式,因为现在的网络基本都使用了交换机,因此混杂模式也似乎变得无用武之地了。

         Sniffer实现的底层支持有多种,如libpcap、套接字方式,libpcap是unix/linux平台下的网络数据包捕获函数包,对应windows下的是winpcap,大多数网络监控软件都以它为基础,比如大名鼎鼎的wireshark。libpcap目前支持源自Berkeley内核中的BPF、Solaris 2.X 和HP-UX中的DLPI、SunOS 4.1.x中的NIT、Linux的SOCK_PACKET套接字和PF_PACKET套接字。也就是说,linpcap在linux下的实现是基于以上两类套接字的,而我们主要讨论的就是直接通过套接字来获取链路层的数据。

          Linux先后有两个从数据链路层获取分组的方法,较旧的方法是创建类型为SOCK_PACKET的套接字,这个方法的可用面较宽,但是缺乏灵活性,较新的方法是创建协议族为PF_PACKET的套接字,这个方法引入了更多的过滤和性能特性。举例来说,从数据链路层接受所有帧应如下创建套接字:

        fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));       /*较新的方法*/
    或
        fd = socket(AF_INET, SOCK_PACKET, htons(ETH_P_ALL));       /*较旧的方法*/

           这里要说明的是,这两个函数的最后一个参数表明了接受链路层所有类型的以太网帧,若只想捕获IPv4帧,那就把最后一个参数改为htons(ETH_P_IP),其宏定义在linux/if_ether.h头文件中。另外,PF_PACKET协议簇支持两个不同的SOCKET类型,SOCK_DGRAM和SOCK_RAW,用SOCK_RAW创建的套接字,我们获得的是包含二层头的帧,而使用SOCK_DGRAM套接字类型,我们获取的数据不包含二层的头。

           如果想设置网卡的混杂模式, 对于PF_PACKET套接字,通过设置PACKET_ADD_MEMBERSHIP套接字选项实现,在作为setsockopt第四个参数传递的packet_mreq结构中需指定网络接口和值为PACKET_MR_PROMISC。linux的数据链路层访问方法不提供内核缓冲,而且也只有较新的方法提供内核过滤(通过设置SO_ATTACH_FILTER套接字选项安装),在本程序中我们没有使用过滤功能。

    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<netinet/ip_icmp.h>
    #include<netinet/tcp.h>
    #include<netinet/udp.h>
    #include<arpa/inet.h>
    #include<sys/socket.h>
    #include<sys/types.h>
    #include<linux/if_ether.h>
    #include<arpa/inet.h>
    #include <unistd.h>
    
    #define BUFFSIZE 1024
    
    int main(int argc, char *argv[]){
    
        int rawsock;
        unsigned char buff[BUFFSIZE];
        int n;
        int count = 0;
        char ch;
        char proto[6],
             saddr[20] = {},
             daddr[20] ={},
             address[20]= {};
        int slen = 0;
    
        rawsock = socket(PF_PACKET,SOCK_DGRAM, htons(ETH_P_IP));
        if(rawsock < 0){
            printf("raw socket error!
    ");
            exit(1);
        }
        while((ch = getopt(argc, argv, "p:s:d:h")) != -1){
            switch (ch) {
                case 'p':
                    slen = strlen(optarg);
                    if(slen > 4){
                        fprintf(stdout, "The protocol is error!
    ");
                        return -1;
                    }
                    memcpy(proto, optarg, slen);
                    proto[slen] = '';
                    break;
                case 's':
                    slen = strlen(optarg);
                    if(slen > 15 || slen < 7){
                        fprintf(stdout, "The IP address is error!
    ");
                        return -1;
                    }
                    memcpy(saddr, optarg, slen);
                    saddr[slen] = '';
                    break;
                case 'd':
                    slen = strlen(optarg);
                    if(slen > 15 || slen < 7){
                        fprintf(stdout, "The IP address is error!
    ");
                        return -1;
                    }
                    memcpy(daddr, optarg, slen);
                    saddr[slen] = '';
                    break;
                case 'h':
                    fprintf(stdout, "usage: snffer [-p protocol] [-s source_ip_address] [-d dest_ip_address]
    "
                                    "    -p    protocol[TCP/UDP/ICMP]
    "
                                    "    -s    souce ip address
    "
                                    "    -d    dest ip address
    ");
                    exit(0);
                case '?':
                    fprintf(stdout, "unrecongized option: %c
    ", ch);
                    exit(-1);
            }
        }
        while(1){    
            n = recvfrom(rawsock,buff,BUFFSIZE,0,NULL,NULL);
            if(n<0){
                printf("receive error!
    ");
                exit(1);
            }
    
            count++;
            struct ip *ip = (struct ip*)(buff);
            if(strlen(proto)){
                if(!strcmp(proto, "TCP")){
                    if(ip->ip_p != IPPROTO_TCP)
                        continue;
                    else 
                        goto addr;
                }else if(!strcmp(proto, "UDP")){
                    if(ip->ip_p != IPPROTO_UDP)
                        continue;
                    else 
                        goto addr;
                }else if(!strcmp(proto, "ICMP")){
                    if(ip->ip_p != IPPROTO_ICMP)
                        continue;
                    else
                        goto addr;
                }
            }
    
    addr:
            if(strlen(saddr)){
                strcpy(address, inet_ntoa(ip->ip_src));
                if(strcmp(address, saddr) != 0)
                    continue;
            }
            if(strlen(daddr)){
                strcpy(address, inet_ntoa(ip->ip_dst));
                if(strcmp(address, daddr) != 0)
                    continue;
            }
    
    
            printf("%4d    %15s",count,inet_ntoa(ip->ip_src));
            printf("%15s    %5d    %5d
    ",inet_ntoa(ip->ip_dst),ip->ip_p,ntohs(ip->ip_len));
    
            int i=0,j=0;
            for(i=0;i<n;i++){
                if(i!=0 && i%16==0){
                    printf("    ");
                    for(j=i-16;j<i;j++){
                        if(buff[j]>=32&&buff[j]<=128)
                            printf("%c",buff[j]);
                        else printf(".");
                    }
                    printf("
    ");
                }
                if(i%16 == 0) printf("%04x    ",i);            
                printf("%02x",buff[i]);
    
                if(i==n-1){
                    for(j=0;j<15-i%16;j++) printf("  ");
                    printf("    ");
                    for(j=i-i%16;j<=i;j++){
                        if(buff[j]>=32&&buff[j]<127)
                            printf("%c",buff[j]);
                        else printf(".");
    
                    }
    
                }
    
            }
    
            printf("
    
    ");
    
        }
    }    
  • 相关阅读:
    模拟105 题解
    模拟104 题解
    模拟103 题解
    模拟102 题解
    python与 Ajax跨域请求
    Django--进阶--中间件的使用
    Django--权限组件
    python 最基本的的单例模型的实现及应用
    Django-数据库访问优化
    Create views of OpenCASCADE objects in the Debugger
  • 原文地址:https://www.cnblogs.com/big-xuyue/p/3650072.html
Copyright © 2011-2022 走看看