mac报文:14个字节
recvfrom接收链路层帧数据,不经过网络层、传输层,不会给发送者的地址结构赋值,因此后两个参数为NULL。
设计思路:①创建一个原始套接字。
②while(1)利用recvfrom不断接收网络数据。
③解析获得mac头部中的源mac和目的mac,并判断网络层的协议类型。
④若是IP报文,则获得源IP和目的IP,并解析获得传输层协议类型。
⑤若传输层为TCP或UDP协议,则解析报文获得数据
#include测试:sudo运行.out文件#include #include #include #include #include int main() { //1.创建一个原始套接字(ETH_P_ALL表示收发任何数据类型) int sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); if(sockfd<0){ perror("socket"); return 0; } else{ printf("sockfd=%dn",sockfd); } //2.使用recvfrom接收网络数据(数据多,需要用while) while(1) { //定义buf存放帧数据,大小unsigned char1500 unsigned char buf[1500]=""; int len = recvfrom(sockfd, buf, sizeof(buf), 0, NULL, NULL); printf("len= %dn",len); char src_mac[18]=""; char dst_mac[18]=""; sprintf(dst_mac,"%02x:%02x:02x:02x:02x:02x:",buf[0],buf[1],buf[2],buf[3],buf[4],buf[5]); //组目的mac sprintf(src_mac,"%02x:%02x:02x:02x:02x:02x:",buf[0+6],buf[1+6],buf[2+6],buf[3+6],buf[4+6],buf[5+6]); //组源的mac printf("%s--->%sn", src_mac, dst_mac); //判断mac头部中的协议类型 (IP:0x0800 ARP:0x0806 RARP:0x8035) unsigned short mac_type = ntohs(*(unsigned short *)(buf+12)); //取出后为网络字节序,需转成主机字节序 if( mac_type == 0x0800 ){ printf("mac_type = %#x IP报文n", mac_type); //%#X,会在打印的十六进制结果前面加上0X //分析IP头部 unsigned char *ip_addr = buf+14; //+14为了跳过mac头 //ip_addr跳到源IP的起始位置 ip_addr += 12; //跳过3行,一行4字节 char src_ip[16]=""; char dst_ip[16]=""; sprintf(src_ip,"%d.%d.%d.%d",ip_addr[0],ip_addr[1],ip_addr[2],ip_addr[3]); //源IP ip_addr +=4; sprintf(dst_ip,"%d.%d.%d.%d",ip_addr[0],ip_addr[1],ip_addr[2],ip_addr[3]); //目的IP printf("%s--->%sn", src_ip, dst_ip); //判断网络层的上一层协议类型 ip_addr = buf+14; //跳回IP起始位置 unsigned char *ip_type = ip_addr + 9; //跳到协议类型位置 if(*ip_type == 1){ printf("ICMP报文n"); } else if(*ip_type == 2){ printf("IGMP报文n"); } else if(*ip_type == 6){ printf("TCP报文n"); ip_addr = buf + 14; //回到IP起始位置 int ip_head_len = (*ip_addr&0x0f)*4; //获得IP报文头部长度(&0x0f目的为了获得低八位) unsigned char *tcp_addr = buf + 14 + ip_head_len; //tcp_addr:TCP起始位置 unsigned src_port = ntohs(*(unsigned short *)tcp_addr); //获取源端口 unsigned dst_port = ntohs(*(unsigned short *)(tcp_addr+2)); //获取目的端口 //打印 printf("%hu--->%hun",src_port,dst_port); //跳到TCP首部长度的位置 unsigned char *tcp_headLen_addr = tcp_addr+12; int tcp_head_len = (*tcp_headLen_addr>>4)&0x0f; //高4位移动到低4位后再取 //打印数据 printf("TCP:%sn",tcp_addr + tcp_head_len); } else if(*ip_type == 17){ printf("UDP报文n"); ip_addr = buf + 14; //回到IP起始位置 int ip_head_len = (*ip_addr&0x0f)*4; //获得IP报文头部长度(&0x0f目的为了获得低位数据) unsigned char *udp_addr = buf + 14 + ip_head_len; //udp_addr:UDP起始位置 unsigned src_port = ntohs(*(unsigned short *)udp_addr); //获取源端口 unsigned dst_port = ntohs(*(unsigned short *)(udp_addr+2)); //获取目的端口 //打印 printf("%hu--->%hun",src_port,dst_port); //打印数据 printf("UDP:%sn",udp_addr+8); //应用层数据 } } else if(mac_type == 0x0806 ){ printf("mac_type = %#x ARP报文n", mac_type); } else if(mac_type == 0x8035 ){ printf("mac_type = %#x RARP报文n", mac_type); } } //关闭套接字 close(sockfd); return 0; }



