airkiss 用于智能配网,基于 802.11 协议,本文记录相关知识点
概述
airkiss 首先需要网卡有监听空中无线包的能力,包括 监听 和 混杂 两种模式,并以 802.11 格式从数据链路层截取数据(要求的是不带 radiotap header 的 802.11 数据帧)
radiotap header
radiotap 包含了信号强度、噪声强度、信道、时间戳等信息。 radiotap 比传统的 Prism 或 AVS 头更有灵活性,成为 ieee802.11 事实上的标准。在 WLAN 无线网络抓包的时候不管是用 wireshark、 tcpdump 还是 scapy 都会出现 Radiotap、 LLC、 SNAP 协议层。典型数据帧如下
Frame 6662: 103 bytes on wire (824 bits), 103 bytes captured (824 bits) on interface 0
Radiotap Header v0, Length 21
Header revision: 0
Header pad: 0
Header length: 21
Present flags
Flags: 0x00
Channel frequency: 2422 [BG 3]
Channel flags: 0x0480, 2 GHz spectrum, Dynamic CCK-OFDM
Antenna signal: -49dBm
Antenna: 1
RX flags: 0x0000
MCS information
[Data Rate: 65.0 Mb/s]
802.11 radio information
IEEE 802.11 QoS Data, Flags: .p.....T
Data (48 bytes)协议
每一次接收到的 802.11 帧中只需要解析出 length, airkiss 就是围绕 length 进行编码的协议, length 为 802.11 数据帧长度,
配合开源工程 Airkiss 分析协议过程如下
Cap len为读取携带radiotap header的原始数据长度,十进制length为计算之后802.11数据长度,且过滤不符合的数据帧,十六进制
length 为计算之后 802.11 数据长度,且过滤不符合的数据帧,十六进制
discover- 发现过程
协议规定发送前导码 {1, 2, 3, 4},这个值是差异值,在 wireshark 抓包如下
314 0.000342132 HuaweiTe_0e:74:56 Broadcast 802.11 100 795 QoS Data, SN=795, FN=0, Flags=.p.....T
318 0.000077578 HuaweiTe_0e:74:56 Broadcast 802.11 101 796 QoS Data, SN=796, FN=0, Flags=.p.....T
322 0.000007695 HuaweiTe_0e:74:56 Broadcast 802.11 102 797 QoS Data, SN=797, FN=0, Flags=.p.....T
326 0.000035866 HuaweiTe_0e:74:56 Broadcast 802.11 103 798 QoS Data, SN=798, FN=0, Flags=.p.....T其中 radiotap header 长度为 21,代码判断如下
// 1 2 3 4
if((_akcontext.data.guide_code.length_record[1] - _akcontext.data.guide_code.length_record[0] == 1) &&
(_akcontext.data.guide_code.length_record[2] - _akcontext.data.guide_code.length_record[1] == 1) &&
(_akcontext.data.guide_code.length_record[3] - _akcontext.data.guide_code.length_record[2] == 1))
{
_akcontext.base_len = _akcontext.data.guide_code.length_record[0] - 1;
success = 1;
}
if(success)
{
_akcontext.airkiss_state = AIRKISS_STATE_SRC_LOCKED;
resest_airkiss_data();
akconf->printf("airkiss_recv_discover success\n");
akconf->printf("base len:%d\n", _akcontext.base_len);
}
调试打印
Cap len:100
length:4f --> 0x1
Cap len:46
length:1c
Cap len:34
length:10
Cap len:28
length:a
Cap len:101
length:50 --> 0x2
Cap len:46
length:1c
Cap len:44
length:1a
Cap len:28
length:a
Cap len:34
length:10
Cap len:28
length:a
Cap len:102
length:51 -> 0x3
Cap len:46
length:1c
Cap len:28
length:a
Cap len:34
length:10
Cap len:28
length:a
Cap len:103
length:52 --> 0x4
airkiss_recv_discover success
base len:78
Lock channel in 3magic code 字段
magic code 由 4 个 9bits 组成,格式如下
第 1 个 9bits 0x0 length(high)
第 2 个 9bits 0x1 length(low)
第 3 个 9bits 0x2 ssid crc(high)
第 4 个 9bits 0x3 ssid crc(low)length 为要发送数据的长度, ssid crc 为要发送 ssid 的 crc8 值
代码如下
if(((_akcontext.data.magic_code.record[0]&0x01f0)==0x0000)&&
((_akcontext.data.magic_code.record[1]&0x01f0)==0x0010)&&
((_akcontext.data.magic_code.record[2]&0x01f0)==0x0020)&&
((_akcontext.data.magic_code.record[3]&0x01f0)==0x0030))
{
_akcontext.total_len = ((_akcontext.data.magic_code.record[0] & 0x000F) << 4) + (_akcontext.data.magic_code.record[1] & 0x000F);
_akcontext.ssid_crc = ((_akcontext.data.magic_code.record[2] & 0x000F) << 4) + (_akcontext.data.magic_code.record[3] & 0x000F);
//TODO:double check magic code
_akcontext.airkiss_state = AIRKISS_STATE_MAGIC_CODE_COMPLETE;
resest_airkiss_data();
akconf->printf("airkiss_process_magic_code success\n");
akconf->printf("total_len:%d, ssid crc:%x\n", _akcontext.total_len, _akcontext.ssid_crc);
}
调试打印信息
Cap len:100
length:4f --> 0x1
Cap len:46
Cap len:34
Cap len:34
Cap len:34
Cap len:28
Cap len:124
length:67 --> 0x19
Cap len:46
Cap len:119
Cap len:131
length:6e --> 0x20
Cap len:46
Cap len:162
length:8d --> 0x3f
airkiss_process_magic_code success
total_len:25, ssid crc:fprefix code
prefix code 由 4 个 9bits 组成,格式如下
第 1 个 9bits 0x4 psw length(high)
第 2 个 9bits 0x5 psw length(low)
第 3 个 9bits 0x6 psw len crc(high)
第 4 个 9bits 0x7 psw len crc(low)psw length 为要发送 psw 的长度, psw len crc 为 psw len 的 crc8 值
代码如下:
if((_akcontext.data.prefix_code.record[0]&0x01f0)==0x0040&&
(_akcontext.data.prefix_code.record[1]&0x01f0)==0x0050&&
(_akcontext.data.prefix_code.record[2]&0x01f0)==0x0060&&
(_akcontext.data.prefix_code.record[3]&0x01f0)==0x0070)
{
_akcontext.pswd_len = ((_akcontext.data.prefix_code.record[0] & 0x000F) << 4) + (_akcontext.data.prefix_code.record[1] & 0x000F);
if(_akcontext.pswd_len > PASSWORD_MAX_LEN)
_akcontext.pswd_len = 0;
_akcontext.pswd_lencrc = ((_akcontext.data.prefix_code.record[2] & 0x000F) << 4) + (_akcontext.data.prefix_code.record[3] & 0x000F);
if(calcrc_1byte(_akcontext.pswd_len)==_akcontext.pswd_lencrc)
{
_akcontext.airkiss_state = AIRKISS_STATE_PREFIX_CODE_COMPLETE;
}
else
{
akconf->printf("password length crc error.\n");
resest_airkiss_data();
return;
}
// only receive password and random
_akcontext.need_seq = ((_akcontext.pswd_len + 1) + 3)/4;
_akcontext.seq_success_map_cmp = (1 << _akcontext.need_seq) - 1;
resest_airkiss_data();
akconf->printf("airkiss_process_prefix_code success\n");
akconf->printf("pswd_len:%d, pswd_lencrc:%x, need seq:%d, seq map:%x\n",
_akcontext.pswd_len, _akcontext.pswd_lencrc, _akcontext.need_seq, _akcontext.seq_success_map_cmp);
}
调试信息
Cap len:163
length:8e --> ox40
Cap len:46
Cap len:158
Cap len:34
Cap len:28
Cap len:190
length:a9 --> 0x5b
Cap len:46
Cap len:185
Cap len:34
Cap len:34
Cap len:34
Cap len:28
Cap len:197
length:b0 --> 0x62
Cap len:46
Cap len:192
Cap len:34
Cap len:28
Cap len:211
length:be --> 0x70
airkiss_process_prefix_code success
pswd_len:11, pswd_lencrc:20, need seq:3, seq map:7sequence header & data
将要发送的数据按照 4 字节为单位进行划分,每 4 个数据加上 sequence header 组成一个 sequence,以 sequence 为单位进行数据发送,如果最后一个 sequence 不够 4 字节,不用补全,格式如下
sequence header 格式如下
第 1 个 9bits 0 1 sequence crc8(低 7 位)
第 2 个 9bits 0 1 sequence indexdata 格式如下
第 1 个 9bits 1 data(第 7-0bit)
第 2 个 9bits 1 data(第 7-0bit)
第 3 个 9bits 1 data(第 7-0bit)
第 4 个 9bits 1 data(第 7-0bit)代码实现如下
if(((_akcontext.data.seq_code.record[0]&0x180)==0x80) &&
((_akcontext.data.seq_code.record[1]&0x180)==0x80) &&
((_akcontext.data.seq_code.record[2]&0x0100)==0x0100) &&
((_akcontext.data.seq_code.record[3]&0x0100)==0x0100) &&
((_akcontext.data.seq_code.record[4]&0x0100)==0x0100) &&
((_akcontext.data.seq_code.record[5]&0x0100)==0x0100) &&
((_akcontext.data.seq_code.record[1]&0x7F) <= ((_akcontext.total_len>>2)+1)))
{
unsigned char tempBuffer[6] = {0};
tempBuffer[0]=_akcontext.data.seq_code.record[0]&0x7F; //seq crc
tempBuffer[1]=_akcontext.data.seq_code.record[1]&0x7F; //seq index
tempBuffer[2]=_akcontext.data.seq_code.record[2]&0xFF; //data, same as following
tempBuffer[3]=_akcontext.data.seq_code.record[3]&0xFF;
tempBuffer[4]=_akcontext.data.seq_code.record[4]&0xFF;
tempBuffer[5]=_akcontext.data.seq_code.record[5]&0xFF;
if(tempBuffer[0] == (calcrc_bytes(tempBuffer+1,5)&0x7F) )
...
}
}
调试信息
Cap len:408
Cap len:338
length:13d --> 0xef
Cap len:46
Cap len:34
Cap len:28
Cap len:229
length:d0 --> 0x82
Cap len:46
Cap len:42
Cap len:28
Cap len:42
Cap len:28
Cap len:34
Cap len:34
Cap len:28
Cap len:412
length:187 -> 0x139
Cap len:46
Cap len:34
Cap len:28
Cap len:408
length:183 -> 0x135
Cap len:46
Cap len:34
Cap len:28
Cap len:412
length:187 -> 0x139
Cap len:46
Cap len:28
Cap len:34
Cap len:34
Cap len:34
Cap len:34
Cap len:34
Cap len:34
Cap len:34
Cap len:34
Cap len:28
Cap len:416
length:18b -> 0x13d
[crc:6f][index:2]:39,35,39,3d; seq mapped:4sequence header 数据为 0x13d-78 0xd0-78 –> 0xef 0x82
802.11/802.2
IEEE 802.11定义了媒体访问控制层(MAC 层)和物理层。物理层IEEE 802.2是对数据链路层上层逻辑链路控制 (LLC) 连接的建立和管理的规范
几个概念:
PHY物理层的芯片我们简称之为 PHY,物理层Physical Layer- 数据链路层
Data Link Layer是OSI模型的第二层,负责建立和管理节点间的链路。该层通常又被分为介质访问控制MAC和逻辑链路控制LLC两个子层MAC数据链路层的芯片一般简称之为 MAC 控制器LLC子层的主要任务是建立和维护网络连接,执行差错校验、流量控制和链路控制
** WIFI MAC 和 PHY 层及协议在 OSI 位置**

Airkiss 需要关心的 length 从 802.2 SNAP LLC 解析,数据格式
802.11 帧结构如下, airkiss 对 Address1/Address2/Address3 字段进行了过滤
协议细节理解
前导码及发现过程
利用
802.2 SNAP数据包中的Length字段进行通信。在实际应用中采用UDP广播包作为信息的载体。每一包的数据都是按照Airkiss通信协议进行编码。一个UDP包发送要经过IP层、数据链路层的封装,并且通过加密 (WPA2、WPA、WEP) 后才被发送出去,所以发送方发送UDP长度与接收方监听SNAP包长度存在差异,而且由于底层加密方式的差异,使得这个差异值也具有不确定性
因此需要监听信道计算差异值,这个差异值就是底层封装对 Length 的差异,后续传输的所有 Length 需要减去差异值
误识别
如果发送数据中包括递增值,例如 1234、 4567 或 abcd 会导致前导码识别错误,正式库中有处理?
应用数据组成
password + random + ssid
password和ssid可以发送经过AES加密后的数据,AES Key私下协商,Airkiss协议无规定?random为airkiss server生成的随机数,在连接成功之后airkiss client将这个值发送回来以完成配网
端口的选择
airkiss server可以是eth或wlanairkiss client可以是eth或wlan- 可以使用
setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, (void *)&ifr, sizeof(ifr)))限制使用具体interface