zoukankan      html  css  js  c++  java
  • Linux数据链路层的包解析

    仅以此文作为学习笔记,初学者,如有错误欢迎批评指正,但求轻喷。
    一般而言,Linux系统截获数据包后,会通过协议栈,按照TCP/IP层次进行解析,那我们如何直接获得更为底层的数据报文呢,这里用到一个类型SOCK_PACKET类型。

    1 int sockfd = socket(AF_INET,SOCK_PACKET,htons(0x0003));  

    通过上面这个函数可以获得一个特殊的套接字,其中:
    AF_INET:                              表示因特网协议族
    SOCK_PACKET:                   表示数据包截取在物理层
    0x0003:                                 表示数据帧类型不确定
    修改网络接口结构:

    1 struct ifreq ifr;
    2 strcpy(ifr.ifr_name,"eth0");
    3 ioctl(sockfd,SIOCGIFFLAGS,&ifr);

    设置混杂模式

    1 ifr.ifr_flags| = IFR_PROMISC;
    2 ioctl(sockfd,SIOCSIFFLAGS,&ifr);

    注意:

     进行标志位设定时,遵循以下步骤:
    (1)取出原标识位;
    (2)与待设定标志位进行位或运算(“|”);
    (3)重新写入;
    一个小小的抓包程序

    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<iostream>
    #include<unistd.h>
    #include<sys/types.h>
    #include<sys/socket.h>
    #include<sys/ioctl.h>
    #include<net/if.h>
    #include<arpa/inet.h>
    #include<netinet/if_ether.h>
    #include<netinet/in.h>
    #include<netinet/ip.h>
    #include<netinet/tcp.h>
    #include<netinet/udp.h>
    
    using namespace std;
    
    char ethernet_frame[ETH_FRAME_LEN];//定义一个数据帧的长度
    struct iphdr *ipheader;//定义ip头部指针
    
    int socketcreate()
    {
        int sockfd = socket(AF_INET,SOCK_PACKET,htons(0x0003));    
        //构建了一个数据链路层的数据包;
        if(sockfd == -1)
        {
            cout<<"Socket init error!"<<endl;    
            return -1;
        }
        /*
            下面设置接口结构
        */
        char *ifname = "eth0";
        struct ifreq ifr;
        strcpy(ifr.ifr_name,ifname);
        int result = ioctl(sockfd,SIOCGIFFLAGS,&ifr);
        if(result == -1)
        {
            cout<<"Can't get flags!"<<endl;
            close(sockfd);
            return -2;
        }
        ifr.ifr_flags|= IFF_PROMISC;
        /*
        一般而言,Linux系统截获数据包后,会通过协议栈,按照TCP/IP层次进行解析,那我们如何直接获得更为底层的数据报文呢,这里用到一个类型SOCK_PACKET类型。
                       int sockfd = socket(AF_INET,SOCK_PACKET,htons(0x0003));
                       通过上面这个函数可以获得一个特殊的套接字,其中:
                       AF_INET:                              表示因特网协议族
                       SOCK_PACKET:                   表示数据包截取在物理层
                       0x0003:                                 表示数据帧类型不确定
    
                       修改网络接口结构:
                       struct ifreq ifr;
                       strcpy(ifr.ifr_name,"eth0");
                       ioctl(sockfd,SIOCGIFFLAGS,&ifr);
    
                       设置混杂模式
                       ifr.ifr_flags| = IFR_PROMISC;
                       ioctl(sockfd,SIOCSIFFLAGS,&ifr);
                       注意:
                              进行标志位设定时,遵循以下步骤:
                            (1)取出原标识位;
                            (2)与待设定标志位进行位或运算(“|”);
                            (3)重新写入;
        */
        result = ioctl(sockfd,SIOCSIFFLAGS,&ifr);
        if(result == -1)
        {
            cout<<"Can't set flags!"<<endl;
            close(sockfd);
            return -3;
        }
        
        
        
        return sockfd;
    }
    int getframe(int sockfd,int num)
    {
        struct ethhdr* fheader;
        fheader = (struct ethhdr*)ethernet_frame;
        memset(ethernet_frame,0,ETH_FRAME_LEN);
        int size = read(sockfd,ethernet_frame,ETH_FRAME_LEN);
        if(size <= 0)
        {
            cout<<"No packet or packet error!"<<endl;    
            return -1;
        }
        cout<<"************************Packet"<<num<<"received from eth0 START!************************"<<endl;
        printf("DST MAC: ");
        for(int i=0;i<ETH_ALEN-1;i++)
        {
            printf("%2x-",fheader->h_dest[i]);    
        }
        printf("%2x
    ",fheader->h_dest[ETH_ALEN-1]);
        printf("SRC MAC: ");
        for(int i=0;i<ETH_ALEN-1;i++)
        {
            printf("%2x-",fheader->h_source[i]);    
        }
        printf("%2x
    ",fheader->h_source[ETH_ALEN-1]);
        if(ntohs(fheader->h_proto) == 0x0800)
        {
            cout<<"Protocol: IP"<<endl;    
        }
        if(ntohs(fheader->h_proto) == 0x0806)
        {
            cout<<"Protocol: RAP"<<endl;    
        }
        if(ntohs(fheader->h_proto) == 0x8035)
        {
            cout<<"Protocol: RARP"<<endl;    
        }
        int ret = ntohs(fheader->h_proto);
        return ret;
    }
    
    int getip(int protocol,int num)
    {
            if(protocol != 0x0800)
            {
                cout<<"NO IP Packet!"<<endl;
                cout<<"************************Packet"<<num<<"received from eth0 END!**************************"<<endl;
                return 0;    
            }
            ipheader = (struct iphdr*)(ethernet_frame+ETH_HLEN);
            printf("Version: 4");
            cout<<endl;
            in_addr *p,*q;
            p = (struct in_addr*)&ipheader->saddr;
            printf("SRC IP: %s",inet_ntoa(*p));
            cout<<endl;
            q = (struct in_addr*)&ipheader->daddr;
            printf("DST IP: %s",inet_ntoa(*q));
            cout<<endl;
            if(ipheader->protocol == 1)
            {
                cout<<"PROTOCOL: ICMP"<<endl;    
            }
            if(ipheader->protocol == 6)
            {
                cout<<"PROTOCOL: TCP"<<endl;    
            }
            if(ipheader->protocol == 17)
            {
                cout<<"PROTOCOL: UDP"<<endl;    
            }
            return ipheader->protocol;
    }
    
    int gettcp(int protocol)
    {
        if(protocol != 6)
        {
            return -1;    
        }
        struct tcphdr* tcph;
        tcph = (struct tcphdr*)(ipheader+((ipheader->ihl)*4));
        printf("SRC PORT: %d",ntohs(tcph->source));
        cout<<endl;
        printf("DST PORT: %d",ntohs(tcph->dest));
        cout<<endl;
        return 0;
    }
    
    int getudp(int protocol)
    {
        if(protocol != 17)
        {
            return -1;    
        }
        struct udphdr* udph;
        udph = (struct udphdr*)(ipheader+((ipheader->ihl)*4));
        printf("SRC PORT: %d",ntohs(udph->source));
        cout<<endl;
        printf("DST PORT: %d",ntohs(udph->dest));
        cout<<endl;
        return 0;
    }
    
    int main(int argc,char *argv[])
    {        
        if(argc < 2)
        {
            cout<<"Please input the nummber of packet that you want to catch!"<<endl;
            return 0;
        }
        int num = (int)argv[1][0];
        int sock = socketcreate();
        for(int i=1;i<num;i++)
        {
            int ip_protocol = getframe(sock,i);
            int trasnport_protocol = getip(ip_protocol,i);
            gettcp(trasnport_protocol);
            getudp(trasnport_protocol);
            cout<<"************************Packet"<<num<<"received from eth0 END!**************************"<<endl;
            cout<<endl;
            cout<<endl;
            cout<<endl;
            cout<<endl;
        }
        return 0;
    }
  • 相关阅读:
    day54——Python 处理图片
    day53——Python 处理 Excel 数据
    day52——Python 处理附件
    day51——爬虫(一)
    大数据治理体系简谈
    redis环境的安装
    微服务体系操作日志如何记录?
    mysql数据库设计规范
    win系统下git代码批量克隆,批量更新
    java实现二维码登录功能
  • 原文地址:https://www.cnblogs.com/KevinGeorge/p/7866735.html
Copyright © 2011-2022 走看看