diff options
-rw-r--r-- | src/arping.py | 30 | ||||
-rw-r--r-- | src/main.py | 1 | ||||
-rwxr-xr-x | src/snmp_users.py | 98 |
3 files changed, 129 insertions, 0 deletions
diff --git a/src/arping.py b/src/arping.py new file mode 100644 index 00000000..1846f474 --- /dev/null +++ b/src/arping.py @@ -0,0 +1,30 @@ +#!/usr/bin/python2 + +import logging +log = logging.getLogger('arpingy') +import os +try: + if (os.geteuid() != 0): + raise Exception('no root permissions') + from scapy.all import * #might throws "no such module" + + def arpingy(iprange="10.42.1.0/24",iface='eth0'): + log.debug("pinging"+ str(iprange)) + """Arping function takes IP Address or Network, returns nested mac/ip list""" + try: + conf.verb=0 + ans,unans=arping(iprange,iface=iface,timeout=1) + + collection = [] + for snd, rcv in ans: + result = rcv.sprintf(r"%ARP.psrc% %Ether.src%").split() + log.debug(result) + return result # take just the first arp reply + except Exception as e: + print ("something went wrong while arpinging " + str(e)) + return [] + +except Exception as e: + log.error("Cannot load arping functions!" + str(e)) + def arpingy(iprange='',iface=''): + raise Exception ('arping not available') diff --git a/src/main.py b/src/main.py new file mode 100644 index 00000000..0e1d5dde --- /dev/null +++ b/src/main.py @@ -0,0 +1 @@ +#!/usr/bin/python2 diff --git a/src/snmp_users.py b/src/snmp_users.py new file mode 100755 index 00000000..1d6cf9be --- /dev/null +++ b/src/snmp_users.py @@ -0,0 +1,98 @@ +#!/usr/bin/python2 + +import logging, subprocess,re +from multiprocessing import Pool +from genericore import Configurable +from arping import arpingy +log = logging.getLogger('snmp_users') + +DEFAULT_CONFIG= { + "snmp" : { + "server" : "10.42.0.1", + "community" : "shammunity", + "tree" : "1.3.6.1.2.1.3.1.1.2" + }, + "arping" : { + "active" : True, + "dev" : "eth0" + } +} + +def arping_helper(dic): + return arpingy(**dic) + +class snmp_users(Configurable): + mac_list = {} + + def __init__(self,config={}): + Configurable.__init__(self,DEFAULT_CONFIG) + self.load_conf(config) + + def call_external(self): + """returns an array of lines produced by snmpwalk """ + conf = self.config['snmp'] + + out = subprocess.Popen( + ['snmpwalk', + '-v2c', + '-c',conf['community'], + conf['server'], + conf['tree']], + stdout=subprocess.PIPE).communicate()[0] + return out.split('\n') + + def parse_output(self,output): + """ parses output lines produced by snmpwalk """ + data = [] + for i in output: + if i == '': + continue + data.append(re.sub(r'.*\.(\d+\.\d+\.\d+\.\d+) = Hex-STRING: ([ 0-9A-F]*) ', r'\1 : \2',i).split(' : ')) + data = [ [ip,':'.join(mac.split()).lower()] for ip,mac in data] #sanitize + + return data + + def update_results(self,new): + """ Verifies ip and mac via ARP Scan + in addition it adds the correct ip to the mac_list """ + macl = self.mac_list + + for ip,mac in new: # fill the mac_list + if not macl.get(mac,None): + macl[mac] = [] + macl[mac].append(ip) + + return True + + def verify(self,snmp_data): + """ verifies retrieved data where data is an array of arrays where + [0] is the ip and [1] is the mac (space-delimited)""" + arp_data = self.arping_parallel(snmp_data) + self.update_results(arp_data) + + def arping_parallel(self,data): + conf = self.config['arping'] + if conf['active']: + p = Pool(10) + tmp = [ {'iprange':dat[0],'iface':conf['dev']} for dat in data] + try: + return filter(lambda x:x , p.map(arping_helper, tmp)) + except Exception as e: + log.warning("Something happened,falling back to original data: "+ str(e)) + return data + + def collect(self): + output = self.call_external() + data = self.parse_output(output) + macs = self.verify(data) + self.print_results(self.mac_list) + def print_results(self,macs): + log.debug('printing results:') + print '\n'.join([ mac + " => %s" % + str(ips) for mac,ips in macs.items() ]) + print '%d *unique* nodes in network' % len(macs) + +if __name__ == "__main__": + logging.basicConfig(level=logging.INFO) + a = snmp_users() + a.collect() |