diff --git a/Network/tests/PSKReporter/PSKReporter.IESpec b/Network/tests/PSKReporter/PSKReporter.IESpec new file mode 100644 index 000000000..8e95ffd08 --- /dev/null +++ b/Network/tests/PSKReporter/PSKReporter.IESpec @@ -0,0 +1,12 @@ +senderCallsign(30351/1)[65535] +receiverCallsign(30351/2)[65535] +senderLocator(30351/3)[65535] +receiverLocator(30351/4)[65535] +frequency(30351/5)[4] +sNR(30351/6)[1] +iMD(30351/7)[1] +decoderSoftware(30351/8)[65535] +antennaInformation(30351/9)[65535] +mode(30351/10)[65535] +informationSource(30351/11)[1] +persistentIdentifier(30351/12)[65535] diff --git a/Network/tests/PSKReporter/listener.py b/Network/tests/PSKReporter/listener.py new file mode 100644 index 000000000..b2e830e34 --- /dev/null +++ b/Network/tests/PSKReporter/listener.py @@ -0,0 +1,94 @@ +from __future__ import unicode_literals +import sys +import argparse +import logging +import time +import threading +import ipfix.ie +import ipfix.reader +import ipfix.message +import socketserver +import socket + +class IPFixDatagramHandler (socketserver.DatagramRequestHandler): + + def handle (self): + logging.info (f'Connection from {self.client_address}') + try: + self.server.msg_buffer.from_bytes (self.packet) + for rec in self.server.msg_buffer.namedict_iterator (): + logging.info (f't: {self.server.msg_buffer.get_export_time()}: {rec}') + except: + logging.error ('Unexpected exception:', sys.exc_info ()[0]) + + +class IPFixUdpServer (socketserver.UDPServer): + + def __init__ (self, *args, **kwargs): + + self.msg_buffer = ipfix.message.MessageBuffer () + super ().__init__ (*args, **kwargs) + +class IPFixStreamHandler (socketserver.StreamRequestHandler): + + def handle (self): + logging.info (f'Connection from {self.client_address}') + try: + msg_reader = ipfix.reader.from_stream (self.rfile) + for rec in msg_reader.namedict_iterator (): + logging.info (f't: {msg_reader.msg.get_export_time()}: {rec}') + logging.info (f'{self.client_address} closed their connection') + except ConnectionResetError: + logging.info (f'{self.client_address} connection reset') + except TimeoutError: + logging.info (f'{self.client_address} connection timed out') + except: + logging.error ('Unexpected exception:', sys.exc_info ()[0]) + + +if __name__ == "__main__": + INTERFACE, PORT = '', 4739 + + ap = argparse.ArgumentParser (description='Dump IPFIX data collectedover UDP') + ap.add_argument ('-l', '--log', metavar='loglevel', default='WARNING', help='logging level') + ap.add_argument ('-s', '--spec', metavar='specfile', help='iespec file to read') + args = ap.parse_args () + + log_level = getattr (logging, args.log.upper (), None) + if not isinstance (log_level, int): + raise ValueError (f'Invalif log level: {log_level}') + logging.basicConfig ( + level=log_level + , format='[%(levelname)s] (%(threadName)-10s) %(message)s' + , + ) + + logging.info (f'Starting IPFix servers on service port: {PORT}') + + ipfix.ie.use_iana_default () + ipfix.ie.use_5103_default () + if args.spec: + ipfix.ie.use_specfile (args.spec) + + udp_server = IPFixUdpServer ((INTERFACE, PORT), IPFixDatagramHandler) + udp_thread = threading.Thread (name='UDP Server', target=udp_server.serve_forever) + + tcp_server = socketserver.TCPServer ((INTERFACE, PORT), IPFixStreamHandler) + tcp_server.allow_reuse_address = True + tcp_server.socket.setsockopt (socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) + tcp_thread = threading.Thread (name='TCP/IP Server', target=tcp_server.serve_forever) + + udp_thread.start () + tcp_thread.start () + + try: + while True: + time.sleep (1000) + except KeyboardInterrupt: + logging.warning ('Closing down servers') + udp_server.shutdown () + tcp_server.shutdown () + + udp_thread.join () + tcp_thread.join () + logging.info ('Servers closed') diff --git a/Network/tests/PSKReporter/python-ipfix.patch b/Network/tests/PSKReporter/python-ipfix.patch new file mode 100644 index 000000000..cb6797094 --- /dev/null +++ b/Network/tests/PSKReporter/python-ipfix.patch @@ -0,0 +1,64 @@ +The following changes since commit e487dfbead9965c1a251d110dc55039a7ba4afef: + + sphinx doc update (2017-09-20 16:07:22 +0200) + +are available in the Git repository at: + + git@github.com:g4wjs/python-ipfix.git varlen-and-padding + +for you to fetch changes up to 6dcc106f22d25ac21b27f8ccb9b82be12e7eb18e: + + Parse and emit data elements correctly when variable length items included (2020-06-19 19:53:33 +0100) + +---------------------------------------------------------------- +Bill Somerville (2): + Allow for alignment padding when parsing sets + Parse and emit data elements correctly when variable length items included + + ipfix/message.py | 3 ++- + ipfix/template.py | 4 ++-- + 2 files changed, 4 insertions(+), 3 deletions(-) + +diff --git a/ipfix/message.py b/ipfix/message.py +index 0af2fad..71c1328 100644 +--- a/ipfix/message.py ++++ b/ipfix/message.py +@@ -398,7 +398,7 @@ class MessageBuffer(object): + offset += _sethdr_st.size # skip set header in decode + if setid == template.TEMPLATE_SET_ID or\ + setid == template.OPTIONS_SET_ID: +- while offset < setend: ++ while offset + 4 < setend: # allow for padding up to 4 byte alignment + (tmpl, offset) = template.decode_template_from( + self.mbuf, offset, setid) + # FIXME handle withdrawal +@@ -431,6 +431,7 @@ class MessageBuffer(object): + # KeyError on template lookup - unknown data set + self.unknown_data_set_hook(self, + self.mbuf[offset-_sethdr_st.size:setend]) ++ offset = setend # real end may be greater that accumulated offset + + def namedict_iterator(self): + """ +diff --git a/ipfix/template.py b/ipfix/template.py +index 1203e55..26cd8c1 100644 +--- a/ipfix/template.py ++++ b/ipfix/template.py +@@ -187,7 +187,7 @@ class Template(object): + offset += packplan.st.size + + # short circuit on no varlen +- if not self.varlenslice: ++ if self.varlenslice is None: + return (vals, offset) + + # direct iteration over remaining IEs +@@ -239,7 +239,7 @@ class Template(object): + offset += packplan.st.size + + # shortcircuit no varlen +- if not self.varlenslice: ++ if self.varlenslice is None: + return offset + + # direct iteration over remaining IEs