snmpCallbackDomain.c

00001 #include <net-snmp/net-snmp-config.h>
00002 
00003 #include <stdio.h>
00004 #include <sys/types.h>
00005 #include <ctype.h>
00006 #include <errno.h>
00007 
00008 #ifdef WIN32
00009 #include <net-snmp/library/winpipe.h>
00010 #endif
00011 #if HAVE_STRING_H
00012 #include <string.h>
00013 #else
00014 #include <strings.h>
00015 #endif
00016 #if HAVE_STDLIB_H
00017 #include <stdlib.h>
00018 #endif
00019 #if HAVE_UNISTD_H
00020 #include <unistd.h>
00021 #endif
00022 #if HAVE_SYS_SOCKET_H
00023 #include <sys/socket.h>
00024 #endif
00025 #if HAVE_SYS_UN_H
00026 #include <sys/un.h>
00027 #endif
00028 #if HAVE_IO_H
00029 #include <io.h>
00030 #endif
00031 #if HAVE_FCNTL_H
00032 #include <fcntl.h>
00033 #endif
00034 
00035 #if HAVE_DMALLOC_H
00036 #include <dmalloc.h>
00037 #endif
00038 
00039 #include <net-snmp/types.h>
00040 #include <net-snmp/output_api.h>
00041 #include <net-snmp/config_api.h>
00042 #include <net-snmp/utilities.h>
00043 
00044 #include <net-snmp/library/snmp_transport.h>
00045 #include <net-snmp/library/snmpUnixDomain.h>
00046 #include <net-snmp/library/snmp_api.h>
00047 #include <net-snmp/library/snmp_client.h>
00048 #include <net-snmp/library/snmpCallbackDomain.h>
00049 
00050 #ifndef NETSNMP_STREAM_QUEUE_LEN
00051 #define NETSNMP_STREAM_QUEUE_LEN  5
00052 #endif
00053 
00054 #ifdef SNMP_TRANSPORT_CALLBACK_DOMAIN
00055 
00056 static netsnmp_transport_list *trlist = NULL;
00057 
00058 static int      callback_count = 0;
00059 
00060 typedef struct callback_hack_s {
00061     void           *orig_transport_data;
00062     netsnmp_pdu    *pdu;
00063 } callback_hack;
00064 
00065 typedef struct callback_queue_s {
00066     int             callback_num;
00067     netsnmp_callback_pass *item;
00068     struct callback_queue_s *next, *prev;
00069 } callback_queue;
00070 
00071 callback_queue *thequeue;
00072 
00073 static netsnmp_transport *
00074 find_transport_from_callback_num(int num)
00075 {
00076     static netsnmp_transport_list *ptr;
00077     for (ptr = trlist; ptr; ptr = ptr->next)
00078         if (((netsnmp_callback_info *) ptr->transport->data)->
00079             callback_num == num)
00080             return ptr->transport;
00081     return NULL;
00082 }
00083 
00084 static void
00085 callback_debug_pdu(const char *ourstring, netsnmp_pdu *pdu)
00086 {
00087     netsnmp_variable_list *vb;
00088     int             i = 1;
00089     DEBUGMSGTL((ourstring,
00090                 "PDU: command = %d, errstat = %d, errindex = %d\n",
00091                 pdu->command, pdu->errstat, pdu->errindex));
00092     for (vb = pdu->variables; vb; vb = vb->next_variable) {
00093         DEBUGMSGTL((ourstring, "  var %d:", i++));
00094         DEBUGMSGVAR((ourstring, vb));
00095         DEBUGMSG((ourstring, "\n"));
00096     }
00097 }
00098 
00099 void
00100 callback_push_queue(int num, netsnmp_callback_pass *item)
00101 {
00102     callback_queue *newitem = SNMP_MALLOC_TYPEDEF(callback_queue);
00103     callback_queue *ptr;
00104 
00105     newitem->callback_num = num;
00106     newitem->item = item;
00107     if (thequeue) {
00108         for (ptr = thequeue; ptr && ptr->next; ptr = ptr->next) {
00109         }
00110         ptr->next = newitem;
00111         newitem->prev = ptr;
00112     } else {
00113         thequeue = newitem;
00114     }
00115     DEBUGIF("dump_send_callback_transport") {
00116         callback_debug_pdu("dump_send_callback_transport", item->pdu);
00117     }
00118 }
00119 
00120 netsnmp_callback_pass *
00121 callback_pop_queue(int num)
00122 {
00123     netsnmp_callback_pass *cp;
00124     callback_queue *ptr;
00125 
00126     for (ptr = thequeue; ptr; ptr = ptr->next) {
00127         if (ptr->callback_num == num) {
00128             if (ptr->prev) {
00129                 ptr->prev->next = ptr->next;
00130             } else {
00131                 thequeue = ptr->next;
00132             }
00133             if (ptr->next) {
00134                 ptr->next->prev = ptr->prev;
00135             }
00136             cp = ptr->item;
00137             SNMP_FREE(ptr);
00138             DEBUGIF("dump_recv_callback_transport") {
00139                 callback_debug_pdu("dump_recv_callback_transport",
00140                                    cp->pdu);
00141             }
00142             return cp;
00143         }
00144     }
00145     return NULL;
00146 }
00147 
00148 /*
00149  * Return a string representing the address in data, or else the "far end"
00150  * address if data is NULL.  
00151  */
00152 
00153 char *
00154 netsnmp_callback_fmtaddr(netsnmp_transport *t, void *data, int len)
00155 {
00156     char buf[SPRINT_MAX_LEN];
00157     netsnmp_callback_info *mystuff;
00158 
00159     if (!t)
00160         return strdup("callback: unknown");
00161 
00162     mystuff = (netsnmp_callback_info *) t->data;
00163 
00164     if (!mystuff)
00165         return strdup("callback: unknown");
00166 
00167     snprintf(buf, SPRINT_MAX_LEN, "callback: %d on fd %d",
00168              mystuff->callback_num, mystuff->pipefds[0]);
00169     return strdup(buf);
00170 }
00171 
00172 
00173 
00174 /*
00175  * You can write something into opaque that will subsequently get passed back 
00176  * to your send function if you like.  For instance, you might want to
00177  * remember where a PDU came from, so that you can send a reply there...  
00178  */
00179 
00180 int
00181 netsnmp_callback_recv(netsnmp_transport *t, void *buf, int size,
00182                       void **opaque, int *olength)
00183 {
00184     int rc = -1;
00185     char newbuf[1];
00186     netsnmp_callback_info *mystuff = (netsnmp_callback_info *) t->data;
00187 
00188     DEBUGMSGTL(("transport_callback", "hook_recv enter\n"));
00189 
00190     while (rc < 0) {
00191 #ifdef WIN32
00192         rc = recv(mystuff->pipefds[0], newbuf, 1, 0);
00193 #else
00194         rc = read(mystuff->pipefds[0], newbuf, 1);
00195 #endif
00196         if (rc < 0 && errno != EINTR) {
00197             break;
00198         }
00199     }
00200 
00201     if (mystuff->linkedto) {
00202         /*
00203          * we're the client.  We don't need to do anything. 
00204          */
00205     } else {
00206         /*
00207          * malloc the space here, but it's filled in by
00208          * snmp_callback_created_pdu() below 
00209          */
00210         int            *returnnum = (int *) calloc(1, sizeof(int));
00211         *opaque = returnnum;
00212         *olength = sizeof(int);
00213     }
00214     DEBUGMSGTL(("transport_callback", "hook_recv exit\n"));
00215     return rc;
00216 }
00217 
00218 
00219 
00220 int
00221 netsnmp_callback_send(netsnmp_transport *t, void *buf, int size,
00222                       void **opaque, int *olength)
00223 {
00224     int from, rc = -1;
00225     netsnmp_callback_info *mystuff = (netsnmp_callback_info *) t->data;
00226     netsnmp_callback_pass *cp;
00227 
00228     /*
00229      * extract the pdu from the hacked buffer 
00230      */
00231     netsnmp_transport *other_side;
00232     callback_hack  *ch = (callback_hack *) * opaque;
00233     netsnmp_pdu    *pdu = ch->pdu;
00234     *opaque = ch->orig_transport_data;
00235     SNMP_FREE(ch);
00236 
00237     DEBUGMSGTL(("transport_callback", "hook_send enter\n"));
00238 
00239     cp = SNMP_MALLOC_TYPEDEF(netsnmp_callback_pass);
00240     if (!cp)
00241         return -1;
00242 
00243     cp->pdu = snmp_clone_pdu(pdu);
00244     if (cp->pdu->transport_data) {
00245         /*
00246          * not needed and not properly freed later 
00247          */
00248         SNMP_FREE(cp->pdu->transport_data);
00249     }
00250 
00251     if (cp->pdu->flags & UCD_MSG_FLAG_EXPECT_RESPONSE)
00252         cp->pdu->flags ^= UCD_MSG_FLAG_EXPECT_RESPONSE;
00253 
00254     /*
00255      * push the sent pdu onto the stack 
00256      */
00257     /*
00258      * AND send a bogus byte to the remote callback receiver's pipe 
00259      */
00260     if (mystuff->linkedto) {
00261         /*
00262          * we're the client, send it to the parent 
00263          */
00264         cp->return_transport_num = mystuff->callback_num;
00265 
00266         other_side = find_transport_from_callback_num(mystuff->linkedto);
00267         if (!other_side) {
00268             snmp_free_pdu(cp->pdu);
00269             SNMP_FREE(cp);
00270             return -1;
00271         }
00272 
00273         while (rc < 0) {
00274 #ifdef WIN32
00275             rc = send(((netsnmp_callback_info*) other_side->data)->pipefds[1], " ", 1, 0);
00276 #else
00277             rc = write(((netsnmp_callback_info *)other_side->data)->pipefds[1],
00278                        " ", 1);
00279 #endif
00280             if (rc < 0 && errno != EINTR) {
00281                 break;
00282             }
00283         }
00284         callback_push_queue(mystuff->linkedto, cp);
00285         /*
00286          * we don't need the transport data any more 
00287          */
00288         if (*opaque) {
00289             SNMP_FREE(*opaque);
00290             *opaque = NULL;
00291         }
00292     } else {
00293         /*
00294          * we're the server, send it to the person that sent us the request 
00295          */
00296         from = **((int **) opaque);
00297         /*
00298          * we don't need the transport data any more 
00299          */
00300         if (*opaque) {
00301             SNMP_FREE(*opaque);
00302             *opaque = NULL;
00303         }
00304         other_side = find_transport_from_callback_num(from);
00305         if (!other_side) {
00306             snmp_free_pdu(cp->pdu);
00307             SNMP_FREE(cp);
00308             return -1;
00309         }
00310         while (rc < 0) {
00311 #ifdef WIN32
00312             rc = send(((netsnmp_callback_info*) other_side->data)->pipefds[1], " ", 1, 0);
00313 #else
00314             rc = write(((netsnmp_callback_info *)other_side->data)->pipefds[1],
00315                        " ", 1);
00316 #endif
00317             if (rc < 0 && errno != EINTR) {
00318                 break;
00319             }
00320         }
00321         callback_push_queue(from, cp);
00322     }
00323 
00324     DEBUGMSGTL(("transport_callback", "hook_send exit\n"));
00325     return 0;
00326 }
00327 
00328 
00329 
00330 int
00331 netsnmp_callback_close(netsnmp_transport *t)
00332 {
00333     int             rc;
00334     netsnmp_callback_info *mystuff = (netsnmp_callback_info *) t->data;
00335     DEBUGMSGTL(("transport_callback", "hook_close enter\n"));
00336 
00337 #ifdef WIN32
00338     rc  = closesocket(mystuff->pipefds[0]);
00339     rc |= closesocket(mystuff->pipefds[1]);
00340 #else
00341     rc  = close(mystuff->pipefds[0]);
00342     rc |= close(mystuff->pipefds[1]);
00343 #endif
00344 
00345     rc |= netsnmp_transport_remove_from_list(&trlist, t);
00346 
00347     DEBUGMSGTL(("transport_callback", "hook_close exit\n"));
00348     return rc;
00349 }
00350 
00351 
00352 
00353 int
00354 netsnmp_callback_accept(netsnmp_transport *t)
00355 {
00356     DEBUGMSGTL(("transport_callback", "hook_accept enter\n"));
00357     DEBUGMSGTL(("transport_callback", "hook_accept exit\n"));
00358     return 0;
00359 }
00360 
00361 
00362 
00363 /*
00364  * Open a Callback-domain transport for SNMP.  Local is TRUE if addr
00365  * is the local address to bind to (i.e. this is a server-type
00366  * session); otherwise addr is the remote address to send things to
00367  * (and we make up a temporary name for the local end of the
00368  * connection).  
00369  */
00370 
00371 netsnmp_transport *
00372 netsnmp_callback_transport(int to)
00373 {
00374 
00375     netsnmp_transport *t = NULL;
00376     netsnmp_callback_info *mydata;
00377     int             rc;
00378 
00379     /*
00380      * transport 
00381      */
00382     t = SNMP_MALLOC_TYPEDEF(netsnmp_transport);
00383     if (!t)
00384         return NULL;
00385 
00386     /*
00387      * our stuff 
00388      */
00389     mydata = SNMP_MALLOC_TYPEDEF(netsnmp_callback_info);
00390     mydata->linkedto = to;
00391     mydata->callback_num = ++callback_count;
00392     mydata->data = NULL;
00393     t->data = mydata;
00394 
00395 #ifdef WIN32
00396     rc = create_winpipe_transport(mydata->pipefds);
00397 #else
00398     rc = pipe(mydata->pipefds);
00399 #endif
00400     t->sock = mydata->pipefds[0];
00401 
00402     if (rc) {
00403         SNMP_FREE(mydata);
00404         SNMP_FREE(t);
00405         return NULL;
00406     }
00407 
00408     t->f_recv    = netsnmp_callback_recv;
00409     t->f_send    = netsnmp_callback_send;
00410     t->f_close   = netsnmp_callback_close;
00411     t->f_accept  = netsnmp_callback_accept;
00412     t->f_fmtaddr = netsnmp_callback_fmtaddr;
00413 
00414     netsnmp_transport_add_to_list(&trlist, t);
00415 
00416     if (to)
00417         DEBUGMSGTL(("transport_callback", "initialized %d linked to %d\n",
00418                     mydata->callback_num, to));
00419     else
00420         DEBUGMSGTL(("transport_callback",
00421                     "initialized master listening on %d\n",
00422                     mydata->callback_num));
00423     return t;
00424 }
00425 
00426 int
00427 netsnmp_callback_hook_parse(netsnmp_session * sp,
00428                             netsnmp_pdu *pdu,
00429                             u_char * packetptr, size_t len)
00430 {
00431     if (SNMP_MSG_RESPONSE == pdu->command ||
00432         SNMP_MSG_REPORT == pdu->command)
00433         pdu->flags |= UCD_MSG_FLAG_RESPONSE_PDU;
00434     else
00435         pdu->flags &= (~UCD_MSG_FLAG_RESPONSE_PDU);
00436 
00437     return SNMP_ERR_NOERROR;
00438 }
00439 
00440 int
00441 netsnmp_callback_hook_build(netsnmp_session * sp,
00442                             netsnmp_pdu *pdu, u_char * ptk, size_t * len)
00443 {
00444     /*
00445      * very gross hack, as this is passed later to the transport_send
00446      * function 
00447      */
00448     callback_hack  *ch = SNMP_MALLOC_TYPEDEF(callback_hack);
00449     DEBUGMSGTL(("transport_callback", "hook_build enter\n"));
00450     ch->pdu = pdu;
00451     ch->orig_transport_data = pdu->transport_data;
00452     pdu->transport_data = ch;
00453     switch (pdu->command) {
00454     case SNMP_MSG_GETBULK:
00455         if (pdu->max_repetitions < 0) {
00456             sp->s_snmp_errno = SNMPERR_BAD_REPETITIONS;
00457             return -1;
00458         }
00459         if (pdu->non_repeaters < 0) {
00460             sp->s_snmp_errno = SNMPERR_BAD_REPEATERS;
00461             return -1;
00462         }
00463         break;
00464     case SNMP_MSG_RESPONSE:
00465     case SNMP_MSG_TRAP:
00466     case SNMP_MSG_TRAP2:
00467         pdu->flags &= (~UCD_MSG_FLAG_EXPECT_RESPONSE);
00468         /*
00469          * Fallthrough
00470          */
00471     default:
00472         if (pdu->errstat == SNMP_DEFAULT_ERRSTAT)
00473             pdu->errstat = 0;
00474         if (pdu->errindex == SNMP_DEFAULT_ERRINDEX)
00475             pdu->errindex = 0;
00476         break;
00477     }
00478 
00479     /*
00480      * Copy missing values from session defaults
00481      */
00482     switch (pdu->version) {
00483 #ifndef DISABLE_SNMPV1
00484     case SNMP_VERSION_1:
00485 #endif
00486 #ifndef DISABLE_SNMPV2C
00487     case SNMP_VERSION_2c:
00488 #endif
00489 #if !defined(DISABLE_SNMPV1) || !defined(DISABLE_SNMPV2C)
00490         if (pdu->community_len == 0) {
00491             if (sp->community_len == 0) {
00492                 sp->s_snmp_errno = SNMPERR_BAD_COMMUNITY;
00493                 return -1;
00494             }
00495             pdu->community = (u_char *) malloc(sp->community_len);
00496             if (pdu->community == NULL) {
00497                 sp->s_snmp_errno = SNMPERR_MALLOC;
00498                 return -1;
00499             }
00500             memmove(pdu->community,
00501                     sp->community, sp->community_len);
00502             pdu->community_len = sp->community_len;
00503         }
00504         break;
00505 #endif
00506     case SNMP_VERSION_3:
00507         if (pdu->securityNameLen == 0) {
00508             pdu->securityName = malloc(sp->securityNameLen);
00509             if (pdu->securityName == NULL) {
00510                 sp->s_snmp_errno = SNMPERR_MALLOC;
00511                 return -1;
00512             }
00513             memmove(pdu->securityName,
00514                      sp->securityName, sp->securityNameLen);
00515             pdu->securityNameLen = sp->securityNameLen;
00516         }
00517         if (pdu->securityModel == -1)
00518             pdu->securityModel = sp->securityModel;
00519         if (pdu->securityLevel == 0)
00520             pdu->securityLevel = sp->securityLevel;
00521         /* WHAT ELSE ?? */
00522     }
00523     *len = 1;
00524     DEBUGMSGTL(("transport_callback", "hook_build exit\n"));
00525     return 1;
00526 }
00527 
00528 int
00529 netsnmp_callback_check_packet(u_char * pkt, size_t len)
00530 {
00531     return 1;
00532 }
00533 
00534 netsnmp_pdu    *
00535 netsnmp_callback_create_pdu(netsnmp_transport *transport,
00536                             void *opaque, size_t olength)
00537 {
00538     netsnmp_pdu    *pdu;
00539     netsnmp_callback_pass *cp =
00540         callback_pop_queue(((netsnmp_callback_info *) transport->data)->
00541                            callback_num);
00542     if (!cp)
00543         return NULL;
00544     pdu = cp->pdu;
00545     pdu->transport_data = opaque;
00546     pdu->transport_data_length = olength;
00547     if (opaque)                 /* if created, we're the server */
00548         *((int *) opaque) = cp->return_transport_num;
00549     SNMP_FREE(cp);
00550     return pdu;
00551 }
00552 
00553 netsnmp_session *
00554 netsnmp_callback_open(int attach_to,
00555                       int (*return_func) (int op,
00556                                           netsnmp_session * session,
00557                                           int reqid, netsnmp_pdu *pdu,
00558                                           void *magic),
00559                       int (*fpre_parse) (netsnmp_session *,
00560                                          struct netsnmp_transport_s *,
00561                                          void *, int),
00562                       int (*fpost_parse) (netsnmp_session *, netsnmp_pdu *,
00563                                           int))
00564 {
00565     netsnmp_session callback_sess, *callback_ss;
00566     netsnmp_transport *callback_tr;
00567 
00568     callback_tr = netsnmp_callback_transport(attach_to);
00569     snmp_sess_init(&callback_sess);
00570     callback_sess.callback = return_func;
00571     if (attach_to) {
00572         /*
00573          * client 
00574          */
00575         /*
00576          * trysess.community = (u_char *) callback_ss; 
00577          */
00578     } else {
00579         callback_sess.isAuthoritative = SNMP_SESS_AUTHORITATIVE;
00580     }
00581     callback_sess.remote_port = 0;
00582     callback_sess.retries = 0;
00583     callback_sess.timeout = 30000000;
00584     callback_sess.version = SNMP_DEFAULT_VERSION;       /* (mostly) bogus */
00585     callback_ss = snmp_add_full(&callback_sess, callback_tr,
00586                                 fpre_parse,
00587                                 netsnmp_callback_hook_parse, fpost_parse,
00588                                 netsnmp_callback_hook_build,
00589                                 NULL,
00590                                 netsnmp_callback_check_packet,
00591                                 netsnmp_callback_create_pdu);
00592     if (callback_ss)
00593         callback_ss->local_port =
00594             ((netsnmp_callback_info *) callback_tr->data)->callback_num;
00595     return callback_ss;
00596 }
00597 
00598 
00599 
00600 void
00601 netsnmp_clear_callback_list(void)
00602 {
00603 
00604     netsnmp_transport_list *list = trlist, *next = NULL;
00605     netsnmp_transport *tr = NULL;
00606 
00607     DEBUGMSGTL(("callback_clear", "called netsnmp_callback_clear_list()\n"));
00608     while (list != NULL) {
00609         next = list->next;
00610         tr = list->transport;
00611 
00612         if (tr != NULL) {
00613             tr->f_close(tr);
00614             netsnmp_transport_remove_from_list(&trlist, list->transport);
00615             netsnmp_transport_free(list->transport);
00616         }
00617         list = next;
00618     }
00619     trlist = NULL;
00620 
00621 }
00622 
00623 #endif /* SNMP_TRANSPORT_CALLBACK_DOMAIN */

net-snmpに対してSat Sep 5 13:14:25 2009に生成されました。  doxygen 1.4.7