diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | modules/people/README.md | 14 | ||||
-rw-r--r-- | modules/people/TODO.md | 4 | ||||
-rw-r--r-- | modules/people/VERSION | 1 | ||||
-rwxr-xr-x | modules/people/bin/run.sh | 5 | ||||
-rw-r--r-- | modules/people/conf/example.json | 22 | ||||
-rw-r--r-- | modules/people/src/arping.py | 30 | ||||
-rwxr-xr-x | modules/people/src/main.py | 33 | ||||
-rwxr-xr-x | modules/people/src/snmp_users.py | 122 |
9 files changed, 232 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..0d20b648 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.pyc diff --git a/modules/people/README.md b/modules/people/README.md new file mode 100644 index 00000000..d28100d3 --- /dev/null +++ b/modules/people/README.md @@ -0,0 +1,14 @@ +SNMP Users +========== + +asks an snmp-router for its arp-list and tries to verify this list via +ARPING. The snmping is done via snmp-net and command line parsing, +the arping uses 'scapy'. + +This script needs superuser rights and otherwise will just skip the +verification + +SNMPWALK Command +=============== + +snmpwalk -c shammunity 10.42.0.1 1.3.6.1.2.1.3.1.1.2 diff --git a/modules/people/TODO.md b/modules/people/TODO.md new file mode 100644 index 00000000..dfefa9a0 --- /dev/null +++ b/modules/people/TODO.md @@ -0,0 +1,4 @@ +BUGS +===== +- an exception is thrown but handled wrong when snmp servers and arping is + unreachable diff --git a/modules/people/VERSION b/modules/people/VERSION new file mode 100644 index 00000000..6c50e659 --- /dev/null +++ b/modules/people/VERSION @@ -0,0 +1 @@ ++++++++[>+++++++>+++++++<<-]>.>---.<-. diff --git a/modules/people/bin/run.sh b/modules/people/bin/run.sh new file mode 100755 index 00000000..6da3d059 --- /dev/null +++ b/modules/people/bin/run.sh @@ -0,0 +1,5 @@ +#!/bin/bash +echo basedir $0 +BINDIR="`dirname $0`/../src" + +python2 "$BINDIR/main.py" $@ diff --git a/modules/people/conf/example.json b/modules/people/conf/example.json new file mode 100644 index 00000000..f34c20f0 --- /dev/null +++ b/modules/people/conf/example.json @@ -0,0 +1,22 @@ +{ + "snmp_users": { + "amqp": { + "connection": { + "login": "guest", + "password": "guest", + "host": "localhost" + }, + "out": { + "exchange": "snmp_src" + } + }, + "snmp": { + "server": "127.0.0.1", + "community": "community" + }, + "arping": { + "active": true, + "dev": "eth0" + } + } +} diff --git a/modules/people/src/arping.py b/modules/people/src/arping.py new file mode 100644 index 00000000..11fb81a9 --- /dev/null +++ b/modules/people/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/modules/people/src/main.py b/modules/people/src/main.py new file mode 100755 index 00000000..c70bffd4 --- /dev/null +++ b/modules/people/src/main.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python2 +import sys,json,time +from snmp_users import snmp_users +import logging +import genericore as gen +MODULE_NAME='snmp_users' +log = logging.getLogger(MODULE_NAME) +PROTO_VERSION = 1 +DESCRIPTION = 'performes statistical analysis against mails from stream' + + +# set up instances of needed modules +conf = gen.Configurator(PROTO_VERSION,DESCRIPTION) +amqp = gen.auto_amqp(MODULE_NAME) +s = snmp_users(MODULE_NAME) # the magic mail parsing class + +conf.configure([amqp,s]) #set up parser and eval parsed stuff + +# start network connections +amqp.create_connection() + +log.info('Starting up snmp_users') +print ' Sending Messages in Intervals. To exit press CTRL+C' +try: + while True: + log.info("collecting data from network") + ret = s.collect() + data = { 'type' : 'snmp', 'subtype' : 0, 'data' : ret} + log.debug("writing data to queue : %s" % data) + amqp.publish(json.dumps(data)) + time.sleep(s.repeat) +except Exception as e: + print "something happened :( " + str(e) diff --git a/modules/people/src/snmp_users.py b/modules/people/src/snmp_users.py new file mode 100755 index 00000000..871ed9dd --- /dev/null +++ b/modules/people/src/snmp_users.py @@ -0,0 +1,122 @@ +#!/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" : "127.0.0.1", + "community" : "community", + "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,MODULE_NAME,config=None): + self.NAME=MODULE_NAME + newConf = { MODULE_NAME : DEFAULT_CONFIG } + Configurable.__init__(self,newConf) + self.load_conf(config) + + def call_external(self): + """returns an array of lines produced by snmpwalk """ + conf = self.config[self.NAME]['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 get_own_addr(self): + data = subprocess.Popen(['/sbin/ifconfig',self.config[self.NAME]['arping']['dev']], + stdout=subprocess.PIPE).communicate()[0].replace('\n','') + return re.sub(r'.*HWaddr ([0-9:A-F]*).*inet addr:([0-9.]*).*' ,r'\1 \2',data).split() + + + def arping_parallel(self,data): + conf = self.config[self.NAME]['arping'] + if conf['active']: + tmp = [ {'iprange':dat[0],'iface':conf['dev']} for dat in data] + try: + p = Pool(10) + ret = filter(lambda x:x , p.map(arping_helper, tmp)) + + myip,mymac = self.get_own_addr() #append self to list + ret.append([mymac,myip ] ) + p.terminate() + return ret + 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) + if not data: + raise Exception('External tool had not returned any parsable output') + log.debug('Got following output from snmpwalk program: ' +str(data)) + macs = self.verify(data) + #self.print_results(self.mac_list) + return 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) + + def populate_parser(self,parser): + parser.add_argument('--repeat',type=int,dest='repeat',default=30,help='Seconds between Scans',metavar='SECS') #TODO add this to configuration + + def eval_parser(self,parsed): + self.repeat = parsed.repeat + +if __name__ == "__main__": + logging.basicConfig(level=logging.INFO) + a = snmp_users() + print a.get_own_addr() + a.collect() + a.print_results(a.mac_list) |