Допустим имеется 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