Commit 297a524fd43fbd3e916a49042777b42bb8862162

Authored by Eduardo Santos
2 parents bc60b941 d8fe80a0
Exists in master

Persistência dos ativos de rede num banco local

cocar/__init__.py
... ... @@ -7,7 +7,6 @@ import ConfigParser
7 7 import logging
8 8 import logging.config
9 9 from sqlalchemy.engine import create_engine
10   -from sqlalchemy.ext.declarative import declarative_base
11 10 from sqlalchemy.orm import scoped_session, sessionmaker
12 11  
13 12  
... ... @@ -46,11 +45,8 @@ class Cocar(object):
46 45 # SQLAlchemy
47 46 sqlalchemy_url = self.config.get('sqlalchemy', 'url')
48 47 self.engine = create_engine(sqlalchemy_url, echo=True)
49   - self.Base = declarative_base()
50   - self.Base.metadata.bind = self.engine
51   - self.session = scoped_session(
  48 + self.Session = scoped_session(
52 49 sessionmaker(bind=self.engine,
53   - autocommit=True,
54   - #expire_on_commit=False
55   - )
56   - )
  50 + autocommit=True
  51 + )
  52 + )
57 53 \ No newline at end of file
... ...
cocar/model/__init__.py
1 1 #!/bin/env python
2 2 # -*- coding: utf-8 -*-
3   -__author__ = 'eduardo'
4 3 \ No newline at end of file
  4 +__author__ = 'eduardo'
  5 +
  6 +from sqlalchemy.ext.declarative import declarative_base
  7 +
  8 +Base = declarative_base()
5 9 \ No newline at end of file
... ...
cocar/model/computer.py
1 1 #!/bin/env python
2 2 # -*- coding: utf-8 -*-
3 3 __author__ = 'eduardo'
4   -
  4 +from sqlalchemy.schema import Column
  5 +from sqlalchemy.types import *
  6 +from sqlalchemy import ForeignKey
5 7 from .host import Host
6 8  
7 9  
... ... @@ -9,6 +11,12 @@ class Computer(Host):
9 11 """
10 12 Ativo de rede identificado como estação de trabalho
11 13 """
  14 + __tablename__ = 'computador'
  15 + network_ip = Column(String(16), ForeignKey("host.network_ip"), nullable=False, primary_key=True)
  16 + so_name = Column(String)
  17 + so_version = Column(String)
  18 + accuracy = Column(Integer)
  19 +
12 20 def __init__(self,
13 21 so,
14 22 *args,
... ... @@ -19,4 +27,10 @@ class Computer(Host):
19 27 :param so: Sistema Operacional encontrado
20 28 """
21 29 Host.__init__(self, *args, **kwargs)
22   - self.so = so
23 30 \ No newline at end of file
  31 + self.so = so
  32 +
  33 + #SQLAlchemy parameters
  34 + os_elm = self.so.items()[0]
  35 + self.so_name = os_elm[1]['osfamily']
  36 + self.so_version = os_elm[1]['version']
  37 + self.accuracy = os_elm[1]['accuracy']
24 38 \ No newline at end of file
... ...
cocar/model/host.py
... ... @@ -2,12 +2,23 @@
2 2 # -*- coding: utf-8 -*-
3 3 __author__ = 'eduardo'
4 4 from netaddr import IPAddress
  5 +from sqlalchemy.schema import Column
  6 +from sqlalchemy.types import String, Integer
  7 +from . import Base
5 8  
6 9  
7   -class Host(object):
  10 +class Host(Base):
8 11 """
9 12 Classe que define um ativo de rede
10 13 """
  14 + __tablename__ = 'host'
  15 + network_ip = Column(String(16), primary_key=True, nullable=False)
  16 + mac_address = Column(String(18))
  17 + name = Column(String)
  18 + inclusion_date = Column(String(20))
  19 + scantime = Column(Integer)
  20 + ports = Column(String)
  21 +
11 22 def __init__(self,
12 23 ip_address,
13 24 mac_address=None,
... ... @@ -32,4 +43,25 @@ class Host(object):
32 43 self.hostname = hostname
33 44 self.inclusion_date = inclusion_date
34 45 self.scantime = scantime
35   - self.open_ports = open_ports
36 46 \ No newline at end of file
  47 + self.open_ports = open_ports
  48 +
  49 + # Parâmetros do SQLAlchemy
  50 + self.network_ip = str(self.ip_address)
  51 + self.ports = ','.join(map(str, self.open_ports.keys()))
  52 + if len(self.hostname.values()) > 0:
  53 + self.name = self.hostname.values()[0]
  54 + else:
  55 + self.name = None
  56 +
  57 + def __repr__(self):
  58 + """
  59 + Metodo que passa a lista de parametros da classe
  60 + """
  61 + return "<Host('%s, %s, %s, %s, %s, %s')>" % (
  62 + self.network_ip,
  63 + self.mac_address,
  64 + self.name,
  65 + self.inclusion_date,
  66 + self.scantime,
  67 + self.ports
  68 + )
37 69 \ No newline at end of file
... ...
cocar/model/network.py
... ... @@ -4,14 +4,25 @@ __author__ = &#39;eduardo&#39;
4 4 import os.path
5 5 from .. import Cocar
6 6 from netaddr import IPNetwork, IPSet
  7 +from ..model import Base
  8 +from sqlalchemy.schema import Column
  9 +from sqlalchemy.types import String, Integer
7 10  
8 11  
9   -class Network(Cocar):
  12 +class Network(Base):
10 13 """
11 14 Rede onde a busca será realizada
12 15 """
  16 + __tablename__ = 'network'
  17 + ip_network = Column(String(16), nullable=False, primary_key=True)
  18 + network_file = Column(String)
  19 + netmask = Column(String(16))
  20 + prefixlen = Column(Integer)
  21 + name = Column(String)
  22 +
13 23 def __init__(self,
14 24 network_ip,
  25 + network_file=None,
15 26 netmask=None,
16 27 prefixlen=None,
17 28 name=None
... ... @@ -22,17 +33,19 @@ class Network(Cocar):
22 33 :param cidr: CIDR para calcular a máscara da rede
23 34 :param name: Nome da rede
24 35 """
25   - Cocar.__init__(self)
26 36 self.network_ip = IPNetwork(network_ip)
27 37 self.netmask = netmask
28 38 self.prefixlen = prefixlen
29 39 self.name = name
30   - self.network_file = self.cocar_data_dir + "/" + str(self.network_ip.ip) + ".xml"
  40 + self.network_file = network_file
31 41 if self.netmask is None:
32 42 self.netmask = self.network_ip.netmask
33 43 if self.prefixlen is None:
34 44 self.prefixlen = self.network_ip.prefixlen
35 45  
  46 + # SQLAlchemy attribute
  47 + self.ip_network = str(self.network_ip.ip)
  48 +
36 49 def ip_list(self):
37 50 """
38 51 Método que encontra a lista de IP's da subrede
... ...
cocar/model/printer.py
... ... @@ -3,16 +3,26 @@
3 3 __author__ = 'eduardo'
4 4  
5 5 from .host import Host
  6 +from sqlalchemy import ForeignKey
  7 +from sqlalchemy.schema import Column
  8 +from sqlalchemy.types import String, Integer
6 9  
7 10  
8 11 class Printer(Host):
9 12 """
10 13 Classe que identifica uma impressora
11 14 """
  15 + __tablename__ = 'printer'
  16 + network_ip = Column(String(16), ForeignKey("host.network_ip"), nullable=False, primary_key=True)
  17 + counter = Column(Integer)
  18 + serial = Column(String(50))
  19 + description = Column(String)
  20 +
12 21 def __init__(self,
13 22 counter=None,
14 23 model=None,
15 24 serial=None,
  25 + description=None,
16 26 *args,
17 27 **kwargs
18 28 ):
... ... @@ -24,4 +34,5 @@ class Printer(Host):
24 34 Host.__init__(self, *args, **kwargs)
25 35 self.counter = counter
26 36 self.model = model
27   - self.serial = serial
28 37 \ No newline at end of file
  38 + self.serial = serial
  39 + self.description = description
29 40 \ No newline at end of file
... ...
cocar/tests/__init__.py
... ... @@ -4,6 +4,7 @@ __author__ = &#39;eduardo&#39;
4 4 from .. import Cocar
5 5 import os
6 6 import os.path
  7 +from ..model import Base
7 8  
8 9 cocar = Cocar(environment='test')
9 10 test_dir = os.path.dirname(os.path.realpath(__file__))
... ... @@ -13,7 +14,7 @@ def setup_package():
13 14 """
14 15 Setup test data for the package
15 16 """
16   - cocar.Base.metadata.create_all(cocar.engine)
  17 + Base.metadata.create_all(cocar.engine)
17 18 pass
18 19  
19 20  
... ... @@ -21,5 +22,5 @@ def teardown_package():
21 22 """
22 23 Remove test data
23 24 """
24   - cocar.Base.metadata.drop_all(cocar.engine)
  25 + Base.metadata.drop_all(cocar.engine)
25 26 pass
26 27 \ No newline at end of file
... ...
cocar/tests/test_discover.py
... ... @@ -74,7 +74,7 @@ class TestDiscover(unittest.TestCase):
74 74 self.assertTrue(os.path.isfile(session.outfile))
75 75  
76 76 # Apaga arquivo
77   - os.unlink(session.outfile)
  77 + #os.unlink(session.outfile)
78 78  
79 79 def test_scan_rede(self):
80 80 """
... ...
cocar/tests/test_identify.py
... ... @@ -60,8 +60,9 @@ class TestIdentify(unittest.TestCase):
60 60 self.assertIsInstance(computer, Computer)
61 61  
62 62 # Se é um computer, tenho que identificar o SO
63   - os_elm = computer.so.items()[0]
64   - self.assertEqual(os_elm[1]['osfamily'], 'Linux')
  63 + self.assertEqual(computer.so_name, 'Linux')
  64 + self.assertEqual(computer.so_version, 'Linux 3.7 - 3.9')
  65 + self.assertEqual(computer.accuracy, '98')
65 66  
66 67 def test_identify_printer(self):
67 68 """
... ...
cocar/tests/test_persistence.py
... ... @@ -6,6 +6,8 @@ import unittest
6 6 import cocar.tests
7 7 from ..xml_utils import NmapXML
8 8 from ..model.computer import Computer
  9 +from ..model.printer import Printer
  10 +from ..model.network import Network
9 11  
10 12  
11 13 class TestPersistence(unittest.TestCase):
... ... @@ -20,12 +22,13 @@ class TestPersistence(unittest.TestCase):
20 22 self.network_file = cocar.tests.test_dir + "/fixtures/192.168.0.0-24.xml"
21 23 self.localhost_file = cocar.tests.test_dir + "/fixtures/127.0.0.1.xml"
22 24 self.printer_file = cocar.tests.test_dir + "/fixtures/printer.xml"
  25 + self.session = cocar.tests.cocar.Session
23 26  
24 27 def test_connect(self):
25 28 """
26 29 Testa conexão do SQLAlchemy
27 30 """
28   - db_session = cocar.tests.cocar.session
  31 + db_session = self.session
29 32 self.assertIsNotNone(db_session)
30 33  
31 34 def test_persist_computer(self):
... ... @@ -40,8 +43,54 @@ class TestPersistence(unittest.TestCase):
40 43 computer = nmap_xml.identify_host(hostname)
41 44 self.assertIsInstance(computer, Computer)
42 45  
  46 + # Agora testa a persistência
  47 + self.session.add(computer)
  48 + self.session.flush()
  49 +
  50 + # Tenta ver se gravou
  51 + results = self.session.query(Computer).first()
  52 + self.assertIsNotNone(results)
  53 +
  54 + def test_persist_printer(self):
  55 + """
  56 + Grava impressora no banco de dados
  57 + """
  58 + hostname = '10.72.168.3'
  59 + nmap_xml = NmapXML(self.printer_file)
  60 + host = nmap_xml.parse_xml()
  61 + assert host
  62 +
  63 + printer = nmap_xml.identify_host(hostname)
  64 + self.assertIsInstance(printer, Printer)
  65 +
  66 + # Agora testa a persistência
  67 + self.session.add(printer)
  68 + self.session.flush()
  69 +
  70 + # Tenta ver se gravou
  71 + results = self.session.query(Printer).first()
  72 + self.assertIsNotNone(results)
  73 +
  74 + def test_persist_network(self):
  75 + """
  76 + Testa gravação dos dados de rede
  77 + """
  78 + rede = Network(
  79 + network_ip='192.168.0.0',
  80 + netmask='255.255.255.0',
  81 + network_file='/tmp/network.xml',
  82 + name='Rede de Teste'
  83 + )
  84 + self.session.add(rede)
  85 + self.session.flush()
  86 +
  87 + # Tenta ver se gravou
  88 + results = self.session.query(Network).first()
  89 + self.assertIsNotNone(results)
  90 +
43 91 def tearDown(self):
44 92 """
45 93 Remove dados
46 94 """
  95 + self.session.close()
47 96 pass
48 97 \ No newline at end of file
... ...
cocar/xml_utils.py
... ... @@ -69,7 +69,8 @@ class NmapXML(object):
69 69 'vendor': osclass.get('vendor'),
70 70 'osfamily': osclass.get('osfamily'),
71 71 'accuracy': osclass.get('accuracy'),
72   - 'cpe': osclass.findtext('cpe')
  72 + 'cpe': osclass.findtext('cpe'),
  73 + 'version': osmatch.get('name')
73 74 }
74 75  
75 76 # General attributes
... ... @@ -86,11 +87,12 @@ class NmapXML(object):
86 87  
87 88 # Ordena os sistemas operacionais por accuracy
88 89 host = self.hosts[hostname]
89   - accuracy = 0
  90 + accuracy = int(0)
90 91 if host.get('os'):
91 92 # Nesse caso já sei que é computador. Precisa identificar o OS
92 93 for os in host['os'].keys():
93 94 if int(host['os'][os]['accuracy']) > accuracy:
  95 + accuracy = int(host['os'][os]['accuracy'])
94 96 os_final = os
95 97  
96 98 scantime = int(host.get('endtime')) - int(host.get('starttime'))
... ...