Skip to content

Commit 61ce2ca

Browse files
authored
Merge pull request #54 from lawndoc/docker-deploy
Add docker compose file
2 parents 84b07ef + 6a9050d commit 61ce2ca

File tree

3 files changed

+32
-16
lines changed

3 files changed

+32
-16
lines changed

Diff for: Dockerfile

+2-1
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,12 @@ RUN apt-get update && apt-get install --no-install-recommends -y python3.12 pyth
2626
RUN mkdir -p /run
2727
WORKDIR /run
2828
COPY . .
29+
COPY config.json.template /config/config.json
2930
COPY --from=deps /root/venv /root/venv
3031

3132
# prepare runtime environment
3233
USER root
3334
ENV VIRTUAL_ENV=/root/venv
3435
ENV PATH="/root/venv/bin:$PATH"
3536

36-
ENTRYPOINT ["python", "-u", "./respotter.py"]
37+
ENTRYPOINT ["python", "-u", "./respotter.py", "-c", "/config/config.json", "--state-file", "/state/state.json"]

Diff for: docker-compose.yaml

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
version: "3.9"
2+
services:
3+
plexms:
4+
container_name: respotter
5+
image: ghcr.io/lawndoc/respotter:latest
6+
network_mode: host
7+
restart: always
8+
volumes:
9+
- ./config:/config
10+
- ./state:/state

Diff for: respotter.py

+20-15
Original file line numberDiff line numberDiff line change
@@ -33,16 +33,17 @@
3333
class Respotter:
3434
def __init__(self,
3535
delay=30,
36+
discord_webhook="",
3637
excluded_protocols=[],
3738
hostname="Loremipsumdolorsitamet",
39+
slack_webhook="",
40+
state_file="state/state.json",
3841
subnet="",
42+
syslog_address="",
43+
teams_webhook="",
44+
test_webhooks=False,
3945
timeout=1,
4046
verbosity=2,
41-
discord_webhook="",
42-
slack_webhook="",
43-
teams_webhook="",
44-
syslog_address="",
45-
test_webhooks=False
4647
):
4748
# initialize logger
4849
self.log = logging.getLogger('respotter')
@@ -64,9 +65,10 @@ def __init__(self,
6465
self.timeout = timeout
6566
self.verbosity = verbosity
6667
# state persistence
68+
self.state_file = state_file
6769
self.state_lock = Lock()
6870
try:
69-
with open("state/state.json", "r+") as state_file:
71+
with open(self.state_file, "r+") as state_file:
7072
try:
7173
previous_state = json.load(state_file)
7274
self.responder_alerts = previous_state["responder_alerts"]
@@ -82,7 +84,7 @@ def __init__(self,
8284
self.responder_alerts = {}
8385
self.vulnerable_alerts = {}
8486
Path("state").mkdir(parents=True, exist_ok=True)
85-
with open("state/state.json", "w") as state_file:
87+
with open(self.state_file, "w") as state_file:
8688
json.dump({"responder_alerts": {}, "vulnerable_alerts": {}}, state_file)
8789
# get broadcast IP for Netbios
8890
if subnet:
@@ -131,7 +133,7 @@ def webhook_responder_alert(self, responder_ip):
131133
except WebhookException as e:
132134
self.log.error(f"[!] {service.capitalize()} webhook failed: {e}")
133135
self.responder_alerts[responder_ip] = datetime.now()
134-
with open("state/state.json", "r+") as state_file:
136+
with open(self.state_file, "r+") as state_file:
135137
state = json.load(state_file)
136138
new_state = deepcopy(self.responder_alerts)
137139
for ip in new_state:
@@ -159,7 +161,7 @@ def webhook_sniffer_alert(self, protocol, requester_ip, requested_hostname):
159161
self.vulnerable_alerts[requester_ip][protocol] = datetime.now()
160162
else:
161163
self.vulnerable_alerts[requester_ip] = {protocol: datetime.now()}
162-
with open("state/state.json", "r+") as state_file:
164+
with open(self.state_file, "r+") as state_file:
163165
state = json.load(state_file)
164166
new_state = deepcopy(self.vulnerable_alerts)
165167
for ip in new_state:
@@ -327,6 +329,7 @@ def parse_options():
327329
"exclude": "",
328330
"hostname": "Loremipsumdolorsitamet",
329331
"slack_webhook": "",
332+
"state_file": "state/state.json",
330333
"subnet": "",
331334
"syslog_address": "",
332335
"teams_webhook": "",
@@ -352,6 +355,7 @@ def parse_options():
352355
parser.add_argument("-x", "--exclude", help="Protocols to exclude from scanning (e.g. 'llmnr,nbns')")
353356
parser.add_argument("-l", "--syslog-address", help="Syslog server address")
354357
parser.add_argument("--test-webhooks", action="store_true", help="Test configured webhooks")
358+
parser.add_argument("--state-file", help="Path to state file")
355359
args = parser.parse_args(remaining_argv)
356360
if int(args.verbosity) > 4:
357361
print(f"Final config: {args}\n")
@@ -372,16 +376,17 @@ def parse_options():
372376
exit(1)
373377

374378
respotter = Respotter(delay=int(options.delay),
379+
discord_webhook=options.discord_webhook,
375380
excluded_protocols=excluded_protocols,
376381
hostname=options.hostname,
377-
subnet=options.subnet,
378-
timeout=int(options.timeout),
379-
verbosity=int(options.verbosity),
380-
discord_webhook=options.discord_webhook,
381382
slack_webhook=options.slack_webhook,
382-
teams_webhook=options.teams_webhook,
383+
state_file=options.state_file,
384+
subnet=options.subnet,
383385
syslog_address=options.syslog_address,
384-
test_webhooks=options.test_webhooks
386+
teams_webhook=options.teams_webhook,
387+
test_webhooks=options.test_webhooks,
388+
timeout=int(options.timeout),
389+
verbosity=int(options.verbosity)
385390
)
386391

387392
respotter.daemon()

0 commit comments

Comments
 (0)