Skip to content

Commit e77f786

Browse files
authored
Merge pull request #836 from Sahilgill24/feat/resource-management
feat: implementing a resource manager to prevent resource exhaustion attacks
2 parents 2180277 + 3ff8d78 commit e77f786

68 files changed

Lines changed: 13371 additions & 74 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docs/conf.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,21 @@
5050
"sphinx_rtd_theme",
5151
]
5252

53+
# Configure Python domain to prefer canonical imports
54+
# This helps resolve ambiguous references like ResourceManager
55+
python_use_unqualified_type_names = False
56+
57+
# Configure autodoc to prefer specific imports for ambiguous references
58+
autodoc_type_aliases = {
59+
"ResourceManager": "libp2p.rcmgr.ResourceManager",
60+
}
61+
62+
# Suppress specific warnings about ambiguous cross-references
63+
# Since ResourceManager is intentionally re-exported, both locations are valid
64+
suppress_warnings = [
65+
"ref.python", # Suppress ambiguous cross-reference warnings
66+
]
67+
5368
# Add any paths that contain templates here, relative to this directory.
5469
templates_path = ["_templates"]
5570

docs/getting_started.rst

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,25 @@ Now that you have configured a **Transport**, **Crypto** and **Stream Multiplexe
7979
.. literalinclude:: ../examples/doc-examples/example_running.py
8080
:language: python
8181

82+
Resource Management
83+
^^^^^^^^^^^^^^^^^^^
84+
85+
py-libp2p enables resource protection by default. When you create a host with
86+
``new_host()`` (or a network service with ``new_swarm()``), a default
87+
``ResourceManager`` is created automatically if you do not provide one. This
88+
guards connections and streams out of the box.
89+
90+
If you want to customize limits, construct and pass your own manager:
91+
92+
.. code-block:: python
93+
94+
from libp2p import new_host
95+
from libp2p.rcmgr import ResourceLimits, new_resource_manager
96+
97+
limits = ResourceLimits(max_connections=512, max_streams=4096, max_memory_mb=256)
98+
rm = new_resource_manager(limits=limits)
99+
host = new_host(resource_manager=rm)
100+
82101
Custom Setup
83102
~~~~~~~~~~~~
84103

docs/libp2p.rcmgr.rst

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
libp2p.rcmgr package
2+
====================
3+
4+
Submodules
5+
----------
6+
7+
libp2p.rcmgr.allowlist module
8+
-----------------------------
9+
10+
.. automodule:: libp2p.rcmgr.allowlist
11+
:members:
12+
:show-inheritance:
13+
:undoc-members:
14+
15+
libp2p.rcmgr.exceptions module
16+
------------------------------
17+
18+
.. automodule:: libp2p.rcmgr.exceptions
19+
:members:
20+
:show-inheritance:
21+
:undoc-members:
22+
23+
libp2p.rcmgr.limits module
24+
--------------------------
25+
26+
.. automodule:: libp2p.rcmgr.limits
27+
:members:
28+
:show-inheritance:
29+
:undoc-members:
30+
31+
libp2p.rcmgr.manager module
32+
---------------------------
33+
34+
.. automodule:: libp2p.rcmgr.manager
35+
:members:
36+
:show-inheritance:
37+
:undoc-members:
38+
39+
libp2p.rcmgr.metrics module
40+
---------------------------
41+
42+
.. automodule:: libp2p.rcmgr.metrics
43+
:members:
44+
:show-inheritance:
45+
:undoc-members:
46+
47+
48+
Module contents
49+
---------------
50+
51+
.. automodule:: libp2p.rcmgr
52+
:members:
53+
:show-inheritance:
54+
:undoc-members:

docs/libp2p.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ Subpackages
1717
libp2p.peer
1818
libp2p.protocol_muxer
1919
libp2p.pubsub
20+
libp2p.rcmgr
2021
libp2p.records
2122
libp2p.relay
2223
libp2p.security

examples/monitoring-demo/README.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Monitoring Demo
2+
3+
Configure Prometheus target (match exporter port):
4+
```bash
5+
cd examples/monitoring-demo
6+
python configure.py --port 8000 # or: DEMO_EXPORTER_PORT=8010 python configure.py
7+
docker compose up -d
8+
```
9+
10+
Run exporter (auto-picks a free port; you can also set DEMO_EXPORTER_PORT):
11+
```bash
12+
cd ../../
13+
. .venv/bin/activate
14+
python examples/monitoring-demo/run_demo.py # or: DEMO_EXPORTER_PORT=8010 python examples/monitoring-demo/run_demo.py
15+
```
16+
17+
Open UIs:
18+
- Prometheus: http://localhost:9090/targets
19+
- Grafana: http://localhost:3000
20+
21+
Notes:
22+
- The Grafana dashboard `py-libp2p Resource Manager` is auto-provisioned.
23+
- If you change the exporter port, re-run `configure.py` and `docker compose restart prometheus`.
24+
25+
Stop:
26+
```bash
27+
pkill -f run_demo.py || true
28+
cd examples/monitoring-demo
29+
docker compose down
30+
```
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#!/usr/bin/env python3
2+
import argparse
3+
import os
4+
from pathlib import Path
5+
import re
6+
7+
PROM_PATH = Path(__file__).parent / "prometheus.yml"
8+
9+
10+
def set_exporter_port(port: int) -> None:
11+
content = PROM_PATH.read_text()
12+
pattern = r"host\\.docker\\.internal:\\d+"
13+
replacement = f"host.docker.internal:{port}"
14+
new = re.sub(pattern, replacement, content)
15+
PROM_PATH.write_text(new)
16+
print(f"Updated Prometheus target to host.docker.internal:{port}")
17+
18+
19+
def main() -> None:
20+
parser = argparse.ArgumentParser()
21+
parser.add_argument(
22+
"--port",
23+
type=int,
24+
default=int(os.getenv("DEMO_EXPORTER_PORT", "8000")),
25+
)
26+
args = parser.parse_args()
27+
set_exporter_port(args.port)
28+
29+
30+
if __name__ == "__main__":
31+
main()
32+
33+
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
services:
2+
prometheus:
3+
image: prom/prometheus:latest
4+
container_name: py-libp2p-prometheus
5+
ports:
6+
- "9090:9090"
7+
extra_hosts:
8+
- "host.docker.internal:host-gateway"
9+
volumes:
10+
- ./prometheus.yml:/etc/prometheus/prometheus.yml
11+
- prometheus_data:/prometheus
12+
command:
13+
- '--config.file=/etc/prometheus/prometheus.yml'
14+
- '--storage.tsdb.path=/prometheus'
15+
- '--web.enable-lifecycle'
16+
- '--storage.tsdb.retention.time=30d'
17+
restart: unless-stopped
18+
19+
grafana:
20+
image: grafana/grafana:latest
21+
container_name: py-libp2p-grafana
22+
depends_on:
23+
- prometheus
24+
ports:
25+
- "3000:3000"
26+
environment:
27+
- GF_AUTH_DISABLE_LOGIN_FORM=true
28+
- GF_AUTH_ANONYMOUS_ENABLED=true
29+
- GF_AUTH_ANONYMOUS_ORG_ROLE=Admin
30+
- GF_SECURITY_ALLOW_EMBEDDING=true
31+
volumes:
32+
- ./grafana/provisioning/dashboards:/etc/grafana/provisioning/dashboards
33+
- ./grafana/provisioning/datasources:/etc/grafana/provisioning/datasources
34+
- ./grafana/dashboards:/var/lib/grafana/dashboards
35+
- grafana_data:/var/lib/grafana
36+
restart: unless-stopped
37+
38+
volumes:
39+
prometheus_data:
40+
grafana_data:
41+
42+

0 commit comments

Comments
 (0)