📄 snmp.xs
字号:
/* -*- C -*- SNMP.xs -- Perl 5 interface to the Net-SNMP toolkit written by G. S. Marzot (marz@users.sourceforge.net) Copyright (c) 1995-2006 G. S. Marzot. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.*/#define WIN32SCK_IS_STDSCK#include "EXTERN.h"#include "perl.h"#include "XSUB.h"#include <net-snmp/net-snmp-config.h>#include <net-snmp/net-snmp-includes.h>#include <sys/types.h>#include <arpa/inet.h>#include <errno.h>#ifndef MSVC_PERL #include <signal.h>#endif#include <stdio.h>#include <ctype.h>#ifdef I_SYS_TIME#include <sys/time.h>#endif#include <netdb.h>#include <stdlib.h>#ifndef MSVC_PERL #include <unistd.h>#endif#ifdef HAVE_REGEX_H#include <regex.h>#endif#ifndef __P#define __P(x) x#endif#ifndef na#define na PL_na#endif#ifndef sv_undef#define sv_undef PL_sv_undef#endif#ifndef stack_base#define stack_base PL_stack_base#endif#ifndef G_VOID#define G_VOID G_DISCARD#endif#ifdef WIN32#define SOCK_STARTUP winsock_startup()#define SOCK_CLEANUP winsock_cleanup()#define strcasecmp _stricmp#define strncasecmp _strnicmp#else#define SOCK_STARTUP#define SOCK_CLEANUP#endif#include "perlsnmp.h"#define SUCCESS 1#define FAILURE 0#define ZERO_BUT_TRUE "0 but true"#define VARBIND_TAG_F 0#define VARBIND_IID_F 1#define VARBIND_VAL_F 2#define VARBIND_TYPE_F 3#define TYPE_UNKNOWN 0#define MAX_TYPE_NAME_LEN 32#define STR_BUF_SIZE (MAX_TYPE_NAME_LEN * MAX_OID_LEN)#define ENG_ID_BUF_SIZE 32#define SYS_UPTIME_OID_LEN 9#define SNMP_TRAP_OID_LEN 11#define NO_RETRY_NOSUCH 0static oid sysUpTime[SYS_UPTIME_OID_LEN] = {1, 3, 6, 1, 2, 1, 1, 3, 0};static oid snmpTrapOID[SNMP_TRAP_OID_LEN] = {1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0};/* Internal flag to determine snmp_main_loop() should return after callback */static int mainloop_finish = 0;/* these should be part of transform_oids.h ? */#define USM_AUTH_PROTO_MD5_LEN 10#define USM_AUTH_PROTO_SHA_LEN 10#define USM_PRIV_PROTO_DES_LEN 10/* why does ucd-snmp redefine sockaddr_in ??? */#define SIN_ADDR(snmp_addr) (((struct sockaddr_in *) &(snmp_addr))->sin_addr)typedef netsnmp_session SnmpSession;typedef struct tree SnmpMibNode;typedef struct snmp_xs_cb_data { SV* perl_cb; SV* sess_ref;} snmp_xs_cb_data;static void __recalc_timeout _((struct timeval*,struct timeval*, struct timeval*,struct timeval*, int* ));static in_addr_t __parse_address _((char*));static int __is_numeric_oid _((char*));static int __is_leaf _((struct tree*));static int __translate_appl_type _((char*));static int __translate_asn_type _((int));static int __snprint_value _((char *, size_t, netsnmp_variable_list*, struct tree *, int, int));static int __sprint_num_objid _((char *, oid *, int));static int __scan_num_objid _((char *, oid *, size_t *));static int __get_type_str _((int, char *));static int __get_label_iid _((char *, char **, char **, int));static int __oid_cmp _((oid *, size_t, oid *, size_t));static int __tp_sprint_num_objid _((char*,SnmpMibNode *));static SnmpMibNode * __get_next_mib_node _((SnmpMibNode *));static struct tree * __oid2tp _((oid*, int, struct tree *, int*));static struct tree * __tag2oid _((char *, char *, oid *, size_t *, int *, int));static int __concat_oid_str _((oid *, size_t *, char *));static int __add_var_val_str _((netsnmp_pdu *, oid *, size_t, char *, int, int));static int __send_sync_pdu _((netsnmp_session *, netsnmp_pdu *, netsnmp_pdu **, int , SV *, SV *, SV *));static int __snmp_xs_cb __P((int, netsnmp_session *, int, netsnmp_pdu *, void *));static SV* __push_cb_args2 _((SV * sv, SV * esv, SV * tsv));#define __push_cb_args(a,b) __push_cb_args2(a,b,NULL)static int __call_callback _((SV * sv, int flags));static char* __av_elem_pv _((AV * av, I32 key, char *dflt));#define USE_NUMERIC_OIDS 0x08#define NON_LEAF_NAME 0x04#define USE_LONG_NAMES 0x02#define FAIL_ON_NULL_IID 0x01#define NO_FLAGS 0x00/* Structures used by snmp_bulkwalk method to track requested OID's/subtrees. */typedef struct bulktbl { oid req_oid[MAX_OID_LEN]; /* The OID originally requested. */ oid last_oid[MAX_OID_LEN]; /* Last-seen OID under this branch. */ AV *vars; /* Array of Varbinds for this OID. */ size_t req_len; /* Length of requested OID. */ size_t last_len; /* Length of last-seen OID. */ char norepeat; /* Is this a non-repeater OID? */ char complete; /* Non-zero if this tree complete. */ char ignore; /* Ignore this OID, not requested. */} bulktbl;/* Context for bulkwalk() sessions. Used to store state across callbacks. */typedef struct walk_context { SV *sess_ref; /* Reference to Perl SNMP session object. */ SV *perl_cb; /* Pointer to Perl callback func or array. */ bulktbl *req_oids; /* Pointer to bulktbl[] for requested OIDs. */ bulktbl *repbase; /* Pointer to first repeater in req_oids[]. */ bulktbl *reqbase; /* Pointer to start of requests req_oids[]. */ int nreq_oids; /* Number of valid bulktbls in req_oids[]. */ int req_remain; /* Number of outstanding requests remaining */ int non_reps; /* Number of nonrepeater vars in req_oids[] */ int repeaters; /* Number of repeater vars in req_oids[]. */ int max_reps; /* Maximum repetitions of variable per PDU. */ int exp_reqid; /* Expect a response to this request only. */ int getlabel_f; /* Flag long/numeric names for get_label(). */ int sprintval_f; /* Flag enum/sprint values for sprintval(). */ int pkts_exch; /* Number of packet exchanges with agent. */ int oid_total; /* Total number of OIDs received this walk. */ int oid_saved; /* Total number of OIDs saved as results. */} walk_context;/* Prototypes for bulkwalk support functions. */static netsnmp_pdu *_bulkwalk_send_pdu _((walk_context *context));static int _bulkwalk_done _((walk_context *context));static int _bulkwalk_recv_pdu _((walk_context *context, netsnmp_pdu *pdu));static int _bulkwalk_finish _((walk_context *context, int okay));static int _bulkwalk_async_cb _((int op, SnmpSession *ss, int reqid, netsnmp_pdu *pdu, void *context_ptr));/* Structure to hold valid context sessions. */struct valid_contexts { walk_context **valid; /* Array of valid walk_context pointers. */ int sz_valid; /* Maximum size of valid contexts array. */ int num_valid; /* Count of valid contexts in the array. */};static struct valid_contexts *_valid_contexts = NULL;static int _context_add _((walk_context *context));static int _context_del _((walk_context *context));static int _context_okay _((walk_context *context));/* Wrapper around fprintf(stderr, ...) for clean and easy debug output. */#ifdef DEBUGGINGstatic int _debug_level = 0;#define DBOUT PerlIO_stderr(),#define DBPRT(severity, otherargs) \ do { \ if (_debug_level && severity <= _debug_level) { \ (void)PerlIO_printf otherargs; \ } \ } while (/*CONSTCOND*/0)char _debugx[1024]; /* Space to sprintf() into - used by sprint_objid(). */#define DBDCL(x) x/* wrapper around snprint_objid to snprint_objid to return the pointer instead of length */static char *__snprint_oid(const oid *objid, size_t objidlen) { snprint_objid(_debugx, sizeof(_debugx), objid, objidlen); return _debugx;} #else /* DEBUGGING */#define DBDCL(x) #define DBOUT#define DBPRT(severity, otherargs) /* Ignore */#endif /* DEBUGGING */void__libraries_init(char *appname) { static int have_inited = 0; if (have_inited) return; have_inited = 1; snmp_set_quick_print(1); snmp_enable_stderrlog(); init_snmp(appname); netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DONT_BREAKDOWN_OIDS, 1); netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_PRINT_SUFFIX_ONLY, 1); netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_OID_OUTPUT_FORMAT, NETSNMP_OID_OUTPUT_SUFFIX); SOCK_STARTUP; }static void__recalc_timeout (tvp, ctvp, ltvp, itvp, block)struct timeval* tvp;struct timeval* ctvp;struct timeval* ltvp;struct timeval* itvp;int *block;{ struct timeval now; if (!timerisset(itvp)) return; /* interval zero means loop forever */ *block = 0; gettimeofday(&now,(struct timezone *)0); if (ctvp->tv_sec < 0) { /* first time or callback just fired */ timersub(&now,ltvp,ctvp); timersub(ctvp,itvp,ctvp); timersub(itvp,ctvp,ctvp); timeradd(ltvp,itvp,ltvp); } else { timersub(&now,ltvp,ctvp); timersub(itvp,ctvp,ctvp); } /* flag is set for callback but still hasnt fired so set to something * small and we will service packets first if there are any ready * (also guard against negative timeout - should never happen?) */ if (!timerisset(ctvp) || ctvp->tv_sec < 0 || ctvp->tv_usec < 0) { ctvp->tv_sec = 0; ctvp->tv_usec = 10; } /* if snmp timeout > callback timeout or no more requests to process */ if (timercmp(tvp, ctvp, >) || !timerisset(tvp)) { *tvp = *ctvp; /* use the smaller non-zero timeout */ timerclear(ctvp); /* used as a flag to let callback fire on timeout */ }}static in_addr_t__parse_address(address)char *address;{ in_addr_t addr; struct sockaddr_in saddr; struct hostent *hp; if ((addr = inet_addr(address)) != -1) return addr; hp = gethostbyname(address); if (hp == NULL){ return (-1); /* error value */ } else { memcpy(&saddr.sin_addr, hp->h_addr, hp->h_length); return saddr.sin_addr.s_addr; }}static int__is_numeric_oid (oidstr)char* oidstr;{ if (!oidstr) return 0; for (; *oidstr; oidstr++) { if (isalpha((int)*oidstr)) return 0; } return(1);}static int__is_leaf (tp)struct tree* tp;{ char buf[MAX_TYPE_NAME_LEN]; return (tp && __get_type_str(tp->type,buf));}static SnmpMibNode*__get_next_mib_node (tp)SnmpMibNode* tp;{ /* printf("tp = %lX, parent = %lX, peer = %lX, child = %lX\n", tp, tp->parent, tp->next_peer, tp->child_list); */ if (tp->child_list) return(tp->child_list); if (tp->next_peer) return(tp->next_peer); if (!tp->parent) return(NULL); for (tp = tp->parent; !tp->next_peer; tp = tp->parent) { if (!tp->parent) return(NULL); } return(tp->next_peer);}static int__translate_appl_type(typestr)char* typestr;{ if (typestr == NULL || *typestr == '\0') return TYPE_UNKNOWN; if (!strncasecmp(typestr,"INTEGER32",8)) return(TYPE_INTEGER32); if (!strncasecmp(typestr,"INTEGER",3)) return(TYPE_INTEGER); if (!strncasecmp(typestr,"UNSIGNED32",3)) return(TYPE_UNSIGNED32); if (!strcasecmp(typestr,"COUNTER")) /* check all in case counter64 */ return(TYPE_COUNTER); if (!strncasecmp(typestr,"GAUGE",3)) return(TYPE_GAUGE); if (!strncasecmp(typestr,"IPADDR",3)) return(TYPE_IPADDR); if (!strncasecmp(typestr,"OCTETSTR",3)) return(TYPE_OCTETSTR); if (!strncasecmp(typestr,"TICKS",3)) return(TYPE_TIMETICKS); if (!strncasecmp(typestr,"OPAQUE",3)) return(TYPE_OPAQUE); if (!strncasecmp(typestr,"OBJECTID",3)) return(TYPE_OBJID); if (!strncasecmp(typestr,"NETADDR",3)) return(TYPE_NETADDR); if (!strncasecmp(typestr,"COUNTER64",3)) return(TYPE_COUNTER64); if (!strncasecmp(typestr,"NULL",3)) return(TYPE_NULL); if (!strncasecmp(typestr,"BITS",3)) return(TYPE_BITSTRING); if (!strncasecmp(typestr,"ENDOFMIBVIEW",3)) return(SNMP_ENDOFMIBVIEW); if (!strncasecmp(typestr,"NOSUCHOBJECT",7)) return(SNMP_NOSUCHOBJECT); if (!strncasecmp(typestr,"NOSUCHINSTANCE",7)) return(SNMP_NOSUCHINSTANCE); if (!strncasecmp(typestr,"UINTEGER",3)) return(TYPE_UINTEGER); /* historic - should not show up */ /* but it does? */ if (!strncasecmp(typestr, "NOTIF", 3)) return(TYPE_NOTIFTYPE); if (!strncasecmp(typestr, "TRAP", 4)) return(TYPE_TRAPTYPE); return(TYPE_UNKNOWN);}static int__translate_asn_type(type)int type;{ switch (type) { case ASN_INTEGER: return(TYPE_INTEGER); break; case ASN_OCTET_STR: return(TYPE_OCTETSTR); break; case ASN_OPAQUE: return(TYPE_OPAQUE); break; case ASN_OBJECT_ID: return(TYPE_OBJID); break; case ASN_TIMETICKS: return(TYPE_TIMETICKS); break; case ASN_GAUGE: return(TYPE_GAUGE); break; case ASN_COUNTER: return(TYPE_COUNTER); break; case ASN_IPADDRESS: return(TYPE_IPADDR); break; case ASN_BIT_STR: return(TYPE_BITSTRING); break; case ASN_NULL: return(TYPE_NULL); break; /* no translation for these exception type values */ case SNMP_ENDOFMIBVIEW:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -