IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 利用C语言编写一个网络分析器 -> 正文阅读

[C++知识库]利用C语言编写一个网络分析器

一、链路层数据格式

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()
{
	//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=%d\n",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= %d\n",len);
		/*buf不要用%s遍历。帧数据大多都是不可识别的ASCII值,有太多的0x00;
		  不可sleep(),当休眠时有速度过来,数据会被协议栈提取一层一层往上走,
		  对于链路层就没有了,会丢失数据。
		*/

		/*解析buf中的mac头部信息。[mac][ip][tcp/udp][data]  eg:ff:ff:ff:ff:ff:ff 长度2*6+5+1=18
		  mac头部结构:目的mac(6B) 源mac(6B) 类型(2B) 
		*/
		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--->%s\n", 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--->%s\n", 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--->%hu\n",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:%s\n",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--->%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文件

在这里插入图片描述

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-05-07 11:00:54  更:2022-05-07 11:01:11 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/21 5:44:12-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码