From 3b207c35685d69c255657872683f96a77e927b14 Mon Sep 17 00:00:00 2001 From: Dominik Pataky Date: Sun, 2 May 2021 16:15:38 +0200 Subject: [PATCH] Update README --- README.md | 8 +++++--- nf-workflow.png | Bin 0 -> 19224 bytes 2 files changed, 5 insertions(+), 3 deletions(-) create mode 100644 nf-workflow.png diff --git a/README.md b/README.md index 5135098..1a35cfd 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,11 @@ # Python NetFlow/IPFIX library -This package contains libraries and tools for **NetFlow versions 1, 5 and 9, and IPFIX**. +This package contains libraries and tools for **NetFlow versions 1, 5 and 9, and IPFIX**. It is available [on PyPI as "netflow"](https://pypi.org/project/netflow/). Version 9 is the first NetFlow version using templates. Templates make dynamically sized and configured NetFlow data flowsets possible, which makes the collector's job harder. The library provides the `netflow.parse_packet()` function as the main API point (see below). By importing `netflow.v1`, `netflow.v5` or `netflow.v9` you have direct access to the respective parsing objects, but at the beginning you probably will have more success by running the reference collector (example below) and look into its code. IPFIX (IP Flow Information Export) is based on NetFlow v9 and standardized by the IETF. All related classes are contained in `netflow.ipfix`. -Copyright 2016-2020 Dominik Pataky +![Data flow diagram](nf-workflow.png) + +Copyright 2016-2021 Dominik Pataky Licensed under MIT License. See LICENSE. @@ -34,7 +36,7 @@ assert p.header.version == 5 # NetFlow v5 packet assert p.flows[0].PROTO == 1 # ICMP flow ``` -In NetFlow v9 and IPFIX, templates are used instead of a fixed set of fields (like `PROTO`). See `collector.py` on how to handle these. +In NetFlow v9 and IPFIX, templates are used instead of a fixed set of fields (like `PROTO`). See `collector.py` on how to handle these. You **must** store received templates in between exports and pass them to the parser when new packets arrive. Not storing the templates will always result in parsing failures. ## Using the collector and analyzer Since v0.9.0 the `netflow` library also includes reference implementations of a collector and an analyzer as CLI tools. diff --git a/nf-workflow.png b/nf-workflow.png new file mode 100644 index 0000000000000000000000000000000000000000..67cdd50ab79e81cfbc26ef56022d4ae21004f9dd GIT binary patch literal 19224 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