summaryrefslogtreecommitdiffstats
path: root/god/Monitoring/nagios/plugins/nmap_discovery_runner.py
diff options
context:
space:
mode:
authormakefu <github@syntax-fehler.de>2013-01-14 14:46:22 +0100
committermakefu <github@syntax-fehler.de>2013-01-14 14:46:22 +0100
commitdbe2d838ba6834788265029162b2dd7d82473335 (patch)
treea4eb38f7fc91d91269b6f83453de62242c6ddc23 /god/Monitoring/nagios/plugins/nmap_discovery_runner.py
parent5a782f6c8f7923f9f415afd504ce6e71acbc7fef (diff)
parentabf9916bc1add17888308877fa4eb9da330297ef (diff)
Merge branch 'master' of github.com:krebscode/painload
Conflicts: god/temper/Makefile god/temper/collectd-temper.sh
Diffstat (limited to 'god/Monitoring/nagios/plugins/nmap_discovery_runner.py')
-rwxr-xr-xgod/Monitoring/nagios/plugins/nmap_discovery_runner.py419
1 files changed, 419 insertions, 0 deletions
diff --git a/god/Monitoring/nagios/plugins/nmap_discovery_runner.py b/god/Monitoring/nagios/plugins/nmap_discovery_runner.py
new file mode 100755
index 00000000..338e211f
--- /dev/null
+++ b/god/Monitoring/nagios/plugins/nmap_discovery_runner.py
@@ -0,0 +1,419 @@
+#!/usr/bin/env python
+#Copyright (C) 2009-2010 :
+# Gabes Jean, naparuba@gmail.com
+# Gerhard Lausser, Gerhard.Lausser@consol.de
+# Gregory Starck, g.starck@gmail.com
+#
+#This file is part of Shinken.
+#
+#Shinken is free software: you can redistribute it and/or modify
+#it under the terms of the GNU Affero General Public License as published by
+#the Free Software Foundation, either version 3 of the License, or
+#(at your option) any later version.
+#
+#Shinken 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 Affero General Public License for more details.
+#
+#You should have received a copy of the GNU Affero General Public License
+#along with Shinken. If not, see <http://www.gnu.org/licenses/>.
+
+#sudo nmap 192.168.0.1 -T4 -O --traceroute -oX toto.xml
+
+import optparse
+import sys
+import os
+import tempfile
+import subprocess
+
+try:
+ # xml.etree.ElementTree is new in Python 2.5
+ from xml.etree.ElementTree import ElementTree
+except ImportError:
+ sys.exit("This script needs the Python ElementTree module. Please install it")
+
+VERSION = '0.1'
+
+parser = optparse.OptionParser(
+ "%prog [options] -t nmap scanning targets",
+ version="%prog " + VERSION)
+
+parser.add_option('-t', '--targets', dest="targets",
+ help="NMap scanning targets.")
+parser.add_option('-v', '--verbose', dest="verbose", action='store_true',
+ help="Verbose output.")
+
+targets = []
+opts, args = parser.parse_args()
+if not opts.targets:
+ parser.error("Requires at least one nmap target for scanning (option -t/--targets")
+else:
+ targets.append(opts.targets)
+
+if not opts.verbose:
+ verbose = False
+else:
+ verbose = True
+
+if args:
+ targets.extend(args)
+
+print "Got our target", targets
+
+def debug(txt):
+ if verbose:
+ print txt
+
+# Says if a host is up or not
+def is_up(h):
+ status = h.find('status')
+ state = status.attrib['state']
+ return state == 'up'
+
+
+
+class DetectedHost:
+ def __init__(self):
+ self.ip = ''
+ self.mac_vendor = ''
+ self.host_name = ''
+
+ self.os_possibilities = []
+ self.os = ('', '')
+ self.open_ports = []
+
+ self.parent = ''
+
+
+ # Keep the first name we've got
+ def set_host_name(self, name):
+ if self.host_name == '':
+ self.host_name = name
+
+
+ # Get a identifier for this host
+ def get_name(self):
+ if self.host_name != '':
+ return self.host_name
+ if self.ip != '':
+ return self.ip
+ return None
+
+ # We look for the host VMWare
+ def is_vmware_esx(self):
+ # If it's not a virtual machine bail out
+ if self.mac_vendor != 'VMware':
+ return False
+ # If we got all theses ports, we are quite ok for
+ # a VMWare host
+ needed_ports = [22, 80, 443, 902, 903, 5989]
+ for p in needed_ports:
+ if p not in self.open_ports:
+ # find one missing port, not a VMWare host
+ return False
+ # Ok all ports are found, we are a ESX :)
+ return True
+
+ # Says if we are a virtual machine or not
+ def is_vmware_vm(self):
+ # special case : the esx host itself
+ if self.is_vmware_esx():
+ return False
+ # Else, look at the mac vendor
+ return self.mac_vendor == 'VMware'
+
+
+ # Fill the different os possibilities
+ def add_os_possibility(self, os, osgen, accuracy):
+ self.os_possibilities.append( (os, osgen, accuracy) )
+
+
+ # We search if our potential parent is present in the
+ # other detected hosts. If so, set it as my parent
+ def look_for_parent(self, all_hosts):
+ self.parents = []
+ parent = self.parent
+ debug("Look for my parent %s -> %s" % (self.get_name(), parent))
+ # Ok, we didn't find any parent
+ # we bail out
+ if parent == '':
+ return
+ for h in all_hosts:
+ debug("Is it you? %s" % h.get_name())
+ if h.get_name() == parent:
+ debug("Houray, we find our parent %s -> %s" % (self.get_name(), h.get_name()))
+ self.parents.append(h.get_name())
+
+
+
+
+ # Look at ours oses and see which one is the better
+ def compute_os(self):
+ self.os_name = 'Unknown OS'
+ self.os_version = 'Unknown Version'
+
+ # bailout if we got no os :(
+ if len(self.os_possibilities) == 0:
+ return
+
+ max_accuracy = 0
+ for (os, osgen, accuracy) in self.os_possibilities:
+ if accuracy > max_accuracy:
+ max_accuracy = accuracy
+
+ # now get the entry with the max value
+ for (os, osgen, accuracy) in self.os_possibilities:
+ print "Can be", (os, osgen, accuracy)
+ if accuracy == max_accuracy:
+ self.os = (os, osgen)
+
+ print "Try to match", self.os
+
+ #Ok, unknown os... not good
+ if self.os == ('', ''):
+ return
+
+ map = {('Windows', '2000') : 'windows',
+ ('Windows', '2003') : 'windows',
+ ('Windows', '7') : 'windows',
+ ('Windows', 'XP') : 'windows',
+ # ME? you are a stupid moron!
+ ('Windows', 'Me') : 'windows',
+ ('Windows', '2008') : 'windows',
+ # that's a good boy :)
+ ('Linux', '2.6.X') : 'linux',
+ ('Linux', '2.4.X') : 'linux',
+ # HPUX? I think you didn't choose...
+ ('HP-UX', '11.X') : 'hpux',
+ ('HP-UX', '10.X') : 'hpux',
+ }
+
+ if self.os not in map:
+ return
+
+ self.os_name = map[self.os]
+ self.os_version = self.os[1]
+# self.templates.append(t)
+#
+# # Look for VMWare VM or hosts
+# if self.h.is_vmware_vm():
+# self.templates.append('vmware-vm')
+# # Now is an host?
+# if self.h.is_vmware_esx():
+# self.templates.append('vmware-host')
+
+
+ # Return the string of the 'discovery' items
+ def get_discovery_output(self):
+ r = []
+ r.append('%s::isup=1' % self.get_name())
+ r.append(self.get_discovery_system())
+ r.append(self.get_discovery_macvendor())
+ op = self.get_discovery_ports()
+ if op != '':
+ r.append(op)
+ par = self.get_discovery_parents()
+ if par != '':
+ r.append(par)
+ fqdn = self.get_dicovery_fqdn()
+ if fqdn != '':
+ r.append(fqdn)
+ ip = self.get_discovery_ip()
+ if ip != '':
+ r.append(ip)
+ return r
+
+
+ # for system output
+ def get_discovery_system(self):
+ r = '%s::os=%s' % (self.get_name(), self.os_name)+'\n'
+ r += '%s::osversion=%s' % (self.get_name(), self.os_version)
+ return r
+
+ def get_discovery_macvendor(self):
+ return '%s::macvendor=%s' % (self.get_name(), self.mac_vendor)
+
+ def get_discovery_ports(self):
+ if self.open_ports == []:
+ return ''
+ return '%s::openports=%s' % (self.get_name(), ','.join([str(p) for p in self.open_ports]))
+
+ def get_discovery_parents(self):
+ if self.parents == []:
+ return ''
+ return '%s::parents=%s' % (self.get_name(), ','.join(self.parents))
+
+ def get_dicovery_fqdn(self):
+ if self.host_name == '':
+ return ''
+ return '%s::fqdn=%s' % (self.get_name(), self.host_name)
+
+ def get_discovery_ip(self):
+ if self.ip == '':
+ return ''
+ return '%s::ip=%s' % (self.get_name(), self.ip)
+
+
+(_, tmppath) = tempfile.mkstemp()
+
+print "propose a tmppath", tmppath
+
+cmd = "sudo nmap %s -T4 -O --traceroute -oX %s" % (' '.join(targets) , tmppath)
+print "Launching command,", cmd
+try:
+ nmap_process = subprocess.Popen(
+ cmd,
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE,
+ close_fds=True, shell=True)
+except OSError , exp:
+ print "Debug : Error in launching command:", cmd, exp
+ sys.exit(2)
+
+print "Try to communicate"
+(stdoutdata, stderrdata) = nmap_process.communicate()
+
+if nmap_process.returncode != 0:
+ print "Error : the nmap return an error : '%s'" % stderrdata
+ sys.exit(2)
+
+print "Got it", (stdoutdata, stderrdata)
+
+xml_input = tmppath
+
+tree = ElementTree()
+try:
+ tree.parse(xml_input)
+except IOError, exp:
+ print "Error opening file '%s' : %s" % (xml_input, exp)
+ sys.exit(2)
+
+hosts = tree.findall('host')
+debug("Number of hosts : %d" % len(hosts))
+
+
+all_hosts = []
+
+for h in hosts:
+ # Bypass non up hosts
+ if not is_up(h):
+ continue
+
+ dh = DetectedHost()
+
+ # Now we get the ipaddr and the mac vendor
+ # for future VMWare matching
+ #print h.__dict__
+ addrs = h.findall('address')
+ for addr in addrs:
+ #print "Address", addr.__dict__
+ addrtype = addr.attrib['addrtype']
+ if addrtype == 'ipv4':
+ dh.ip = addr.attrib['addr']
+ if addrtype == "mac":
+ if 'vendor' in addr.attrib:
+ dh.mac_vendor = addr.attrib['vendor']
+
+
+ # Now we've got the hostnames
+ host_names = h.findall('hostnames')
+ for h_name in host_names:
+ h_names = h_name.findall('hostname')
+ for h_n in h_names:
+ #print 'hname', h_n.__dict__
+ #print 'Host name', h_n.attrib['name']
+ dh.set_host_name(h_n.attrib['name'])
+
+
+ # Now print the traceroute
+ traces = h.findall('trace')
+ for trace in traces:
+ #print trace.__dict__
+ hops = trace.findall('hop')
+ #print "Number of hops", len(hops)
+ distance = len(hops)
+ if distance >= 2:
+ for hop in hops:
+ ttl = int(hop.attrib['ttl'])
+ #We search for the direct father
+ if ttl == distance-1:
+ #print ttl
+ #print "Super hop", hop.__dict__
+ # Get the host name if possible, if not
+ # take the IP
+ if 'host' in hop.attrib:
+ dh.parent = hop.attrib['host']
+ else:
+ dh.parent = hop.attrib['ipaddr']
+
+
+ # Now the OS detection
+ ios = h.find('os')
+ #print os.__dict__
+ cls = ios.findall('osclass')
+ for c in cls:
+ #print "Class", c.__dict__
+ family = c.attrib['osfamily']
+ accuracy = c.attrib['accuracy']
+ if 'osgen' in c.attrib:
+ osgen = c.attrib['osgen']
+ else:
+ osgen = None
+ #print "Type:", family, osgen, accuracy
+ dh.add_os_possibility(family, osgen, accuracy)
+ # Ok we can compute our OS now :)
+ dh.compute_os()
+
+
+ # Now the ports :)
+ allports = h.findall('ports')
+ for ap in allports:
+ ports = ap.findall('port')
+ for p in ports:
+ #print "Port", p.__dict__
+ p_id = p.attrib['portid']
+ s = p.find('state')
+ #print s.__dict__
+ state = s.attrib['state']
+ if state == 'open':
+ dh.open_ports.append(int(p_id))
+
+ #print dh.__dict__
+ all_hosts.append(dh)
+ #print "\n\n"
+
+
+
+for h in all_hosts:
+ name = h.get_name()
+ if not name:
+ continue
+
+ debug("Doing name %s" % name)
+ #path = os.path.join(output_dir, name+'.discover')
+ #print "Want path", path
+ #f = open(path, 'wb')
+ #cPickle.dump(h, f)
+ #f.close()
+ debug(str(h.__dict__))
+ # And generate the configuration too
+ h.look_for_parent(all_hosts)
+ #c.fill_system_conf()
+ #c.fill_ports_services()
+ #c.fill_system_services()
+# c.write_host_configuration()
+ #print "Host config", c.get_cfg_for_host()
+# c.write_services_configuration()
+ #print "Service config"
+ #print c.get_cfg_for_services()
+ #print c.__dict__
+ print '\n'.join(h.get_discovery_output())
+ #print "\n\n\n"
+
+
+# Try to remove the temppath
+try:
+ os.unlink(tmppath)
+except Exception:
+ pass
+