summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorroot <root@krebs>2011-05-09 21:02:54 +0200
committerroot <root@krebs>2011-05-09 21:02:54 +0200
commit9e22c8b62b449af8391e28477d9d8ff4b50e86d8 (patch)
tree1e181e39f3794252dbf653c4737c7447fe745a27
parent8aad7ae37a2ac51dbeb07da7bb18810ca15af865 (diff)
parent483a46be9a90ef46b3f478d62f108d675159cdc6 (diff)
Merge remote branch 'snmp_users/master'
-rw-r--r--.gitignore1
-rw-r--r--modules/people/README.md14
-rw-r--r--modules/people/TODO.md4
-rw-r--r--modules/people/VERSION1
-rwxr-xr-xmodules/people/bin/run.sh5
-rw-r--r--modules/people/conf/example.json22
-rw-r--r--modules/people/src/arping.py30
-rwxr-xr-xmodules/people/src/main.py33
-rwxr-xr-xmodules/people/src/snmp_users.py122
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)