britram / python-ipfix

IPFIX implementation for Python 3.x
GNU Lesser General Public License v3.0
40 stars 20 forks source link

UDP IPFIX Collector not Working #27

Open tal-zvon opened 5 years ago

tal-zvon commented 5 years ago

collector_test.py seems to be old, and uses TCP. I needed to do almost exactly the same thing it was trying to demo, but using UDP.

This is what I got:

#!/usr/bin/env python3

import socketserver
import ipfix.reader
import ipfix.ie

ipfix.ie.use_iana_default()
ipfix.ie.use_5103_default()

class CollectorDictHandler(socketserver.DatagramRequestHandler):
    def handle(self):
        print("=" * 80) 
        r = ipfix.reader.from_stream(self.rfile)

        for rec in r.namedict_iterator():
            print('-' * 80) 
            for key in rec:
                print("%s: %s" % (key, rec[key]))

ss = socketserver.UDPServer(("0.0.0.0", 1234), CollectorDictHandler)
ss.serve_forever()

The device exporting the flows is a Mikrotik. The code above runs, but r.namedict_iterator() never returns any records, so all I get is '====...' across my screen every time it receives a packet, but no actual data.

From what I understand, ipfix.reader is smart enough to read templates from the stream, and use them when trying to decode incoming data. Is this correct?

Am I doing something else wrong?

michalac commented 2 years ago

Hello,

had same problem. It's because when every UDP packet arrives, there is new instance of CollectorDictHandler created with new ipfix.message.MessageBuffer. If packet contains template, MessageBuffer learns it. But after next UDP packet arrives, there is new MessageBuffer created with empty template list. MessageBuffer then can't parse packet and returns no data from namedict_iterator().

Solution is to use same MessageBuffer instance for every UDP packet. Something like:

 class CollectorDictHandler(socketserver.DatagramRequestHandler):
    # class static variable
    msgBuff = ipfix.message.MessageBuffer()

    def handle(self):
        print("=" * 80) 
        CollectorDictHandler.msgBuff.from_bytes(self.rfile.read())

        for rec in CollectorDictHandler.msgBuff.namedict_iterator():
            print('-' * 80) 
            for key in rec:
                print("%s: %s" % (key, rec[key]))

If multiple clients (with differrent templates), there must be single MessageBuffer for each client.