一、链路层数据格式
mac报文:14个字节
二、IP数据报文格式
三、TCP数据报文格式
四、UDP数据报文格式
五、demo(网络分析器)
recvfrom接收链路层帧数据,不经过网络层、传输层,不会给发送者的地址结构赋值,因此后两个参数为NULL。
设计思路:
①创建一个原始套接字。 ②while(1)利用recvfrom不断接收网络数据。 ③解析获得mac头部中的源mac和目的mac,并判断网络层的协议类型。 ④若是IP报文,则获得源IP和目的IP,并解析获得传输层协议类型。 ⑤若传输层为TCP或UDP协议,则解析报文获得数据
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/ether.h>
#include <arpa/inet.h>
#include <errno.h>
int main()
{
int sockfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if(sockfd<0){
perror("socket");
return 0;
}
else{
printf("sockfd=%d\n",sockfd);
}
while(1)
{
unsigned char buf[1500]="";
int len = recvfrom(sockfd, buf, sizeof(buf), 0, NULL, NULL);
printf("len= %d\n",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]);
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]);
printf("%s--->%s\n", src_mac, dst_mac);
unsigned short mac_type = ntohs(*(unsigned short *)(buf+12));
if( mac_type == 0x0800 ){
printf("mac_type = %#x IP报文\n", mac_type);
unsigned char *ip_addr = buf+14;
ip_addr += 12;
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_addr +=4;
sprintf(dst_ip,"%d.%d.%d.%d",ip_addr[0],ip_addr[1],ip_addr[2],ip_addr[3]);
printf("%s--->%s\n", src_ip, dst_ip);
ip_addr = buf+14;
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;
int ip_head_len = (*ip_addr&0x0f)*4;
unsigned char *tcp_addr = buf + 14 + ip_head_len;
unsigned src_port = ntohs(*(unsigned short *)tcp_addr);
unsigned dst_port = ntohs(*(unsigned short *)(tcp_addr+2));
printf("%hu--->%hu\n",src_port,dst_port);
unsigned char *tcp_headLen_addr = tcp_addr+12;
int tcp_head_len = (*tcp_headLen_addr>>4)&0x0f;
printf("TCP:%s\n",tcp_addr + tcp_head_len);
}
else if(*ip_type == 17){
printf("UDP报文\n");
ip_addr = buf + 14;
int ip_head_len = (*ip_addr&0x0f)*4;
unsigned char *udp_addr = buf + 14 + ip_head_len;
unsigned src_port = ntohs(*(unsigned short *)udp_addr);
unsigned dst_port = ntohs(*(unsigned short *)(udp_addr+2));
printf("%hu--->%hu\n",src_port,dst_port);
printf("UDP:%s\n",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;
}
测试:sudo运行.out文件
|