forked from ungleich-public/cdist
[scanner] add minimal error handling, consolidate CLI args processing
This commit is contained in:
parent
acf9bf91f1
commit
a4464209b6
3 changed files with 37 additions and 63 deletions
|
@ -492,12 +492,16 @@ def get_parsers():
|
||||||
help='Try to configure detected hosts')
|
help='Try to configure detected hosts')
|
||||||
parser['scan'].add_argument(
|
parser['scan'].add_argument(
|
||||||
'-I', '--interfaces',
|
'-I', '--interfaces',
|
||||||
action='append', default=[],
|
action='append', default=[], required=True,
|
||||||
help='On which interfaces to scan/trigger')
|
help='On which interfaces to scan/trigger')
|
||||||
parser['scan'].add_argument(
|
parser['scan'].add_argument(
|
||||||
'-d', '--delay',
|
'-d', '--delay',
|
||||||
action='store', default=3600,
|
action='store', default=3600, type=int,
|
||||||
help='How long to wait before reconfiguring after last try')
|
help='How long (seconds) to wait before reconfiguring after last try')
|
||||||
|
parser['scan'].add_argument(
|
||||||
|
'-t', '--trigger-delay',
|
||||||
|
action='store', default=5, type=int,
|
||||||
|
help='How long (seconds) to wait between ICMPv6 echo requests')
|
||||||
parser['scan'].set_defaults(func=cdist.scan.commandline.commandline)
|
parser['scan'].set_defaults(func=cdist.scan.commandline.commandline)
|
||||||
|
|
||||||
for p in parser:
|
for p in parser:
|
||||||
|
|
|
@ -24,26 +24,29 @@ import sys
|
||||||
|
|
||||||
log = logging.getLogger("scan")
|
log = logging.getLogger("scan")
|
||||||
|
|
||||||
|
# CLI processing is defined outside of the main scan class to handle
|
||||||
# define this outside of the class to not handle scapy import errors by default
|
# non-available optional scapy dependency (instead of crashing mid-flight).
|
||||||
def commandline(args):
|
def commandline(args):
|
||||||
log.debug(args)
|
log.debug(args)
|
||||||
|
|
||||||
|
# Check if we have the optional scapy dependency available.
|
||||||
try:
|
try:
|
||||||
import cdist.scan.scan as scan
|
import cdist.scan.scan as scan
|
||||||
except ModuleNotFoundError:
|
except ModuleNotFoundError:
|
||||||
print('cdist scan requires scapy to be installed! Exiting.',
|
log.error('cdist scan requires scapy to be installed. Exiting.')
|
||||||
file=sys.stderr)
|
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
processes = []
|
# Default operation mode.
|
||||||
|
|
||||||
if not args.mode:
|
if not args.mode:
|
||||||
# By default scan and trigger, but do not call any action
|
# By default scan and trigger, but do not call any action.
|
||||||
args.mode = ['scan', 'trigger', ]
|
args.mode = ['scan', 'trigger', ]
|
||||||
|
|
||||||
|
# We run each component in a separate process since they
|
||||||
|
# must not block on each other.
|
||||||
|
processes = []
|
||||||
|
|
||||||
if 'trigger' in args.mode:
|
if 'trigger' in args.mode:
|
||||||
t = scan.Trigger(interfaces=args.interfaces)
|
t = scan.Trigger(interfaces=args.interfaces, sleeptime=args.trigger_delay)
|
||||||
t.start()
|
t.start()
|
||||||
processes.append(t)
|
processes.append(t)
|
||||||
log.debug("Trigger started")
|
log.debug("Trigger started")
|
||||||
|
|
|
@ -61,20 +61,22 @@ import datetime
|
||||||
|
|
||||||
import cdist.config
|
import cdist.config
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.DEBUG)
|
||||||
log = logging.getLogger("scan")
|
log = logging.getLogger("scan")
|
||||||
|
|
||||||
|
|
||||||
class Trigger(object):
|
class Trigger(object):
|
||||||
"""
|
"""
|
||||||
Trigger an ICMPv6EchoReply from all hosts that are alive
|
Trigger an ICMPv6EchoReply from all hosts that are alive
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, interfaces=None, verbose=False):
|
def __init__(self, interfaces, sleeptime, verbose=False):
|
||||||
self.interfaces = interfaces
|
self.interfaces = interfaces
|
||||||
|
|
||||||
|
# Used by scapy / send in trigger/2.
|
||||||
self.verbose = verbose
|
self.verbose = verbose
|
||||||
|
|
||||||
# Wait 5 seconds before triggering again - FIXME: add parameter
|
# Delay in seconds between sent ICMPv6EchoRequests.
|
||||||
self.sleeptime = 5
|
self.sleeptime = sleeptime
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
self.processes = []
|
self.processes = []
|
||||||
|
@ -93,9 +95,12 @@ class Trigger(object):
|
||||||
time.sleep(self.sleeptime)
|
time.sleep(self.sleeptime)
|
||||||
|
|
||||||
def trigger(self, interface):
|
def trigger(self, interface):
|
||||||
packet = IPv6(dst="ff02::1{}".format(interface)) / ICMPv6EchoRequest()
|
try:
|
||||||
log.debug("Sending request on %s", interface)
|
log.debug("Sending ICMPv6EchoRequest on %s", interface)
|
||||||
|
packet = IPv6(dst="ff02::1%{}".format(interface)) / ICMPv6EchoRequest()
|
||||||
send(packet, verbose=self.verbose)
|
send(packet, verbose=self.verbose)
|
||||||
|
except Exception as e:
|
||||||
|
log.error( "Could not send ICMPv6EchoRequest: %s", e)
|
||||||
|
|
||||||
|
|
||||||
class Scanner(object):
|
class Scanner(object):
|
||||||
|
@ -103,7 +108,7 @@ class Scanner(object):
|
||||||
Scan for replies of hosts, maintain the up-to-date database
|
Scan for replies of hosts, maintain the up-to-date database
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, interfaces=None, args=None, outdir=None):
|
def __init__(self, interfaces, args=None, outdir=None):
|
||||||
self.interfaces = interfaces
|
self.interfaces = interfaces
|
||||||
|
|
||||||
if outdir:
|
if outdir:
|
||||||
|
@ -148,47 +153,9 @@ class Scanner(object):
|
||||||
|
|
||||||
def scan(self):
|
def scan(self):
|
||||||
log.debug("Scanning - zzzzz")
|
log.debug("Scanning - zzzzz")
|
||||||
|
try:
|
||||||
sniff(iface=self.interfaces,
|
sniff(iface=self.interfaces,
|
||||||
filter="icmp6",
|
filter="icmp6",
|
||||||
prn=self.handle_pkg)
|
prn=self.handle_pkg)
|
||||||
|
except Exception as e:
|
||||||
|
log.error( "Could not start listener: %s", e)
|
||||||
if __name__ == '__main__':
|
|
||||||
t = Trigger(interfaces=["wlan0"])
|
|
||||||
t.start()
|
|
||||||
|
|
||||||
# Scanner can listen on many interfaces at the same time
|
|
||||||
s = Scanner(interfaces=["wlan0"])
|
|
||||||
s.scan()
|
|
||||||
|
|
||||||
# Join back the trigger processes
|
|
||||||
t.join()
|
|
||||||
|
|
||||||
# Test in my lan shows:
|
|
||||||
# [18:48] bridge:cdist% ls -1d fe80::*
|
|
||||||
# fe80::142d:f0a5:725b:1103
|
|
||||||
# fe80::20d:b9ff:fe49:ac11
|
|
||||||
# fe80::20d:b9ff:fe4c:547d
|
|
||||||
# fe80::219:d2ff:feb2:2e12
|
|
||||||
# fe80::21b:fcff:feee:f446
|
|
||||||
# fe80::21b:fcff:feee:f45c
|
|
||||||
# fe80::21b:fcff:feee:f4b1
|
|
||||||
# fe80::21b:fcff:feee:f4ba
|
|
||||||
# fe80::21b:fcff:feee:f4bc
|
|
||||||
# fe80::21b:fcff:feee:f4c1
|
|
||||||
# fe80::21d:72ff:fe86:46b
|
|
||||||
# fe80::42b0:34ff:fe6f:f6f0
|
|
||||||
# fe80::42b0:34ff:fe6f:f863
|
|
||||||
# fe80::42b0:34ff:fe6f:f9b2
|
|
||||||
# fe80::4a5d:60ff:fea1:e55f
|
|
||||||
# fe80::77a3:5e3f:82cc:f2e5
|
|
||||||
# fe80::9e93:4eff:fe6c:c1f4
|
|
||||||
# fe80::ba69:f4ff:fec5:6041
|
|
||||||
# fe80::ba69:f4ff:fec5:8db7
|
|
||||||
# fe80::bad8:12ff:fe65:313d
|
|
||||||
# fe80::bad8:12ff:fe65:d9b1
|
|
||||||
# fe80::ce2d:e0ff:fed4:2611
|
|
||||||
# fe80::ce32:e5ff:fe79:7ea7
|
|
||||||
# fe80::d66d:6dff:fe33:e00
|
|
||||||
# fe80::e2ff:f7ff:fe00:20e6
|
|
||||||
# fe80::f29f:c2ff:fe7c:275e
|
|
||||||
|
|
Loading…
Reference in a new issue