基于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值代表了不同的内容。
|