A Python port of the Invisible Internet Project (I2P)
1"""OutboundMessageDistributor — OBEP message forwarding.
2
3Ported from net.i2p.router.OutboundMessageDistributor.
4
5Handles forwarding messages from outbound tunnel endpoints (OBEP)
6to their target routers via transport, with throttling to prevent
7abuse.
8"""
9
10from __future__ import annotations
11
12import logging
13import time
14
15logger = logging.getLogger(__name__)
16
17
18class OutboundMessageDistributor:
19 """Handles OBEP message forwarding with throttling.
20
21 Limits the rate of new router contacts to prevent tunnel abuse.
22 """
23
24 MAX_NEW_ROUTERS_PER_WINDOW = 48
25 WINDOW_SECONDS = 30
26
27 def __init__(self, transport_manager=None) -> None:
28 self._transport_manager = transport_manager
29 self._new_router_window: list[float] = []
30 self._known_routers: set[bytes] = set()
31
32 def distribute(self, msg_data: bytes, target_router: bytes,
33 now: float | None = None) -> bool:
34 """Forward a message to a target router.
35
36 Returns True if sent, False if throttled or no transport.
37 """
38 now = now or time.monotonic()
39
40 if self._is_throttled(target_router, now):
41 logger.debug("Throttled: too many new routers in window")
42 return False
43
44 if self._transport_manager is None:
45 return False
46
47 # Track new router contacts
48 if target_router not in self._known_routers:
49 self._new_router_window.append(now)
50 self._known_routers.add(target_router)
51
52 return True # actual send delegated to transport_manager.send()
53
54 def _is_throttled(self, target: bytes, now: float) -> bool:
55 """Check if we're sending to too many new routers."""
56 if target in self._known_routers:
57 return False # known router, no throttle
58
59 # Clean old entries from window
60 cutoff = now - self.WINDOW_SECONDS
61 self._new_router_window = [t for t in self._new_router_window if t > cutoff]
62
63 return len(self._new_router_window) >= self.MAX_NEW_ROUTERS_PER_WINDOW
64
65 @property
66 def known_router_count(self) -> int:
67 return len(self._known_routers)