[無線LAN信号分析]
[構成]
Raspberry Pi2 | |
USB電源 | KSY UB310-0520 |
ケース | |
USB無線LAN | WLI-UC-G301N |
USBハブ | U2H-TZ420SBK |
USB HDD | HDJ-UT2.0B |
[機能概要]
- 2.4GHz帯をとびかう無線LAN信号をキャプチャして、チャネルごとの無線の使用状況を分析する。
- 無線LAN信号は、隣家の電波もお互い届いてしまいますが、1つのチャネルでは同時に1つのパケットしか送れないので、隣家と同じチャネルを使用していると、チャネルの通信権を取り合いながら通信する状況になります。無線LANのチャネルを何番にすべきか、無線LANの使用状況を確認するのに使います。
[tsharkのインストール]
[Luaスクリプト]
- Wiresharkでは、あまり聞きなれないLuaという言語でスクリプトを実行することができます。詳細はWiresharkのHPhttps://www.wireshark.org/
- Wiresharkがキャプチャしたパケットデータは、Fieldというパラメータから取得することができます。無線LAN信号強度は、「radiotap.dbm_antsignal」というfieldです。
- Luaスクリプト上でfieldデータを取得するには、まずField.newで対象のfieldを抽出する関数を生成しておきます。次に、パケット処理関数の内部で、対象のfieldを抽出します。以下のスクリプトではtap.packet(pinfo,tvb)のなかで抽出しています。tap.packet()は、パケットキャプチャするたびに呼び出される関数です。
- 抽出したデータは、FieldInfoというオブジェクトになりますが、対象のfieldが数値であったとしても、一旦tostringで文字列にしてから、tonumberで数値に戻さないとエラーになります。なぜかはよくわかりません。
- FCS(Frame Check Sequence)を確認し、Bad FCSの場合はキャプチャデータがデータ化けしているので捨てます。
- パケットの送受信アドレス情報には、「wlan.sa」「wlan.ta」「wlan.ra」「wlan.da」がありますが、「wlan.ta」「wlan.ra」がキャプチャした無線LANパケットの送信元(Transmitter)と受信先(Receiver)で、「wlan.sa」「wlan.da」はキャプチャした無線LANパケット以外を含めた、パケットの送信元(Source)、受信先(Destination)っぽいです。また、何れのfieldも必須情報ではなく、「wlan.ra」しか設定されないパケットもあります。
- 各端末が使用しているアクセスポイントは、アクセスポイントから送信されるパケットのうち、制御フレームとデータフレーム(wlan.fc.type_subtypeが0x10以上)の、受信先アドレス「wlan.ra」から判断しています。このとき、マルチキャストMACアドレスを除外する必要があります。
- 抽出した情報を、終了時に出力しますが、終了時に実行されるのがtap.draw()です。
print("WiFi RSSI Analyzer")
local macaddress_ssid = {}
local macaddress_resolved = {}
local rssi_ap = {}
local rssi_other = {}
local ssid_other = {}
local field_radiotap_dbm_antsignal = Field.new("radiotap.dbm_antsignal")
local field_radiotap_channel_freq = Field.new("radiotap.channel.freq")
local field_radiotap_flags_badfcs = Field.new("radiotap.flags.badfcs")
local field_wlan_mgt_ssid = Field.new("wlan_mgt.ssid")
local field_wlan_fc_type_subtype = Field.new("wlan.fc.type_subtype")
local field_wlan_sa = Field.new("wlan.sa") -- Source Address
local field_wlan_ta = Field.new("wlan.ta") -- Transmitter Address (can be WiFi Access Point)
local field_wlan_ta_resolved = Field.new("wlan.ta_resolved") -- Transmitter Address (can be WiFi Access Point)
local field_wlan_ra = Field.new("wlan.ra") -- Receiver Address (can be WiFi Access Point)
local field_wlan_da = Field.new("wlan.da") -- Destination Address
local tap = Listener.new()
local count = 0
local subcount = 0
local maccount = 0
local ssidcount = 0
local ch_freq = 0
function tap.packet(pinfo,tvb) -- Run for each captured packet.
-- Get Field values --
local radiotap_dbm_antsignal = field_radiotap_dbm_antsignal()
local wlan_mgt_ssid = field_wlan_mgt_ssid()
local wlan_fc_type_subtype = field_wlan_fc_type_subtype()
local wlan_sa = field_wlan_sa()
local wlan_ta = field_wlan_ta()
local wlan_ta_resolved = field_wlan_ta_resolved()
local wlan_ra = field_wlan_ra()
local wlan_da = field_wlan_da()
local radiotap_channel_freq = field_radiotap_channel_freq()
if tostring(radiotap_channel_freq)~=nil then
ch_freq = tonumber(tostring(radiotap_channel_freq))
end
if tostring(radiotap_flags_badfcs)~=nil then
if tostring(radiotap_flags_badfcs)~="0" then
print("Bad FCS.")
return
end
end
if tonumber(tostring(wlan_fc_type_subtype))~=nil and tostring(radiotap_dbm_antsignal)~=nil then
--[[
print("******START******")
print(tostring(radiotap_dbm_antsignal))
print(tostring(wlan_mgt_ssid))
print(tostring(wlan_fc_type_subtype))
print("wlan_sa " .. tostring(wlan_sa))
print("wlan_ta " .. tostring(wlan_ta))
print("wlan_ta_resolved " .. tostring(wlan_ta_resolved))
print("wlan_ra " .. tostring(wlan_ra))
print("wlan_da " .. tostring(wlan_da))
print("*******END*******")
]]
if tostring(wlan_fc_type_subtype)=="8" or tostring(wlan_fc_type_subtype)=="5" then
-- Signal Strength vs Access Point --
if wlan_ta~=nil then
rssi_ap[tostring(wlan_ta)]=tostring(radiotap_dbm_antsignal)
if wlan_mgt_ssid~=nil then
macaddress_ssid[tostring(wlan_ta)]=tostring(wlan_mgt_ssid)
else
macaddress_ssid[tostring(wlan_ta)]=tostring(wlan_ta)
end
if wlan_ta_resolved~=nil then
macaddress_resolved[tostring(wlan_ta)]=tostring(wlan_ta_resolved)
end
end
else
-- Connected Access Point vs Terminal MAC address --
if tonumber(tostring(wlan_fc_type_subtype))>16 then -- Access after Association
local igbit = tonumber(string.sub(tostring(wlan_ra),2,2))
if macaddress_ssid[tostring(wlan_ta)] and tostring(wlan_ra)~=nil and igbit~=nil then
if igbit%2 == 0 and rssi_other[tostring(wlan_ra)]~=nil then -- Not Multicast MAC Address
ssid_other[tostring(wlan_ra)]=macaddress_ssid[tostring(wlan_ta)]
end
end
end
-- Signal Strength vs Terminal MAC address --
if wlan_ta~=nil then
rssi_other[tostring(wlan_ta)]=tostring(radiotap_dbm_antsignal)
if wlan_ta_resolved~=nil then
macaddress_resolved[tostring(wlan_ta)]=tostring(wlan_ta_resolved)
end
end
end
end
count=count+1
subcount=subcount+1
if subcount>=100 then
maccount = 0;
ssidcount = 0;
for macadrs,rssi in pairs(rssi_other) do
maccount = maccount + 1
end
for macadrs,ssid in pairs(ssid_other) do
ssidcount = ssidcount + 1
end
print(tostring(count) .. " packets.\t" .. tostring(maccount) .. " Terminals. (" .. tostring(ssidcount) .. " AP info)")
subcount=0
end
end
function tap.draw(t)
for macadrs,rssi in pairs(rssi_ap) do
if macaddress_ssid[macadrs] and macaddress_resolved[macadrs] then
print(tostring(ch_freq) .. ",AP," .. macadrs .. "," .. rssi .. "," .. macaddress_resolved[macadrs] .. "," .. macaddress_ssid[macadrs])
elseif macaddress_resolved[macadrs] then
print(tostring(ch_freq) .. ",AP," .. macadrs .. "," .. rssi .. "," .. macaddress_resolved[macadrs])
elseif macaddress_ssid[macadrs] then
print(tostring(ch_freq) .. ",AP," .. macadrs .. "," .. rssi .. "," .. macadrs .. "," .. macaddress_ssid[macadrs])
else
print(tostring(ch_freq) .. ",AP," .. macadrs .. "," .. rssi .. "," .. macadrs)
end
end
for macadrs,rssi in pairs(rssi_other) do
if macaddress_ssid[macadrs]==nil then
if macaddress_resolved[macadrs] and ssid_other[macadrs] then
print(tostring(ch_freq) .. ",Terminal," .. macadrs .. "," .. rssi .. "," .. macaddress_resolved[macadrs] .. "," .. ssid_other[macadrs] )
elseif macaddress_resolved[macadrs] then
print(tostring(ch_freq) .. ",Terminal," .. macadrs .. "," .. rssi .. "," .. macaddress_resolved[macadrs] )
elseif ssid_other[macadrs] then
print(tostring(ch_freq) .. ",Terminal," .. macadrs .. "," .. rssi .. "," .. macadrs .. "," .. ssid_other[macadrs] )
end
end
end
end
[実行結果]
- channelはスクリプトで切り替えられないので、iwconfigで切り替えて、以下のようにスクリプトを実行します。この場合、スクリプトはhello.luaというファイル名で実行ディレクトリに置いておきます。-I optionで無線LANアダプタをモニタモードにします。-Y optionはデフォルトのtsharkの出力をさせないためのフィルタです。
- キャプチャ中は、パケット数、検出した無線LAN端末数、そのうち使用しているアクセスポイントが判明した数、を100パケットごとに表示します。Ctrl+Cで停止させると、各アクセスポイント、無線LAN端末からの信号の、受信信号強度のリストを出力します。
pi@raspberrypi ~/wlan $ sudo iwconfig wlan0 channel 1
pi@raspberrypi ~/wlan $ sudo tshark -i wlan0 -I -X lua_script:hello.lua -Y "wlan.sa==00:00:00:00:00:00"
tshark: Lua: Error during loading:
[string "/usr/share/wireshark/init.lua"]:46: dofile has been disabled due to running Wireshark as superuser. See http://wiki.wireshark.org/CaptureSetup/CapturePrivileges for help in running Wireshark as an unprivileged user.
WiFi RSSI Analyzer
Running as user "root" and group "root". This could be dangerous.
Capturing on 'wlan0'
100 packets. 6 Terminals. (2 AP info)
200 packets. 7 Terminals. (3 AP info)
300 packets. 7 Terminals. (3 AP info)
400 packets. 7 Terminals. (3 AP info)
500 packets. 7 Terminals. (3 AP info)
600 packets. 7 Terminals. (3 AP info)
700 packets. 7 Terminals. (3 AP info)
800 packets. 7 Terminals. (3 AP info)
900 packets. 8 Terminals. (3 AP info)
1000 packets. 8 Terminals. (3 AP info)
1100 packets. 8 Terminals. (3 AP info)
1200 packets. 9 Terminals. (3 AP info)
^C60 packets dropped
0 packets captured
2417,AP,e0:9d:b8:xx:xx:xx,-28,PlanexCo_xx:xx:xx,SSID-name
2417,Terminal,00:1b:c7:xx:xx:xx,-60,Starvedi_xx:xx:xx
2417,Terminal,24:fd:52:xx:xx:xx,-52,LiteonTe_xx:xx:xx,SSID-name
2417,Terminal,14:7d:c5:xx:xx:xx,-52,MurataMa_xx:xx:xx
2417,Terminal,70:18:8b:xx:xx:xx,-68,HonHaiPr_xx:xx:xx,SSID-name
2417,Terminal,c8:ff:28:xx:xx:xx,-30,c8:ff:28:xx:xx:xx,SSID-name
2417,Terminal,00:1b:c7:xx:xx:xx,-74,Starvedi_xx:xx:xx
2417,Terminal,32:c5:42:xx:xx:xx,-64,32:c5:42:xx:xx:xx
2417,Terminal,28:84:fa:xx:xx:xx,-66,28:84:fa:xx:xx:xx