TCP/IP协议分析--数据链路

来源:互联网 发布:ih5软件下载 编辑:程序博客网 时间:2024/05/17 04:41

数据链路数据的格式由五部分组成:目的MAC(6)、本地MAC(6)、数据类型(2)、数据(len)、CRC校验(4)

目的MAC和本地MAC就是收发机器的MAC地址,如果目的MAC的所有bit均为1,则为广播包,局域网内所有机器都会接收这个包,一般用于ARP询问。

数据类型有三种:ARP包(0x0806)、RARP包(0x8035)、IP包(0x0800)

数据:根据数据类型的不同,数据有不同的意义。

对于绝大部分以太网芯片来说,CRC校验是由硬件完成的,所以对于软件来说是不可见的,除非用数据分析仪直接抓网线中的数据。


首先定义链路层的结构体:

//eth.h#ifndef  __ETH__#define  __ETH__typedef unsigned int   u32;typedef unsigned short u16;typedef unsigned char  u8;typedef struct{u8 destMAC[6];   //目的MACu8 sourMAC[6];   //源MACu16 type;        //类型u8 data[1024];   //数据}ETH_HEADER;typedef enum{    ARP_PACKET=0x0806,    RARP_PACKET=0x8035,    IP_PACKET=0x0800}PACKET_TYPE;#endif

在linux下,可以通过socket(PF_PACKET,SOCK_RAW,htons(ETH_P_ALL))来申请链路层的套接字,这是一个无链接的套接字。

//eth.c#include<stdio.h>#include<netinet/if_ether.h>#include"eth.h"/*将二进制网卡地址转换为可读的字符地址,与ifconfig命令中的格式相同*/void StrMac(u8* str,u8* bin){    sprintf(str,"%02X:%02X:%02X:%02X:%02X:%02X",bin[0],bin[1],bin[2],bin[3],bin[4],bin[5]);}u16 analyseETH(ETH_HEADER* eth){    u8 mac[20];    StrMac(mac,eth->destMAC);    printf("destMAC:%s\n",mac);    StrMac(mac,eth->sourMAC);    printf("sourMAC:%s\n",mac);    printf("ETH_type:%04x\n",htons(eth->type)); //htons返回小端格式的数据    return eth->type;}int main(){    int socket_fd;    ETH_HEADER* eth;    u32 num = 0;    u16 type;    u8  buf[10240];    ssize_t len;    socket_fd = socket(PF_PACKET,SOCK_RAW,htons(ETH_P_ALL)); //申请链路层的套接字    if(socket_fd == -1)    {        printf("socket error!\n");        return -1;    }    while(1)    {        len = recv(socket_fd,buf,sizeof(buf),0);        if(len == -1)        {            printf("recv error!\n");            break;        }        else if(len == 0)        {            continue;        }        printf("*********ETH HEADER[%d]*********\n",num++);                printf("recv_len:%d\n",len);        eth = (ETH_HEADER*)buf;        type = analyseETH(eth);        switch(htons(type))        {            case ARP_PACKET:                printf("ARP_PACKET!\n");                break;            case RARP_PACKET:                printf("RARP_PACKET!\n");                                break;            case IP_PACKET:                printf("IP_PACKET!\n");                break;            default:                printf("what?\n");                break;        }    }    close(socket_fd);    return 0;}

执行gcc eth.c -o eth

运行./eth即可看到打印出的链路层信息

0 0
原创粉丝点击