[scanner] add to beta commands
This commit is contained in:
		
					parent
					
						
							
								91d99bf08a
							
						
					
				
			
			
				commit
				
					
						09dfcfe81e
					
				
			
		
					 4 changed files with 124 additions and 6 deletions
				
			
		| 
						 | 
					@ -8,10 +8,11 @@ import cdist.configuration
 | 
				
			||||||
import cdist.log
 | 
					import cdist.log
 | 
				
			||||||
import cdist.preos
 | 
					import cdist.preos
 | 
				
			||||||
import cdist.info
 | 
					import cdist.info
 | 
				
			||||||
 | 
					import cdist.scan.commandline
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# set of beta sub-commands
 | 
					# set of beta sub-commands
 | 
				
			||||||
BETA_COMMANDS = set(('install', 'inventory', ))
 | 
					BETA_COMMANDS = set(('install', 'inventory', 'scan', ))
 | 
				
			||||||
# set of beta arguments for sub-commands
 | 
					# set of beta arguments for sub-commands
 | 
				
			||||||
BETA_ARGS = {
 | 
					BETA_ARGS = {
 | 
				
			||||||
    'config': set(('tag', 'all_tagged_hosts', 'use_archiving', )),
 | 
					    'config': set(('tag', 'all_tagged_hosts', 'use_archiving', )),
 | 
				
			||||||
| 
						 | 
					@ -470,6 +471,35 @@ def get_parsers():
 | 
				
			||||||
            'pattern', nargs='?', help='Glob pattern.')
 | 
					            'pattern', nargs='?', help='Glob pattern.')
 | 
				
			||||||
    parser['info'].set_defaults(func=cdist.info.Info.commandline)
 | 
					    parser['info'].set_defaults(func=cdist.info.Info.commandline)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Scan = config + further
 | 
				
			||||||
 | 
					    parser['scan'] = parser['sub'].add_parser('scan', add_help=False,
 | 
				
			||||||
 | 
					                                                 parents=[parser['config']])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    parser['scan'] = parser['sub'].add_parser(
 | 
				
			||||||
 | 
					            'scan', parents=[parser['loglevel'],
 | 
				
			||||||
 | 
					                             parser['beta'],
 | 
				
			||||||
 | 
					                             parser['colored_output'],
 | 
				
			||||||
 | 
					                             parser['common'],
 | 
				
			||||||
 | 
					                             parser['config_main']])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    parser['scan'].add_argument(
 | 
				
			||||||
 | 
					        '-m', '--mode', help='Which modes should run',
 | 
				
			||||||
 | 
					        action='append', default=[],
 | 
				
			||||||
 | 
					        choices=['scan', 'trigger'])
 | 
				
			||||||
 | 
					    parser['scan'].add_argument(
 | 
				
			||||||
 | 
					        '--config',
 | 
				
			||||||
 | 
					        action='store_true',
 | 
				
			||||||
 | 
					        help='Try to configure detected hosts')
 | 
				
			||||||
 | 
					    parser['scan'].add_argument(
 | 
				
			||||||
 | 
					        '-I', '--interfaces',
 | 
				
			||||||
 | 
					        action='append',  default=[],
 | 
				
			||||||
 | 
					        help='On which interfaces to scan/trigger')
 | 
				
			||||||
 | 
					    parser['scan'].add_argument(
 | 
				
			||||||
 | 
					        '-d', '--delay',
 | 
				
			||||||
 | 
					        action='store',  default=3600,
 | 
				
			||||||
 | 
					        help='How long to wait before reconfiguring after last try')
 | 
				
			||||||
 | 
					    parser['scan'].set_defaults(func=cdist.scan.commandline.commandline)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for p in parser:
 | 
					    for p in parser:
 | 
				
			||||||
        parser[p].epilog = EPILOG
 | 
					        parser[p].epilog = EPILOG
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										55
									
								
								cdist/scan/commandline.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								cdist/scan/commandline.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,55 @@
 | 
				
			||||||
 | 
					# -*- coding: utf-8 -*-
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# 2020 Nico Schottelius (nico-cdist at schottelius.org)
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# This file is part of cdist.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# cdist is free software: you can redistribute it and/or modify
 | 
				
			||||||
 | 
					# it under the terms of the GNU General Public License as published by
 | 
				
			||||||
 | 
					# the Free Software Foundation, either version 3 of the License, or
 | 
				
			||||||
 | 
					# (at your option) any later version.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# cdist is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					# but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					# GNU General Public License for more details.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# You should have received a copy of the GNU General Public License
 | 
				
			||||||
 | 
					# along with cdist. If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import logging
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					log = logging.getLogger("scan")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# define this outside of the class to not handle scapy import errors by default
 | 
				
			||||||
 | 
					def commandline(args):
 | 
				
			||||||
 | 
					    log.debug(args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        import cdist.scan.scan as scan
 | 
				
			||||||
 | 
					    except ModuleNotFoundError:
 | 
				
			||||||
 | 
					        print('cdist scan requires scapy to be installed')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    processes = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if not args.mode:
 | 
				
			||||||
 | 
					        # By default scan and trigger, but do not call any action
 | 
				
			||||||
 | 
					        args.mode = ['scan', 'trigger' ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if 'trigger' in args.mode:
 | 
				
			||||||
 | 
					        t = scan.Trigger(interfaces=args.interfaces)
 | 
				
			||||||
 | 
					        t.start()
 | 
				
			||||||
 | 
					        processes.append(t)
 | 
				
			||||||
 | 
					        log.debug("Trigger started")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if 'scan' in args.mode:
 | 
				
			||||||
 | 
					        s = scan.Scanner(interfaces=args.interfaces, args=args)
 | 
				
			||||||
 | 
					        s.start()
 | 
				
			||||||
 | 
					        processes.append(s)
 | 
				
			||||||
 | 
					        log.debug("Scanner started")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for process in processes:
 | 
				
			||||||
 | 
					        process.join()
 | 
				
			||||||
| 
						 | 
					@ -50,13 +50,14 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from multiprocessing import Process
 | 
					from multiprocessing import Process
 | 
				
			||||||
import os
 | 
					import os
 | 
				
			||||||
 | 
					import logging
 | 
				
			||||||
# FIXME: fail gracefully if non existent - i.e. "scapy required for scanner - please install python3-scapy"
 | 
					 | 
				
			||||||
from scapy.all import *
 | 
					from scapy.all import *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Datetime overwrites scapy.all.datetime - needs to be imported AFTER
 | 
					# Datetime overwrites scapy.all.datetime - needs to be imported AFTER
 | 
				
			||||||
import datetime
 | 
					import datetime
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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
 | 
				
			||||||
| 
						 | 
					@ -87,6 +88,7 @@ class Trigger(object):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def trigger(self, interface):
 | 
					    def trigger(self, interface):
 | 
				
			||||||
        packet = IPv6(dst=f"ff02::1%{interface}") / ICMPv6EchoRequest()
 | 
					        packet = IPv6(dst=f"ff02::1%{interface}") / ICMPv6EchoRequest()
 | 
				
			||||||
 | 
					        log.debug(f"Sending request on {interface}")
 | 
				
			||||||
        send(packet, verbose=self.verbose)
 | 
					        send(packet, verbose=self.verbose)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Scanner(object):
 | 
					class Scanner(object):
 | 
				
			||||||
| 
						 | 
					@ -94,18 +96,18 @@ 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, outdir=None):
 | 
					    def __init__(self, interfaces=None, args=None, outdir=None):
 | 
				
			||||||
        self.interfaces = interfaces
 | 
					        self.interfaces = interfaces
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if outdir:
 | 
					        if outdir:
 | 
				
			||||||
            self.outdir = outdir
 | 
					            self.outdir = outdir
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            self.outdir = "."
 | 
					            self.outdir = os.path.join(os.environ['HOME'], '.cdist', 'scan')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def handle_pkg(self, pkg):
 | 
					    def handle_pkg(self, pkg):
 | 
				
			||||||
        if ICMPv6EchoReply in pkg:
 | 
					        if ICMPv6EchoReply in pkg:
 | 
				
			||||||
            host = pkg['IPv6'].src
 | 
					            host = pkg['IPv6'].src
 | 
				
			||||||
            print(f"Host {host} is alive")
 | 
					            log.verbose(f"Host {host} is alive")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            dir = os.path.join(self.outdir, host)
 | 
					            dir = os.path.join(self.outdir, host)
 | 
				
			||||||
            fname = os.path.join(dir, "last_seen")
 | 
					            fname = os.path.join(dir, "last_seen")
 | 
				
			||||||
| 
						 | 
					@ -118,13 +120,21 @@ class Scanner(object):
 | 
				
			||||||
            with open(fname, "w") as fd:
 | 
					            with open(fname, "w") as fd:
 | 
				
			||||||
                fd.write(f"{now}\n")
 | 
					                fd.write(f"{now}\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def start(self):
 | 
				
			||||||
 | 
					        self.process = Process(target=self.scan)
 | 
				
			||||||
 | 
					        self.process.start()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def join(self):
 | 
				
			||||||
 | 
					        self.process.join()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def scan(self):
 | 
					    def scan(self):
 | 
				
			||||||
 | 
					        log.debug("Scanning - zzzzz")
 | 
				
			||||||
        sniff(iface=self.interfaces,
 | 
					        sniff(iface=self.interfaces,
 | 
				
			||||||
              filter="icmp6",
 | 
					              filter="icmp6",
 | 
				
			||||||
              prn=self.handle_pkg)
 | 
					              prn=self.handle_pkg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if __name__ == '__main__':
 | 
					if __name__ == '__main__':
 | 
				
			||||||
    t = Trigger(interfaces=["wlan0"])
 | 
					    t = Trigger(interfaces=["wlan0"])
 | 
				
			||||||
    t.start()
 | 
					    t.start()
 | 
				
			||||||
| 
						 | 
					@ -32,3 +32,26 @@
 | 
				
			||||||
     - Record when configured (successfully)
 | 
					     - Record when configured (successfully)
 | 
				
			||||||
     - Record when seen
 | 
					     - Record when seen
 | 
				
			||||||
   - Enables configurations in stateless environments
 | 
					   - Enables configurations in stateless environments
 | 
				
			||||||
 | 
					** Sample output v2020-10-29
 | 
				
			||||||
 | 
					23:14] bridge:~% sudo  cdist scan -b -I wlan0 -vv
 | 
				
			||||||
 | 
					VERBOSE: cdist: version 6.8.0-36-g91d99bf0
 | 
				
			||||||
 | 
					VERBOSE: scan: Host fe80::21d:72ff:fe86:46b is alive
 | 
				
			||||||
 | 
					VERBOSE: scan: Host fe80::ce2d:e0ff:fed4:2611 is alive
 | 
				
			||||||
 | 
					VERBOSE: scan: Host fe80::21b:fcff:feee:f4c1 is alive
 | 
				
			||||||
 | 
					VERBOSE: scan: Host fe80::e2ff:f7ff:fe00:20e6 is alive
 | 
				
			||||||
 | 
					VERBOSE: scan: Host fe80::20d:b9ff:fe49:ac11 is alive
 | 
				
			||||||
 | 
					VERBOSE: scan: Host fe80::9e93:4eff:fe6c:c1f4 is alive
 | 
				
			||||||
 | 
					VERBOSE: scan: Host fe80::ce32:e5ff:fe79:7ea7 is alive
 | 
				
			||||||
 | 
					VERBOSE: scan: Host fe80::219:d2ff:feb2:2e12 is alive
 | 
				
			||||||
 | 
					VERBOSE: scan: Host fe80::d66d:6dff:fe33:e00 is alive
 | 
				
			||||||
 | 
					VERBOSE: scan: Host fe80::21b:fcff:feee:f446 is alive
 | 
				
			||||||
 | 
					VERBOSE: scan: Host fe80::21b:fcff:feee:f4b1 is alive
 | 
				
			||||||
 | 
					VERBOSE: scan: Host fe80::20d:b9ff:fe4c:547d is alive
 | 
				
			||||||
 | 
					VERBOSE: scan: Host fe80::bad8:12ff:fe65:313d is alive
 | 
				
			||||||
 | 
					VERBOSE: scan: Host fe80::42b0:34ff:fe6f:f6f0 is alive
 | 
				
			||||||
 | 
					VERBOSE: scan: Host fe80::ba69:f4ff:fec5:6041 is alive
 | 
				
			||||||
 | 
					VERBOSE: scan: Host fe80::f29f:c2ff:fe7c:275e is alive
 | 
				
			||||||
 | 
					VERBOSE: scan: Host fe80::ba69:f4ff:fec5:8db7 is alive
 | 
				
			||||||
 | 
					VERBOSE: scan: Host fe80::42b0:34ff:fe6f:f863 is alive
 | 
				
			||||||
 | 
					VERBOSE: scan: Host fe80::21b:fcff:feee:f4bc is alive
 | 
				
			||||||
 | 
					...
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue