1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
| import asyncudp import asyncio import logging from logging.handlers import RotatingFileHandler from pysnmp.hlapi.asyncio import *
def setup_logger(): logger = logging.getLogger('snmp_proxy') logger.setLevel(logging.INFO) file_handler = RotatingFileHandler( 'snmp_proxy.log', maxBytes=5*1024*1024, backupCount=2 ) file_handler.setLevel(logging.INFO) console_handler = logging.StreamHandler() console_handler.setLevel(logging.INFO) formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s') file_handler.setFormatter(formatter) console_handler.setFormatter(formatter) logger.addHandler(file_handler) logger.addHandler(console_handler) return logger
logger = setup_logger() LOCAL_ADDR = ('0.0.0.0', 161)
async def snmp_get(target_ip, port, community, oid): try: logger.info(f"向目标设备 {target_ip}:{port} 发送SNMP请求, OID: {oid}") snmp_engine = SnmpEngine()
transport_target = await UdpTransportTarget.create( (target_ip, port), timeout=5.0, retries=3 )
iterator = get_cmd( snmp_engine, CommunityData(community, mpModel=1), transport_target, ContextData(), ObjectType(ObjectIdentity(oid)) )
error_indication, error_status, error_index, var_binds = await iterator
if error_indication: error_msg = f"SNMP请求错误: {error_indication}" logger.error(error_msg) return f"ERROR: {error_indication}" elif error_status: error_msg = f"SNMP状态错误: {error_status.prettyPrint()}" logger.error(error_msg) return f"ERROR: {error_status.prettyPrint()}" else: for var_bind in var_binds: result = var_bind[1].prettyPrint() logger.info(f"从目标设备 {target_ip}:{port} 收到响应: {result}") return result except Exception as e: error_msg = f"SNMP请求异常: {str(e)}" logger.error(error_msg) return f"EXCEPTION: {str(e)}" finally: snmp_engine.close_dispatcher()
async def proxy_handler(sock, addr, data): client_ip, client_port = addr logger.info(f"接收到来自客户端 {client_ip}:{client_port} 的请求")
try: decoded = data.decode('utf-8').strip() parts = decoded.split('|', 3) if len(parts) != 4: error_msg = f"来自客户端 {client_ip}:{client_port} 的请求格式错误" logger.error(error_msg) sock.sendto(b"ERROR: INVALID FORMAT", addr) return
target_ip, port_str, community, oid = parts try: port = int(port_str) except ValueError: error_msg = f"来自客户端 {client_ip}:{client_port} 的端口号无效" logger.error(error_msg) sock.sendto(b"ERROR: INVALID PORT", addr) return
logger.info(f"转发请求到 {target_ip}:{port} | OID: {oid} | 社区: {community}") result = await snmp_get(target_ip, port, community, oid) logger.info(f"向客户端 {client_ip}:{client_port} 发送响应") sock.sendto(result.encode('utf-8'), addr) except Exception as e: error_msg = f"处理客户端 {client_ip}:{client_port} 请求时发生内部错误: {str(e)}" logger.error(error_msg) sock.sendto(b"ERROR: INTERNAL SERVER ERROR", addr)
async def run_proxy(): sock = await asyncudp.create_socket(local_addr=LOCAL_ADDR) logger.info(f"SNMP代理服务器已启动,监听地址: {LOCAL_ADDR}")
while True: data, addr = await sock.recvfrom() asyncio.create_task(proxy_handler(sock, addr, data))
if __name__ == "__main__": asyncio.run(run_proxy())
|