QNX系统上用Berkeley Packet Filter直接进行原始数据的收发
2017-02-22 17:06
1356 查看
这次我们讲的是在QNX系统上直接操作网络的数据链路层进行原始数据包收发的过程,即通过Berkeley Packet Filter我们可以绕过TCP/IP并且收发自己定义的协议。
在QNX系统的帮助文档上,很明确的写到:
即伯克利包过滤语言通过网络接口提供数据链路层的数据的访问通道,具体实现步骤为:
1、打开 BPF 设备(即向系统声明使用BPF设备)
在这里由于避免因各种原因打开设备失败,所以后面紧接一个迭代函数再次尝试打开设备,因为/dev/bpf是一个可以多次重复打开的设备,所以可以这样实现。
2.使用ioctl()函数来控制设备的操作
首先使用BIOCSETIF ioctl() 命令来绑定bpf和一个真正的网络接口,接口是在结构体ifreq中定义的。
在这步骤之后,可以根据自己的需求来设定网卡的操作模式和接收数据包的方式等。具体可以参考QNX系统的帮助文档里的ioctl()函数解释。
3、在做好以后上述两个步骤之后在第三步里就可以构建自己所要传输的数据包了。
即:目的地址+原地址+
//—————————————————————————————————
//——————————————————————————————-
//——————————————————————————————————-
4、在组建好数据包之后,我们就可以通过write()函数将数据包发送到网卡驱动上
并且可以用read()函数来读取网络上的数据包。
注:借用raw_socket的方法
源代码如下:
参考资料:
http://blog.chinaunix.net/uid-23069658-id-3280895.html
Linux网络编程:原始套接字的魔力【上】
http://blog.chinaunix.net/uid-23069658-id-3283534.html
Linux网络编程:原始套接字的魔力【下】
http://blog.csdn.net/dean_gdp/article/details/34088435
使用PF_PACKET和SOCK_RAW发送自定义type以太网数据包
在QNX系统的帮助文档上,很明确的写到:
即伯克利包过滤语言通过网络接口提供数据链路层的数据的访问通道,具体实现步骤为:
1、打开 BPF 设备(即向系统声明使用BPF设备)
/* using BPF device */ char bpfname[16] = {"/dev/bpf\0"}; int i=0; /* opening autocloning BFP device */ bpf = open(bpfname, O_RDWR);
在这里由于避免因各种原因打开设备失败,所以后面紧接一个迭代函数再次尝试打开设备,因为/dev/bpf是一个可以多次重复打开的设备,所以可以这样实现。
if (bpf < 0){ /* no autocloning BPF found: fall back to iteration */ for(i=0; i<128; i++){ snprintf(bpfname, sizeof(bpfname), "/dev/bpf%d", i); bpf = open(bpfname, O_RDWR); if(bpf != -1) break; }
2.使用ioctl()函数来控制设备的操作
首先使用BIOCSETIF ioctl() 命令来绑定bpf和一个真正的网络接口,接口是在结构体ifreq中定义的。
const char* ifname = "wm0"; struct ifreq iface; strncpy(iface.ifr_name, ifname, sizeof(ifname)); if( ioctl(bpf, BIOCSETIF, &iface) > 0){ printf("Could not bind %s to BPF\n", ifname); } printf("Associated with \"%s\"\n", ifname);
在这步骤之后,可以根据自己的需求来设定网卡的操作模式和接收数据包的方式等。具体可以参考QNX系统的帮助文档里的ioctl()函数解释。
3、在做好以后上述两个步骤之后在第三步里就可以构建自己所要传输的数据包了。
即:目的地址+原地址+
dst_mac[0] = 0x10;//设置目的网卡地址 dst_mac[1] = 0x78; dst_mac[2] = 0xd2; dst_mac[3] = 0xc6; dst_mac[4] = 0x2f; dst_mac[5] = 0x89;
//—————————————————————————————————
src_mac[0] = 0x11;//设置目的网卡地址 src_mac[1] = 0x78; src_mac[2] = 0xd2; src_mac[3] = 0xc6; src_mac[4] = 0x2f; src_mac[5] = 0x89;
//——————————————————————————————-
datalen = 12; data[0] = 'h'; data[1] = 'e'; data[2] = 'l'; data[3] = 'l'; data[4] = 'o'; data[5] = ' '; data[6] = 'w'; data[7] = 'o'; data[8] = 'r'; data[9] = 'l'; data[10] = 'd'; data[11] = '!';
//——————————————————————————————————-
frame_length = 6 + 6 + 2 + datalen; memcpy (ether_frame, dst_mac, 6); memcpy (ether_frame + 6, src_mac, 6); ether_frame[12] = ETH / 256; ether_frame[13] = ETH % 256; // data package memcpy (ether_frame + 14 , data, datalen);
4、在组建好数据包之后,我们就可以通过write()函数将数据包发送到网卡驱动上
write(bpf, ether_frame, frame_length);
并且可以用read()函数来读取网络上的数据包。
注:借用raw_socket的方法
socket (PF_PACKET, SOCK_RAW, htons (ETH_P_ALL))) < 0)来直接访问数据链路层的方法在QNX系统上行不通,QNX官方推荐了两种访问数据链路层的方法,第一种是使用bpf接口,即我们本文所使用的。第二种是使用pfil hooks来直接操作io-net。见QNX帮助文档里的packet filter章节。
源代码如下:
#include <stdlib.h> #include <stdio.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/types.h> #include <sys/ioctl.h> #include <arpa/inet.h> #include <net/bpf.h> #include <net/ethertypes.h> #include <net/if_ether.h> #include <unistd.h> // close() #include <string.h> // strcpy, memset(), and memcpy() #include <netdb.h> // struct addrinfo #include <sys/types.h> // needed for socket(), uint8_t, uint16_t, uint32_t #include <netinet/in.h> // IPPROTO_ICMP, INET_ADDRSTRLEN #include <netinet/ip.h> // struct ip and IP_MAXPACKET (which is 65535) #include <netinet/ip_icmp.h> // struct icmp, ICMP_ECHO #include <arpa/inet.h> // inet_pton() and inet_ntop() #include <sys/ioctl.h> // macro ioctl is defined #include <net/if.h> // struct ifreq #include <errno.h> // errno, perror() #define ETH_P_DEAN 0x8874 //自定义的以太网协议type #static int bpf = 0;
int main(int argc, char **argv)
{
//---------------------------------------------------------------------------//数据包结构体定义
int datalen,frame_length;
uint8_t data[IP_MAXPACKET];
uint8_t src_mac[6];
uint8_t dst_mac[6];;
uint8_t ether_frame[IP_MAXPACKET];
//-------------------------------------------------------------------------------
/* using BPF device */ char bpfname[16] = {"/dev/bpf\0"}; int i=0; /* opening autocloning BFP device */ bpf = open(bpfname, O_RDWR);
if (bpf < 0){ /* no autocloning BPF found: fall back to iteration */ for(i=0; i<128; i++){ snprintf(bpfname, sizeof(bpfname), "/dev/bpf%d", i); bpf = open(bpfname, O_RDWR); if(bpf != -1) break; }if(bpf < 0){
printf("Error: could not open any /dev/bpf device.\n");
}
}
printf("Opened BPF device \"%s\"\n", bpfname);
/* binding with real interface */
const char* ifname = "wm0"; struct ifreq iface; strncpy(iface.ifr_name, ifname, sizeof(ifname)); if( ioctl(bpf, BIOCSETIF, &iface) > 0){ printf("Could not bind %s to BPF\n", ifname); } printf("Associated with \"%s\"\n", ifname);
/* set immediate: returns on packet arrived instead of when buffer full */
int setimmediate = 1;
if( ioctl(bpf, BIOCIMMEDIATE, &setimmediate) == -1){
printf("Could set IO immediate");
}
/* set promiscuous mode */
// int promiscuous = 1;
// if( ioctl(bpf, BIOCPROMISC, &promiscuous) == -1){
// printf("Could get disable BIOCPROMISC");
// }
//---------------------------------------------------------------------------------------------------
// Set destination MAC address: you need to fill these out
dst_mac[0] = 0x10;
dst_mac[1] = 0x78;
dst_mac[2] = 0xd2;
dst_mac[3] = 0xc6;
dst_mac[4] = 0x2f;
dst_mac[5] = 0x89;
//---------------------------------------------------------------------------------------------------
src_mac[0] = 0x11;//设置目的网卡地址
src_mac[1] = 0x78;
src_mac[2] = 0xd2;
src_mac[3] = 0xc6;
src_mac[4] = 0x2f;
src_mac[5] = 0x89;
//---------------------------------------------------------------
datalen = 12;
data[0] = 'h';
data[1] = 'e';
data[2] = 'l';
data[3] = 'l';
data[4] = 'o';
data[5] = ' ';
data[6] = 'w';
data[7] = 'o';
data[8] = 'r';
data[9] = 'l';
data[10] = 'd';
data[11] = '!';
//-------------------------------------------------------------------------------------------------------
frame_length = 6 + 6 + 2 + datalen;
// Destination and Source MAC addresses
memcpy (ether_frame, dst_mac, 6);
memcpy (ether_frame + 6, src_mac, 6);
ether_frame[12] = ETH_P_DEAN / 256;
ether_frame[13] = ETH_P_DEAN % 256;
// data package
memcpy (ether_frame + 14 , data, datalen);
//-------------------------------------------------------------------------------------------------
/* 进行数据包的读写 */
while(!stop)
{
write(bpf, ether_frame, frame_length);
printf("data package is sending!\n");
close(bpf);
return 0;
}
//----------------------------------------------------------------------------------------------
参考资料:
http://blog.chinaunix.net/uid-23069658-id-3280895.html
Linux网络编程:原始套接字的魔力【上】
http://blog.chinaunix.net/uid-23069658-id-3283534.html
Linux网络编程:原始套接字的魔力【下】
http://blog.csdn.net/dean_gdp/article/details/34088435
使用PF_PACKET和SOCK_RAW发送自定义type以太网数据包
相关文章推荐
- Caffe学习(四)训练数据层设置和种类和直接采用原始图片数据进行训练!
- 系统损坏,移植Oracle(9.2.0.1)数据库(无备份数据文件进行恢复)
- fqyz一卡通系统kp考勤子系统,对原始记录进行处理的t-sql语句(二)
- 对ERP系统进行数据安检的必要性
- Linux中利用RAW SOCKET直接通过网卡收发数据
- 以原始套接字方式对网络数据进行捕获(转)
- 以原始套接字方式对网络数据进行捕获
- 很多人在进行数据迁移时,希望把数据导入不同于原系统的表空间,在导入之后却往往发现,数据被导入了原表空间
- FPGA控制DM9000A进行以太网数据收发的Verilog实现
- 基于半边数据结构(翼边数据结构)的Eular操作来实现扫成 通过OpenGL进行CAD实体建模 经测试可直接运行
- 利用原始套接字(SOCK_RAW)对ip数据进行监听
- 地磅称量系统之(37~39) 直接向数据库的数据表WtBill添加测试数据以及绑定用户控件和使用编码的方式控制dataGridView控件的每列属性和添加数据数据库的表中不存在的字段(非绑定列)
- 在网络中使用IO流进行数据收发
- 对ERP系统进行数据安检的必要性 推荐
- [转]在网络中使用IO流进行数据收发
- Ycnd 2D教程---GUI系统教程4---与控件进行数据交换(下)
- 直接删除数据文件后无法进入系统的解决方案
- 使用Git在Mac和Windows系统之间进行同步数据
- 直接删除数据文件后无法进入系统的解决方案
- 对【直接插入排序算法】的原始代码进行跟踪输出测试的梳理