使用PF_PACKET发送自定义type以太网数据包

目标

  • 利用PF_PACKET 和SOCK_RAW创建套接字发送一个任意的以太网帧

背景

  • 以太网是一个链路层协议。大多数网络程序员关注网络栈的传输层及以上,所以不需要直接处理以太网帧,但是某些场景下关注传输层以下也是有必要的。如:

    1)实现网络协议栈里面没有内置的以太网协议类型
    2)为测试目的,产生一个畸形或者其它非常规帧

使用场景

  • 已知发送方和接收方的mac地址,就可以使用这个以太网协议发送接收数据。

编程

  1. 使用PF_PACKET 和SOCK_RAW创建套接字
    注:用这个套接字的打开需要用户有root权限
	if((fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) < 0){
		perror("socket create failed");
		exit (EXIT_FAILURE);
	} 
参数1:PF_PACKET,该参数是从MAC层直接收发原始数据。
参数2:SOCK_RAW,使用该参数需要自己构造以太网数据包。
			SOCK_DGRAM,填这个参数是以太网头已经构造好了。
参数3:ETH_P_ALL自身定义于  /usr/include/linux/if_ether.h中,使用它是包含所有协议类型。

2.将网络接口赋值给原始套接字地址结构

    memset(&device, 0, sizeof(device));
	strncpy(req.ifr_name, interface, IFNAMSIZ);	//指定网卡名称
	//赋值以太网接口的索引值
	ioctl(fd, SIOCGIFINDEX, &req);
	bzero(&device, sizeof(device));
	device.sll_ifindex = req.ifr_ifindex;
	
	dst_mac[0] = 0x00;
	dst_mac[1] = 0x50;		
	dst_mac[2] = 0x90;				
	dst_mac[3] = 0xb0;
	dst_mac[4] = 0xb0;		
	dst_mac[5] = 0xb0;
     //Fill out sockaddr_ll.
    device.sll_family = AF_PACKET;
    memcpy(device.sll_addr, dst_mac, 6);
    device.sll_halen = htons(6);
	device.sll_protocol = htons(ETH_P_ALL);
里面除了以太网接口的索引值,其他赋值都是可以不用的,因为你下面自己会构造以太网包,目标mac会你构造的包中的mac为准。

3.构造协议包

    char org_buf[60] = {		
			0x00, 0x50, 0x90, 0xb0, 0xb0, 0xb0,  // 目的mac
			0x00, 0x50, 0x90, 0xcc, 0xcc, 0xcc,  // 源mac
            0x80, 0x01,	//以太网协议type
            0, 1, 0, 42,
            1, 4, 0, 0,
            2, 4, 0, 0,
            3, 4, 0, 0,
            4, 4, 0, 0,
            5, 4, 0, 0,
            6, 4, 0, 0,
            7, 4, 0, 0,
            8, 4, 0, 0,
            9, 6, 0, 0, 0, 0, 
            0, 0, 0, 0, 
	};

前6字节为目的mac,后6字节为源mac,0x8001为以太网协议type。注意,自己要发送的数据要从第21字节开始。
下面是协议类型,我们这里的0x8001是自己定义的。

#define ETH_P_LOOP      0x0060          /* Ethernet Loopbackpacket     */      
#define ETH_P_PUP       0x0200          /* Xerox PUP packet             */      
#define ETH_P_PUPAT     0x0201          /* Xerox PUP Addr Trans packet  */      
#define ETH_P_IP        0x0800          /* Internet Protocol packet     */      
#define ETH_P_X25       0x0805          /* CCITT X.25                   */      
#define ETH_P_ARP       0x0806          /* Address Resolution packet    */      
#define ETH_P_BPQ       0x08FF          /* G8BPQ AX.25 Ethernet Packet  [ NOT AN
#define ETH_P_IEEEPUP   0x0a00          /* Xerox IEEE802.3 PUP packet */        
#define ETH_P_IEEEPUPAT 0x0a01          /* Xerox IEEE802.3 PUP Addr Trans packet*/

4.使用sendto发送帧

int ret = sendto(fd,frame_buf,60,0, (struct sockaddr *)&device,lllen);
if(ret == -1){
	perror("sendto error");
}

5.完整代码

int generate_frame(char *buf, GENERATE *generate)
{
//	int i = 0;
	
    const char org_buf[60] = {
//			0xB0, 0x5C, 0xDA, 0x62, 0xE0, 0xF5,	// 目的mac
//          0x00, 0xd8, 0x61, 0x1a, 0xc3, 0xd9,	// 源mac		
			0xB0, 0x5C, 0xDA, 0x62, 0xE0, 0xF5,  
			0x00, 0x50, 0x90, 0xcc, 0xcc, 0xcc,  
            0x80, 0x01,	//以太网协议type
            // content
            0, 1, 0, 42,
            1, 4, 0, 0,
            2, 4, 0, 0,
            3, 4, 0, 0,
            4, 4, 0, 0,
            5, 4, 0, 0,
            6, 4, 0, 0,
            7, 4, 0, 0,
            8, 4, 0, 0,
            9, 6, 0, 0, 0, 0, 
            0, 0, 0, 0, 
            // 0, 0, 0, 0,
	};
	memcpy(buf, org_buf, sizeof(org_buf));
//	for(i = 0; i < 6; i++){
//		buf[i] = dst_mac[i]; 
//		buf[i+6] = src_mac[i]; 
//	}
	putUint16(buf+20+0*4, cnvPlmn(generate->plmn));
	putUint16(buf+20+1*4, cnvType(generate->type));
	putUint16(buf+20+2*4, cnvRssi(generate->rssi));            
	putUint16(buf+20+3*4, cnvData(generate->dataEnable));
	putUint16(buf+20+4*4, cnvDataErrno(generate->dataErrno));
	putUint16(buf+20+5*4, cnvWifi(generate->wifiStat));
	putUint16(buf+20+6*4, cnvWifiErrno(generate->wifiErrno));
	putUint16(buf+20+7*4, cnvSim(generate->simEnable));
	putIP(buf+20+8*4,generate->ip);
	
	return sizeof(org_buf);
}            

int main(int argc, char* argv[])
{
	int fd = -1;
	char frame_buf[1024] = {0};
	struct sockaddr_ll device;
//	unsigned char src_mac[8] = {0};
    unsigned char dst_mac[8] = {0};	
	int lllen = 0;
	struct ifreq req;
	struct ifreq ifr;	
	int i = 0;
	GENERATE generate = {0};
	char plmn_buf[30] = {0};
	char type_buf[30] = {0};
	int nrssi = 0;
	int nOffset = 0;
	char sTarg[4] = {0};
	
	if((fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) < 0){
		perror("socket create failed");
		exit (EXIT_FAILURE);
	} 

    memset(&device, 0, sizeof(device));

	strncpy(req.ifr_name, interface, IFNAMSIZ);	//指定网卡名称
	//4.将网络接口赋值给原始套接字地址结构
	ioctl(fd, SIOCGIFINDEX, &req);
	bzero(&device, sizeof(device));
	device.sll_ifindex = req.ifr_ifindex;	

	dst_mac[0] = 0xB0;
	dst_mac[1] = 0x5C;		
	dst_mac[2] = 0xDA;				
	dst_mac[3] = 0x62;
	dst_mac[4] = 0xE0;		
	dst_mac[5] = 0xF5;

     //Fill out sockaddr_ll.
    device.sll_family = AF_PACKET;
    memcpy(device.sll_addr, dst_mac, 6);
    device.sll_halen = htons(6);
	device.sll_protocol = htons(ETH_P_ALL);

	while(1){
		Sleep(T1);
		//电信运营商
		cfg_get_item("nv_plmn",plmn_buf,sizeof(plmn_buf));
		if(strlen(plmn_buf)){
			generate.plmn = atoi(plmn_buf);
		}
		//网络类型
		cfg_get_item("network_type",type_buf,sizeof(type_buf));
		if(!strcmp(type_buf, "LTE")){	//4G
			generate.type = 3;
		}else if(!strcmp(type_buf, "WCDMA")){	//3G
			generate.type = 2;
		}else if(!strcmp(type_buf, "GSM")){	//2G
			generate.type = 1;
		}
		//rssi
		tw_get_rssi(&nrssi);
		generate.rssi = nrssi;
		memset(type_buf,0,sizeof(type_buf));
		//数据连接是否在线
		cfg_get_item("pdp_status",type_buf,sizeof(type_buf));	
		if(atoi(type_buf) == 1){
			generate.dataEnable = 2;
			generate.dataErrno = 2;
		}else{
			generate.dataEnable = 1;
			generate.dataErrno = 1;
		}
		//SIM卡状态
		memset(type_buf,0,sizeof(type_buf));
		cfg_get_item("modem_main_state",type_buf,sizeof(type_buf));	
		if(!strcmp(type_buf, "modem_init_complete")){
			generate.simEnable = 2;
		}else{
			generate.simEnable = 1;
		}
		//wifiStat/wifiErrno
		generate.wifiStat = 1;
		generate.wifiErrno = 2;
		//公网IP		
		generate.ip = 0;
		memset(type_buf,0,sizeof(type_buf));
		cfg_get_item("wan1_ip",type_buf,sizeof(type_buf));	
		printf("wan1_ip:%s\r\n",type_buf);
		nOffset = 0;
		nOffset += StrTok(type_buf+nOffset,sTarg,'.');
		generate.ip += atoi(sTarg) << 24;
		nOffset += StrTok(type_buf+nOffset,sTarg,'.');
		generate.ip += atoi(sTarg) << 16;
		nOffset += StrTok(type_buf+nOffset,sTarg,'.');
		generate.ip += atoi(sTarg) << 8;
		nOffset += StrTok(type_buf+nOffset,sTarg,'.');
		generate.ip += atoi(sTarg);		
		generate_frame(frame_buf,&generate);
		lllen = sizeof(struct sockaddr_ll);
		int ret = sendto(fd,frame_buf,60,0, (struct sockaddr *)&device,lllen);
		if(ret == -1){
			perror("sendto error");
		}
	}
	close(fd);
	return 0;
}
				

6.wireshark抓包实测
在这里插入图片描述

在这里插入图片描述

上面Protocol为0x8001的就是我们在目的mac上抓的包,具体数据也可以看到。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值