diff --git a/README.md b/README.md index a527624..19b723c 100644 --- a/README.md +++ b/README.md @@ -20,31 +20,27 @@ Note that `netbox-scanner` will require [Nmap](https://nmap.org/) and an instanc ## Usage -`netbox-scanner` can be used both in your Python programs or as a script. To use `netbox-scanner` as a script, edit `netbox-scanner/config.py` with your setup, and run the command below: +`netbox-scanner` can be used both in your Python programs or as a script. To use `netbox-scanner` as a script, simply run `netbox-scanner/netbox-scanner.py` and it'll create its configuration file (`.netbox-scanner.conf`) in your home folder: - $ netbox-scanner.py + $ python netbox-scanner.py + +After that, you'll just need to edit that file with your environment settings and run the script again. `netbox-scanner` will do the following tasks: -1. It will scan all networks defined in `netbox-scanner/config.py` or via parameters. +1. It will scan all networks defined in the configuration file. 2. For each discovered host it will: - 1. If host is in NetBox, description is different, and `tag` is equal to `netbox-scanner/config.py/TAG`, it's description will be updated. + 1. If host is in NetBox, description is different, and `tag` is equal to that defined in the configuration file, it's description will be updated in NetBox. 2. If host is not in NetBox, it'll be created. -3. It will iterate through each network to find and delete any hosts registered in NetBox that did not respond to scan, and have the tag `netbox-scanner/config.py/TAG`. +3. It will iterate through each network to find and delete any hosts registered in NetBox that did not respond to scan, and have the tag defined in the configuration file. -This way, if some hosts in your monitored networks are eventually down, but you don't want `netbox-scanner` to manage them, just make sure that they don't have the tag defined in `netbox-scanner/config.py/TAG`. - -To see a list of all available parameters in `netbox-scanner.py`, simple use the `-h` option --please note that all parameters are optional, because all of them can be set using `netbox-scanner/config.py` file: - - $ netbox-scanner.py -h +For instance, if some hosts in your monitored networks are eventually down, but you don't want `netbox-scanner` to manage them, just make sure that they **don't** have the tag defined in the configuration file. Of course, you can use `cron` to automatically run `netbox-scanner`. ## Configuration File -`netbox-scanner` have a configuration file (`netbox-scanner/netbox-scanner/config.py`) with all parameters needed to scan networks and synchronize them to NetBox. Before using `netbox-scanner/netbox-scannner/netbox-scanner.py` you should read that file and fill all variables according to your environment. - -It is strongly recommended that you use this file instead of passing parameters via command line, because it's easier and avoid common mistakes in multiple executions. You should use command line parameters occasionally, in single scans. +`netbox-scanner` have a configuration file with all parameters needed to scan networks and synchronize them to NetBox. By default, this file is located at user's home folder and is created when `netbox-scanner.py` is executed for the first time. Before using `netbox-scanner.py` you should edit that file and fill all variables according to your environment. ## License diff --git a/netbox-scanner/nbscan.py b/netbox-scanner/nbscan.py index 3eb3bf0..601919f 100644 --- a/netbox-scanner/nbscan.py +++ b/netbox-scanner/nbscan.py @@ -17,10 +17,11 @@ logging.getLogger('paramiko').setLevel(logging.CRITICAL) # paramiko is noisy class NetBoxScanner(object): - def __init__(self, address, token, tls_verify, nmap_args, devs_auth, tag, unknown): + def __init__(self, address, token, tls_verify, nmap_args, tacacs, tag, + unknown): self.netbox = api(address, token=token, ssl_verify=tls_verify) self.nmap_args = nmap_args - self.devs = devs_auth + self.tacacs = tacacs self.tag = tag self.unknown = unknown self.stats = {'created':0, 'updated':0, 'deleted':0, @@ -52,17 +53,17 @@ class NetBoxScanner(object): return name else: c = CPE(cpe[0], CPE.VERSION_2_3) - vendor = c.get_vendor()[0].upper() - if vendor in self.devs: + vendor = c.get_vendor()[0] + if self.tacacs and vendor == 'cisco': try: client = SSHClient() client.set_missing_host_key_policy(AutoAddPolicy()) - client.connect(address, username=self.devs[vendor]['USER'], - password=self.devs[vendor]['PASSWORD']) - stdin, stdout, stderr = client.exec_command(self.devs[vendor]['COMMAND']) + client.connect(address, username=self.tacacs['user'], + password=self.tacacs['password']) + stdin,stdout,stderr = client.exec_command(self.tacacs['command']) return '{}:{}'.format(vendor.lower(), - re.search(self.devs[vendor]['REGEX'], - str(stdout.read().decode('utf-8'))).group(self.devs[vendor]['REGROUP'])) + re.search(self.tacacs['regex'], + str(stdout.read().decode('utf-8'))).group(self.tacacs['regroup'])) except (AuthenticationException, SSHException, NoValidConnectionsError, TimeoutError, ConnectionResetError): diff --git a/netbox-scanner/netbox-scanner.py b/netbox-scanner/netbox-scanner.py index a9246a1..935fc4e 100644 --- a/netbox-scanner/netbox-scanner.py +++ b/netbox-scanner/netbox-scanner.py @@ -1,48 +1,76 @@ #!/usr/bin/env python3 import logging -from argparse import ArgumentParser + +from configparser import ConfigParser +from os import fsync +from os.path import expanduser +from getpass import getpass from datetime import datetime from urllib3 import disable_warnings from urllib3.exceptions import InsecureRequestWarning -import config from nbscan import NetBoxScanner -argp = ArgumentParser() -argp.add_argument('-l', '--log', help='logfile path', default=config.LOG) -argp.add_argument('-a', '--address', help='netbox address', - default=config.NETBOX['ADDRESS']) -argp.add_argument('-t', '--token', help='netbox access token', - default=config.NETBOX['TOKEN']) -argp.add_argument('-v', '--verify', help='tls verify', - action='store_true', default=config.NETBOX['TLS_VERIFY']) -argp.add_argument('-m', '--nmap', help='set Nmap arguments', - default=config.NMAP_ARGS) -argp.add_argument('-d', '--devices', help='device authentication crendentials', - default=config.DEVICE_AUTH) -argp.add_argument('-g', '--tag', help='netbox-scanner tag', - default=config.TAG) -argp.add_argument('-u', '--unknown', help='netbox-scanner unknown host', - default=config.UNKNOWN) -argp.add_argument('-n', '--networks', nargs='+', help='networks to be scanned', - default=config.NETWORKS) -args = argp.parse_args() +template = ''' +[GENERAL] +tag = auto +unknown = unknown host +log = . +nmap_args = -T4 -O -F --host-timeout 30s -logging.basicConfig(filename='{}/netbox-scanner-{}.log'.format(args.log, - datetime.now().strftime('%Y%m%dT%H%M%SZ')), - level=logging.INFO, +[NETBOX] +address = https:// +token = +tls_verify = True + +[TACACS] +user = netbox +password = +command = show run | inc hostname +regex = hostname ([A-Z|a-z|0-9|\-|_]+) +regroup = 1 + +[SCAN] +networks = 10.1.2.3/24,10.2.3.4/24 +''' +conffile = expanduser('~/.netbox-scanner.conf') + +try: + config = ConfigParser() + config.read(conffile) + general_conf = config['GENERAL'] + netbox_conf = config['NETBOX'] + networks = config['SCAN']['networks'].split(',') + tacacs_conf = dict() + for key in config['TACACS']: + tacacs_conf[key] = config['TACACS'][key] + tacacs_conf['regroup'] = int(tacacs_conf['regroup']) +except KeyError: + with open(conffile,'w+') as f: + f.write(template) + fsync(f) + print('Config file was created at {}'.format(conffile)) + print('Fill all fields before run the script again.') + exit(1) + +logfile = '{}/netbox-scanner-{}.log'.format(general_conf['log'], + datetime.now().strftime('%Y%m%dT%H%M%SZ')) +logging.basicConfig(filename=logfile, level=logging.INFO, format='%(asctime)s\tnetbox-scanner\t%(levelname)s\t%(message)s') disable_warnings(InsecureRequestWarning) -nbs = NetBoxScanner(args.address, args.token, args.verify, args.nmap, - args.devices, args.tag, args.unknown) -logging.info('started: {} networks'.format(len(args.networks))) -nbs.sync(args.networks) -logging.info('finished: +{} ~{} -{} ?{} !{}'.format(nbs.stats['created'], - nbs.stats['updated'], nbs.stats['deleted'], nbs.stats['undiscovered'], - nbs.stats['duplicated'])) + +if __name__ == '__main__': + nbs = NetBoxScanner(netbox_conf['address'], netbox_conf['token'], + netbox_conf.getboolean('tls_verify'), general_conf['nmap_args'], + tacacs_conf, general_conf['tag'], general_conf['unknown']) + logging.info('started: {} networks'.format(len(networks))) + nbs.sync(networks) + logging.info('finished: +{} ~{} -{} ?{} !{}'.format(nbs.stats['created'], + nbs.stats['updated'], nbs.stats['deleted'], nbs.stats['undiscovered'], + nbs.stats['duplicated'])) exit(0) diff --git a/setup.py b/setup.py index 95de765..5c6abf7 100644 --- a/setup.py +++ b/setup.py @@ -7,7 +7,7 @@ with open('README.md', 'r') as fh: setuptools.setup( name='netbox-scanner', - version='0.5.6', + version='0.6.0', author='José Lopes de Oliveira Jr.', author_email='jlojunior@gmail.com', description='A scanner util for NetBox',