Repository: secdev/scapy

Issue:
NetflowHeaderV9 Counts flowsets instead of records
### Brief description

According to the [RFC 3954](https://www.rfc-editor.org/rfc/rfc3954#section-5.1), the count field in the Netflow header is defined as :

>    Count
         The total number of records in the Export Packet, which is the
         sum of Options FlowSet records, Template FlowSet records, and
         Data FlowSet records.

However, the [NetflowHeaderV9](https://github.com/secdev/scapy/blob/master/scapy/layers/netflow.py#L1261-L1269) counts the number of flowsets within the Netflow packet

```python
# scapy.layers.netflow.NetflowHeaderV9
# ...
    def post_build(self, pkt, pay):
        if self.count is None:
            count = sum(1 for x in self.layers() if x in [
                NetflowFlowsetV9,
                NetflowDataflowsetV9,
                NetflowOptionsFlowsetV9]
            )
            pkt = struct.pack("!H", count) + pkt[2:]
        return pkt + pay
```
Can you confirm it is a bug ? 

### Scapy version

2.4.5

### Python version

3.10.6

### Operating system

Linux 5.15.0

### Additional environment information

_No response_

### How to reproduce

```python
from scapy.all import IP, UDP, Ether, wrpcap
from scapy.fields import IntField, XByteField
from scapy.layers.inet import UDP
from scapy.layers.netflow import (GetNetflowRecordV9, NetflowDataflowsetV9,
                                  NetflowFlowsetV9, NetflowHeader,
                                  NetflowHeaderV9,
                                  NetflowOptionsFlowsetOptionV9,
                                  NetflowOptionsFlowsetScopeV9,
                                  NetflowOptionsFlowsetV9, NetflowRecordV9,
                                  NetflowTemplateFieldV9, NetflowTemplateV9)
from scapy.packet import Packet

# Let's define two templates, 256 for IPv4 and 257 for IPv6
template_flowset = NetflowFlowsetV9(
    templates=[ NetflowTemplateV9(
        template_fields=[
            NetflowTemplateFieldV9(fieldType="IN_BYTES", fieldLength=1),
            NetflowTemplateFieldV9(fieldType="IN_PKTS", fieldLength=4),
            NetflowTemplateFieldV9(fieldType="PROTOCOL"),
            NetflowTemplateFieldV9(fieldType="IPV4_SRC_ADDR"),
            NetflowTemplateFieldV9(fieldType="IPV4_DST_ADDR"),
        ],
        templateID=256,
        fieldCount=5),
        NetflowTemplateV9(
        template_fields=[
            NetflowTemplateFieldV9(fieldType="IN_BYTES", fieldLength=1),
            NetflowTemplateFieldV9(fieldType="IN_PKTS", fieldLength=4),
            NetflowTemplateFieldV9(fieldType="PROTOCOL"),
            NetflowTemplateFieldV9(fieldType="IPV6_SRC_ADDR"),
            NetflowTemplateFieldV9(fieldType="IPV6_DST_ADDR"),
        ],
        templateID=257,
        fieldCount=5)
    ],
    flowSetID=0
)

# Generate classes for data records
Record256 = GetNetflowRecordV9(template_flowset, templateID = 256)
Record257 = GetNetflowRecordV9(template_flowset, templateID = 257)

# Now lets build a dataFlowSet with 5* #256 records
dataFlowset_1 = NetflowDataflowsetV9(
    templateID=256,
    records=[
        Record256(
            IN_BYTES=b"\x12",
            IN_PKTS=b"\0\0\0\0",
            PROTOCOL=1,
            IPV4_SRC_ADDR="192.168.0.10",
            IPV4_DST_ADDR="192.168.0.11"
        ),
        Record256(
            IN_BYTES=b"\x0c",
            IN_PKTS=b"\1\1\1\1",
            PROTOCOL=2,
            IPV4_SRC_ADDR="172.0.0.10",
            IPV4_DST_ADDR="172.0.0.11"
        ),
        Record256(
            IN_BYTES=b"\x0c",
            IN_PKTS=b"\1\1\1\1",
            PROTOCOL=3,
            IPV4_SRC_ADDR="172.0.0.10",
            IPV4_DST_ADDR="172.0.0.11"
        ),
        Record256(
            IN_BYTES=b"\x0c",
            IN_PKTS=b"\1\1\1\1",
            PROTOCOL=4,
            IPV4_SRC_ADDR="172.0.0.10",
            IPV4_DST_ADDR="172.0.0.11"
        ),
        Record256(
            IN_BYTES=b"\x0c",
            IN_PKTS=b"\1\1\1\1",
            PROTOCOL=5,
            IPV4_SRC_ADDR="172.0.0.10",
            IPV4_DST_ADDR="172.0.0.11"
        )
    ],
)

# and another one of 2*257 Records
dataFlowset_2 = NetflowDataflowsetV9(
    templateID=257,
    records=[
        Record257(
            IN_BYTES=b"\x12",
            IN_PKTS=b"\0\0\0\0",
            PROTOCOL=1,
            IPV6_SRC_ADDR="2001:db8:3333:4444:5555:6666:7777:8888",
            IPV6_DST_ADDR="2001:db8::"
        ),
        Record257(
            IN_BYTES=b"\x0c",
            IN_PKTS=b"\1\1\1\1",
            PROTOCOL=2,
            IPV6_SRC_ADDR="2001:db8:3333:4444:CCCC:DDDD:EEEE:FFFF",
            IPV6_DST_ADDR="2001:db8::"
        )
    ],
)

# An option template flowset, containing an unique template
opttmpl258_flowSet = NetflowOptionsFlowsetV9(
    templateID = 258,
    option_scope_length = 4*1,
    option_field_length = 4*2,
    scopes = [
        NetflowOptionsFlowsetScopeV9(scopeFieldType= 1,	scopeFieldlength= 4),
    ],
    options = [
        NetflowOptionsFlowsetOptionV9(optionFieldType= 34,	optionFieldlength= 4),
        NetflowOptionsFlowsetOptionV9(optionFieldType= 35,	optionFieldlength= 1)
    ])

# And finally a Record class for #258 Options
class Record_258(NetflowRecordV9):
    name = "Option interface-table"
    fields_desc = [
        IntField("System", 0),
        IntField("SAMPLING_INTERVAL", 4),
        XByteField("SAMPLING_ALGORITHM", 1)
    ]
    match_subclass = True

# to generate a last record Flowset
optiondataFlowset = NetflowDataflowsetV9(
    templateID=258,
    records=[
        Record_258(
            System=424242,
            SAMPLING_INTERVAL=100,
            SAMPLING_ALGORITHM=0x01
        ),
        Record_258(
            System=242424,
            SAMPLING_INTERVAL=1000,
            SAMPLING_ALGORITHM=0x02
        )
    ],
)

netflow_header = NetflowHeader() / NetflowHeaderV9(unixSecs=1547927349.328283)
pkt =  netflow_header / template_flowset / opttmpl258_flowSet / dataFlowset_1 / dataFlowset_2 / optiondataFlowset
#      Count: 12      =        2        +         1           +       5       +       2       +        2

pkt.show2()
wrpcap('bad_netflow_header_count.pcap', Ether() / IP() / UDP() / pkt)

# Count = 5, the number of flowsets and not the total number of records,
# Sould be 12
```

### Actual result

```
###[ Netflow Header ]### 
  version   = 9
###[ Netflow Header V9 ]### 
     count     = 5
     ...
```

### Expected result

```
###[ Netflow Header ]### 
  version   = 9
###[ Netflow Header V9 ]### 
     count     = 12
     ...
```

### Related resources

[bad_netflow_header_count.zip](https://github.com/secdev/scapy/files/10724793/bad_netflow_header_count.zip)

NetflowHeaderV9 Counts flowsets instead of records
### Brief description

According to the [RFC 3954](https://www.rfc-editor.org/rfc/rfc3954#section-5.1), the count field in the Netflow header is defined as :

>    Count
         The total number of records in the Export Packet, which is the
         sum of Options FlowSet records, Template FlowSet records, and
         Data FlowSet records.

However, the [NetflowHeaderV9](https://github.com/secdev/scapy/blob/master/scapy/layers/netflow.py#L1261-L1269) counts the number of flowsets within the Netflow packet

```python
# scapy.layers.netflow.NetflowHeaderV9
# ...
    def post_build(self, pkt, pay):
        if self.count is None:
            count = sum(1 for x in self.layers() if x in [
                NetflowFlowsetV9,
                NetflowDataflowsetV9,
                NetflowOptionsFlowsetV9]
            )
            pkt = struct.pack("!H", count) + pkt[2:]
        return pkt + pay
```
Can you confirm it is a bug ? 

### Scapy version

2.4.5

### Python version

3.10.6

### Operating system

Linux 5.15.0

### Additional environment information

_No response_

### How to reproduce

```python
from scapy.all import IP, UDP, Ether, wrpcap
from scapy.fields import IntField, XByteField
from scapy.layers.inet import UDP
from scapy.layers.netflow import (GetNetflowRecordV9, NetflowDataflowsetV9,
                                  NetflowFlowsetV9, NetflowHeader,
                                  NetflowHeaderV9,
                                  NetflowOptionsFlowsetOptionV9,
                                  NetflowOptionsFlowsetScopeV9,
                                  NetflowOptionsFlowsetV9, NetflowRecordV9,
                                  NetflowTemplateFieldV9, NetflowTemplateV9)
from scapy.packet import Packet

# Let's define two templates, 256 for IPv4 and 257 for IPv6
template_flowset = NetflowFlowsetV9(
    templates=[ NetflowTemplateV9(
        template_fields=[
            NetflowTemplateFieldV9(fieldType="IN_BYTES", fieldLength=1),
            NetflowTemplateFieldV9(fieldType="IN_PKTS", fieldLength=4),
            NetflowTemplateFieldV9(fieldType="PROTOCOL"),
            NetflowTemplateFieldV9(fieldType="IPV4_SRC_ADDR"),
            NetflowTemplateFieldV9(fieldType="IPV4_DST_ADDR"),
        ],
        templateID=256,
        fieldCount=5),
        NetflowTemplateV9(
        template_fields=[
            NetflowTemplateFieldV9(fieldType="IN_BYTES", fieldLength=1),
            NetflowTemplateFieldV9(fieldType="IN_PKTS", fieldLength=4),
            NetflowTemplateFieldV9(fieldType="PROTOCOL"),
            NetflowTemplateFieldV9(fieldType="IPV6_SRC_ADDR"),
            NetflowTemplateFieldV9(fieldType="IPV6_DST_ADDR"),
        ],
        templateID=257,
        fieldCount=5)
    ],
    flowSetID=0
)

# Generate classes for data records
Record256 = GetNetflowRecordV9(template_flowset, templateID = 256)
Record257 = GetNetflowRecordV9(template_flowset, templateID = 257)

# Now lets build a dataFlowSet with 5* #256 records
dataFlowset_1 = NetflowDataflowsetV9(
    templateID=256,
    records=[
        Record256(
            IN_BYTES=b"\x12",
            IN_PKTS=b"\0\0\0\0",
            PROTOCOL=1,
            IPV4_SRC_ADDR="192.168.0.10",
            IPV4_DST_ADDR="192.168.0.11"
        ),
        Record256(
            IN_BYTES=b"\x0c",
            IN_PKTS=b"\1\1\1\1",
            PROTOCOL=2,
            IPV4_SRC_ADDR="172.0.0.10",
            IPV4_DST_ADDR="172.0.0.11"
        ),
        Record256(
            IN_BYTES=b"\x0c",
            IN_PKTS=b"\1\1\1\1",
            PROTOCOL=3,
            IPV4_SRC_ADDR="172.0.0.10",
            IPV4_DST_ADDR="172.0.0.11"
        ),
        Record256(
            IN_BYTES=b"\x0c",
            IN_PKTS=b"\1\1\1\1",
            PROTOCOL=4,
            IPV4_SRC_ADDR="172.0.0.10",
            IPV4_DST_ADDR="172.0.0.11"
        ),
        Record256(
            IN_BYTES=b"\x0c",
            IN_PKTS=b"\1\1\1\1",
            PROTOCOL=5,
            IPV4_SRC_ADDR="172.0.0.10",
            IPV4_DST_ADDR="172.0.0.11"
        )
    ],
)

# and another one of 2*257 Records
dataFlowset_2 = NetflowDataflowsetV9(
    templateID=257,
    records=[
        Record257(
            IN_BYTES=b"\x12",
            IN_PKTS=b"\0\0\0\0",
            PROTOCOL=1,
            IPV6_SRC_ADDR="2001:db8:3333:4444:5555:6666:7777:8888",
            IPV6_DST_ADDR="2001:db8::"
        ),
        Record257(
            IN_BYTES=b"\x0c",
            IN_PKTS=b"\1\1\1\1",
            PROTOCOL=2,
            IPV6_SRC_ADDR="2001:db8:3333:4444:CCCC:DDDD:EEEE:FFFF",
            IPV6_DST_ADDR="2001:db8::"
        )
    ],
)

# An option template flowset, containing an unique template
opttmpl258_flowSet = NetflowOptionsFlowsetV9(
    templateID = 258,
    option_scope_length = 4*1,
    option_field_length = 4*2,
    scopes = [
        NetflowOptionsFlowsetScopeV9(scopeFieldType= 1,	scopeFieldlength= 4),
    ],
    options = [
        NetflowOptionsFlowsetOptionV9(optionFieldType= 34,	optionFieldlength= 4),
        NetflowOptionsFlowsetOptionV9(optionFieldType= 35,	optionFieldlength= 1)
    ])

# And finally a Record class for #258 Options
class Record_258(NetflowRecordV9):
    name = "Option interface-table"
    fields_desc = [
        IntField("System", 0),
        IntField("SAMPLING_INTERVAL", 4),
        XByteField("SAMPLING_ALGORITHM", 1)
    ]
    match_subclass = True

# to generate a last record Flowset
optiondataFlowset = NetflowDataflowsetV9(
    templateID=258,
    records=[
        Record_258(
            System=424242,
            SAMPLING_INTERVAL=100,
            SAMPLING_ALGORITHM=0x01
        ),
        Record_258(
            System=242424,
            SAMPLING_INTERVAL=1000,
            SAMPLING_ALGORITHM=0x02
        )
    ],
)

netflow_header = NetflowHeader() / NetflowHeaderV9(unixSecs=1547927349.328283)
pkt =  netflow_header / template_flowset / opttmpl258_flowSet / dataFlowset_1 / dataFlowset_2 / optiondataFlowset
#      Count: 12      =        2        +         1           +       5       +       2       +        2

pkt.show2()
wrpcap('bad_netflow_header_count.pcap', Ether() / IP() / UDP() / pkt)

# Count = 5, the number of flowsets and not the total number of records,
# Sould be 12
```

### Actual result

```
###[ Netflow Header ]### 
  version   = 9
###[ Netflow Header V9 ]### 
     count     = 5
     ...
```

### Expected result

```
###[ Netflow Header ]### 
  version   = 9
###[ Netflow Header V9 ]### 
     count     = 12
     ...
```

### Related resources

[bad_netflow_header_count.zip](https://github.com/secdev/scapy/files/10724793/bad_netflow_header_count.zip)



Discussion:

Resolving patch:
diff --git a/scapy/layers/netflow.py b/scapy/layers/netflow.py
--- a/scapy/layers/netflow.py
+++ b/scapy/layers/netflow.py
@@ -32,6 +32,7 @@
 
 import socket
 import struct
+from collections import Counter
 
 from scapy.config import conf
 from scapy.data import IP_PROTOS
@@ -1259,11 +1260,23 @@ class NetflowHeaderV9(Packet):
                    IntField("SourceID", 0)]
 
     def post_build(self, pkt, pay):
+
+        def count_by_layer(layer):
+            if type(layer) == NetflowFlowsetV9:
+                return len(layer.templates)
+            elif type(layer) == NetflowDataflowsetV9:
+                return len(layer.records)
+            elif type(layer) == NetflowOptionsFlowsetV9:
+                return 1
+            else:
+                return 0
+
         if self.count is None:
-            count = sum(1 for x in self.layers() if x in [
-                NetflowFlowsetV9,
-                NetflowDataflowsetV9,
-                NetflowOptionsFlowsetV9]
+            # https://www.rfc-editor.org/rfc/rfc3954#section-5.1
+            count = sum(
+                sum(count_by_layer(self.getlayer(layer_cls, nth))
+                    for nth in range(1, n + 1))
+                for layer_cls, n in Counter(self.layers()).items()
             )
             pkt = struct.pack("!H", count) + pkt[2:]
         return pkt + pay


Test patch:
diff --git a/test/scapy/layers/netflow.uts b/test/scapy/layers/netflow.uts
--- a/test/scapy/layers/netflow.uts
+++ b/test/scapy/layers/netflow.uts
@@ -173,6 +173,182 @@ option_templateFlowSet_256 = NetflowOptionsFlowsetV9(
     ])
 assert raw(option_templateFlowSet_256) == b'\x00\x01\x00\x1c\x01\x00\x00\x04\x00\x0c\x00\x01\x00\x04\x00\n\x00\x04\x00R\x00 \x00S\x00\xf0\x00\x00'
 
+= NetflowV9 - Advanced build, multiple flowsets and multiple records by flowset
+~ netflow
+
+template_flowset = NetflowFlowsetV9(
+    templates=[ NetflowTemplateV9(
+        template_fields=[
+            NetflowTemplateFieldV9(fieldType="IN_BYTES", fieldLength=1),
+            NetflowTemplateFieldV9(fieldType="IN_PKTS", fieldLength=4),
+            NetflowTemplateFieldV9(fieldType="PROTOCOL"),
+            NetflowTemplateFieldV9(fieldType="IPV4_SRC_ADDR"),
+            NetflowTemplateFieldV9(fieldType="IPV4_DST_ADDR"),
+        ],
+        templateID=256,
+        fieldCount=5),
+        NetflowTemplateV9(
+        template_fields=[
+            NetflowTemplateFieldV9(fieldType="IN_BYTES", fieldLength=1),
+            NetflowTemplateFieldV9(fieldType="IN_PKTS", fieldLength=4),
+            NetflowTemplateFieldV9(fieldType="PROTOCOL"),
+            NetflowTemplateFieldV9(fieldType="IPV6_SRC_ADDR"),
+            NetflowTemplateFieldV9(fieldType="IPV6_DST_ADDR"),
+        ],
+        templateID=257,
+        fieldCount=5)
+    ],
+    flowSetID=0
+)
+
+# Generate classes for data records
+Record256 = GetNetflowRecordV9(template_flowset, templateID = 256)
+Record257 = GetNetflowRecordV9(template_flowset, templateID = 257)
+
+# Now lets build a dataFlowSet with 5* #256 records
+dataFlowset_1 = NetflowDataflowsetV9(
+    templateID=256,
+    records=[
+        Record256(
+            IN_BYTES=b"\x12",
+            IN_PKTS=b"\0\0\0\0",
+            PROTOCOL=1,
+            IPV4_SRC_ADDR="192.168.0.10",
+            IPV4_DST_ADDR="192.168.0.11"
+        ),
+        Record256(
+            IN_BYTES=b"\x0c",
+            IN_PKTS=b"\1\1\1\1",
+            PROTOCOL=2,
+            IPV4_SRC_ADDR="172.0.0.10",
+            IPV4_DST_ADDR="172.0.0.11"
+        ),
+        Record256(
+            IN_BYTES=b"\x0c",
+            IN_PKTS=b"\1\1\1\1",
+            PROTOCOL=3,
+            IPV4_SRC_ADDR="172.0.0.10",
+            IPV4_DST_ADDR="172.0.0.11"
+        ),
+        Record256(
+            IN_BYTES=b"\x0c",
+            IN_PKTS=b"\1\1\1\1",
+            PROTOCOL=4,
+            IPV4_SRC_ADDR="172.0.0.10",
+            IPV4_DST_ADDR="172.0.0.11"
+        ),
+        Record256(
+            IN_BYTES=b"\x0c",
+            IN_PKTS=b"\1\1\1\1",
+            PROTOCOL=5,
+            IPV4_SRC_ADDR="172.0.0.10",
+            IPV4_DST_ADDR="172.0.0.11"
+        )
+    ],
+)
+
+dataFlowset_2 = NetflowDataflowsetV9(
+    templateID=257,
+    records=[
+        Record257(
+            IN_BYTES=b"\x12",
+            IN_PKTS=b"\0\0\0\0",
+            PROTOCOL=1,
+            IPV6_SRC_ADDR="2001:db8:3333:4444:5555:6666:7777:8888",
+            IPV6_DST_ADDR="2001:db8::"
+        ),
+        Record257(
+            IN_BYTES=b"\x0c",
+            IN_PKTS=b"\1\1\1\1",
+            PROTOCOL=2,
+            IPV6_SRC_ADDR="2001:db8:3333:4444:CCCC:DDDD:EEEE:FFFF",
+            IPV6_DST_ADDR="2001:db8::"
+        )
+    ],
+)
+
+# An option template flowset, containing an unique template
+opttmpl258_flowSet = NetflowOptionsFlowsetV9(
+    templateID = 258,
+    option_scope_length = 4*1,
+    option_field_length = 4*2,
+    scopes = [
+        NetflowOptionsFlowsetScopeV9(scopeFieldType= 1,	scopeFieldlength= 4),
+    ],
+    options = [
+        NetflowOptionsFlowsetOptionV9(optionFieldType= 34,	optionFieldlength= 4),
+        NetflowOptionsFlowsetOptionV9(optionFieldType= 35,	optionFieldlength= 1)
+    ])
+
+# And finally a Record class for #258 Options
+class Record_258(NetflowRecordV9):
+    name = "Option interface-table"
+    fields_desc = [
+        IntField("System", 0),
+        IntField("SAMPLING_INTERVAL", 4),
+        XByteField("SAMPLING_ALGORITHM", 1)
+    ]
+    match_subclass = True
+
+
+# with a record Flowset
+optiondataFlowset = NetflowDataflowsetV9(
+    templateID=258,
+    records=[
+        Record_258(
+            System=424242,
+            SAMPLING_INTERVAL=100,
+            SAMPLING_ALGORITHM=0x01
+        ),
+        Record_258(
+            System=242424,
+            SAMPLING_INTERVAL=1000,
+            SAMPLING_ALGORITHM=0x02
+        )
+    ],
+)
+
+netflow_header = NetflowHeader()/NetflowHeaderV9(unixSecs=1547927349.328283)
+pkt =  netflow_header / template_flowset / opttmpl258_flowSet / dataFlowset_1 / dataFlowset_2 / optiondataFlowset
+#      Count: 12      =        2        +         1           +       5       +       2       +        2
+
+assert raw(pkt) == b'\x00\t\x00\x0c\x00\x00\x00\x00\\C\x7f5\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x004\x01\x00\x00\x05\x00\x01\x00\x01\x00\x02\x00\x04\x00\x04\x00\x01\x00\x08\x00\x04\x00\x0c\x00\x04\x01\x01\x00\x05\x00\x01\x00\x01\x00\x02\x00\x04\x00\x04\x00\x01\x00\x1b\x00\x10\x00\x1c\x00\x10\x00\x01\x00\x18\x01\x02\x00\x04\x00\x08\x00\x01\x00\x04\x00"\x00\x04\x00#\x00\x01\x00\x00\x01\x00\x00L\x12\x00\x00\x00\x00\x01\xc0\xa8\x00\n\xc0\xa8\x00\x0b\x0c\x01\x01\x01\x01\x02\xac\x00\x00\n\xac\x00\x00\x0b\x0c\x01\x01\x01\x01\x03\xac\x00\x00\n\xac\x00\x00\x0b\x0c\x01\x01\x01\x01\x04\xac\x00\x00\n\xac\x00\x00\x0b\x0c\x01\x01\x01\x01\x05\xac\x00\x00\n\xac\x00\x00\x0b\x00\x00\x01\x01\x00P\x12\x00\x00\x00\x00\x01 \x01\r\xb833DDUUffww\x88\x88 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0c\x01\x01\x01\x01\x02 \x01\r\xb833DD\xcc\xcc\xdd\xdd\xee\xee\xff\xff \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x02\x00\x18\x00\x06y2\x00\x00\x00d\x01\x00\x03\xb2\xf8\x00\x00\x03\xe8\x02\x00\x00'
+
+
+= NetflowV9 - Advanced dissection, complete example
+~ netflow
+
+pkt = NetflowHeader(b'\x00\t\x00\x0c\x00\x00\x00\x00\\C\x7f5\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x004\x01\x00\x00\x05\x00\x01\x00\x01\x00\x02\x00\x04\x00\x04\x00\x01\x00\x08\x00\x04\x00\x0c\x00\x04\x01\x01\x00\x05\x00\x01\x00\x01\x00\x02\x00\x04\x00\x04\x00\x01\x00\x1b\x00\x10\x00\x1c\x00\x10\x00\x01\x00\x18\x01\x02\x00\x04\x00\x08\x00\x01\x00\x04\x00"\x00\x04\x00#\x00\x01\x00\x00\x01\x00\x00L\x12\x00\x00\x00\x00\x01\xc0\xa8\x00\n\xc0\xa8\x00\x0b\x0c\x01\x01\x01\x01\x02\xac\x00\x00\n\xac\x00\x00\x0b\x0c\x01\x01\x01\x01\x03\xac\x00\x00\n\xac\x00\x00\x0b\x0c\x01\x01\x01\x01\x04\xac\x00\x00\n\xac\x00\x00\x0b\x0c\x01\x01\x01\x01\x05\xac\x00\x00\n\xac\x00\x00\x0b\x00\x00\x01\x01\x00P\x12\x00\x00\x00\x00\x01 \x01\r\xb833DDUUffww\x88\x88 \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0c\x01\x01\x01\x01\x02 \x01\r\xb833DD\xcc\xcc\xdd\xdd\xee\xee\xff\xff \x01\r\xb8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x02\x00\x18\x00\x06y2\x00\x00\x00d\x01\x00\x03\xb2\xf8\x00\x00\x03\xe8\x02\x00\x00')
+
+nf_header = pkt.getlayer(NetflowHeader)
+assert nf_header.version == 9
+nfv9_header = pkt.getlayer(NetflowHeaderV9)
+assert nf_header.count == 12
+
+flowset_1 = pkt.getlayer(NetflowFlowsetV9, 1)
+assert len(flowset_1.templates) == 2
+assert flowset_1.templates[0].templateID == 256
+assert flowset_1.templates[1].templateID == 257
+assert flowset_1.templates[1].fieldCount == 5
+assert flowset_1.templates[1].template_fields[1].fieldLength == 4
+
+flowset_2 = pkt.getlayer(NetflowOptionsFlowsetV9, 1)
+assert flowset_2.templateID == 258
+assert len(flowset_2.scopes) == 1
+assert len(flowset_2.options) == 2
+assert flowset_2.pad == b'\x00\x00'
+
+flowset_3 = pkt.getlayer(NetflowDataflowsetV9, 1)
+assert flowset_3.templateID == 256
+assert flowset_3.length == 76
+
+flowset_4 = pkt.getlayer(NetflowDataflowsetV9, 2)
+assert flowset_4.templateID == 257
+
+flowset_5 = pkt.getlayer(NetflowDataflowsetV9, 3)
+assert flowset_5.templateID == 258
+
+
 ############
 ############
 + Netflow v10 (aka IPFix)