这次我们讲的是在QNX系统上直接操作网络的数据链路层进行原始数据包收发的过程,即通过Berkeley Packet Filter我们可以绕过TCP/IP并且收发自己定义的协议。
在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、在组建好数据包