Skip to content

Commit a6e67e2

Browse files
authored
Merge pull request certtools#2567 from sebix/fake-expert
add new bot to fake data
2 parents 164013f + 748769a commit a6e67e2

File tree

8 files changed

+137
-0
lines changed

8 files changed

+137
-0
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
- `intelmq.bots.experts.securitytxt`:
4444
- Added new bot (PR#2538 by Frank Westers and Sebastian Wagner)
4545
- `intelmq.bots.experts.misp`: Use `PyMISP` class instead of deprecated `ExpandedPyMISP` (PR#2532 by Radek Vyhnal)
46+
- `intelmq.bots.experts.fake.expert`: New expert to fake data (PR#2567 by Sebastian Wagner).
4647

4748
#### Outputs
4849
- `intelmq.bots.outputs.cif3.output`:

docs/user/bots.md

+33
Original file line numberDiff line numberDiff line change
@@ -2682,6 +2682,39 @@ is `$portal_url + '/api/1.0/ripe/contact?cidr=%s'`.
26822682

26832683
---
26842684

2685+
### Fake <div id="intelmq.bots.experts.fake.expert" />
2686+
2687+
Adds fake data to events. Currently supports setting the IP address and network.
2688+
2689+
For each incoming event, the bots chooses one random IP network range from the configured data file.
2690+
It set's the first IP address of the range as `source.ip` and the network itself as `source.network`.
2691+
To adapt the `source.asn` field accordingly, use the [ASN Lookup Expert](#asn-lookup).
2692+
2693+
**Module:** `intelmq.bots.experts.fake.expert`
2694+
2695+
**Parameters:**
2696+
2697+
**`database`**
2698+
2699+
(required, string) Path to a JSON file in the following format:
2700+
```
2701+
{
2702+
"ip_network": [
2703+
"10.0.0.0/8",
2704+
...
2705+
]
2706+
}
2707+
```
2708+
2709+
**`overwrite`**
2710+
2711+
(optional, boolean) Whether to overwrite existing fields. Defaults to false.
2712+
2713+
For data consistency `source.network` will only be set if `source.ip` was set or overridden.
2714+
If overwrite is false, `source.ip` was did not exist before but `source.network` existed before, `source.network` will still be overridden.
2715+
2716+
---
2717+
26852718
### Field Reducer <div id="intelmq.bots.experts.field_reducer.expert" />
26862719

26872720
The field reducer bot is capable of removing fields from events.

intelmq/bots/experts/fake/__init__.py

Whitespace-only changes.

intelmq/bots/experts/fake/expert.py

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# SPDX-FileCopyrightText: 2025 Institute for Common Good Technology, Sebastian Wagner
2+
#
3+
# SPDX-License-Identifier: AGPL-3.0-or-later
4+
5+
from ipaddress import ip_network
6+
from random import choice
7+
from json import load as json_load
8+
9+
from intelmq.lib.bot import ExpertBot
10+
11+
12+
class FakeExpertBot(ExpertBot):
13+
"""Add fake data"""
14+
15+
overwrite: bool = False
16+
database: str = None # TODO: should be pathlib.Path
17+
18+
def init(self):
19+
with open(self.database) as database:
20+
self.networks = json_load(database)['ip_network']
21+
22+
def process(self):
23+
event = self.receive_message()
24+
network = choice(self.networks)
25+
26+
updated = False
27+
try:
28+
updated = event.add('source.ip', ip_network(network)[1], overwrite=self.overwrite)
29+
except IndexError:
30+
updated = event.add('source.ip', ip_network(network)[0], overwrite=self.overwrite)
31+
# For consistency, only set the network if the source.ip was set or overwritten, but then always overwrite it
32+
if updated:
33+
event.add('source.network', network, overwrite=True)
34+
35+
self.send_message(event)
36+
self.acknowledge_message()
37+
38+
def check(parameters: dict):
39+
try:
40+
with open(parameters['database']) as database:
41+
json_load(database)['ip_network']
42+
except Exception as exc:
43+
return [['error', exc]]
44+
45+
46+
BOT = FakeExpertBot

intelmq/tests/bots/experts/fake/__init__.py

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"ip_network": [
3+
"10.0.0.0/8"
4+
]
5+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
SPDX-FileCopyrightText: 2025 Institute for Common Good Technology, Sebastian Wagner
2+
SPDX-License-Identifier: AGPL-3.0-or-later
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# SPDX-FileCopyrightText: 2025 Institute for Common Good Technology, Sebastian Wagner
2+
#
3+
# SPDX-License-Identifier: AGPL-3.0-or-later
4+
5+
import unittest
6+
from json import loads as json_loads
7+
from ipaddress import ip_network, ip_address
8+
9+
import pkg_resources
10+
11+
import intelmq.lib.test as test
12+
from intelmq.bots.experts.fake.expert import FakeExpertBot
13+
14+
FAKE_DB = pkg_resources.resource_filename('intelmq', 'tests/bots/experts/fake/data.json')
15+
EXAMPLE_INPUT = {"__type": "Event",
16+
"source.ip": "93.184.216.34", # example.com
17+
}
18+
NETWOK_EXISTS = {"__type": "Event",
19+
"source.network": "93.184.216.0/24",
20+
}
21+
22+
class TestFakeExpertBot(test.BotTestCase, unittest.TestCase):
23+
24+
@classmethod
25+
def set_bot(cls):
26+
cls.bot_reference = FakeExpertBot
27+
cls.sysconfig = {'database': FAKE_DB}
28+
29+
def test_nochange(self):
30+
self.input_message = EXAMPLE_INPUT
31+
self.run_bot()
32+
self.assertMessageEqual(0, EXAMPLE_INPUT)
33+
34+
def test_overwrite(self):
35+
self.input_message = EXAMPLE_INPUT
36+
self.run_bot(parameters={'overwrite': True})
37+
msg = json_loads(self.get_output_queue()[0])
38+
self.assertIn(ip_address(msg['source.ip']), ip_network("10.0.0.0/8"))
39+
self.assertEqual(msg['source.network'], "10.0.0.0/8")
40+
41+
def test_network_exists(self):
42+
self.input_message = NETWOK_EXISTS
43+
self.run_bot(parameters={'overwrite': False})
44+
msg = json_loads(self.get_output_queue()[0])
45+
self.assertIn(ip_address(msg['source.ip']), ip_network("10.0.0.0/8"))
46+
self.assertEqual(msg['source.network'], "10.0.0.0/8")
47+
48+
49+
if __name__ == '__main__': # pragma: no cover
50+
unittest.main()

0 commit comments

Comments
 (0)