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 | ) | ... | ... |