Допустим имеется pcap файл, содержащий CFLOW трафик. Нам необходимо получить информацию об анонсируемых шаблонах (какие, в каком фрейме) и о данных (сколько DataSet'ов, сколько Flow).
Для этих целей реализован постдиссектор (см. в конце).
Пример запуска:
tshark -q -d"udp.port==8819,cflow" -X lua_script:./misc/cflow.analyze.lua -r build/20140326.analisys/merged.pcap
Существует важная особенность при анализе информации на уровне flow. tshark начинает понимать как правильно разбирать DataSet'ы только после того, как поймает анонс соответствующего шаблона. Соответственно все пакеты до фрейма с шаблонами будут пропущены. Для решения этой проблемы можно прогнать pcap-файл через анализатор, получить номер фрейма с анонсами шаблонов, выделить этот фрейм:
tshark -Y"frame.number==4320" -r dump.pcap -w templates.pcap
и подсоединить в начало:
mergecap -a templates.pcap dump.pcap -w merged.pcap
Второй тонкий момент. Если обратить внимание на lua-скрипт, то можно
заметить, что ВСЕ flow должны быть перечислимы по какому-либо полю. То
есть надо найти такое поле, которое встречалось бы и содержало значение
у всех наборов данных. В коде ниже - это поля cflow.firewall_event
,
cflow.observation_time_milliseconds
. Это необходимо для корректной
обработки данных в цикле получения всех flow.
do
print("cflow analyzer loaded")
local frame_num_extractor = Field.new("frame.number")
local src_ip_extractor = Field.new("ip.src")
local src_port_extractor = Field.new("udp.srcport")
local flowset_id_extractor = Field.new("cflow.flowset_id")
local flowset_len_extractor = Field.new("cflow.flowset_length")
local template_id_extractor = Field.new("cflow.template_id")
local template_fcount_extractor = Field.new("cflow.template_field_count")
-- choose correct inumerate field here
local flow_fw_event_extractor = Field.new("cflow.firewall_event")
local flow_obs_time_extractor = Field.new("cflow.observation_time_milliseconds")
local fw_events = {}
local flowsets = {}
local templates = {}
local bytes_total = 0
local flow_count_total = 0
local flowset_count_total = 0
local function init_listener()
local tap = Listener.new("udp", "")
function tap.packet(pinfo, tvb, udp)
local frame_num = tonumber(tostring(frame_num_extractor()))
local src_ip = src_ip_extractor()
local src_port = src_port_extractor()
local flowset_ids = {flowset_id_extractor()}
local flowset_lens = {flowset_len_extractor()}
local flowset_offsets = {}
for i=1,#flowset_ids do
flowset_id = flowset_ids[i].range:int()
flowset_len = flowset_lens[i].range:int()
table.insert(flowset_offsets, {flowset_id, flowset_ids[i].range:offset()})
if flowset_id ~= 0 then
if flowsets[flowset_id] == nil then
flowsets[flowset_id] = {}
flowsets[flowset_id].flowset_count = 0
flowsets[flowset_id].flow_count = 0
flowsets[flowset_id].bytes = 0
end
flowsets[flowset_id].bytes = flowsets[flowset_id].bytes + flowset_len
flowsets[flowset_id].flowset_count = flowsets[flowset_id].flowset_count + 1
flowset_count_total = flowset_count_total + 1
bytes_total = bytes_total + flowset_len;
end
end
table.sort(flowset_offsets, function(a,b) return a[2] < b[2] end)
local flow_fw_events = {flow_fw_event_extractor()}
local flow_obs_times = {flow_obs_time_extractor()}
flow_count_total = flow_count_total + #flow_obs_times
for i=1,#flow_fw_events do
local flow_fw_event = flow_fw_events[i].range:int()
local flow_offset = flow_fw_events[i].range:offset()
local template_id = 0
for n,v in ipairs(flowset_offsets) do
if flow_offset < v[2] then
break
end
template_id = v[1]
end
flowsets[template_id].flow_count = flowsets[template_id].flow_count + 1
if not fw_events[flow_fw_event] then
fw_events[flow_fw_event] = {}
table.insert(fw_events[flow_fw_event], template_id)
else
function has_elem(val, tab)
for k,v in ipairs(tab) do
if v == val then
return true;
end
end
return false
end
if not has_elem(template_id, fw_events[flow_fw_event]) then
table.insert(fw_events[flow_fw_event], template_id)
end
end
end
local template_ids = {template_id_extractor()}
local template_fcounts = {template_fcount_extractor()}
for i=1,#template_ids do
template_id = template_ids[i].range:int()
template_fcount = template_fcounts[i].range:int()
local template_id_str = tostring(template_id).."("..tostring(template_fcount)..")"
if not templates[template_id_str] then
templates[template_id_str] = {}
templates[template_id_str].fcount = template_fcount
templates[template_id_str].frame = frame_num
end
end
end
function tap.draw()
print("\nTemplates meet (id, fields count, frame number):")
for k,v in pairs(templates) do
print(k, v.frame)
end
print("\nData stats (template, datasets total, flows total, bytes total):")
for k,v in pairs(flowsets) do
local flow_count_with_pct = "0(0%)"
local flowset_count_with_pct = "0(0%)"
local bytes_with_pct = "0(0%)"
if flow_count_total ~= 0 then
flow_count_with_pct = string.format("%d(%d%%)", v.flow_count, v.flow_count*100/flow_count_total)
end
if flowset_count_with_pct ~= 0 then
flowset_count_with_pct = string.format("%d(%d%%)", v.flowset_count, v.flowset_count*100/flowset_count_total)
end
if bytes_with_pct ~= 0 then
bytes_with_pct =string.format("%d(%d%%)", v.bytes, v.bytes*100/bytes_total)
end
print(k, flowset_count_with_pct, flow_count_with_pct, bytes_with_pct)
end
print("\nFW_EVENTS:")
for k,v in pairs(fw_events) do
local out = k .. ": "
for kk, vv in ipairs(v) do
out = out .. " " .. vv
end
print(out)
end
print(string.format("\nTotal datasets: %d, flows: %d, data bytes: %d", flowset_count_total, flow_count_total, bytes_total))
end
end
init_listener()
end
Comments
comments powered by Disqus