|
1 | 1 | from bbot.modules.base import BaseModule |
| 2 | +import time |
2 | 3 |
|
3 | 4 |
|
4 | 5 | class shodan_idb(BaseModule): |
@@ -46,23 +47,48 @@ class shodan_idb(BaseModule): |
46 | 47 | "created_date": "2023-12-22", |
47 | 48 | "author": "@TheTechromancer", |
48 | 49 | } |
| 50 | + options = {"retries": None} |
| 51 | + options_desc = { |
| 52 | + "retries": "How many times to retry API requests (e.g. after a 429 error). Overrides the global web.api_retries setting." |
| 53 | + } |
49 | 54 |
|
50 | | - # we get lots of 404s, that's normal |
| 55 | + # we typically don't want to abort this module |
51 | 56 | _api_failure_abort_threshold = 9999999999 |
52 | 57 |
|
53 | | - # there aren't any rate limits to speak of, so our outgoing queue can be pretty big |
54 | | - _qsize = 500 |
| 58 | + # since there are rate limits, we set a lower qsize |
| 59 | + # this way when our queue is full, we can give the API a break |
| 60 | + _qsize = 100 |
55 | 61 |
|
56 | 62 | base_url = "https://internetdb.shodan.io" |
57 | 63 |
|
| 64 | + async def setup(self): |
| 65 | + await super().setup() |
| 66 | + self.last_request_time = 0 |
| 67 | + return True |
| 68 | + |
58 | 69 | def _incoming_dedup_hash(self, event): |
59 | 70 | return hash(self.get_ip(event)) |
60 | 71 |
|
| 72 | + @property |
| 73 | + def api_retries(self): |
| 74 | + # allow the module to override global retry setting |
| 75 | + return self.config.get("retries", None) or super().api_retries |
| 76 | + |
61 | 77 | async def handle_event(self, event): |
62 | 78 | ip = self.get_ip(event) |
63 | 79 | if ip is None: |
64 | 80 | return |
65 | 81 | url = f"{self.base_url}/{ip}" |
| 82 | + |
| 83 | + # Rate limiting: ensure at least 1 second between requests |
| 84 | + current_time = time.time() |
| 85 | + time_since_last = current_time - self.last_request_time |
| 86 | + if time_since_last < 1: |
| 87 | + await self.helpers.sleep(1 - time_since_last) |
| 88 | + |
| 89 | + # Update the last request time |
| 90 | + self.last_request_time = time.time() |
| 91 | + |
66 | 92 | r = await self.api_request(url) |
67 | 93 | if r is None: |
68 | 94 | self.debug(f"No response for {event.data}") |
|
0 commit comments