Commit 6b7ffc655b74983648fd01515b0d00800891d1d9
Exists in
master
Adição dos comandos para ver como se comportam
Showing
7 changed files
with
197 additions
and
6 deletions
Show diff stats
| ... | ... | @@ -0,0 +1,167 @@ |
| 1 | +#!/bin/env python | |
| 2 | +# -*- coding: utf-8 -*- | |
| 3 | +__author__ = 'eduardo' | |
| 4 | +import logging | |
| 5 | +import os | |
| 6 | +import os.path | |
| 7 | +from paste.script import command | |
| 8 | +from .. import Cocar | |
| 9 | +from ..model import Base | |
| 10 | +from ..model.network import Network | |
| 11 | +from ..csv_utils import NetworkCSV | |
| 12 | +from ..session import NmapSession | |
| 13 | +from multiprocessing import Process, Queue | |
| 14 | + | |
| 15 | +log = logging.getLogger() | |
| 16 | + | |
| 17 | + | |
| 18 | +class ScanCommands(command.Command): | |
| 19 | + """ | |
| 20 | + Comandos para realizar o scan da rede | |
| 21 | + Usage:: | |
| 22 | + paster scan create_db -c <path to config file> | |
| 23 | + - Cria banco de dados | |
| 24 | + paster scan drop_db -c <path to config file> | |
| 25 | + - Remove banco de dados | |
| 26 | + paster scan networks -c <path to config file> | |
| 27 | + - Faz a busca das redes | |
| 28 | + | |
| 29 | + Os comandos devem ser executados a partir da raiz do módulo Cocar | |
| 30 | + """ | |
| 31 | + max_args = 1 | |
| 32 | + min_args = 1 | |
| 33 | + summary = __doc__.split('\n')[0] | |
| 34 | + usage = __doc__ | |
| 35 | + group_name = "Scan Commands" | |
| 36 | + | |
| 37 | + parser = command.Command.standard_parser(verbose=True) | |
| 38 | + | |
| 39 | + parser.add_option('-f', '--full', | |
| 40 | + action='store', | |
| 41 | + dest='full', | |
| 42 | + help='Full scan or regular scan' | |
| 43 | + ) | |
| 44 | + | |
| 45 | + def __init__(self, name): | |
| 46 | + """ | |
| 47 | + Constructor method | |
| 48 | + | |
| 49 | + """ | |
| 50 | + super(ScanCommands, self).__init__(name) | |
| 51 | + self.cocar = Cocar(environment='production') | |
| 52 | + self.networks_dir = self.cocar.cocar_data_dir + "/networks" | |
| 53 | + self.networks_csv = self.cocar.config.get('cocar', 'networks_csv') | |
| 54 | + if not os.path.isdir(self.networks_dir): | |
| 55 | + os.mkdir(self.networks_dir) | |
| 56 | + | |
| 57 | + def command(self): | |
| 58 | + """ | |
| 59 | + Parse command line arguments and call appropriate method. | |
| 60 | + """ | |
| 61 | + | |
| 62 | + if not self.args or self.args[0] in ['--help', '-h', 'help']: | |
| 63 | + print(ScanCommands.__doc__) | |
| 64 | + return | |
| 65 | + | |
| 66 | + cmd = self.args[0] | |
| 67 | + | |
| 68 | + if cmd == 'create_db': | |
| 69 | + self.create_db() | |
| 70 | + return | |
| 71 | + if cmd == 'drop_db': | |
| 72 | + self.drop_db() | |
| 73 | + return | |
| 74 | + if cmd == 'load_networks': | |
| 75 | + self.load_networks() | |
| 76 | + return | |
| 77 | + if cmd == 'scan_networks': | |
| 78 | + self.scan_networks() | |
| 79 | + return | |
| 80 | + else: | |
| 81 | + log.error('Command "%s" not recognized' % (cmd,)) | |
| 82 | + | |
| 83 | + def create_db(self): | |
| 84 | + """ | |
| 85 | + Create database | |
| 86 | + """ | |
| 87 | + Base.metadata.create_all(self.cocar.engine) | |
| 88 | + | |
| 89 | + def drop_db(self): | |
| 90 | + """ | |
| 91 | + Drop database | |
| 92 | + """ | |
| 93 | + Base.metadata.drop_all(self.cocar.engine) | |
| 94 | + | |
| 95 | + def load_networks(self): | |
| 96 | + """ | |
| 97 | + Load networks from CSV file | |
| 98 | + """ | |
| 99 | + networks_csv = NetworkCSV(csv_file=self.networks_csv) | |
| 100 | + session = self.cocar.Session | |
| 101 | + for elm in networks_csv.parse_csv(): | |
| 102 | + results = session.query(Network).filter(Network.ip_network == elm.ip_network).first() | |
| 103 | + if results is None: | |
| 104 | + log.info("Adicionando a rede: %s", elm.network_ip) | |
| 105 | + session.add(elm) | |
| 106 | + else: | |
| 107 | + log.info("Rede já cadastrada: %s", elm.network_ip) | |
| 108 | + session.flush() | |
| 109 | + session.close() | |
| 110 | + | |
| 111 | + def scan_networks(self): | |
| 112 | + """ | |
| 113 | + Scan all networks | |
| 114 | + """ | |
| 115 | + processes = int(self.cocar.config.get('cocar', 'processes')) | |
| 116 | + # Create queues | |
| 117 | + task_queue = Queue() | |
| 118 | + done_queue = Queue() | |
| 119 | + | |
| 120 | + session = self.cocar.Session | |
| 121 | + results = session.query(Network).all() | |
| 122 | + for network in results: | |
| 123 | + network.network_ip = network.ip_network | |
| 124 | + if self.options.full is None: | |
| 125 | + nmap_session = NmapSession( | |
| 126 | + network.network_ip.cidr, | |
| 127 | + outfile=self.networks_dir + "/" + str(network.network_ip.cidr).replace("/", "-") + ".xml", | |
| 128 | + full=False | |
| 129 | + ) | |
| 130 | + else: | |
| 131 | + nmap_session = NmapSession( | |
| 132 | + network.network_ip.cidr, | |
| 133 | + outfile=self.networks_dir + "/" + str(network.network_ip.cidr).replace("/", "-") + ".xml", | |
| 134 | + full=True | |
| 135 | + ) | |
| 136 | + task_queue.put(nmap_session) | |
| 137 | + | |
| 138 | + #Start worker processes | |
| 139 | + for i in range(processes): | |
| 140 | + Process(target=worker, args=(task_queue, done_queue)).start() | |
| 141 | + | |
| 142 | + # Get and print results | |
| 143 | + print 'Unordered results:' | |
| 144 | + for i in range(len(results)): | |
| 145 | + print '\t', done_queue.get() | |
| 146 | + | |
| 147 | + # Tell child processes to stop | |
| 148 | + for i in range(processes): | |
| 149 | + task_queue.put('STOP') | |
| 150 | + | |
| 151 | + | |
| 152 | +def make_query(host): | |
| 153 | + """This does the actual snmp query | |
| 154 | + | |
| 155 | + This is a bit fancy as it accepts both instances | |
| 156 | + of SnmpSession and host/ip addresses. This | |
| 157 | + allows a user to customize mass queries with | |
| 158 | + subsets of different hostnames and community strings | |
| 159 | + """ | |
| 160 | + return host.scan() | |
| 161 | + | |
| 162 | + | |
| 163 | +# Function run by worker processes | |
| 164 | +def worker(inp, output): | |
| 165 | + for func in iter(inp.get, 'STOP'): | |
| 166 | + result = make_query(func) | |
| 167 | + output.put(result) | |
| 0 | 168 | \ No newline at end of file | ... | ... |
cocar/model/network.py
| 1 | 1 | #!/bin/env python |
| 2 | 2 | # -*- coding: utf-8 -*- |
| 3 | 3 | __author__ = 'eduardo' |
| 4 | +from iptools.ipv4 import netmask2prefix | |
| 4 | 5 | from netaddr import IPNetwork, IPSet |
| 5 | 6 | from ..model import Base |
| 6 | 7 | from sqlalchemy.schema import Column |
| ... | ... | @@ -31,7 +32,7 @@ class Network(Base): |
| 31 | 32 | :param cidr: CIDR para calcular a máscara da rede |
| 32 | 33 | :param name: Nome da rede |
| 33 | 34 | """ |
| 34 | - self.network_ip = IPNetwork(network_ip) | |
| 35 | + self.network_ip = network_ip | |
| 35 | 36 | self.netmask = netmask |
| 36 | 37 | self.prefixlen = prefixlen |
| 37 | 38 | self.name = name |
| ... | ... | @@ -44,6 +45,19 @@ class Network(Base): |
| 44 | 45 | # SQLAlchemy attribute |
| 45 | 46 | self.ip_network = str(self.network_ip.ip) |
| 46 | 47 | |
| 48 | + @property | |
| 49 | + def network_ip(self): | |
| 50 | + return self._network_ip | |
| 51 | + | |
| 52 | + @network_ip.setter | |
| 53 | + def network_ip(self, value): | |
| 54 | + self._network_ip = IPNetwork(value) | |
| 55 | + if self._network_ip.prefixlen == 32: | |
| 56 | + if self.netmask is not None: | |
| 57 | + prefixlen = netmask2prefix(self.netmask) | |
| 58 | + self._network_ip = IPNetwork(str(self._network_ip.ip) + "/" + str(prefixlen)) | |
| 59 | + self.prefixlen = prefixlen | |
| 60 | + | |
| 47 | 61 | def ip_list(self): |
| 48 | 62 | """ |
| 49 | 63 | Método que encontra a lista de IP's da subrede | ... | ... |
cocar/query.py
| ... | ... | @@ -50,7 +50,7 @@ def main(): |
| 50 | 50 | for i in range(NUMBER_OF_PROCESSES): |
| 51 | 51 | Process(target=worker, args=(task_queue, done_queue)).start() |
| 52 | 52 | |
| 53 | - # Get and print results | |
| 53 | + # Get and print results | |
| 54 | 54 | print 'Unordered results:' |
| 55 | 55 | for i in range(len(hosts)): |
| 56 | 56 | print '\t', done_queue.get().query | ... | ... |
cocar/session.py
| ... | ... | @@ -62,7 +62,7 @@ class SnmpSession(Cocar): |
| 62 | 62 | return self.hostrec |
| 63 | 63 | |
| 64 | 64 | |
| 65 | -class NmapSession(Cocar): | |
| 65 | +class NmapSession(object): | |
| 66 | 66 | """ |
| 67 | 67 | Realiza busca Nmap num ativo de rede |
| 68 | 68 | Inspirado em https://github.com/c0r3dump3d/pylanos |
| ... | ... | @@ -75,13 +75,12 @@ class NmapSession(Cocar): |
| 75 | 75 | """ |
| 76 | 76 | Parâmetros obrigatórios |
| 77 | 77 | """ |
| 78 | - Cocar.__init__(self) | |
| 79 | 78 | self.host = host |
| 80 | 79 | self.full = full |
| 81 | 80 | if outfile is not None: |
| 82 | 81 | self.outfile = outfile |
| 83 | 82 | else: |
| 84 | - self.outfile = self.cocar_data_dir + "/" + str(self.host).replace("/", "-") + ".xml" | |
| 83 | + self.outfile = str(self.host).replace("/", "-") + ".xml" | |
| 85 | 84 | |
| 86 | 85 | def scan(self): |
| 87 | 86 | """ | ... | ... |
development.ini-dist
setup.py
| ... | ... | @@ -7,7 +7,9 @@ requires = [ |
| 7 | 7 | 'netaddr', |
| 8 | 8 | 'netifaces', |
| 9 | 9 | 'lxml', |
| 10 | - 'sqlalchemy' | |
| 10 | + 'sqlalchemy', | |
| 11 | + 'PasteScript', | |
| 12 | + 'iptools' | |
| 11 | 13 | ] |
| 12 | 14 | |
| 13 | 15 | |
| ... | ... | @@ -23,4 +25,9 @@ setup( |
| 23 | 25 | description='Agente coletor do software Cocar', |
| 24 | 26 | test_suite='cocar', |
| 25 | 27 | install_requires=requires, |
| 28 | + entry_points="""\ | |
| 29 | + [paste.paster_command] | |
| 30 | + scan = cocar.commands:ScanCommands | |
| 31 | + """, | |
| 32 | + | |
| 26 | 33 | ) | ... | ... |