计网课设思路

用c语言实现某种协议数据包构造与解析

/*

​ @author: Isadora

​ @time:2021/9/20

*/

  • 选择协议以及确定数据报格式

以ICMP为例:

其数据报格式如下:

img

wireshark抓包分析如下:

img

实际数据域分析:

img

对应代码片段:

/* 下面是ICMP协议格式的定义*/   
class icmp_header   
{  public: 
    u_int8_t icmp_type;    /* ICMP类型 */   
    u_int8_t icmp_code;    /* ICMP代码 */   
    u_int16_t icmp_checksum;    /* 校验和 */   
    u_int16_t icmp_id;    /* 标识符 */   
    u_int16_t icmp_sequence;   /* 序列码 */      
};   
  • 构造报文

确定协议各字段后用文件操作按各字段写入文件

#include "stdio.h"
#include "string.h"

int main(void)
{
	char ch[4];//定义一个字符型数组
	short i;  //短整型
	FILE *fp1,*fp2;
	fp1=fopen("C:/Users/15212/Desktop/Internet/file1.txt","w");//路径自行修改
	fp2=fopen("C:/Users/15212/Desktop/Internet/file2.bin","wb");//bin为二进制文件,wb表示以二进制模式访问文件
	//判断文件是否打开成功
	if (NULL==fp1 || NULL==fp2)
	{
		printf("can not create file\n");
		return -1;
	}

	memset(ch,0,sizeof(ch));//文件写入0
	strcpy(ch,"123");//复制字符串
	fwrite(ch,strlen(ch),1,fp1);//写文件
	
	
	i=123;
	fwrite(&i,sizeof(short),1,fp2);
	//fwrite(ch,strlen(ch),1,fp2);

	fclose(fp1);
	fclose(fp2);
	
	return 0;
}

写字段

/*
ICMP类型:8(请求报文)
ICMP代码:0
校验和:0x4ce9
标识符:256(0x0100)
序列:29184(0x7200)
*/
icmp_type = 8;
icmp_code = 0;
icmp_checksum = 0x4ce9;//需要转十进制?可能不需要
icmp_id = 256;
icmp_sequence = 29184;
//接下来开始傻瓜式写入
fwrite(&icmp_type,sizeof(u_int8_t),1,fp1);
fwrite(&icmp_code,sizeof(u_int8_t),1,fp1);
fwrite(&icmp_checksum,sizeof(u_int16_t),1,fp1);
fwrite(&icmp_id,sizeof(u_int16_t),1,fp1);
fwrite(&icmp_sequemce,sizeof(u_int16_t),1,fp1);

wireshark考虑到window系统与Linux系统发出的ping报文(主要指ping应用字段而非包含IP头的ping包)的字节顺序不一样(windows为LE:little-endian byte order,Linux为BE:big-endian),别分告诉信息,其本质内容是没有不变的,只是表达形式不同。

  • 校验和计算函数(根据情况自行修改,不是每个协议都需要校验和)
/CheckSum:计算校验和的子函数 
USHORT checksum(USHORT *buffer, int size) 
{ 
    unsigned long cksum=0; 
    while(size >1) 
    { 
        cksum+=*buffer++; 
        size -=sizeof(USHORT); 
    } 
    if(size) 
    { 
        cksum += *(UCHAR*)buffer; 
    } 

    cksum = (cksum >> 16) + (cksum & 0xffff); 
    cksum += (cksum >>16); 
    return (USHORT)(~cksum); 
}
  • 解析报文
/* 下面是实现分析ICMP协议的函数,函数类型与回调函数相同   */   
void icmp_protocol_packet_callback(u_char *argument, const  pcap_pkthdr *packet_header, const u_char *packet_content)   
{   
    class icmp_header *icmp_protocol;  /* ICMP协议变量 */    
    icmp_protocol = (icmp_header*)(packet_content + 14+20);  /* 获得ICMP协议内容 */    
   cout<<"          ICMP协议         "<<endl;   
   cout<<"ICMP类型:"<<icmp_protocol->icmp_type<<endl;     /* 获得ICMP类型 */  
   
    switch (icmp_protocol->icmp_type)   
    {   
        case 8:   
           cout<<"ICMP回显请求协议"<<endl;   
           cout<<"ICMP代码:"<<icmp_protocol->icmp_code<<endl;   
           cout<<"标识符:"<<icmp_protocol->icmp_id<<endl;   
           cout<<"序列码:"<<icmp_protocol->icmp_sequence<<endl;   
            break;   
        case 0:   
           cout<<"ICMP回显应答协议"<<endl;   
           cout<<"ICMP代码: "<< icmp_protocol->icmp_code<<endl;   
           cout<<"标识符: "<< setw(4) << setfill('0') << hex<<int(icmp_protocol->icmp_id) << endl;  
           cout<<"序列码: "<< icmp_protocol->icmp_sequence<<endl;   
            break;   
        default:   
            break;   
    }   
   cout<<"ICMP校验和:"<<setw(4) << setfill('0') << hex << ntohs(icmp_protocol->icmp_checksum) << endl;    /* 获得ICMP校验和 */   
    return ;   
}   
  • 主函数
/*主函数 */   
void main()   
{   
   	pcap_if_t *alldevs; 
	pcap_if_t *d; 
	int inum; 
	int i=0; 
	pcap_t *pcap_handle;  /* Winpcap句柄 */   
    char error_content[PCAP_ERRBUF_SIZE];   /* 存储错误信息 */   
    //char *net_interface;  /* 网络接口 */   
    bpf_program bpf_filter;  /* BPF过滤规则 */   
    char bpf_filter_string[] = ""; /* 过滤规则字符串 */    
    bpf_u_int32 net_mask;  /* 掩码 */     
    bpf_u_int32 net_ip;  /* 网络地址 */  
    //net_interface = pcap_lookupdev(error_content); /* 获得可用的网络接口 */ 
	
	if (pcap_findalldevs(&alldevs, error_content) == -1) 
	{  
		fprintf(stderr,"Error in pcap_findalldevs:%s\n", error_content); 
		exit(1); 
	} 
	
	/* 打印 list */ 
	for(d=alldevs; d; d=d->next) 
	{ 
		printf("%d. %s", ++i, d->name); 
		if (d->description) printf(" (%s)\n", d->description); 
		else printf(" (No description available)\n"); 		
	} 
	
	if(i==0) 
	{ 
		printf("\nNo interfaces found! Make sure WinPcap is installed.\n"); 
		return; 
	} 
	
	printf("Enter the interface number (1-%d):",i); 
		scanf("%d", &inum); 
	
	if(inum < 1 || inum > i) 
	{ 
		printf("\nInterface number out of range.\n"); 
		pcap_freealldevs(alldevs); /* Free the device list */ 
		return; 
	} 
	
	/* 跳转到指定的网卡 */ 
	for(d=alldevs, i=0; i< inum-1 ;d=d->next, i++); 
	//pcap_lookupnet(d->description, &net_ip, &net_mask, error_content);/* 获得网络地址和掩码地址 */      
	
	IN_ADDR sinaddr;
	pcap_addr_t *a;
	
	for(a=d->addresses;a;a=a->next) 
	{
		switch(a->addr->sa_family) 
		{ 
		  case AF_INET: 
           
//			printf("\tAddress Family Name: AF_INET\n");//打印网络地址类型 

			if(a->addr)//打印IP地址 
			{
				sinaddr=((struct sockaddr_in *)a->addr)->sin_addr;
				net_ip=sinaddr.S_un.S_addr;
			 /*printf("\tAddress:%d.%d.%d.%d\n",
				 sinaddr.S_un.S_un_b.s_b1,sinaddr.S_un.S_un_b.s_b2,
				 sinaddr.S_un.S_un_b.s_b3,sinaddr.S_un.S_un_b.s_b4);*/
           	}
			if (a->netmask)//打印掩码 
			{	sinaddr=((struct sockaddr_in *)a->netmask)->sin_addr;
				net_mask=sinaddr.S_un.S_addr;
			//  printf("\tNetmask:%s\n",inet_ntoa(sinaddr));
			}
			/*if (a->broadaddr)//打印广播地址 
			{   sinaddr=((struct sockaddr_in *)a->broadaddr)->sin_addr;
			    printf("\tBroadcast Address:%s\n",inet_ntoa(sinaddr));
			}
			if (a->dstaddr)//目的地址 
			{ sinaddr=((struct sockaddr_in *)a->dstaddr)->sin_addr;
			  printf("\tDestination Address:%s\n",inet_ntoa(sinaddr));
			}*/
			break; 
			
		//  default:printf("\tAddress Family Name:Unknown\n"); break; 
		} /*end of switch*/
	}
	
	
	pcap_handle = pcap_open_live(d->name/*net_interface*/, 65536, 1, 1000, error_content);  /* 打开网路接口 */    
    pcap_freealldevs(alldevs); 
	pcap_compile(pcap_handle, &bpf_filter, bpf_filter_string, 0, net_ip);  /* 编译BPF过滤规则 */      
    pcap_setfilter(pcap_handle, &bpf_filter);  /* 设置过滤规则 */   
    if (pcap_datalink(pcap_handle) != DLT_EN10MB)   
        return ;   
	cout<<"请输入抓包数量:"<<endl;
	int n;
	cin>>n;
    pcap_loop(pcap_handle,  n, ethernet_protocol_packet_callback, NULL); /* 注册回调函数,循环捕获网络数据包,利用回调函数来处理每个数据包 */     
    pcap_close(pcap_handle); /* 关闭Winpcap操作 */  
       
}

交互式终端:

给一个

cin>>n;

即可。

问题来了:

我选择ICMP协议,它的内层是否也需要写(以太网协议)

老师好像说过不用

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ISAdora.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值