Skip to content

Commit

Permalink
Merge pull request #54 from lawndoc/docker-deploy
Browse files Browse the repository at this point in the history
Add docker compose file
  • Loading branch information
lawndoc authored Jul 17, 2024
2 parents 84b07ef + 6a9050d commit 61ce2ca
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 16 deletions.
3 changes: 2 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,12 @@ RUN apt-get update && apt-get install --no-install-recommends -y python3.12 pyth
RUN mkdir -p /run
WORKDIR /run
COPY . .
COPY config.json.template /config/config.json
COPY --from=deps /root/venv /root/venv

# prepare runtime environment
USER root
ENV VIRTUAL_ENV=/root/venv
ENV PATH="/root/venv/bin:$PATH"

ENTRYPOINT ["python", "-u", "./respotter.py"]
ENTRYPOINT ["python", "-u", "./respotter.py", "-c", "/config/config.json", "--state-file", "/state/state.json"]
10 changes: 10 additions & 0 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
version: "3.9"
services:
plexms:
container_name: respotter
image: ghcr.io/lawndoc/respotter:latest
network_mode: host
restart: always
volumes:
- ./config:/config
- ./state:/state
35 changes: 20 additions & 15 deletions respotter.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,17 @@
class Respotter:
def __init__(self,
delay=30,
discord_webhook="",
excluded_protocols=[],
hostname="Loremipsumdolorsitamet",
slack_webhook="",
state_file="state/state.json",
subnet="",
syslog_address="",
teams_webhook="",
test_webhooks=False,
timeout=1,
verbosity=2,
discord_webhook="",
slack_webhook="",
teams_webhook="",
syslog_address="",
test_webhooks=False
):
# initialize logger
self.log = logging.getLogger('respotter')
Expand All @@ -64,9 +65,10 @@ def __init__(self,
self.timeout = timeout
self.verbosity = verbosity
# state persistence
self.state_file = state_file
self.state_lock = Lock()
try:
with open("state/state.json", "r+") as state_file:
with open(self.state_file, "r+") as state_file:
try:
previous_state = json.load(state_file)
self.responder_alerts = previous_state["responder_alerts"]
Expand All @@ -82,7 +84,7 @@ def __init__(self,
self.responder_alerts = {}
self.vulnerable_alerts = {}
Path("state").mkdir(parents=True, exist_ok=True)
with open("state/state.json", "w") as state_file:
with open(self.state_file, "w") as state_file:
json.dump({"responder_alerts": {}, "vulnerable_alerts": {}}, state_file)
# get broadcast IP for Netbios
if subnet:
Expand Down Expand Up @@ -131,7 +133,7 @@ def webhook_responder_alert(self, responder_ip):
except WebhookException as e:
self.log.error(f"[!] {service.capitalize()} webhook failed: {e}")
self.responder_alerts[responder_ip] = datetime.now()
with open("state/state.json", "r+") as state_file:
with open(self.state_file, "r+") as state_file:
state = json.load(state_file)
new_state = deepcopy(self.responder_alerts)
for ip in new_state:
Expand Down Expand Up @@ -159,7 +161,7 @@ def webhook_sniffer_alert(self, protocol, requester_ip, requested_hostname):
self.vulnerable_alerts[requester_ip][protocol] = datetime.now()
else:
self.vulnerable_alerts[requester_ip] = {protocol: datetime.now()}
with open("state/state.json", "r+") as state_file:
with open(self.state_file, "r+") as state_file:
state = json.load(state_file)
new_state = deepcopy(self.vulnerable_alerts)
for ip in new_state:
Expand Down Expand Up @@ -327,6 +329,7 @@ def parse_options():
"exclude": "",
"hostname": "Loremipsumdolorsitamet",
"slack_webhook": "",
"state_file": "state/state.json",
"subnet": "",
"syslog_address": "",
"teams_webhook": "",
Expand All @@ -352,6 +355,7 @@ def parse_options():
parser.add_argument("-x", "--exclude", help="Protocols to exclude from scanning (e.g. 'llmnr,nbns')")
parser.add_argument("-l", "--syslog-address", help="Syslog server address")
parser.add_argument("--test-webhooks", action="store_true", help="Test configured webhooks")
parser.add_argument("--state-file", help="Path to state file")
args = parser.parse_args(remaining_argv)
if int(args.verbosity) > 4:
print(f"Final config: {args}\n")
Expand All @@ -372,16 +376,17 @@ def parse_options():
exit(1)

respotter = Respotter(delay=int(options.delay),
discord_webhook=options.discord_webhook,
excluded_protocols=excluded_protocols,
hostname=options.hostname,
subnet=options.subnet,
timeout=int(options.timeout),
verbosity=int(options.verbosity),
discord_webhook=options.discord_webhook,
slack_webhook=options.slack_webhook,
teams_webhook=options.teams_webhook,
state_file=options.state_file,
subnet=options.subnet,
syslog_address=options.syslog_address,
test_webhooks=options.test_webhooks
teams_webhook=options.teams_webhook,
test_webhooks=options.test_webhooks,
timeout=int(options.timeout),
verbosity=int(options.verbosity)
)

respotter.daemon()

0 comments on commit 61ce2ca

Please sign in to comment.