这次我们讲的是在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);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

在这里由于避免因各种原因打开设备失败,所以后面紧接一个迭代函数再次尝试打开设备,因为/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;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

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);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

在这步骤之后,可以根据自己的需求来设定网卡的操作模式和接收数据包的方式等。具体可以参考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;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

//—————————————————————————————————

        src_mac[0] = 0x11;//设置目的网卡地址src_mac[1] = 0x78;src_mac[2] = 0xd2;src_mac[3] = 0xc6;src_mac[4] = 0x2f;src_mac[5] = 0x89;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

//——————————————————————————————-

          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] = '!';
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

//——————————————————————————————————-

       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  packagememcpy (ether_frame + 14 , data, datalen);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

4、在组建好数据包之后,我们就可以通过write()函数将数据包发送到网卡驱动上

       write(bpf, ether_frame, frame_length);
  • 1
  • 2

并且可以用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;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
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 outdst_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 addressesmemcpy (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  packagememcpy (ether_frame + 14 , data, datalen);//-------------------------------------------------------------------------------------------------
/* 进行数据包的读写    */while(!stop){write(bpf, ether_frame, frame_length);printf("data package is sending!\n");close(bpf);return 0;
}
//----------------------------------------------------------------------------------------------
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110

参考资料: 
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系统上用Berkeley Packet Filter直接进行原始数据的收发相关推荐

  1. eBPF(extended Berkeley Packet Filter):Linux系统最具颠覆性的“白盒测试”

    eBPF--Linux系统地图上的"沙盒游戏" 简单介绍eBPF eBPF为什么叫eBPF eBPF家族和全局概览 成熟的eBPF使用场景 跟踪和采样 可视化和监控 网络 安全 e ...

  2. Powerlink总线协议在QNX系统上的移植

    一.硬件平台  通讯主站选用安装QNX系统的工控机,交叉编译工具选用QNX Momentics IDE,QNX Momentics IDE软件是基于WINDOWS系统下的QNX交叉开发环境,使用户可以 ...

  3. 搭建qnx开发环境,虚拟qnx系统+虚拟win7系统+QNX Momentics IDE 4.6

    1.准备说明 VMware Workstation (Pro) win7虚拟机(可参考win7虚拟机详细搭建过程) qnx虚拟机(QNXNeutrino650Target) QNX Momentics ...

  4. [转]QNX系统-基于高通骁龙SA8155平台,中科创达发布智能驾驶舱3.0解决方案

    如果你认为本系列文章对你有所帮助,请大家有钱的捧个钱场,点击此处赞助,赞助额0.1元起步,多少随意 声明:本文只用于个人学习交流,若不慎造成侵权,请及时联系我,立即予以改正 锋影 email:1741 ...

  5. 详细讲解 移植Uboot到ARMer9开发系统上

    首先了解ARMer9开发系统硬件设计上和三星原装SMDK2410之间的区别.让uboot在ARMer9开发系统上跑起来,目前只需要关注如下的硬件区别,解决了下面这个问题,uboot就可以在ARMer9 ...

  6. BPF(BSD Packet Filter)

    源地址: BPF(BSD Packet Filter)--应用和理念扩展 BPF是一个过滤机制,它用于过滤送往特定地点比如用户空间的数据包,它被设计成一种类似汇编语言的语言,可以称之为伪汇编码.虽然被 ...

  7. 百度黑莓宣布联手搞自动驾驶,QNX系统成Apollo平台基础

    李杉 编译整理 量子位 出品 | 公众号 QbitAI 就在昨天夜里,百度Apollo项目和黑莓展开了合作,黑莓的股价应声上涨了近13%. 百度和黑莓的合作领域在车联网和自动驾驶,据美国科技媒体Ven ...

  8. 【Tools系列】在Win7系统上利用Simics安装Solaris 8 SPARC操作系统

    DATE: 2020.12.25 文章目录 1 介绍 2 前期安装准备 2.1 下载Solaris 8 iso映像文件 2.2 下载并安装Simics 3.0.4软件 3 在Simics 上安装Sol ...

  9. 使用wine在mac系统上运行windows程序

    最近想用Clickteam Fusion Developer游戏引擎作作小游戏,这个引擎开发动作类2D游戏简单方便,只有一个问题,就是这个游戏引擎的开发环境只支持windows系统.而我只有一台苹果的 ...

  10. 【FFH】如何在鸿蒙系统上进行抓包测试

    [FFH]如何在鸿蒙系统上进行抓包测试 前言 什么是抓包? Charles工具介绍 Charles代理配置 Charles访问配置 鸿蒙端代理配置 抓取https数据 (一)安装SSL证书 (二)Ht ...

最新文章

  1. 汇编:ret以及retf指令
  2. java 用户名不为空_[Java教程]【关于JavaScript】常见表单用户名、密码不能为空
  3. 网站日志统计查询工具
  4. 机器学习 Machine Learning中向量化矩阵化的技巧
  5. Python量化资源大合集
  6. 惠普打印机突然停止工作
  7. wps页眉显示一级标题_WPS教程--排版和打印--页眉和页脚
  8. mysql 拼音查询_MySQL拼音首字母查询
  9. python 字典嵌套列表 循环打印_python的list的基本操作、list循环、切片、字典基本操作、字典嵌套、字符串常用方法...
  10. 名表依波路borel_依波路手表排名 依波路手表世界排名第几
  11. 《Pajek社会网络探索性分析》书籍简介
  12. 驱动开发:内核遍历进程VAD结构体
  13. 大淘客cms php版本,大淘客cms频繁出现 500错误页面临时解决方法
  14. 中国科学家或揭开生物第六感之谜
  15. 学生鲜花网页设计作品静态HTML网页模板源码 大学生鲜花商城网站制作 简单鲜花网站网页设计成品
  16. html 图片显示的几种方式
  17. MySQL子查询的优缺点_浅谈mysql的子查询
  18. 南京审计大学计算机考研专业课答案
  19. 麻省理工大学教授教你怎样做…
  20. java获取两个时间之间的所有日期、月份、年份,返回列表

热门文章

  1. 毕业设计的开题报告怎么写?
  2. ps5手柄连接android,PS5游戏手柄甚至可以兼容安卓设备?这一次有的玩了
  3. LU分解、LDLT分解和Cholesky分解
  4. idea 搭建flutter 安卓开发环境(因为有idea就不需安装Android Studio)
  5. 安卓游戏 我叫mt 3.5.4.0 3540,data.dat 文件解包记录
  6. matlab simulink教程pdf,Simulink基础入门教程“完整版”.pdf
  7. 【资源】机器学习 周志华
  8. PanDownload:登录百度账号提示浏览器版本太低,点击下载webkit内核,然后重启软件即可
  9. 在密码输入框内按回车就登陆的功能
  10. 运放放大倍数计算公式_运放电路设计【1】