Skip to content

Commit

Permalink
Add to_dict & to_list (#22)
Browse files Browse the repository at this point in the history
* Add to_dict.py

* Add tests

* Add tests

* Update README.md with info about to_dict, to_list
  • Loading branch information
NexSabre authored May 16, 2021
1 parent 5a27b6a commit 4404cd5
Show file tree
Hide file tree
Showing 6 changed files with 146 additions and 13 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
v0.11
* Add `to_dict` and `to_list`. Allow to dump packet layers into dict Dict[AnyStr, AnyStr]
and list List[Dict[AnyStr, AnyStr]]

v0.10.2
* Disable coping to the clipboard after hexdump was provided to the hstrip()

Expand Down
82 changes: 70 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@
![CodeQL](https://github.com/NexSabre/scapy_helper/workflows/CodeQL/badge.svg?branch=master)
[![PyPI version](https://badge.fury.io/py/scapy-helper.svg)](https://badge.fury.io/py/scapy-helper)

# Scapy helper (aka. Packet Helper)
# Scapy helper (aka. Packet Helper)

This micro library popularizes some handy tricks that make it easy usage of Scapy.

## TL;DR

```python
from scapy_helper import *

Expand All @@ -21,7 +23,7 @@ show_hex(Ether())

# Show the differences
# can be result of get_hex() or string or frame
second_ether = "ff ff fc ff ff fa 00 00 00 00 00 00 90 00 11 11 00 22"
second_ether = "ff ff fc ff ff fa 00 00 00 00 00 00 90 00 11 11 00 22"
show_diff(Ether(), second_ether)
# output:
# WARN:: Frame len is not the same
Expand Down Expand Up @@ -52,12 +54,50 @@ show_diff(Ether(), second_ether, index=True, empty_char="+")
```

## Addons
Since version v0.5.1, to the _scapy_helper_ was added `chexdump` and `hexdump`.
With v0.7.1 we introduce a `mac2int` and `int2mac`. Version v0.10 bring `hstrip`.

Since version v0.5.1, to the _scapy_helper_ was added `chexdump` and `hexdump`. With v0.7.1 we introduce a `mac2int`
and `int2mac`. Version v0.10 bring `hstrip`. Version v0.11 adding `to_dict` & `to_list`.

### to_dict

Since v0.11, `to_dict(<packet>)` allows to dump a specific layer into a dict object.

```python
>> packet = Ether(dst="ff:ff:ff:ff:ff:ff", src="00:00:00:00:00:00") / IP() / TCP()

>> to_dict(packet)
{'Ethernet': {'src': '00:00:00:00:00:00', 'dst': 'ff:ff:ff:ff:ff:ff', 'type': 2048}}
```

You can specify id of layer to convert, by providing a `layer` key.

```python
>> packet = Ether(dst="ff:ff:ff:ff:ff:ff", src="00:00:00:00:00:00") / IP() / TCP()

>> to_dict(packet, layer=1) # layer 1 is IP
{'IP': {'frag': 0, 'src': '0.0.0.0', 'proto': 6, 'tos': 0, 'dst': '127.0.0.1',
'chksum': None, 'len': None, 'options': [], 'version': 4, 'flags': None,
'ihl': None, 'ttl': 64, 'id': 1}}
```

### to_list

Since v0.11, `to_list(<packet>)` allows to dump entire frame into a List [ Dict ]

```python
>> packet = Ether(dst="ff:ff:ff:ff:ff:ff", src="00:00:00:00:00:00") / IP() / TCP()

>> to_list(packet)
[{'Ethernet': {'src': '00:00:00:00:00:00', 'dst': 'ff:ff:ff:ff:ff:ff', 'type': 2048}}, {
'IP': {'frag': 0, 'src': '0.0.0.0', 'proto': 6, 'tos': 0, 'dst': '127.0.0.1', 'chksum': None, 'len': None,
'options': [], 'version': 4, 'flags': None, 'ihl': None, 'ttl': 64, 'id': 1}}, {
'TCP': {'reserved': 0, 'seq': 0, 'ack': 0, 'dataofs': None, 'urgptr': 0, 'window': 8192,
'flags': None, 'chksum': None, 'dport': 80, 'sport': 20, 'options': []}}]
```

### hstrip
Since v0.10, allows to convert a Scapies hexdump into clean string-hex format.
Select a hexdump and copy into clipboard.

Since v0.10, allows to convert a Scapies hexdump into clean string-hex format. Select a hexdump and copy into clipboard.

```text
>>> f = Ether()/IP()/TCP()
Expand All @@ -68,6 +108,7 @@ Select a hexdump and copy into clipboard.
0030 20 00 91 7C 00 00 ..|..
>>>
```

In command line type `hstrip`

```text
Expand All @@ -77,9 +118,11 @@ FF FF FF FF FF FF 00 00 00 00 00 00 08 00 45 00
20 00 91 7C 00 00
```

Voilà! You have in your clipboard striped version of hexdump. Now you can paste it into [packetor.com](http://packetor.com)
Voilà! You have in your clipboard striped version of hexdump. Now you can paste it
into [packetor.com](http://packetor.com)

### chexdump

```python
from scapy_helper import chexdump

Expand All @@ -96,6 +139,7 @@ val = chexdump("\x00\x01".encode(), dump=True, to_list=True)
```

### hexdump

```python
from scapy_helper import hexdump

Expand All @@ -115,7 +159,9 @@ val = hexdump(packet, dump=True, to_list=True)
```

### int2mac
Convert an integer value into mac address. Letters by the default are lower case.

Convert an integer value into mac address. Letters by the default are lower case.

```python
from scapy_helper import int2mac

Expand All @@ -124,7 +170,9 @@ int2mac(73596036829, upper=True)
```

### mac2int
Convert a mac address into integer value

Convert a mac address into integer value

```python
from scapy_helper import mac2int

Expand All @@ -133,7 +181,9 @@ mac2int("00:11:22:AA:66:DD")
```

### ip2int

Convert IP address string into int value

```python
from scapy_helper import ip2int

Expand All @@ -142,7 +192,9 @@ ip2int("0.0.0.0")
```

### int2mac

Convert an int value into IP address string

```python
from scapy_helper import int2ip

Expand All @@ -151,16 +203,19 @@ int2ip(0)
```

## Test case usage

### Extends test class using PacketAssert (since v0.3.1)

__Note: In the v0.3.0 this class was called HexEqual__

You can use assertHexEqual/assertHexNotEqual and assertBytesEqual/assertBytesNotEqual in the tests.
When the assertion fails, wrapper produces information about the frames (in hex).
You can use assertHexEqual/assertHexNotEqual and assertBytesEqual/assertBytesNotEqual in the tests. When the assertion
fails, wrapper produces information about the frames (in hex).

```python
import unittest
from scapy_helper.test_case_extensions.packet_assert import PacketAssert


class TestExample(unittest.TestCase, PacketAssert):
def test_example(self):
self.assertHexEqual(Ether(), Ether("10.10.10.10"), "Frame should be the same")
Expand All @@ -172,9 +227,10 @@ class TestExample(unittest.TestCase, PacketAssert):
self.assertBytesEqual(Ether(), Ether(), "Bytes should be equal")
```


### hex_equal (since v0.1.11)

Return bool status of equality and print status if there is a difference between objects

```python
from scapy_helper import hex_equal

Expand All @@ -183,7 +239,9 @@ assert hex_equal(Ether(), second_ether)
```

## Compare

### table_diff (tdiff as shortcut)

```text
from scapy_helper.compare import Compare
Compare(frame_1, frame_2).table_diff()
Expand Down
2 changes: 2 additions & 0 deletions scapy_helper/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@
from scapy_helper.hexdump import hexdump
from scapy_helper.main import get_hex, show_diff, show_hex, table, hex_equal, diff
from scapy_helper.test_case_extensions.packet_assert import PacketAssert

from scapy_helper.helpers.to_dict import to_dict, to_list
26 changes: 26 additions & 0 deletions scapy_helper/helpers/to_dict.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
__values = (int, float, str, bytes, bool,
list, tuple, set,
dict)


def _layer2dict(frame):
temp_dict = {}

if not getattr(frame, 'fields_desc', None):
return
for _field in frame.fields_desc:
value = getattr(frame, _field.name)
if isinstance(value, type(None)):
value = None
elif not isinstance(value, __values):
value = _layer2dict(value)
temp_dict[_field.name] = value
return {frame.name: temp_dict}


def to_dict(packet, layer=0, extend=False):
return _layer2dict(packet.getlayer(layer))


def to_list(packet, extend=False):
return [_layer2dict(packet.getlayer(x)) for x in range(len(packet.layers()))]
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
long_description_content_type="text/markdown",
author="Nex Sabre",
author_email="nexsabre@protonmail.com",
version="0.10.2",
version="0.11",
url="https://github.com/NexSabre/scapy_helper",
packages=find_packages(),
classifiers=[
Expand Down
43 changes: 43 additions & 0 deletions test/test_to_dict.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
from unittest import TestCase

from scapy.layers.inet import TCP, IP
from scapy.layers.l2 import Ether

from scapy_helper.helpers.to_dict import to_dict, to_list


class TestToDict(TestCase):
def test_simple_dict(self):
packet = Ether(dst="ff:ff:ff:ff:ff:ff", src="00:00:00:00:00:00") / IP() / TCP()
packet_result = {'Ethernet': {'src': '00:00:00:00:00:00', 'dst': 'ff:ff:ff:ff:ff:ff', 'type': 2048}}

to_dict_result = to_dict(packet)

self.assertTrue(isinstance(to_dict_result, dict))
self.assertEqual(to_dict_result, packet_result)

def test_simple_dict_get_second_element(self):
packet = Ether(dst="ff:ff:ff:ff:ff:ff", src="00:00:00:00:00:00") / IP() / TCP()
packet_result = {'IP': {'frag': 0, 'src': '0.0.0.0', 'proto': 6, 'tos': 0, 'dst': '127.0.0.1',
'chksum': None, 'len': None, 'options': [], 'version': 4, 'flags': None,
'ihl': None, 'ttl': 64, 'id': 1}}

to_dict_result = to_dict(packet, layer=1) # layer 1 is IP

self.assertTrue(isinstance(to_dict_result, dict))
self.assertEqual(to_dict_result, packet_result)


class TestToList(TestCase):
def test_simple_list(self):
packet = Ether(dst="ff:ff:ff:ff:ff:ff", src="00:00:00:00:00:00") / IP() / TCP()
packet_result = [{'Ethernet': {'src': '00:00:00:00:00:00', 'dst': 'ff:ff:ff:ff:ff:ff', 'type': 2048}}, {
'IP': {'frag': 0, 'src': '0.0.0.0', 'proto': 6, 'tos': 0, 'dst': '127.0.0.1', 'chksum': None, 'len': None,
'options': [], 'version': 4, 'flags': None, 'ihl': None, 'ttl': 64, 'id': 1}}, {
'TCP': {'reserved': 0, 'seq': 0, 'ack': 0, 'dataofs': None, 'urgptr': 0, 'window': 8192,
'flags': None, 'chksum': None, 'dport': 80, 'sport': 20, 'options': []}}]

to_list_result = to_list(packet)

self.assertTrue(isinstance(to_list_result, list))
self.assertEqual(to_list_result, packet_result)

0 comments on commit 4404cd5

Please sign in to comment.