1""" 2Running at secondary network interface 3++++++++++++++++++++++++++++++++++++++ 4 5Listen on all local IPv4 interfaces respond to SNMP GET/SET/GETNEXT/GETBULK 6queries with the following options: 7 8* SNMPv3 9* with USM user 'usr-md5-des', auth: MD5, priv DES 10* allow access to SNMPv2-MIB objects (1.3.6.1.2.1) 11* over IPv4/UDP, listening at 0.0.0.0:161 12* preserve local IP address when responding (Python 3.3+ required) 13 14The following Net-SNMP command will walk this Agent: 15 16| $ snmpwalk -v3 -u usr-md5-des -l authPriv -A authkey1 -X privkey1 localhost .1.3.6 17 18In the situation when UDP responder receives a datagram targeted to 19a secondary (AKA virtial) IP interface or a non-local IP interface 20(e.g. routed through policy routing or iptables TPROXY facility), 21OS stack will by default put primary local IP interface address into 22the IP source field of the response IP packet. Such datagram may not 23reach the sender as either the sender itself or a stateful firewall 24somewhere in between would not be able to match response to original 25request. 26 27The following script solves this problem by preserving original request 28destination IP address and put it back into response IP packet's source 29address field. 30 31To respond from a non-local (e.g. spoofed) IP address, uncomment the 32.enableTransparent() method call and run this script as root. 33 34"""# 35from pysnmp.entity import engine, config 36from pysnmp.entity.rfc3413 import cmdrsp, context 37from pysnmp.carrier.asyncore.dgram import udp 38 39# Create SNMP engine 40snmpEngine = engine.SnmpEngine() 41 42# Transport setup 43 44# Initialize asyncore-based UDP/IPv4 transport 45udpSocketTransport = udp.UdpSocketTransport().openServerMode(('0.0.0.0', 161)) 46 47# Use sendmsg()/recvmsg() for socket communication (used for preserving 48# original destination IP address when responding) 49udpSocketTransport.enablePktInfo() 50 51# Enable IP source spoofing (requires root privileges) 52# udpSocketTransport.enableTransparent() 53 54# Register this transport at SNMP Engine 55config.addTransport( 56 snmpEngine, 57 udp.domainName, 58 udpSocketTransport 59) 60 61# SNMPv3/USM setup 62 63# user: usr-md5-des, auth: MD5, priv DES 64config.addV3User( 65 snmpEngine, 'usr-md5-des', 66 config.usmHMACMD5AuthProtocol, 'authkey1', 67 config.usmDESPrivProtocol, 'privkey1' 68) 69 70# Allow full MIB access for each user at VACM 71config.addVacmUser(snmpEngine, 3, 'usr-md5-des', 'authPriv', (1, 3, 6, 1, 2, 1), (1, 3, 6, 1, 2, 1)) 72 73# Get default SNMP context this SNMP engine serves 74snmpContext = context.SnmpContext(snmpEngine) 75 76# Register SNMP Applications at the SNMP engine for particular SNMP context 77cmdrsp.GetCommandResponder(snmpEngine, snmpContext) 78cmdrsp.SetCommandResponder(snmpEngine, snmpContext) 79cmdrsp.NextCommandResponder(snmpEngine, snmpContext) 80cmdrsp.BulkCommandResponder(snmpEngine, snmpContext) 81 82# Register an imaginary never-ending job to keep I/O dispatcher running forever 83snmpEngine.transportDispatcher.jobStarted(1) 84 85# Run I/O dispatcher which would receive queries and send responses 86try: 87 snmpEngine.transportDispatcher.runDispatcher() 88except: 89 snmpEngine.observer.unregisterObserver() 90 snmpEngine.transportDispatcher.closeDispatcher() 91 raise 92