Update check_mdns.py
This commit is contained in:
102
check_mdns.py
102
check_mdns.py
@@ -1,5 +1,4 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import argparse
|
import argparse
|
||||||
import socket
|
import socket
|
||||||
@@ -24,15 +23,14 @@ for mod, pkg in REQUIRED_MODULES.items():
|
|||||||
missing.append(pkg)
|
missing.append(pkg)
|
||||||
|
|
||||||
if missing:
|
if missing:
|
||||||
print("BŁĄD: Brakuje wymaganych modułów Pythona:")
|
print("UNKNOWN: Brakuje wymaganych modułów Pythona:")
|
||||||
for pkg in missing:
|
for pkg in missing:
|
||||||
print(f" - {pkg}")
|
print(f" - {pkg}")
|
||||||
print("\nZainstaluj je poleceniem:")
|
print(f"\nZainstaluj je poleceniem:\n pip install {' '.join(missing)}")
|
||||||
print(f"pip install {' '.join(missing)}")
|
|
||||||
sys.exit(3)
|
sys.exit(3)
|
||||||
|
|
||||||
import netifaces
|
import netifaces
|
||||||
from zeroconf import Zeroconf, ServiceBrowser, ServiceListener, ServiceInfo
|
from zeroconf import Zeroconf, ServiceBrowser, ServiceListener
|
||||||
|
|
||||||
MDNS_TYPES = [
|
MDNS_TYPES = [
|
||||||
"_http._tcp.local.",
|
"_http._tcp.local.",
|
||||||
@@ -48,6 +46,7 @@ class MDNSListener(ServiceListener):
|
|||||||
if name not in self.services:
|
if name not in self.services:
|
||||||
self.services[name] = type_
|
self.services[name] = type_
|
||||||
|
|
||||||
|
|
||||||
def get_ip_for_interface(interface_name):
|
def get_ip_for_interface(interface_name):
|
||||||
try:
|
try:
|
||||||
addrs = netifaces.ifaddresses(interface_name)
|
addrs = netifaces.ifaddresses(interface_name)
|
||||||
@@ -58,6 +57,7 @@ def get_ip_for_interface(interface_name):
|
|||||||
return None
|
return None
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def get_zeroconf_instance(interface=None):
|
def get_zeroconf_instance(interface=None):
|
||||||
if interface:
|
if interface:
|
||||||
try:
|
try:
|
||||||
@@ -70,6 +70,7 @@ def get_zeroconf_instance(interface=None):
|
|||||||
else:
|
else:
|
||||||
return Zeroconf()
|
return Zeroconf()
|
||||||
|
|
||||||
|
|
||||||
def resolve_service(zeroconf, name, type_):
|
def resolve_service(zeroconf, name, type_):
|
||||||
info = zeroconf.get_service_info(type_, name)
|
info = zeroconf.get_service_info(type_, name)
|
||||||
if info:
|
if info:
|
||||||
@@ -83,6 +84,7 @@ def resolve_service(zeroconf, name, type_):
|
|||||||
}
|
}
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def test_service(ip, port):
|
def test_service(ip, port):
|
||||||
try:
|
try:
|
||||||
conn = http.client.HTTPConnection(ip, port, timeout=5)
|
conn = http.client.HTTPConnection(ip, port, timeout=5)
|
||||||
@@ -92,6 +94,7 @@ def test_service(ip, port):
|
|||||||
except Exception:
|
except Exception:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def scan_mdns_services(timeout=5, interface=None, filter_type=None):
|
def scan_mdns_services(timeout=5, interface=None, filter_type=None):
|
||||||
zeroconf = get_zeroconf_instance(interface)
|
zeroconf = get_zeroconf_instance(interface)
|
||||||
listener = MDNSListener()
|
listener = MDNSListener()
|
||||||
@@ -108,6 +111,7 @@ def scan_mdns_services(timeout=5, interface=None, filter_type=None):
|
|||||||
finally:
|
finally:
|
||||||
zeroconf.close()
|
zeroconf.close()
|
||||||
|
|
||||||
|
|
||||||
def export_services(services, format):
|
def export_services(services, format):
|
||||||
if format == 'json':
|
if format == 'json':
|
||||||
with open('mdns_services.json', 'w') as f:
|
with open('mdns_services.json', 'w') as f:
|
||||||
@@ -121,37 +125,11 @@ def export_services(services, format):
|
|||||||
writer.writerow([name, info['type'], info['ip'], info['port'], info['hostname']])
|
writer.writerow([name, info['type'], info['ip'], info['port'], info['hostname']])
|
||||||
print("Eksportowano do mdns_services.csv")
|
print("Eksportowano do mdns_services.csv")
|
||||||
|
|
||||||
def print_scan_report(services, script_path, interface=None, test_mode=None):
|
|
||||||
print("\n📡 Wykryte urządzenia mDNS:\n")
|
|
||||||
for name, info in services.items():
|
|
||||||
proto_clean = info['type'].split('.')[0].strip('_')
|
|
||||||
if test_mode in ['all', proto_clean]:
|
|
||||||
from http.client import HTTPConnection
|
|
||||||
try:
|
|
||||||
conn = HTTPConnection(info['ip'], info['port'], timeout=5)
|
|
||||||
conn.request("GET", "/")
|
|
||||||
resp = conn.getresponse()
|
|
||||||
test_status = "OK" if resp.status == 200 else f"Błąd {resp.status}"
|
|
||||||
except Exception as e:
|
|
||||||
test_status = "NIE"
|
|
||||||
else:
|
|
||||||
test_status = "-"
|
|
||||||
|
|
||||||
print(f" - {name} [protokoł: {proto_clean}, IP: {info['ip']}, port: {info['port']}, host: {info['hostname']}, test: {test_status}, szczegóły: {info['properties'] if info['properties'] else 'brak'}]")
|
|
||||||
|
|
||||||
print("\n🔧 Propozycje komend do użycia z Nagiosem:\n")
|
|
||||||
for name, info in services.items():
|
|
||||||
safe_device = name.split('.')[0].replace('"', '\\"')
|
|
||||||
cmd = f"{script_path} --device \"{safe_device}\""
|
|
||||||
if interface:
|
|
||||||
cmd += f" --interface {interface}"
|
|
||||||
if test_mode:
|
|
||||||
cmd += f" --test {test_mode}"
|
|
||||||
print(f" {cmd}")
|
|
||||||
|
|
||||||
def should_test(proto, test_mode):
|
def should_test(proto, test_mode):
|
||||||
return test_mode == 'all' or test_mode == proto
|
return test_mode == 'all' or test_mode == proto
|
||||||
|
|
||||||
|
|
||||||
def get_test_status(info, test_mode):
|
def get_test_status(info, test_mode):
|
||||||
proto_clean = info['type'].split('.')[0].strip('_')
|
proto_clean = info['type'].split('.')[0].strip('_')
|
||||||
if should_test(proto_clean, test_mode):
|
if should_test(proto_clean, test_mode):
|
||||||
@@ -164,22 +142,23 @@ def get_test_status(info, test_mode):
|
|||||||
return "NIE"
|
return "NIE"
|
||||||
return "-"
|
return "-"
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser(description="Skrypt Nagios do wykrywania urządzeń mDNS (Bonjour, IPP, AirPrint) z testem działania, eksportem, regexami, filtrowaniem i pełnym podglądem usług.")
|
parser = argparse.ArgumentParser(description="Skrypt Nagios do wykrywania urządzeń mDNS (Bonjour, IPP, AirPrint)")
|
||||||
parser.add_argument("--device", help="Fragment lub regex nazwy urządzenia do wykrycia (np. 'printer|tv')")
|
parser.add_argument("--device", help="Fragment lub regex nazwy urządzenia (np. 'printer|tv')")
|
||||||
parser.add_argument("--timeout", type=int, default=5, help="Czas oczekiwania na odpowiedzi mDNS (sekundy)")
|
parser.add_argument("--timeout", type=int, default=5, help="Czas oczekiwania mDNS (sek)")
|
||||||
parser.add_argument("--scan", action="store_true", help="Skanuj sieć i wypisz dostępne urządzenia z propozycjami komend")
|
parser.add_argument("--scan", action="store_true", help="Skanuj sieć i wypisz urządzenia")
|
||||||
parser.add_argument("--interface", help="Nazwa interfejsu sieciowego lub adres IP (np. eth1 lub 192.168.10.1)")
|
parser.add_argument("--interface", help="Interfejs sieciowy lub adres IP (np. eth1, 192.168.0.1)")
|
||||||
parser.add_argument("--export", choices=['json', 'csv'], help="Eksportuj wyniki skanu do pliku JSON lub CSV")
|
parser.add_argument("--export", choices=['json', 'csv'], help="Eksport wyników")
|
||||||
parser.add_argument("--filter-type", choices=[t.strip('.') for t in MDNS_TYPES], help="Filtruj tylko po określonym typie usługi (np. _ipp._tcp.local.)")
|
parser.add_argument("--filter-type", choices=[t.strip('.') for t in MDNS_TYPES], help="Filtruj usługę")
|
||||||
parser.add_argument("--match-property", help="Sprawdź czy w rekordach TXT znajduje się podana fraza (np. 'UUID')")
|
parser.add_argument("--match-property", help="Sprawdź frazę w rekordach TXT (np. 'UUID')")
|
||||||
parser.add_argument("--service-mode", action="store_true", help="Tryb ciągły - nasłuchiwanie urządzeń i logowanie ich w czasie rzeczywistym")
|
parser.add_argument("--service-mode", action="store_true", help="Tryb ciągły (jeszcze niezaimplementowany)")
|
||||||
parser.add_argument("--test", choices=['ipp', 'http', 'all'], help="Testuj działanie usług: ipp, http lub all")
|
parser.add_argument("--test", choices=['ipp', 'http', 'all'], help="Testuj usługi: ipp, http lub all")
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
if args.service_mode:
|
if args.service_mode:
|
||||||
print("Tryb serwisowy nie został jeszcze zaimplementowany.")
|
print("UNKNOWN: Tryb serwisowy niezaimplementowany")
|
||||||
sys.exit(3)
|
sys.exit(3)
|
||||||
|
|
||||||
if args.scan:
|
if args.scan:
|
||||||
@@ -187,7 +166,10 @@ def main():
|
|||||||
services = scan_mdns_services(args.timeout, args.interface, args.filter_type)
|
services = scan_mdns_services(args.timeout, args.interface, args.filter_type)
|
||||||
if services:
|
if services:
|
||||||
script_path = os.path.realpath(__file__)
|
script_path = os.path.realpath(__file__)
|
||||||
print_scan_report(services, script_path, args.interface, args.test)
|
print("\n📡 Wykryte urządzenia mDNS:\n")
|
||||||
|
for name, info in services.items():
|
||||||
|
proto_clean = info['type'].split('.')[0].strip('_')
|
||||||
|
print(f" - {name} [protokoł: {proto_clean}, IP: {info['ip']}, port: {info['port']}, host: {info['hostname']}]")
|
||||||
if args.export:
|
if args.export:
|
||||||
export_services(services, args.export)
|
export_services(services, args.export)
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
@@ -199,7 +181,7 @@ def main():
|
|||||||
sys.exit(3)
|
sys.exit(3)
|
||||||
|
|
||||||
if not args.device:
|
if not args.device:
|
||||||
print("BŁĄD: Musisz podać parametr --device (chyba że używasz --scan)")
|
print("UNKNOWN: Musisz podać parametr --device (chyba że używasz --scan)")
|
||||||
sys.exit(3)
|
sys.exit(3)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -208,20 +190,38 @@ def main():
|
|||||||
matches = {k: v for k, v in services.items() if pattern.search(k)}
|
matches = {k: v for k, v in services.items() if pattern.search(k)}
|
||||||
|
|
||||||
if args.match_property:
|
if args.match_property:
|
||||||
matches = {k: v for k, v in matches.items() if any(args.match_property.lower() in (v['properties'] or {}).get(pk, '').lower() for pk in (v['properties'] or {}))}
|
matches = {
|
||||||
|
k: v for k, v in matches.items()
|
||||||
|
if any(args.match_property.lower() in (v['properties'] or {}).get(pk, '').lower()
|
||||||
|
for pk in (v['properties'] or {}))
|
||||||
|
}
|
||||||
|
|
||||||
if matches:
|
if matches:
|
||||||
print(f"OK: Urządzenie pasujące do '{args.device}' znalezione w mDNS:")
|
|
||||||
all_ok = True
|
all_ok = True
|
||||||
|
devices_output = []
|
||||||
for name, info in matches.items():
|
for name, info in matches.items():
|
||||||
proto_clean = info['type'].split('.')[0].strip('_')
|
proto_clean = info['type'].split('.')[0].strip('_')
|
||||||
test_status = get_test_status(info, args.test)
|
test_status = get_test_status(info, args.test)
|
||||||
if args.test and should_test(proto_clean, args.test) and test_status != "OK":
|
if args.test and should_test(proto_clean, args.test) and test_status != "OK":
|
||||||
all_ok = False
|
all_ok = False
|
||||||
print(f" - {name} [protokoł: {proto_clean}, IP: {info['ip']}, port: {info['port']}, host: {info['hostname']}, test: {test_status}, szczegóły: {info['properties'] if info['properties'] else 'brak'}]")
|
devices_output.append(
|
||||||
sys.exit(0 if all_ok else 2)
|
f" - {name} [protokoł: {proto_clean}, IP: {info['ip']}, port: {info['port']}, "
|
||||||
|
f"host: {info['hostname']}, test: {test_status}, "
|
||||||
|
f"szczegóły: {info['properties'] if info['properties'] else 'brak'}]"
|
||||||
|
)
|
||||||
|
|
||||||
|
if all_ok:
|
||||||
|
print(f"OK: Urządzenie pasujące do '{args.device}' znalezione w mDNS:")
|
||||||
|
for line in devices_output:
|
||||||
|
print(line)
|
||||||
|
sys.exit(0)
|
||||||
|
else:
|
||||||
|
print(f"WARNING: Urządzenie '{args.device}' znalezione, ale test usług się nie powiódł:")
|
||||||
|
for line in devices_output:
|
||||||
|
print(line)
|
||||||
|
sys.exit(1)
|
||||||
elif services:
|
elif services:
|
||||||
print(f"WARNING: Nie znaleziono pasujących urządzeń do '{args.device}'. Wykryto inne:")
|
print(f"WARNING: Nie znaleziono pasujących urządzeń do '{args.device}'. Dostępne inne:")
|
||||||
for name, info in services.items():
|
for name, info in services.items():
|
||||||
proto_clean = info['type'].split('.')[0].strip('_')
|
proto_clean = info['type'].split('.')[0].strip('_')
|
||||||
print(f" - {name} [protokoł: {proto_clean}, IP: {info['ip']}, port: {info['port']}]")
|
print(f" - {name} [protokoł: {proto_clean}, IP: {info['ip']}, port: {info['port']}]")
|
||||||
@@ -229,9 +229,11 @@ def main():
|
|||||||
else:
|
else:
|
||||||
print("CRITICAL: Nie wykryto żadnych urządzeń mDNS.")
|
print("CRITICAL: Nie wykryto żadnych urządzeń mDNS.")
|
||||||
sys.exit(2)
|
sys.exit(2)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"UNKNOWN: Błąd podczas skanowania mDNS - {e}")
|
print(f"UNKNOWN: Błąd podczas skanowania mDNS - {e}")
|
||||||
sys.exit(3)
|
sys.exit(3)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
Reference in New Issue
Block a user