📄 snmpcallbackdomain.c
字号:
#include <net-snmp/net-snmp-config.h>#include <stdio.h>#include <sys/types.h>#include <ctype.h>#include <errno.h>#if HAVE_STRING_H#include <string.h>#else#include <strings.h>#endif#if HAVE_STDLIB_H#include <stdlib.h>#endif#if HAVE_UNISTD_H#include <unistd.h>#endif#if HAVE_SYS_SOCKET_H#include <sys/socket.h>#endif#if HAVE_SYS_UN_H#include <sys/un.h>#endif#if HAVE_IO_H#include <io.h>#endif#if HAVE_FCNTL_H#include <fcntl.h>#endif#if HAVE_DMALLOC_H#include <dmalloc.h>#endif#include <net-snmp/types.h>#include <net-snmp/output_api.h>#include <net-snmp/config_api.h>#include <net-snmp/utilities.h>#include <net-snmp/library/snmp_transport.h>#include <net-snmp/library/snmpUnixDomain.h>#include <net-snmp/library/snmp_api.h>#include <net-snmp/library/snmp_client.h>#include <net-snmp/library/snmpCallbackDomain.h>#ifndef NETSNMP_STREAM_QUEUE_LEN#define NETSNMP_STREAM_QUEUE_LEN 5#endifstatic netsnmp_transport_list *trlist = NULL;static int callback_count = 0;typedef struct callback_hack_s { void *orig_transport_data; netsnmp_pdu *pdu;} callback_hack;typedef struct callback_queue_s { int callback_num; netsnmp_callback_pass *item; struct callback_queue_s *next, *prev;} callback_queue;callback_queue *thequeue;static netsnmp_transport *find_transport_from_callback_num(int num){ static netsnmp_transport_list *ptr; for (ptr = trlist; ptr; ptr = ptr->next) if (((netsnmp_callback_info *) ptr->transport->data)-> callback_num == num) return ptr->transport; return NULL;}static voidcallback_debug_pdu(const char *ourstring, netsnmp_pdu *pdu){ netsnmp_variable_list *vb; int i = 1; DEBUGMSGTL((ourstring, "PDU: command = %d, errstat = %d, errindex = %d\n", pdu->command, pdu->errstat, pdu->errindex)); for (vb = pdu->variables; vb; vb = vb->next_variable) { DEBUGMSGTL((ourstring, " var %d:", i++)); DEBUGMSGVAR((ourstring, vb)); DEBUGMSG((ourstring, "\n")); }}voidcallback_push_queue(int num, netsnmp_callback_pass *item){ callback_queue *newitem = SNMP_MALLOC_TYPEDEF(callback_queue); callback_queue *ptr; newitem->callback_num = num; newitem->item = item; if (thequeue) { for (ptr = thequeue; ptr && ptr->next; ptr = ptr->next) { } ptr->next = newitem; newitem->prev = ptr; } else { thequeue = newitem; } DEBUGIF("dump_send_callback_transport") { callback_debug_pdu("dump_send_callback_transport", item->pdu); }}netsnmp_callback_pass *callback_pop_queue(int num){ netsnmp_callback_pass *cp; callback_queue *ptr; for (ptr = thequeue; ptr; ptr = ptr->next) { if (ptr->callback_num == num) { if (ptr->prev) { ptr->prev->next = ptr->next; } else { thequeue = ptr->next; } if (ptr->next) { ptr->next->prev = ptr->prev; } cp = ptr->item; free(ptr); DEBUGIF("dump_recv_callback_transport") { callback_debug_pdu("dump_recv_callback_transport", cp->pdu); } return cp; } } return NULL;}/* * Return a string representing the address in data, or else the "far end" * address if data is NULL. */char *netsnmp_callback_fmtaddr(netsnmp_transport *t, void *data, int len){ char buf[SPRINT_MAX_LEN]; netsnmp_callback_info *mystuff; if (!t) return strdup("callback: unknown"); mystuff = (netsnmp_callback_info *) t->data; if (!mystuff) return strdup("callback: unknown"); snprintf(buf, SPRINT_MAX_LEN, "callback: %d on fd %d", mystuff->callback_num, mystuff->pipefds[0]); return strdup(buf);}/* * You can write something into opaque that will subsequently get passed back * to your send function if you like. For instance, you might want to * remember where a PDU came from, so that you can send a reply there... */intnetsnmp_callback_recv(netsnmp_transport *t, void *buf, int size, void **opaque, int *olength){ int rc = -1; char newbuf[1]; netsnmp_callback_info *mystuff = (netsnmp_callback_info *) t->data; DEBUGMSGTL(("transport_callback", "hook_recv enter\n")); while (rc < 0) { rc = read(mystuff->pipefds[0], newbuf, 1); if (rc < 0 && errno != EINTR) { break; } } if (mystuff->linkedto) { /* * we're the client. We don't need to do anything. */ } else { /* * malloc the space here, but it's filled in by * snmp_callback_created_pdu() below */ int *returnnum = (int *) calloc(1, sizeof(int)); *opaque = returnnum; *olength = sizeof(int); } DEBUGMSGTL(("transport_callback", "hook_recv exit\n")); return rc;}intnetsnmp_callback_send(netsnmp_transport *t, void *buf, int size, void **opaque, int *olength){ int from, rc = -1; netsnmp_callback_info *mystuff = (netsnmp_callback_info *) t->data; netsnmp_callback_pass *cp; /* * extract the pdu from the hacked buffer */ netsnmp_transport *other_side; callback_hack *ch = (callback_hack *) * opaque; netsnmp_pdu *pdu = ch->pdu; *opaque = ch->orig_transport_data; free(ch); DEBUGMSGTL(("transport_callback", "hook_send enter\n")); cp = SNMP_MALLOC_TYPEDEF(netsnmp_callback_pass); if (!cp) return -1; cp->pdu = snmp_clone_pdu(pdu); if (cp->pdu->transport_data) { /* * not needed and not properly freed later */ SNMP_FREE(cp->pdu->transport_data); } if (cp->pdu->flags & UCD_MSG_FLAG_EXPECT_RESPONSE) cp->pdu->flags ^= UCD_MSG_FLAG_EXPECT_RESPONSE; /* * push the sent pdu onto the stack */ /* * AND send a bogus byte to the remote callback receiver's pipe */ if (mystuff->linkedto) { /* * we're the client, send it to the parent */ cp->return_transport_num = mystuff->callback_num; other_side = find_transport_from_callback_num(mystuff->linkedto); if (!other_side) return -1; while (rc < 0) { rc = write(((netsnmp_callback_info *)other_side->data)->pipefds[1], " ", 1); if (rc < 0 && errno != EINTR) { break; } } callback_push_queue(mystuff->linkedto, cp); /* * we don't need the transport data any more */ if (*opaque) { free(*opaque); *opaque = NULL; } } else { /* * we're the server, send it to the person that sent us the request */ from = **((int **) opaque); /* * we don't need the transport data any more */ if (*opaque) { free(*opaque); *opaque = NULL; } other_side = find_transport_from_callback_num(from); if (!other_side) return -1; while (rc < 0) { rc = write(((netsnmp_callback_info *)other_side->data)->pipefds[1], " ", 1); if (rc < 0 && errno != EINTR) { break; } } callback_push_queue(from, cp); } DEBUGMSGTL(("transport_callback", "hook_send exit\n")); return 0;}intnetsnmp_callback_close(netsnmp_transport *t){ int rc; netsnmp_callback_info *mystuff = (netsnmp_callback_info *) t->data; DEBUGMSGTL(("transport_callback", "hook_close enter\n")); rc = close(mystuff->pipefds[0]); rc = close(mystuff->pipefds[1]); netsnmp_transport_remove_from_list(&trlist, t); DEBUGMSGTL(("transport_callback", "hook_close exit\n")); return rc;}intnetsnmp_callback_accept(netsnmp_transport *t){ DEBUGMSGTL(("transport_callback", "hook_accept enter\n")); DEBUGMSGTL(("transport_callback", "hook_accept exit\n")); return 0;}/* * Open a Callback-domain transport for SNMP. Local is TRUE if addr * is the local address to bind to (i.e. this is a server-type * session); otherwise addr is the remote address to send things to * (and we make up a temporary name for the local end of the * connection). */netsnmp_transport *netsnmp_callback_transport(int to){ netsnmp_transport *t = NULL; netsnmp_callback_info *mydata; int rc; /* * transport */ t = SNMP_MALLOC_TYPEDEF(netsnmp_transport); if (!t) return NULL; /* * our stuff */ mydata = SNMP_MALLOC_TYPEDEF(netsnmp_callback_info); mydata->linkedto = to; mydata->callback_num = ++callback_count; mydata->data = NULL; t->data = mydata;#ifdef WIN32 rc = _pipe(mydata->pipefds, 1024, O_BINARY);#else rc = pipe(mydata->pipefds);#endif t->sock = mydata->pipefds[0]; if (rc) { free(mydata); free(t); return NULL; } t->f_recv = netsnmp_callback_recv; t->f_send = netsnmp_callback_send; t->f_close = netsnmp_callback_close; t->f_accept = netsnmp_callback_accept; t->f_fmtaddr = netsnmp_callback_fmtaddr; netsnmp_transport_add_to_list(&trlist, t); if (to) DEBUGMSGTL(("transport_callback", "initialized %d linked to %d\n", mydata->callback_num, to)); else DEBUGMSGTL(("transport_callback", "initialized master listening on %d\n", mydata->callback_num)); return t;}intnetsnmp_callback_hook_parse(netsnmp_session * sp, netsnmp_pdu *pdu, u_char * packetptr, size_t len){ if (SNMP_MSG_RESPONSE == pdu->command || SNMP_MSG_REPORT == pdu->command) pdu->flags |= UCD_MSG_FLAG_RESPONSE_PDU; else pdu->flags &= (~UCD_MSG_FLAG_RESPONSE_PDU); return SNMP_ERR_NOERROR;}intnetsnmp_callback_hook_build(netsnmp_session * sp, netsnmp_pdu *pdu, u_char * ptk, size_t * len){ /* * very gross hack, as this is passed later to the transport_send * function */ callback_hack *ch = SNMP_MALLOC_TYPEDEF(callback_hack); DEBUGMSGTL(("transport_callback", "hook_build enter\n")); ch->pdu = pdu; ch->orig_transport_data = pdu->transport_data; pdu->transport_data = ch; switch (pdu->command) { case SNMP_MSG_RESPONSE: case SNMP_MSG_TRAP: case SNMP_MSG_TRAP2: pdu->flags &= (~UCD_MSG_FLAG_EXPECT_RESPONSE); break; } *len = 1; DEBUGMSGTL(("transport_callback", "hook_build exit\n")); return 1;}intnetsnmp_callback_check_packet(u_char * pkt, size_t len){ return 1;}netsnmp_pdu *netsnmp_callback_create_pdu(netsnmp_transport *transport, void *opaque, size_t olength){ netsnmp_pdu *pdu; netsnmp_callback_pass *cp = callback_pop_queue(((netsnmp_callback_info *) transport->data)-> callback_num); if (!cp) return NULL; pdu = cp->pdu; pdu->transport_data = opaque; pdu->transport_data_length = olength; if (opaque) /* if created, we're the server */ *((int *) opaque) = cp->return_transport_num; free(cp); return pdu;}netsnmp_session *netsnmp_callback_open(int attach_to, int (*return_func) (int op, netsnmp_session * session, int reqid, netsnmp_pdu *pdu, void *magic), int (*fpre_parse) (netsnmp_session *, struct netsnmp_transport_s *, void *, int), int (*fpost_parse) (netsnmp_session *, netsnmp_pdu *, int)){ netsnmp_session callback_sess, *callback_ss; netsnmp_transport *callback_tr; callback_tr = netsnmp_callback_transport(attach_to); snmp_sess_init(&callback_sess); callback_sess.callback = return_func; if (attach_to) { /* * client */ /* * trysess.community = (u_char *) callback_ss; */ } else { callback_sess.isAuthoritative = SNMP_SESS_AUTHORITATIVE; } callback_sess.remote_port = 0; callback_sess.retries = 0; callback_sess.timeout = 30000000; callback_sess.version = SNMP_DEFAULT_VERSION; /* (mostly) bogus */ callback_ss = snmp_add_full(&callback_sess, callback_tr, fpre_parse, netsnmp_callback_hook_parse, fpost_parse, netsnmp_callback_hook_build, NULL, netsnmp_callback_check_packet, netsnmp_callback_create_pdu); if (callback_ss) callback_ss->local_port = ((netsnmp_callback_info *) callback_tr->data)->callback_num; return callback_ss;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -