snmpd.c
上传用户:cxs890
上传日期:2021-05-22
资源大小:347k
文件大小:15k
源码类别:

SNMP编程

开发平台:

C/C++

  1. /*
  2.  * snmpd.c - rrespond to SNMP queries from management stations
  3.  *
  4.  */
  5. /***********************************************************
  6. Copyright 1988, 1989 by Carnegie Mellon University
  7.                       All Rights Reserved
  8. Permission to use, copy, modify, and distribute this software and its 
  9. documentation for any purpose and without fee is hereby granted, 
  10. provided that the above copyright notice appear in all copies and that
  11. both that copyright notice and this permission notice appear in 
  12. supporting documentation, and that the name of CMU not be
  13. used in advertising or publicity pertaining to distribution of the
  14. software without specific, written prior permission.  
  15. CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  16. ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
  17. CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
  18. ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  19. WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  20. ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  21. SOFTWARE.
  22. ******************************************************************/
  23. #ifdef OS_VXWORKS
  24. #include <libsys/vos/vos_rtos.h>
  25. #include <global.h>
  26. #endif
  27. #include <ip/socket.h>
  28. #include <config.h>
  29. #include <stdio.h>
  30. #include <errno.h>
  31. #if HAVE_STRING_H
  32. #include <string.h>
  33. #else
  34. #include <strings.h>
  35. #endif
  36. #if HAVE_STDLIB_H
  37. #include <stdlib.h>
  38. #endif
  39. #if HAVE_UNISTD_H
  40. #include <unistd.h>
  41. #endif
  42. #include <sys/types.h>
  43. #if HAVE_NETINET_IN_H
  44. #include <netinet/in.h>
  45. #endif
  46. #if HAVE_ARPA_INET_H
  47. #include <arpa/inet.h>
  48. #endif
  49. #if TIME_WITH_SYS_TIME
  50. # ifdef WIN32
  51. #  include <sys/timeb.h>
  52. # else
  53. #  include <time.h>
  54. # endif
  55. # include <time.h>
  56. #else
  57. # if HAVE_SYS_TIME_H
  58. #  include <sys/time.h>
  59. # else
  60. #  include <time.h>
  61. # endif
  62. #endif
  63. #if HAVE_SYS_SELECT_H
  64. #include <sys/select.h>
  65. #endif
  66. #if HAVE_SYS_SOCKET_H
  67. #include <sys/socket.h>
  68. #elif HAVE_WINSOCK_H
  69. #endif
  70. #if HAVE_NET_IF_H
  71. #include <net/if.h>
  72. #endif
  73. #if HAVE_INET_MIB2_H
  74. #include <inet/mib2.h>
  75. #endif
  76. #if HAVE_SYS_IOCTL_H
  77. #include <sys/ioctl.h>
  78. #endif
  79. #if HAVE_SYS_FILE_H
  80. #include <sys/file.h>
  81. #endif
  82. #ifdef HAVE_FCNTL_H
  83. #include <fcntl.h>
  84. #endif
  85. #if HAVE_SYS_WAIT_H
  86. #include <sys/wait.h>
  87. #endif
  88. #include <signal.h>
  89. #ifdef HAVE_SYS_PARAM_H
  90. #include <sys/param.h>
  91. #endif
  92. #include <ip/inet.h>
  93. #ifndef FD_SET
  94. typedef long    fd_mask;
  95. #define NFDBITS (sizeof(fd_mask) * NBBY)        /* bits per mask */
  96. #define FD_SET(n, p)    ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
  97. #define FD_CLR(n, p)    ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
  98. #define FD_ISSET(n, p)  ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
  99. #define FD_ZERO(p)      memset((p), 0, sizeof(*(p)))
  100. #endif
  101. #if HAVE_DMALLOC_H
  102. #include <dmalloc.h>
  103. #endif
  104. #include "asn1.h"
  105. #include "snmp_api.h"
  106. #include "snmp_impl.h"
  107. #include "read_config.h"
  108. #include "snmp.h"
  109. #include "mib.h"
  110. #include "m2m.h"
  111. #include "snmp_vars.h"
  112. #include "agent_read_config.h"
  113. #include "snmpv3.h"
  114. #include "callback.h"
  115. #include "snmp_alarm.h"
  116. #include "default_store.h"
  117. #include "mib_module_config.h"
  118. #include "snmp_client.h"
  119. #include "snmpd.h"
  120. #include "var_struct.h"
  121. #include "mibgroup/struct.h"
  122. #include "mibgroup/util_funcs.h"
  123. #include "snmp_debug.h"
  124. #include "mib_modules.h"
  125. #include "snmpusm.h"
  126. #include "tools.h"
  127. #include "lcd_time.h"
  128. #include "snmp_agent.h"
  129. #include "agent_trap.h"
  130. #include "ds_agent.h"
  131. #include "agent_read_config.h"
  132. #include "snmp_logging.h"
  133. #include "version.h"
  134. #include "mib_module_includes.h"
  135. #include "system.h"
  136. /*
  137.  * Globals.
  138.  */
  139. #ifdef USE_LIBWRAP
  140. #include <tcpd.h>
  141. int allow_severity  = LOG_INFO;
  142. int deny_severity  = LOG_WARNING;
  143. #endif  /* USE_LIBWRAP */
  144. #define TIMETICK         500000L
  145. #define ONE_SEC         1000000L
  146. int  log_addresses  = 0;
  147. int  snmp_dump_packet;
  148. int             running          = 1;
  149. int reconfig  = 0;
  150. struct addrCache {
  151.     in_addr_t addr;
  152.     int status;
  153. #define UNUSED 0
  154. #define USED 1
  155. #define OLD 2
  156. };
  157. #define ADDRCACHE 10
  158. static struct addrCache addrCache[ADDRCACHE];
  159. static int lastAddrAge = 0;
  160. #define NUM_SOCKETS 32
  161. #ifdef USING_SMUX_MODULE
  162. static int sdlist[NUM_SOCKETS], sdlen = 0;
  163. int smux_listen_sd;
  164. #endif /* USING_SMUX_MODULE */
  165. /*
  166.  * Prototypes.
  167.  */
  168. int snmp_read_packet (int);
  169. int snmp_input (int, struct snmp_session *, int, struct snmp_pdu *, void *);
  170. int main (int, char **);
  171. static void SnmpTrapNodeDown (void);
  172. int receive(void);
  173. int snmp_check_packet(struct snmp_session*, struct soaddr);
  174. int snmp_check_parse(struct snmp_session*, struct snmp_pdu*, int);
  175. extern int  gettimeofday(struct timeval *tp,struct timezone *tzp);
  176. extern void set_trapd_session_ptr (void);
  177. extern void init_trap_retry_timer(void);
  178. #ifdef SIGHUP
  179. RETSIGTYPE
  180. SnmpdReconfig(int a)
  181. {
  182. reconfig = 1;
  183. signal(SIGHUP, SnmpdReconfig);
  184. }
  185. #endif
  186. #ifdef SIGUSR1
  187. extern void dump_registry( void );
  188. RETSIGTYPE
  189. SnmpdDump(int a)
  190. {
  191. dump_registry();
  192. signal(SIGUSR1, SnmpdDump);
  193. }
  194. #endif
  195. static void
  196. SnmpTrapNodeDown(void)
  197. {
  198.     send_easy_trap (SNMP_TRAP_ENTERPRISESPECIFIC, 2);
  199.     /* XXX  2 - Node Down #define it as NODE_DOWN_TRAP */
  200. }
  201. void snmp_set_dump_verbose (int value)
  202. {
  203. ds_set_boolean(DS_APPLICATION_ID, DS_AGENT_VERBOSE, value);
  204. }
  205. /*******************************************************************-o-******
  206.  * main
  207.  *
  208.  * Parameters:
  209.  *  argc
  210.  * *argv[]
  211.  *      
  212.  * Returns:
  213.  * 0 Always succeeds.  (?)
  214.  *
  215.  *
  216.  * Setup and start the agent daemon.
  217.  *
  218.  * Also successfully EXITs with zero for some options.
  219.  */
  220. extern ULONG snmp_source_ip;
  221. extern int output_error;
  222. int
  223. snmpd_init(void)
  224. {
  225. int             ret;
  226. u_short         dest_port = SNMP_PORT;
  227. #if HAVE_GETPID
  228. FILE           *PID;
  229. #endif
  230.     init_agent("snmpd"); /* do what we need to do first. */
  231.     init_mib_modules();
  232. init_start_time();
  233.    /* start library */
  234.     init_snmp("snmpd");
  235.     snmp_source_ip= INADDR_ANY;
  236.     ret = init_master_agent( dest_port,
  237.                        snmp_check_packet,
  238.                        snmp_check_parse );
  239. if( ret != 0 )
  240. {
  241. snmp_trace ("Create socket failn");
  242. return 0;
  243. }
  244. init_start_time ();
  245. memset(addrCache, 0, sizeof(addrCache));
  246. /* 
  247.  * Forever monitor the dest_port for incoming PDUs.
  248.  */
  249. init_mib_system();
  250. ds_set_boolean(DS_LIBRARY_ID, DS_LIB_PRINT_FULL_OID, 0);
  251. output_error = 0;
  252. set_trapd_session_ptr();
  253. init_trap_retry_timer();
  254. return 0;
  255. }  /* End main() -- snmpd */
  256. /*******************************************************************-o-******
  257.  * receive
  258.  *
  259.  * Parameters:
  260.  *      
  261.  * Returns:
  262.  * 0 On success.
  263.  * -1 System error.
  264.  *
  265.  * Infinite while-loop which monitors incoming messges for the agent.
  266.  * Invoke the established message handlers for incoming messages on a per
  267.  * port basis.  Handle timeouts.
  268.  */
  269. int
  270. receive(void)
  271. {
  272.     int numfds;
  273.     fd_set fdset;
  274.     struct timeval timeout, *tvp;
  275.     struct timeval sched,   *svp = &sched,
  276. now,     *nvp = &now;
  277.     int count, block;
  278. #ifdef USING_SMUX_MODULE
  279.     int i, sd;
  280. #endif /* USING_SMUX_MODULE */
  281.     /*
  282.      * Set the 'sched'uled timeout to the current time + one TIMETICK.
  283.      */
  284.     gettimeofday(nvp, (struct timezone *) NULL);
  285.     svp->tv_usec = nvp->tv_usec + TIMETICK;
  286.     svp->tv_sec = nvp->tv_sec;
  287.     
  288.     while (svp->tv_usec >= ONE_SEC){
  289. svp->tv_usec -= ONE_SEC;
  290. svp->tv_sec++;
  291.     }
  292.     /*
  293.      * Loop-forever: execute message handlers for sockets with data,
  294.      * reset the 'sched'uler.
  295.      */
  296.     while (running) {
  297. tvp =  &timeout;
  298. tvp->tv_sec = 0;
  299. tvp->tv_usec = TIMETICK;
  300. numfds = 0;
  301. FD_ZERO(&fdset);
  302.         block = 0;
  303. /*        snmp_select_info(&numfds, &fdset, tvp, &block);*/
  304.         snmp_sess_select_info(NULL, &numfds, &fdset, tvp, &block);
  305.         if (block == 1)
  306.             tvp = NULL; /* block without timeout */
  307. #ifdef USING_SMUX_MODULE
  308. if (smux_listen_sd >= 0) {
  309. FD_SET(smux_listen_sd, &fdset);
  310. numfds = smux_listen_sd >= numfds ? smux_listen_sd + 1 : numfds;
  311. for (i = 0; i < sdlen; i++) {
  312. FD_SET(sdlist[i], &fdset);
  313. numfds = sdlist[i] >= numfds ? sdlist[i] + 1 : numfds;
  314. }
  315. }
  316. #endif /* USING_SMUX_MODULE */
  317. count = so_select(numfds, &fdset, 0, 0, tvp);
  318. if (count > 0){
  319.     snmp_read(&fdset);
  320. } else switch(count){
  321. case 0:
  322.                 snmp_timeout();
  323.                 break;
  324.     case -1:
  325.      tm_wkafter(1);
  326.      break;
  327. /* if (errno == EINTR){
  328.     continue;
  329. } else {
  330.                     snmp_trace("socket select err");
  331. }
  332. return -1;*/
  333.     default:
  334. snmp_trace("select returned %dn", count);
  335. /*return -1;*/
  336. tm_wkafter(1);
  337. break;
  338. }  /* endif -- count>0 */
  339. #ifdef USING_SMUX_MODULE
  340. /* handle the SMUX sd's */
  341. if (smux_listen_sd >= 0) {
  342. for (i = 0; i < sdlen; i++) {
  343. if (FD_ISSET(sdlist[i], &fdset)) {
  344. if (smux_process(sdlist[i]) < 0) {
  345. for (; i < (sdlen - 1); i++) {
  346. sdlist[i] = sdlist[i+1];
  347. }
  348. sdlen--;
  349. }
  350. }
  351. }
  352. /* new connection */
  353. if (FD_ISSET(smux_listen_sd, &fdset)) {
  354. if ((sd = smux_accept(smux_listen_sd)) >= 0) {
  355. sdlist[sdlen++] = sd;
  356. }
  357. }
  358. }
  359. #endif /* USING_SMUX_MODULE */
  360.         /*
  361.          * If the time 'now' is greater than the 'sched'uled time, then:
  362.          *
  363.          *    Check alarm and event timers.
  364.          *    Reset the 'sched'uled time to current time + one TIMETICK.
  365.          *    Age the cache network addresses (from whom messges have
  366.          *        been received).
  367.          */
  368.         gettimeofday(nvp, (struct timezone *) NULL);
  369.         if (nvp->tv_sec > svp->tv_sec
  370.                 || (nvp->tv_sec == svp->tv_sec && nvp->tv_usec > svp->tv_usec)){
  371.             svp->tv_usec = nvp->tv_usec + TIMETICK;
  372.             svp->tv_sec = nvp->tv_sec;
  373.             while (svp->tv_usec >= ONE_SEC){
  374.                 svp->tv_usec -= ONE_SEC;
  375.                 svp->tv_sec++;
  376.             }
  377.             if (log_addresses && lastAddrAge++ > 600){
  378.                 lastAddrAge = 0;
  379.                 for(count = 0; count < ADDRCACHE; count++){
  380.                     if (addrCache[count].status == OLD)
  381.                         addrCache[count].status = UNUSED;
  382.                     if (addrCache[count].status == USED)
  383.                         addrCache[count].status = OLD;
  384.                 }
  385.             }
  386.         }  /* endif -- now>sched */
  387.         /* run requested alarms */
  388.         run_alarms();
  389.         
  390.     }  /* endwhile */
  391.     snmp_trace("Received TERM or STOP signal...  shutting down...n");
  392.     return 0;
  393. }  /* end receive() */
  394. /*******************************************************************-o-******
  395.  * snmp_check_packet
  396.  *
  397.  * Parameters:
  398.  * session, from
  399.  *      
  400.  * Returns:
  401.  * 1 On success.
  402.  * 0 On error.
  403.  *
  404.  * Handler for all incoming messages (a.k.a. packets) for the agent.  If using
  405.  * the libwrap utility, log the connection and deny/allow the access. Print
  406.  * output when appropriate, and increment the incoming counter.
  407.  *
  408.  */
  409. int
  410. snmp_check_packet(struct snmp_session *session,
  411.   struct soaddr from)
  412. {
  413.     struct soaddr_in *fromIp = (struct soaddr_in *)&from;
  414. #ifdef USE_LIBWRAP
  415.     const char *addr_string;
  416.     /*
  417.      * Log the message and/or dump the message.
  418.      * Optionally cache the network address of the sender.
  419.      */
  420.     addr_string = inet_ntoa(fromIp->sin_addr);
  421.     if(!addr_string) {
  422.       addr_string = STRING_UNKNOWN;
  423.     }
  424.     if(hosts_ctl("snmpd", addr_string, addr_string, STRING_UNKNOWN)) {
  425.       snmp_trace( "Connection from %sn", addr_string);
  426.     } else {
  427.       snmp_trace("Connection from %s REFUSEDn", addr_string);
  428.       return(0);
  429.     }
  430. #endif /* USE_LIBWRAP */
  431.     snmp_increment_statistic(STAT_SNMPINPKTS);
  432.     if (log_addresses || ds_get_boolean(DS_APPLICATION_ID, DS_AGENT_VERBOSE)){
  433. int count;
  434. for(count = 0; count < ADDRCACHE; count++){
  435.     if (addrCache[count].status > UNUSED /* used or old */
  436. && fromIp->sin_addr.s_addr == addrCache[count].addr)
  437. break;
  438. }
  439. if (count >= ADDRCACHE ||
  440.             ds_get_boolean(DS_APPLICATION_ID, DS_AGENT_VERBOSE)){
  441.     snmp_trace("nReceived SNMP packet(s) from %sn",
  442.                         inet_ntoa(fromIp->sin_addr));
  443.     for(count = 0; count < ADDRCACHE; count++){
  444. if (addrCache[count].status == UNUSED){
  445.     addrCache[count].addr = fromIp->sin_addr.s_addr;
  446.     addrCache[count].status = USED;
  447.     break;
  448. }
  449.     }
  450. } else {
  451.     addrCache[count].status = USED;
  452. }
  453.     }
  454.     return ( 1 );
  455. }
  456. int snmp_get_do_logging (void)
  457. {
  458. return 0;
  459. }
  460. int
  461. snmp_check_parse( struct snmp_session *session,
  462.     struct snmp_pdu     *pdu,
  463.     int    result)
  464. {
  465.     if ( result == 0 ) {
  466.         if ( ds_get_boolean(DS_APPLICATION_ID, DS_AGENT_VERBOSE)) 
  467. {
  468.      char c_oid [SPRINT_MAX_LEN];
  469.      struct variable_list *var_ptr;
  470.     
  471.     switch (pdu->command) {
  472.     case SNMP_MSG_GET:
  473.      snmp_trace("  SNMP: GET requestn"); break;
  474.     case SNMP_MSG_GETNEXT:
  475.      snmp_trace("  SNMP: GETNEXT requestn"); break;
  476.     case SNMP_MSG_RESPONSE:
  477.      snmp_trace("  SNMP: RESPONSE messagen"); break;
  478.     case SNMP_MSG_SET:
  479.      snmp_trace("  SNMP: SET requestn"); break;
  480.     case SNMP_MSG_TRAP:
  481.      snmp_trace("  SNMP: TRAP messagen"); break;
  482.     case SNMP_MSG_GETBULK:
  483.      snmp_trace("  SNMP: GETBULK request, non-rep=%d, max_rep=%dn",
  484. pdu->errstat, pdu->errindex); break;
  485.     case SNMP_MSG_INFORM:
  486.      snmp_trace("  SNMP: INFORM messagen"); break;
  487.     case SNMP_MSG_TRAP2:
  488.      snmp_trace("  SNMP: TRAP2 messagen"); break;
  489.     case SNMP_MSG_REPORT:
  490.      snmp_trace("  SNMP: REPORT messagen"); break;
  491.     }
  492.      
  493.     for ( var_ptr = pdu->variables ;
  494.         var_ptr != NULL ; var_ptr=var_ptr->next_variable )
  495.     {
  496.                 sprint_objid (c_oid, var_ptr->name, var_ptr->name_length);
  497.                 snmp_trace("    -- %sn", c_oid);
  498.     }
  499. }
  500.      return 1;
  501.     }
  502.     return 0; /* XXX: does it matter what the return value is? */
  503. }
  504. /*******************************************************************-o-******
  505.  * snmp_input
  506.  *
  507.  * Parameters:
  508.  *  op
  509.  * *session
  510.  *  requid
  511.  * *pdu
  512.  * *magic
  513.  *      
  514.  * Returns:
  515.  * 1 On success -OR-
  516.  * Passes through Return from alarmGetResponse() when 
  517.  *      USING_V2PARTY_ALARM_MODULE is defined.
  518.  *
  519.  * Call-back function to manage responses to traps (informs) and alarms.
  520.  * Not used by the agent to process other Response PDUs.
  521.  */
  522. int
  523. snmp_input(int op,
  524.    struct snmp_session *session,
  525.    int reqid,
  526.    struct snmp_pdu *pdu,
  527.    void *magic)
  528. {
  529.     struct get_req_state *state = (struct get_req_state *)magic;
  530.     
  531.     if (op == RECEIVED_MESSAGE) {
  532. if (pdu->command == SNMP_MSG_GET) {
  533.     if (state->type == EVENT_GET_REQ) {
  534. /* this is just the ack to our inform pdu */
  535. return 1;
  536.     }
  537. }
  538.     }
  539.     else if (op == TIMED_OUT) {
  540. if (state->type == ALARM_GET_REQ) {
  541. /* Need a mechanism to replace obsolete SNMPv2p alarm */
  542. }
  543.     }
  544.     return 1;
  545. }  /* end snmp_input() */