分享

基于OpenWRT开发

 deckie 2017-05-19

基于OpenWRT开发(一)

OpenWRT的SDK环境的搭建

可以直接从官网上下载OpenWRT的SDK包直接使用,但是最新版本的包只支持64位的系统,如果电脑是32位的话,有两种解决方法:

1、直接从网站上下载以前的版本;

2、下载OpenWRT的源代码在自己的电脑上编译生成适用的SDK.

这里讲解一下第二种方法。

使用OpenWRT编译生成SDK

为所用的操作系统为ubuntu 12.04TLS,编译过程中会占用大量的磁盘空间,所有请保证有足够的空余空间,大约需要10G。

使用Git下载OpenWRT的源代码:

git clone git://git.openwrt.org/openwrt.git

安装编译需要的组建:

sudo apt-get install gcc 
sudo apt-get install g++ 
sudo apt-get install binutils 
sudo apt-get install patch 
sudo apt-get install bzip2 
sudo apt-get install flex 
sudo apt-get install bison 
sudo apt-get install make 
sudo apt-get install autoconf 
sudo apt-get install gettext 
sudo apt-get install texinfo 
sudo apt-get install unzip 
sudo apt-get install sharutils 
sudo apt-get install subversion 
sudo apt-get install libncurses5-dev 
sudo apt-get install ncurses-term 
sudo apt-get install zlib1g-dev 
sudo apt-get install gawk
sudo apt-get install asciidoc
sudo apt-get install libz-dev

进入到OpenWRT源代码所在的文件夹,之后执行如下操作:

make menuconfig
make V=s

选择Build the OpenWrt SDK

之后就是漫长的等待,预计编译时间为4到5个小时。

基于OpenWRT开发(二)

安装libpcap库

http://www./下载libpcap(tcpdump的源码也可以从这个网站下载)
解压
./configure
make
sudo make install

获取网络接口

首先要使用libpcap,我们必须包含pcap.h头文件,,可以在/usr/local/include/pcap/pcap.h找到,其中包含了每个类型定义的详细说明。
首先我们需要获取监听的网络接口:
我们可以手动指定或让libpcap自动选择,先介绍如何让libpcap自动选择:
char * pcap_lookupdev(char * errbuf)
上面这个函数返回第一个合适的网络接口的字符串指针,如果出错,则返回NULL,errbuf存放出错信息字符串,errbuf至少应该是PCAP_ERRBUF_SIZE个字节长度的。

也可以找到所有的网络接口:
int pcap_findalldevs((pcap_if_t )&alldevs, char errBuf)
上面这个函数将会把所有的网络接口都存在alldevs中,errBuf的使用和pcap_lookupdev()相同。
对于这个函数,如果错误则返回-1 。

释放网络接口

在操作为网络接口后,我们应该要释放它:
void pcap_close(pcap_t * p)
该函数用于关闭pcap_open_live()获取的pcap_t的网络接口对象并释放相关资源。

如果使用了pcap_findalldevs(),那么对于每一个设备在使用完之后都需要调用一次pcap_close();
在所有的接口都遍历结束之后,需要调用pcap_freealldevs(alldevs),来清空存储设备接口的列表。

打开网络接口

获取网络接口后,我们需要打开它:
pcap_t * pcap_open_live(const char * device, int snaplen, int promisc, int to_ms, char * errbuf)
上面这个函数会返回指定接口的pcap_t类型指针,后面的所有操作都要使用这个指针。
第一个参数是第一步获取的网络接口字符串,可以直接使用硬编码。
第二个参数是对于每个数据包,从开头要抓多少个字节,我们可以设置这个值来只抓每个数据包的头部,而不关心具体的内容。典型的以太网帧长度是1518字节,但其他的某些协议的数据包会更长一点,但任何一个协议的一个数据包长度都必然小于65535个字节。
第三个参数指定是否打开混杂模式(Promiscuous Mode),0表示非混杂模式,任何其他值表示混合模式。如果要打开混杂模式,那么网卡必须也要打开混杂模式,可以使用如下的命令打开eth0混杂模式:
ifconfig eth0 promisc
第四个参数指定需要等待的毫秒数,超过这个数值后,第3步获取数据包的这几个函数就会立即返回。0表示一直等待直到有数据包到来。
第五个参数是存放出错信息的数组。

获取数据包

打开网络接口后就已经开始监听了,那如何知道收到了数据包呢?有下面3种方法:
1、u_char * pcap_next(pcap_t * p, struct pcap_pkthdr * h)
如果返回值为NULL,表示没有抓到包
第一个参数是第2步返回的pcap_t类型的指针
第二个参数是保存收到的第一个数据包的pcap_pkthdr类型的指针
pcap_pkthdr类型的定义如下:
struct pcap_pkthdr
{
struct timeval ts; /* time stamp */
bpf_u_int32 caplen; /* length of portion present */
bpf_u_int32 len; /* length this packet (off wire) */
};

2、int pcap_loop(pcap_t * p, int cnt, pcap_handler callback, u_char * user)
第一个参数是第2步返回的pcap_t类型的指针
第二个参数是需要抓的数据包的个数,一旦抓到了cnt个数据包,pcap_loop立即返回。负数的cnt表示pcap_loop永远循环抓包,直到出现错误。
第三个参数是一个回调函数指针,它必须是如下的形式:
void callback(u_char * userarg, const struct pcap_pkthdr * pkthdr, const u_char * packet)
第一个参数是pcap_loop的最后一个参数,当收到足够数量的包后pcap_loop会调用callback回调函数,同时将pcap_loop()的user参数传递给它
第二个参数是收到的数据包的pcap_pkthdr类型的指针
第三个参数是收到的数据包数据

3、int pcap_dispatch(pcap_t * p, int cnt, pcap_handler callback, u_char * user)
这个函数和pcap_loop()非常类似,只是在超过to_ms毫秒后就会返回(to_ms是pcap_open_live()的第4个参数)

分析数据包

抓取到的数据包将会在回调函数中进行处理。


基于OpenWRT开发(三)

ieee80211_radiotap的头文件

TSFT

位置编码:0
字段长度:8 byte
只对接收帧有效,表示MPDU第一个bit到达MAC时,时间同步计时器的计数,单位是微秒;

Flags

位置编码:
字段长度:1 byte
发送或接收到的帧的属性;

Rate

位置编码:2
字段长度:1 byte
传输或接受数据的速率;

Channel

位置编码:3
字段长度:2 byte
发送接收信号的频率,单位是MHz,其Data中可能同时包含如下内容:

FHSS

位置编码:4
字段长度:1 byte
跳频技术,是无线通讯最常用的扩频方式之一;

Antenna signal

位置编码:5
字段长度:1 byte
天线的射频信号强度,单位是dBm;

Antenna noise

位置编码:6
字段长度:1 byte
天线的射频噪声强度,单位是dBm;

Lock quality

位置编码:7
字段长度:2 byte
信号质量(对这个字段了解不多);

TX attenuation

位置编码:8
字段长度:2 byte
与出厂标准最大功率相比的功率衰减,0为最大功率;

dB TX attenuation

位置编码:9
字段长度:2 byte
与出厂标准最大功率相比的功率衰减dB值,0为最大功率;

dBm TX power

位置编码:10
字段长度:1 byte
传输功率的dBm值,这是在天线端口测量的功率绝对值;

Antenna

位置编码:11
字段长度:1 byte
发送或接收该帧的天线索引编号(硬件编号从0开始);

dB antenna signal

位置编码:12
字段长度:1 byte
天线的射频信号的相对功率强度dB值;

dB antenna noise

位置编码:13
字段长度:1 byte
天线的射频噪音的相对功率强度dB值;

RX flags

位置编码:14
字段长度:2 byte
代表接收帧,目前只有以下3种定义:

MCS

位置编码:19
字段长度:1 byte
调制和编码方案索引值,不同的索引值代表不同数据速率,以及其对应的一系列技术参数指标。例如802.11g在使用1个天线、20MHz信道宽度的时候数据速率只能达到54Mbps;而802.11n在使用4个天线、40MHz信道、400ns担保间隔的情况下可以达到600Mbps数据速率。这两种速率分别对应不同的MCS索引值,下表是部分MCS索引值与数据速率的对应表;

A-MPDU status

位置编码:20
字段长度:4 byte
掩码值为1表示该帧是A-MPDU的一个子帧。多信道并行抓包时子帧索引可能重复,所以应用程序需要结合信道值判断子帧属于哪个A-MPDU。
802.11n支持子帧独立传输和重组巨帧使用,标准提供了两种帧聚合方式A-MPDU(Aggregated Mac Protocol Data Unit)和A-MSDU(Aggregated Mac Service Data Unit)。
A-MPDU在硬件层将巨帧分割成子帧进行传输,接收端将所有子帧发给应用层,由应用层重组巨帧,这种方法支持最大64KByte的巨帧,是802.11n标准的强制要求项;
A-MSDU在软件层将巨帧分割成子帧进行传输,它支持最大7935Byte的巨帧,接收端将重组后的巨帧作为一个整体发给应用层,它是802.11n标准的可选项,支持它的设备不是很多;

80211链路层帧的格式

80211的帧总共分为三个大类,分别是数据帧、管理帧和控制帧;

本文将详细讲解数据帧和管理帧,控制帧只做简单介绍。

数据帧

重点分析数据帧的帧头部分,因为大部分的数据帧都是加密的,数据帧中的内容无法解读。

数据帧头文件的格式如下:

struct ieee80211_data_hdr {  
    u16 frame_ctl;  
    u16 duration_id;  
    u8 addr1[ETH_ADD_LEN];  
    u8 addr2[ETH_ADD_LEN];  
    u8 addr3[ETH_ADD_LEN];  
    u16 seq_ctl;  
    u8 addr4[ETH_ADD_LEN];  
} __attribute__((packed));   

帧控制(2 bytes):

用于指示数据帧的类型,是否分片等等信息,说白了,这个字段就是记录了mac 802.11的属性。

Protocol version:

表明版本类型,现在所有帧里面这个字段都是0x00

Type:

指明数据帧类型,是管理帧,数据帧还是控制帧

Subtype:

指明数据帧的子类型,因为就算是控制帧,控制帧还分RTS帧,CTS帧,ACK帧等等,通过这个域判断出该数据帧的具体类型

To DS/From DS:

这两个数据帧表明数据包的发送方向,分四种可能情况讨论

若数据包To DS为0,From DS为0,表明该数据包在网络主机间传输
若数据包To DS为0,From DS为1,表明该数据帧来自AP
若数据包To DS为1,From DS为0,表明该数据帧发送往AP
若数据包To DS为1,From DS为1,表明该数据帧是从AP发送自AP的,也就是说这个是个WDS(Wireless Distribution System)数据帧,至于什么是WDS,可以参考下这里的介绍 #传送门
Moreflag:

分片标志,若数据帧被分片了,那么这个标志为1,否则为0

Retry:

表明是否是重发的帧,若是为1,不是为0

PowerManage:

当网络主机处于省电模式时,该标志为1,否则为0.

Moredata:

当AP缓存了处于省电模式下的网络主机的数据包时,AP给该省电模式下的网络主机的数据帧中该位为1,否则为0

Wep:

加密标志,若为1表示数据内容加密,否则为0

Order:

这个表示用于PCF模式下,这里不予讨论

MAC地址 1-4

这四个地址在不同帧中有不同含义。这些以后会讨论。

以后我们可能会碰到以下类型的mac地址

RA(receiver address):无线网络中,该数据帧的接收者

TA(transmitter address):无线网络中,该数据帧的发送者

BSSID(Basic Service Set ID):在infrastructure BBS中,BSSID就是AP的mac地址。但是在IBBS中,它是一个随机即生成的46位二进制序列,还有最高两位分别是Universal/Local标志位和Individual/Group标志位。IBBS的BSSID中,Universal/Local标志位为1,表示本地MAC,Individual/Group标志位为0,表示是个人MAC。也就是说在IBBS中,BSSID地址应该类如 10xxxxxx-xxxxxxxx-xxxxxxxx-xxxxxxxx-xxxxxxxx-xxxxxxxx(x表示随机数要么0要么1, 2进制表示)

DA(destine address):该帧的目的mac地址

SA(source address):该帧的源mac地址

这里的DA和SA含义和普通以太网中的含义一样,在无线网络中可能我们需要通过AP把数据发送到其它网络内的某台主机中。但是有的人会奇怪,直接在RA中填这台主机的mac地址不就久好了么。但是请注意RA的含义,说的是无线网络中的接收者,不是网络中的接收者,也就是说这台目的主机不再无线网络范围内。在这种情况下我们的RA只是一个中转,所以需要多出一个DA字段来指明该帧的最终目的地,当然,如果有了DA那必须有SA,因为若目的主机要回应的话,SA字段是必不可少的。(假设没有SA字段,那么目的主机回应的数据包就只能发送到源主机所属的AP上了~)

管理帧

管理帧头文件的格式如下:

struct ieee80211_mgt_hdr {
    u16 frame_ctl;  
    u16 duration_id;  
    u8 addr1[ETH_ADD_LEN];  
    u8 addr2[ETH_ADD_LEN];  
    u8 addr3[ETH_ADD_LEN];  
    u16 seq_ctl;  
} __attribute__((packed));

管理帧只有3个地址!

在头文件之后就是管理帧的内容了,管理帧的长度是可变的。

管理帧帧内容的格式如下:

struct ieee80211_info_element {
    u8 id;  
    u8 len;  
    u8 data[0];  
} __attribute__ ((packed));

每个管理帧中都包含了若干个上述结构,每一个结构所存储的内容根据它的id值来确定,不同的id值代表了不同的内容。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多