feat: add infrastructure automation and diagnostic scripts for Zabbix, Nginx, and Authentik

This commit is contained in:
2026-11-12 20:18:37 -05:00
parent 68c108cfe8
commit 336b7759d0
25 changed files with 472 additions and 41 deletions

View File

@@ -0,0 +1,22 @@
import paramiko
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect('140.44.4.71', username='root', key_filename=r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet', timeout=10)
def run(cmd):
print(f">>> {cmd}")
_, o, e = ssh.exec_command(cmd)
out = o.read().decode().strip()
err = e.read().decode().strip()
if out:
print(out)
if err:
print("[stderr]", err)
run("iptables -I FORWARD 1 -m state --state RELATED,ESTABLISHED -j ACCEPT")
run("iptables -I FORWARD 2 -p tcp -d 140.44.4.64 --dport 10051 -j ACCEPT")
run("iptables -L FORWARD -n -v | head -n 8")
ssh.close()

View File

@@ -0,0 +1,32 @@
import json, ssl, urllib.request
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
ZABBIX_URL = 'http://140.44.4.60:8888/api_jsonrpc.php'
payload = {'jsonrpc': '2.0', 'method': 'user.login', 'params': {'username': 'Admin', 'password': 'zabbix'}, 'id': 1}
req = urllib.request.Request(ZABBIX_URL, data=json.dumps(payload).encode(), headers={'Content-Type': 'application/json-rpc'})
token = json.loads(urllib.request.urlopen(req, context=ctx).read())['result']
media_payload = {
'jsonrpc': '2.0',
'method': 'user.update',
'params': {
'userid': '3',
'medias': [
{
'mediatypeid': '70',
'sendto': 'snarf@snarfnet.net',
'active': 0,
'severity': 63, # 1+2+4+8+16+32
'period': '1-7,00:00-24:00'
}
]
},
'id': 2
}
req = urllib.request.Request(ZABBIX_URL, data=json.dumps(media_payload).encode(), headers={'Content-Type': 'application/json-rpc', 'Authorization': f'Bearer {token}'})
res = json.loads(urllib.request.urlopen(req, context=ctx).read())
print("User update result:", res)

View File

@@ -34,6 +34,8 @@ location = /topology.html {
error_page 401 = @goauthentik_proxy_signin;
auth_request_set $auth_cookie $upstream_http_set_cookie;
add_header Set-Cookie $auth_cookie;
add_header Cache-Control "no-cache, no-store, must-revalidate";
expires 0;
alias /data/topology/snarfnet_homelab_topology.html;
default_type text/html;
@@ -45,6 +47,8 @@ location = /topology.png {
error_page 401 = @goauthentik_proxy_signin;
auth_request_set $auth_cookie $upstream_http_set_cookie;
add_header Set-Cookie $auth_cookie;
add_header Cache-Control "no-cache, no-store, must-revalidate";
expires 0;
alias /data/topology/snarfnet_homelab_topology.png;
default_type image/png;
@@ -55,6 +59,8 @@ location = /snarfnet_homelab_topology.html {
error_page 401 = @goauthentik_proxy_signin;
auth_request_set $auth_cookie $upstream_http_set_cookie;
add_header Set-Cookie $auth_cookie;
add_header Cache-Control "no-cache, no-store, must-revalidate";
expires 0;
alias /data/topology/snarfnet_homelab_topology.html;
default_type text/html;
@@ -65,13 +71,14 @@ location = /snarfnet_homelab_topology.png {
error_page 401 = @goauthentik_proxy_signin;
auth_request_set $auth_cookie $upstream_http_set_cookie;
add_header Set-Cookie $auth_cookie;
add_header Cache-Control "no-cache, no-store, must-revalidate";
expires 0;
alias /data/topology/snarfnet_homelab_topology.png;
default_type image/png;
}
"""
# Upload adv_config to a file on remote
stdin, stdout, stderr = c.exec_command("cat > /tmp/adv_config_h21.txt")
stdin.write(adv_config)
stdin.close()
@@ -85,11 +92,7 @@ conf_path = '/var/lib/docker/volumes/nginx-proxy-manager_nginx-data/_data/nginx/
with open('/tmp/adv_config_h21.txt', 'r') as f:
adv = f.read()
# 1. Backup
shutil.copy(db_path, db_path + '.bak_authentik')
shutil.copy(conf_path, conf_path + '.bak_authentik')
# 2. Update DB
# Update DB
conn = sqlite3.connect(db_path)
cur = conn.cursor()
cur.execute("UPDATE proxy_host SET advanced_config = ? WHERE id = 21", (adv,))
@@ -97,21 +100,29 @@ conn.commit()
conn.close()
print("Updated database for host 21.")
# 3. Read conf, replace or insert adv
# Update 21.conf
with open(conf_path, 'r') as f:
conf = f.read()
if '# Buffer tuning for Authentik headers' not in conf:
# Strip existing adv_config block if present
tag = '# Buffer tuning for Authentik headers'
if tag in conf:
idx_start = conf.find(tag)
idx_end = conf.find('location / {', idx_start)
if idx_start != -1 and idx_end != -1:
new_conf = conf[:idx_start] + adv + "\\n\\n " + conf[idx_end:]
else:
new_conf = conf
else:
idx = conf.find('location / {')
if idx != -1:
new_conf = conf[:idx] + adv + "\\n\\n " + conf[idx:]
else:
new_conf = conf.rstrip().rstrip('}') + "\\n\\n" + adv + "\\n}\\n"
with open(conf_path, 'w') as f:
f.write(new_conf)
print("Updated 21.conf.")
else:
print("21.conf already has Authentik configuration.")
with open(conf_path, 'w') as f:
f.write(new_conf)
print("Updated 21.conf.")
"""
stdin, stdout, stderr = c.exec_command("cat > /tmp/apply_h21.py")
@@ -123,7 +134,6 @@ stdin, stdout, stderr = c.exec_command("python3 /tmp/apply_h21.py")
print("Remote python stdout:", stdout.read().decode())
print("Remote python stderr:", stderr.read().decode())
# Test nginx config inside container
stdin, stdout, stderr = c.exec_command("docker exec $(docker ps -q --filter 'name=nginx-proxy-manager_app') nginx -t")
out = stdout.read().decode()
err = stderr.read().decode()
@@ -135,9 +145,5 @@ if "successful" in out or "successful" in err:
stdin, stdout, stderr = c.exec_command("docker exec $(docker ps -q --filter 'name=nginx-proxy-manager_app') nginx -s reload")
print("Reload stdout:", stdout.read().decode())
print("Reload stderr:", stderr.read().decode())
else:
print("FAILED nginx -t test! Restoring backups...")
c.exec_command("cp /var/lib/docker/volumes/nginx-proxy-manager_nginx-data/_data/nginx/proxy_host/21.conf.bak_authentik /var/lib/docker/volumes/nginx-proxy-manager_nginx-data/_data/nginx/proxy_host/21.conf")
c.exec_command("cp /var/lib/docker/volumes/nginx-proxy-manager_nginx-data/_data/database.sqlite.bak_authentik /var/lib/docker/volumes/nginx-proxy-manager_nginx-data/_data/database.sqlite")
c.close()

View File

@@ -0,0 +1,48 @@
import json, ssl, urllib.request
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
ZABBIX_URL = "http://140.44.4.60:8888/api_jsonrpc.php"
def zbx_req(method, params, token=None):
payload = {'jsonrpc': '2.0', 'method': method, 'params': params, 'id': 1}
headers = {'Content-Type': 'application/json-rpc'}
if token:
headers['Authorization'] = f'Bearer {token}'
req = urllib.request.Request(ZABBIX_URL, data=json.dumps(payload).encode('utf-8'), headers=headers, method='POST')
with urllib.request.urlopen(req, timeout=10, context=ctx) as r:
return json.loads(r.read().decode())['result']
token = zbx_req('user.login', {'username': 'Admin', 'password': 'zabbix'})
print("Zabbix Auth Token:", token)
# 1. Actions
actions = zbx_req('action.get', {'output': 'extend', 'selectOperations': 'extend', 'selectFilter': 'extend'}, token)
print("\n=== TRIGGER ACTIONS ===")
for a in actions:
print(f"ID: {a['actionid']}, Name: {a['name']}, Status (0=enabled, 1=disabled): {a['status']}, EventSource: {a['eventsource']}")
print(f" Operations: {a.get('operations')}")
print(f" Filter: {a.get('filter')}")
# 2. Media Types
media_types = zbx_req('mediatype.get', {'output': 'extend'}, token)
print("\n=== MEDIA TYPES ===")
for m in media_types:
print(f"ID: {m['mediatypeid']}, Name: {m['name']}, Type: {m['type']}, Status: {m['status']}")
# 3. User Media
users = zbx_req('user.get', {'output': ['userid', 'username'], 'selectMedias': 'extend'}, token)
print("\n=== USERS & MEDIA ===")
for u in users:
print(f"User: {u['username']} (ID: {u['userid']})")
for med in u.get('medias', []):
print(f" Media: mediatypeid={med['mediatypeid']}, sendto={med['sendto']}, active={med['active']}, severity={med['severity']}")
# 4. Recent Alerts
alerts = zbx_req('alert.get', {'output': 'extend', 'limit': 15, 'sortfield': 'clock', 'sortorder': 'DESC'}, token)
print("\n=== RECENT ALERTS ===")
for al in alerts:
print(f"Alert ID: {al['alertid']}, ActionID: {al['actionid']}, Clock: {al['clock']}, Error: {al.get('error')}, Status: {al.get('status')}, Subject: {al.get('subject')}")

View File

@@ -7,3 +7,4 @@ cmd = "docker exec $(docker ps -q --filter name=nginx-proxy-manager_app) cat /da
_, o, _ = c.exec_command(cmd)
print(o.read().decode())
c.close()

View File

@@ -0,0 +1,19 @@
import json, ssl, urllib.request
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
ZABBIX_URL = 'http://140.44.4.60:8888/api_jsonrpc.php'
payload = {'jsonrpc': '2.0', 'method': 'user.login', 'params': {'username': 'Admin', 'password': 'zabbix'}, 'id': 1}
req = urllib.request.Request(ZABBIX_URL, data=json.dumps(payload).encode(), headers={'Content-Type': 'application/json-rpc'})
token = json.loads(urllib.request.urlopen(req, context=ctx).read())['result']
payload = {'jsonrpc': '2.0', 'method': 'alert.get', 'params': {'output': 'extend', 'limit': 20, 'sortfield': 'clock', 'sortorder': 'DESC'}, 'id': 2}
req = urllib.request.Request(ZABBIX_URL, data=json.dumps(payload).encode(), headers={'Content-Type': 'application/json-rpc', 'Authorization': f'Bearer {token}'})
alerts = json.loads(urllib.request.urlopen(req, context=ctx).read())['result']
for a in alerts:
print(f"ID: {a['alertid']} | Status: {a['status']} | User: {a['userid']} | Error: '{a.get('error')}' | Subject: {a.get('subject')}")

View File

@@ -22,3 +22,4 @@ print("\n=== Authentik Outposts ===")
outposts = req("outposts/instances/")
for o in outposts.get("results", []):
print(o["pk"], o["name"], o["type"], [p for p in o.get("providers", [])])

View File

@@ -13,3 +13,4 @@ for pat in [r'href="([^"]+)"', r'src="([^"]+)"']:
for m in matches:
if any(k in m for k in ['argo', 'tempest', 'weather', 'icon', 'png', 'svg']):
print(m)

20
scripts/check_nat.py Normal file
View File

@@ -0,0 +1,20 @@
import paramiko
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect('140.44.4.71', username='root', key_filename=r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet', timeout=10)
def run(cmd):
print(f">>> {cmd}")
_, o, e = ssh.exec_command(cmd)
print(o.read().decode().strip())
err = e.read().decode().strip()
if err:
print("[stderr]", err)
run("iptables -t nat -L PREROUTING -n -v")
run("iptables -t nat -L POSTROUTING -n -v")
run("sysctl net.ipv4.ip_forward")
ssh.close()

View File

@@ -0,0 +1,20 @@
import paramiko
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect('140.44.4.71', username='root', key_filename=r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet', timeout=10)
stdin, stdout, stderr = ssh.exec_command("docker ps --filter 'name=nginx-proxy-manager_app' --format '{{.Ports}}'")
print("NPM Container Ports:")
print(stdout.read().decode())
stdin, stdout, stderr = ssh.exec_command("docker inspect $(docker ps -q --filter 'name=nginx-proxy-manager_app') --format '{{json .HostConfig.PortBindings}}'")
print("NPM HostConfig PortBindings:")
print(stdout.read().decode())
stdin, stdout, stderr = ssh.exec_command("docker inspect $(docker ps -q --filter 'name=nginx-proxy-manager_app') --format '{{.HostConfig.NetworkMode}}'")
print("NPM NetworkMode:")
print(stdout.read().decode())
ssh.close()

View File

@@ -0,0 +1,11 @@
import paramiko
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect('140.44.4.71', username='root', key_filename=r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet', timeout=10)
stdin, stdout, stderr = ssh.exec_command("python3 -c \"import sqlite3; con = sqlite3.connect('/var/lib/docker/volumes/nginx-proxy-manager_nginx-data/_data/database.sqlite'); print(list(con.execute('SELECT id, incoming_port, forwarding_host, forwarding_port, is_deleted FROM stream')))\"")
print("STREAMS:", stdout.read().decode())
print("ERR:", stderr.read().decode())
ssh.close()

View File

@@ -0,0 +1,24 @@
import json, ssl, urllib.request
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
ZABBIX_URL = 'http://140.44.4.60:8888/api_jsonrpc.php'
payload = {'jsonrpc': '2.0', 'method': 'user.login', 'params': {'username': 'Admin', 'password': 'zabbix'}, 'id': 1}
req = urllib.request.Request(ZABBIX_URL, data=json.dumps(payload).encode(), headers={'Content-Type': 'application/json-rpc'})
token = json.loads(urllib.request.urlopen(req, context=ctx).read())['result']
payload = {'jsonrpc': '2.0', 'method': 'problem.get', 'params': {'output': 'extend'}, 'id': 2}
req = urllib.request.Request(ZABBIX_URL, data=json.dumps(payload).encode(), headers={'Content-Type': 'application/json-rpc', 'Authorization': f'Bearer {token}'})
problems = json.loads(urllib.request.urlopen(req, context=ctx).read())['result']
for p in problems:
if 'active checks' in p['name'].lower():
# Get event
ep = {'jsonrpc': '2.0', 'method': 'event.get', 'params': {'eventids': [p['eventid']], 'selectHosts': ['host', 'name']}, 'id': 3}
er = urllib.request.Request(ZABBIX_URL, data=json.dumps(ep).encode(), headers={'Content-Type': 'application/json-rpc', 'Authorization': f'Bearer {token}'})
events = json.loads(urllib.request.urlopen(er, context=ctx).read())['result']
print(f"Problem: {p['name']} | Event: {events}")

View File

@@ -0,0 +1,23 @@
import json, ssl, urllib.request
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
ZABBIX_URL = 'http://140.44.4.60:8888/api_jsonrpc.php'
payload = {'jsonrpc': '2.0', 'method': 'user.login', 'params': {'username': 'Admin', 'password': 'zabbix'}, 'id': 1}
req = urllib.request.Request(ZABBIX_URL, data=json.dumps(payload).encode(), headers={'Content-Type': 'application/json-rpc'})
token = json.loads(urllib.request.urlopen(req, context=ctx).read())['result']
payload = {'jsonrpc': '2.0', 'method': 'problem.get', 'params': {'output': 'extend', 'selectAcknowledges': 'extend'}, 'id': 2}
req = urllib.request.Request(ZABBIX_URL, data=json.dumps(payload).encode(), headers={'Content-Type': 'application/json-rpc', 'Authorization': f'Bearer {token}'})
resp = json.loads(urllib.request.urlopen(req, context=ctx).read())
if 'error' in resp:
print("API Error:", resp['error'])
else:
problems = resp['result']
print(f"Total problems: {len(problems)}")
for p in problems:
if 'agent' in p['name'].lower():
print(f" - EventID: {p['eventid']} | Severity: {p['severity']} | Name: {p['name']}")

View File

@@ -0,0 +1,19 @@
import json, ssl, urllib.request
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
ZABBIX_URL = 'http://140.44.4.60:8888/api_jsonrpc.php'
payload = {'jsonrpc': '2.0', 'method': 'user.login', 'params': {'username': 'Admin', 'password': 'zabbix'}, 'id': 1}
req = urllib.request.Request(ZABBIX_URL, data=json.dumps(payload).encode(), headers={'Content-Type': 'application/json-rpc'})
token = json.loads(urllib.request.urlopen(req, context=ctx).read())['result']
payload = {'jsonrpc': '2.0', 'method': 'event.get', 'params': {'eventids': ['82136', '82113'], 'selectHosts': ['host', 'name']}, 'id': 2}
req = urllib.request.Request(ZABBIX_URL, data=json.dumps(payload).encode(), headers={'Content-Type': 'application/json-rpc', 'Authorization': f'Bearer {token}'})
events = json.loads(urllib.request.urlopen(req, context=ctx).read())['result']
for e in events:
print(f"Event {e['eventid']}: name={e['name']}, hosts={e.get('hosts')}")

View File

@@ -0,0 +1,23 @@
import paramiko
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# Let's check Spaceport master 140.44.4.41 for CoreDNS / Kubernetes or Pi-hole
ssh.connect('140.44.4.41', username='root', key_filename=r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet', timeout=10)
def run(cmd):
print(f">>> {cmd}")
_, o, e = ssh.exec_command(cmd)
out = o.read().decode().strip()
err = e.read().decode().strip()
if out:
print(out)
if err:
print("[stderr]", err)
run("kubectl get svc -n monitoring")
run("kubectl get pods -n monitoring")
run("kubectl logs deployment/zabbix-zabbix-server -n monitoring -c zabbix-server --tail=50")
ssh.close()

View File

@@ -1,35 +1,32 @@
import paramiko
import paramiko, os
c = paramiko.SSHClient()
c.set_missing_host_key_policy(paramiko.AutoAddPolicy())
c.connect("140.44.4.71", username="root", key_filename=r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet', timeout=10)
# Create /data/topology directory on host
c.exec_command("mkdir -p /var/lib/docker/volumes/nginx-proxy-manager_nginx-data/_data/topology")
sftp = c.open_sftp()
# Read topology files locally
with open('docs/snarfnet_homelab_topology.html', 'r', encoding='utf-8') as f:
html_data = f.read()
remote_dir = "/var/lib/docker/volumes/nginx-proxy-manager_nginx-data/_data/topology"
c.exec_command(f"mkdir -p {remote_dir}")
with open('docs/snarfnet_homelab_topology.png', 'rb') as f:
png_data = f.read()
local_html = os.path.abspath("docs/snarfnet_homelab_topology.html")
local_png = os.path.abspath("docs/snarfnet_homelab_topology.png")
# Send html
stdin, stdout, stderr = c.exec_command("cat > /var/lib/docker/volumes/nginx-proxy-manager_nginx-data/_data/topology/snarfnet_homelab_topology.html")
stdin.write(html_data)
stdin.close()
stdout.read()
print(f"Uploading HTML ({os.path.getsize(local_html)} bytes)...")
sftp.put(local_html, f"{remote_dir}/snarfnet_homelab_topology.html")
# Send png
stdin, stdout, stderr = c.exec_command("cat > /var/lib/docker/volumes/nginx-proxy-manager_nginx-data/_data/topology/snarfnet_homelab_topology.png")
stdin.write(png_data)
stdin.close()
stdout.read()
print(f"Uploading PNG ({os.path.getsize(local_png)} bytes)...")
sftp.put(local_png, f"{remote_dir}/snarfnet_homelab_topology.png")
# Verify files inside NPM container
cmd = "docker exec $(docker ps -q --filter name=nginx-proxy-manager_app) ls -la /data/topology"
_, o, e = c.exec_command(cmd)
print("Files inside NPM container at /data/topology:\n" + o.read().decode())
print("Stderr:\n" + e.read().decode())
sftp.close()
# Verify files inside container
stdin, stdout, stderr = c.exec_command("docker exec $(docker ps -q --filter name=nginx-proxy-manager_app) ls -la /data/topology")
print("Container /data/topology:")
print(stdout.read().decode())
# Check md5sum locally and remotely
stdin, stdout, stderr = c.exec_command(f"md5sum {remote_dir}/*")
print("Remote md5sum:\n", stdout.read().decode())
c.close()

View File

@@ -0,0 +1,22 @@
import paramiko
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect('140.44.4.71', username='root', key_filename=r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet', timeout=10)
def run(cmd):
print(f">>> {cmd}")
_, o, e = ssh.exec_command(cmd)
out = o.read().decode().strip()
err = e.read().decode().strip()
if out:
print(out)
if err:
print("[stderr]", err)
run("systemctl status zabbix-agent2")
run("grep -E '^Server|^Hostname|^HostMetadata' /etc/zabbix/zabbix_agent2.conf")
run("tail -n 25 /var/log/zabbix/zabbix_agent2.log")
ssh.close()

View File

@@ -0,0 +1,24 @@
import paramiko, time
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect('140.44.4.71', username='root', key_filename=r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet', timeout=10)
def run(cmd):
print(f">>> {cmd}")
_, o, e = ssh.exec_command(cmd)
out = o.read().decode().strip()
err = e.read().decode().strip()
if out:
print(out)
if err:
print("[stderr]", err)
run("iptables -t nat -I OUTPUT 1 -p tcp -d 140.44.4.70 --dport 10051 -j DNAT --to-destination 140.44.4.64:10051")
run("iptables -t nat -I OUTPUT 2 -p tcp -d 140.44.4.71 --dport 10051 -j DNAT --to-destination 140.44.4.64:10051")
run("systemctl restart zabbix-agent2")
time.sleep(3)
run("tail -n 15 /var/log/zabbix/zabbix_agent2.log")
ssh.close()

View File

@@ -0,0 +1,13 @@
import paramiko
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect('140.44.4.71', username='root', key_filename=r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet', timeout=10)
cmd = "docker exec $(docker ps -q --filter 'name=nginx-proxy-manager_app') cat /etc/nginx/conf.d/include/assets.conf"
stdin, stdout, stderr = ssh.exec_command(cmd)
print("--- assets.conf ---")
print(stdout.read().decode())
ssh.close()

View File

@@ -23,3 +23,4 @@ stdout.read()
stdin, stdout, stderr = c.exec_command("python3 /tmp/check_adv.py")
print(stdout.read().decode())
c.close()

View File

@@ -12,3 +12,4 @@ _, o, _ = c.exec_command(cmd)
print("Mounts:\n" + o.read().decode())
c.close()

View File

@@ -0,0 +1,39 @@
import paramiko
def apply_to_host(ip):
print(f"=== Applying to {ip} ===")
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(ip, username='root', key_filename=r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet', timeout=10)
commands = [
"iptables -t nat -C PREROUTING -p tcp --dport 10051 -j DNAT --to-destination 140.44.4.64:10051 2>/dev/null || iptables -t nat -I PREROUTING 1 -p tcp --dport 10051 -j DNAT --to-destination 140.44.4.64:10051",
"iptables -t nat -C POSTROUTING -p tcp -d 140.44.4.64 --dport 10051 -j MASQUERADE 2>/dev/null || iptables -t nat -I POSTROUTING 1 -p tcp -d 140.44.4.64 --dport 10051 -j MASQUERADE",
"iptables -t nat -C OUTPUT -p tcp -d 140.44.4.70 --dport 10051 -j DNAT --to-destination 140.44.4.64:10051 2>/dev/null || iptables -t nat -I OUTPUT 1 -p tcp -d 140.44.4.70 --dport 10051 -j DNAT --to-destination 140.44.4.64:10051",
"iptables -t nat -C OUTPUT -p tcp -d 140.44.4.71 --dport 10051 -j DNAT --to-destination 140.44.4.64:10051 2>/dev/null || iptables -t nat -I OUTPUT 2 -p tcp -d 140.44.4.71 --dport 10051 -j DNAT --to-destination 140.44.4.64:10051",
"iptables -t nat -C OUTPUT -p tcp -d 140.44.4.72 --dport 10051 -j DNAT --to-destination 140.44.4.64:10051 2>/dev/null || iptables -t nat -I OUTPUT 3 -p tcp -d 140.44.4.72 --dport 10051 -j DNAT --to-destination 140.44.4.64:10051",
"iptables -C FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT 2>/dev/null || iptables -I FORWARD 1 -m state --state RELATED,ESTABLISHED -j ACCEPT",
"iptables -C FORWARD -p tcp -d 140.44.4.64 --dport 10051 -j ACCEPT 2>/dev/null || iptables -I FORWARD 2 -p tcp -d 140.44.4.64 --dport 10051 -j ACCEPT",
"sysctl -w net.ipv4.ip_forward=1",
"which iptables-save"
]
for cmd in commands:
_, o, e = ssh.exec_command(cmd)
out = o.read().decode().strip()
if out:
print(f" {out}")
err = e.read().decode().strip()
if err:
print(f" [err] {err}")
# Check persistence package (iptables-persistent or netfilter-persistent)
stdin, stdout, stderr = ssh.exec_command("which netfilter-persistent || which iptables-save")
print(f" Persistence tool: {stdout.read().decode().strip()}")
stdin, stdout, stderr = ssh.exec_command("iptables-save > /etc/iptables/rules.v4 2>/dev/null || iptables-save > /etc/iptables.rules 2>/dev/null || true")
ssh.close()
apply_to_host("140.44.4.71")
apply_to_host("140.44.4.72")

21
scripts/test_agent_dns.py Normal file
View File

@@ -0,0 +1,21 @@
import paramiko
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect('140.44.4.71', username='root', key_filename=r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet', timeout=10)
def run(cmd):
print(f">>> {cmd}")
_, o, e = ssh.exec_command(cmd)
print(o.read().decode().strip())
err = e.read().decode().strip()
if err:
print("[stderr]", err)
run("cat /etc/resolv.conf")
run("getent hosts zabbix.snarfnet.net")
run("nc -zv 140.44.4.64 10051")
run("nc -zv zabbix.snarfnet.net 10051")
ssh.close()

View File

@@ -0,0 +1,21 @@
import paramiko
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect('140.44.4.41', username='root', key_filename=r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet', timeout=10)
def run(cmd):
print(f">>> {cmd}")
_, o, e = ssh.exec_command(cmd)
out = o.read().decode().strip()
err = e.read().decode().strip()
if out:
print(out)
if err:
print("[stderr]", err)
run("nc -zv zabbix.snarfnet.net 10051")
run("tail -n 20 /var/log/zabbix/zabbix_agent2.log")
ssh.close()

View File

@@ -0,0 +1,22 @@
import paramiko
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect('140.44.4.71', username='root', key_filename=r'C:\Users\Snarf\.ssh\id_ed25519_snarfnet', timeout=10)
def run(cmd):
print(f">>> {cmd}")
_, o, e = ssh.exec_command(cmd)
out = o.read().decode().strip()
err = e.read().decode().strip()
if out:
print(out)
if err:
print("[stderr]", err)
run("iptables -t nat -I PREROUTING 1 -p tcp --dport 10051 -j DNAT --to-destination 140.44.4.64:10051")
run("iptables -t nat -I POSTROUTING 1 -p tcp -d 140.44.4.64 --dport 10051 -j MASQUERADE")
run("iptables -t nat -L PREROUTING -n -v | head -n 5")
ssh.close()