Changeset 374e7c3da4113ce22e1687b5f03fdba7845dab41

Show
Ignore:
Timestamp:
03/16/09 14:30:25 (5 years ago)
Author:
Theo Schlossnagle <jesus@omniti.com>
git-committer:
Theo Schlossnagle <jesus@omniti.com> 1237213825 +0000
git-parent:

[fc52ce1c8e051b2acc414eb64b229b43f8329b20]

git-author:
Theo Schlossnagle <jesus@omniti.com> 1237213825 +0000
Message:

Working traps. refs #37

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • src/modules/Makefile.in

    r7c400ba r374e7c3  
    106106        @echo "- linking $@" 
    107107 
    108 snmp.lo:        snmp.xmlh 
     108snmp.lo:        snmp.xmlh snmptrap.xmlh 
    109109 
    110110.c.lo: 
  • src/modules/snmp.c

    r09764a1 r374e7c3  
    1111#include <assert.h> 
    1212#include <math.h> 
     13#include <ctype.h> 
    1314 
    1415#include <net-snmp/net-snmp-config.h> 
     
    2324static noit_log_stream_t nlerr = NULL; 
    2425static noit_log_stream_t nldeb = NULL; 
    25 static noit_hash_table target_sessions = NOIT_HASH_EMPTY; 
     26static int __snmp_initialize_once = 0; 
     27 
     28#define SNMPV2_TRAPS_PREFIX     SNMP_OID_SNMPMODULES,1,1,5 
     29oid trap_prefix[]    = { SNMPV2_TRAPS_PREFIX }; 
     30oid cold_start_oid[] = { SNMPV2_TRAPS_PREFIX, 1 };  /* SNMPv2-MIB */ 
     31oid warm_start_oid[] = { SNMPV2_TRAPS_PREFIX, 2 };  /* SNMPv2-MIB */ 
     32oid link_down_oid[]  = { SNMPV2_TRAPS_PREFIX, 3 };  /* IF-MIB */ 
     33oid link_up_oid[]    = { SNMPV2_TRAPS_PREFIX, 4 };  /* IF-MIB */ 
     34oid auth_fail_oid[]  = { SNMPV2_TRAPS_PREFIX, 5 };  /* SNMPv2-MIB */ 
     35oid egp_xxx_oid[]    = { SNMPV2_TRAPS_PREFIX, 99 }; /* ??? */ 
     36 
     37#define SNMPV2_TRAP_OBJS_PREFIX SNMP_OID_SNMPMODULES,1,1,4 
     38oid snmptrap_oid[] = { SNMPV2_TRAP_OBJS_PREFIX, 1, 0 }; 
     39size_t snmptrap_oid_len = OID_LENGTH(snmptrap_oid); 
     40oid snmptrapenterprise_oid[] = { SNMPV2_TRAP_OBJS_PREFIX, 3, 0 }; 
     41size_t snmptrapenterprise_oid_len = OID_LENGTH(snmptrapenterprise_oid); 
     42oid sysuptime_oid[] = { SNMP_OID_MIB2, 1, 3, 0 }; 
     43size_t sysuptime_oid_len = OID_LENGTH(sysuptime_oid); 
     44 
     45#define SNMPV2_COMM_OBJS_PREFIX SNMP_OID_SNMPMODULES,18,1 
     46oid agentaddr_oid[] = { SNMPV2_COMM_OBJS_PREFIX, 3, 0 }; 
     47size_t agentaddr_oid_len = OID_LENGTH(agentaddr_oid); 
     48oid community_oid[] = { SNMPV2_COMM_OBJS_PREFIX, 4, 0 }; 
     49size_t community_oid_len = OID_LENGTH(community_oid); 
     50 
     51#define RECONNOITER_PREFIX     SNMP_OID_ENTERPRISES,32863,1 
     52oid reconnoiter_oid[] = { RECONNOITER_PREFIX }; 
     53size_t reconnoiter_oid_len = OID_LENGTH(reconnoiter_oid); 
     54oid reconnoiter_check_prefix_oid[] = { RECONNOITER_PREFIX,1,1 }; 
     55size_t reconnoiter_check_prefix_oid_len = 
     56  OID_LENGTH(reconnoiter_check_prefix_oid); 
     57size_t reconnoiter_check_oid_len = OID_LENGTH(reconnoiter_check_prefix_oid) + 8; 
     58oid reconnoiter_metric_prefix_oid[] = { RECONNOITER_PREFIX,1,2 }; 
     59size_t reconnoiter_metric_prefix_oid_len = 
     60  OID_LENGTH(reconnoiter_metric_prefix_oid); 
     61 
     62oid reconnoiter_check_status_oid[] = { RECONNOITER_PREFIX,1,3}; 
     63size_t reconnoiter_check_status_oid_len = 
     64  OID_LENGTH(reconnoiter_check_status_oid); 
     65oid reconnoiter_check_state_oid[] = { RECONNOITER_PREFIX,1,3,1}; 
     66size_t reconnoiter_check_state_oid_len = 
     67  OID_LENGTH(reconnoiter_check_state_oid); 
     68oid reconnoiter_check_state_unknown_oid[] = { RECONNOITER_PREFIX,1,3,1,0}; 
     69oid reconnoiter_check_state_good_oid[] = { RECONNOITER_PREFIX,1,3,1,1}; 
     70oid reconnoiter_check_state_bad_oid[] = { RECONNOITER_PREFIX,1,3,1,2}; 
     71size_t reconnoiter_check_state_val_len = 
     72  OID_LENGTH(reconnoiter_check_state_unknown_oid); 
     73/* Boolean */ 
     74oid reconnoiter_check_available_oid[] = { RECONNOITER_PREFIX,1,3,2}; 
     75size_t reconnoiter_check_available_oid_len = 
     76  OID_LENGTH(reconnoiter_check_available_oid); 
     77oid reconnoiter_check_available_unknown_oid[] = { RECONNOITER_PREFIX,1,3,2,0}; 
     78oid reconnoiter_check_available_yes_oid[] = { RECONNOITER_PREFIX,1,3,2,1}; 
     79oid reconnoiter_check_available_no_oid[] = { RECONNOITER_PREFIX,1,3,2,2}; 
     80size_t reconnoiter_check_available_val_len = 
     81  OID_LENGTH(reconnoiter_check_available_unknown_oid); 
     82/* timeticks? gauge/unsigned? */ 
     83oid reconnoiter_check_duration_oid[] = { RECONNOITER_PREFIX,1,3,3}; 
     84size_t reconnoiter_check_duration_oid_len = 
     85  OID_LENGTH(reconnoiter_check_duration_oid); 
     86/* string */ 
     87oid reconnoiter_check_status_msg_oid[] = { RECONNOITER_PREFIX,1,3,4}; 
     88size_t reconnoiter_check_status_msg_oid_len = 
     89  OID_LENGTH(reconnoiter_check_status_msg_oid); 
     90 
     91typedef struct _mod_config { 
     92  noit_hash_table *options; 
     93  noit_hash_table target_sessions; 
     94} snmp_mod_config_t; 
    2695 
    2796struct target_session { 
    2897  void *sess_handle; 
     98  noit_module_t *self; 
    2999  eventer_t timeoutevent; 
    30100  int fd; 
     
    76146} 
    77147 
    78 static int noit_snmp_init(noit_module_t *self) { 
    79   register_mib_handlers(); 
    80   read_premib_configs(); 
    81   read_configs(); 
    82   init_snmp("noitd"); 
    83   return 0; 
     148struct target_session * 
     149_get_target_session(noit_module_t *self, char *target) { 
     150  struct target_session *ts; 
     151  snmp_mod_config_t *conf; 
     152  conf = noit_module_get_userdata(self); 
     153  if(!noit_hash_retrieve(&conf->target_sessions, 
     154                         target, strlen(target), (void **)&ts)) { 
     155    ts = calloc(1, sizeof(*ts)); 
     156    ts->self = self; 
     157    ts->fd = -1; 
     158    ts->refcnt = 0; 
     159    ts->in_table = 1; 
     160    noit_hash_store(&conf->target_sessions, 
     161                    strdup(target), strlen(target), ts); 
     162  } 
     163  return ts; 
    84164} 
    85165 
     
    183263      default: 
    184264        snprint_variable(varbuff, sizeof(varbuff), vars->name, vars->name_length, vars); 
    185         printf("%s!\n", varbuff); 
    186265        /* Advance passed the first space and use that unless there 
    187266         * is no space or we have no more string left. 
     
    196275} 
    197276 
    198 struct target_session * 
    199 _get_target_session(char *target) { 
    200   struct target_session *ts; 
    201   if(!noit_hash_retrieve(&target_sessions, 
    202                          target, strlen(target), (void **)&ts)) { 
    203     ts = calloc(1, sizeof(*ts)); 
    204     ts->fd = -1; 
    205     ts->refcnt = 0; 
    206     ts->in_table = 1; 
    207     noit_hash_store(&target_sessions, 
    208                     strdup(target), strlen(target), ts); 
    209   } 
    210   return ts; 
    211 } 
    212  
    213277static int noit_snmp_session_cleanse(struct target_session *ts) { 
    214278  if(ts->refcnt == 0 && ts->sess_handle) { 
    215279    eventer_remove_fd(ts->fd); 
    216     if(ts->timeoutevent) eventer_remove(ts->timeoutevent); 
    217     ts->timeoutevent = NULL; 
     280    if(ts->timeoutevent) { 
     281      eventer_remove(ts->timeoutevent); 
     282      ts->timeoutevent = NULL; 
     283    } 
    218284    snmp_sess_close(ts->sess_handle); 
    219285    ts->sess_handle = NULL; 
     
    231297  snmp_sess_timeout(ts->sess_handle); 
    232298  noit_snmp_session_cleanse(ts); 
     299  if(ts->timeoutevent == e) 
     300    ts->timeoutevent = NULL; /* this will be freed on return */ 
    233301  return 0; 
    234302} 
     
    248316  struct timeval now; 
    249317  eventer_t e = NULL; 
    250   if(ts->timeoutevent) e = eventer_remove(ts->timeoutevent); 
    251   ts->timeoutevent = NULL; 
     318  if(ts->timeoutevent) { 
     319    e = eventer_remove(ts->timeoutevent); 
     320    ts->timeoutevent = NULL; 
     321  } 
    252322  if(!t) return; 
    253323 
     
    277347  _set_ts_timeout(ts, block ? &timeout : NULL); 
    278348  return EVENTER_READ | EVENTER_EXCEPTION; 
     349} 
     350 
     351/* This 'convert_v1pdu_to_v2' was cribbed directly from netsnmp */ 
     352static netsnmp_pdu * 
     353convert_v1pdu_to_v2( netsnmp_pdu* template_v1pdu ) { 
     354  netsnmp_pdu *template_v2pdu; 
     355  netsnmp_variable_list *first_vb; 
     356  netsnmp_variable_list *var; 
     357  oid enterprise[MAX_OID_LEN]; 
     358  size_t enterprise_len; 
     359 
     360  /* 
     361   * Make a copy of the v1 Trap PDU 
     362   *   before starting to convert this 
     363   *   into a v2 Trap PDU. 
     364   */ 
     365  template_v2pdu = snmp_clone_pdu( template_v1pdu); 
     366  if(!template_v2pdu) { 
     367    snmp_log(LOG_WARNING, 
     368             "send_trap: failed to copy v2 template PDU\n"); 
     369    return NULL; 
     370  } 
     371  template_v2pdu->command = SNMP_MSG_TRAP2; 
     372  first_vb = template_v2pdu->variables; 
     373 
     374  /* 
     375   * Insert an snmpTrapOID varbind before the original v1 varbind list 
     376   *   either using one of the standard defined trap OIDs, 
     377   *   or constructing this from the PDU enterprise & specific trap fields 
     378   */ 
     379  if(template_v1pdu->trap_type == SNMP_TRAP_ENTERPRISESPECIFIC) { 
     380    memcpy(enterprise, template_v1pdu->enterprise, 
     381           template_v1pdu->enterprise_length*sizeof(oid)); 
     382    enterprise_len = template_v1pdu->enterprise_length; 
     383    enterprise[enterprise_len++] = 0; 
     384    enterprise[enterprise_len++] = template_v1pdu->specific_type; 
     385  } else { 
     386    memcpy(enterprise, cold_start_oid, sizeof(cold_start_oid)); 
     387    enterprise[9]  = template_v1pdu->trap_type+1; 
     388    enterprise_len = sizeof(cold_start_oid)/sizeof(oid); 
     389  } 
     390 
     391  var = NULL; 
     392  if(!snmp_varlist_add_variable(&var, 
     393                                snmptrap_oid, snmptrap_oid_len, 
     394                                ASN_OBJECT_ID, 
     395                                (u_char*)enterprise, 
     396                                enterprise_len*sizeof(oid))) { 
     397    noitL(nlerr, "send_trap: failed to insert copied snmpTrapOID varbind\n"); 
     398    snmp_free_pdu(template_v2pdu); 
     399    return NULL; 
     400  } 
     401  var->next_variable        = template_v2pdu->variables; 
     402  template_v2pdu->variables = var; 
     403 
     404  /* 
     405   * Insert a sysUptime varbind at the head of the v2 varbind list 
     406   */ 
     407  var = NULL; 
     408  if(!snmp_varlist_add_variable(&var, 
     409                                sysuptime_oid, sysuptime_oid_len, 
     410                                ASN_TIMETICKS, 
     411                                (u_char*)&(template_v1pdu->time),  
     412                                sizeof(template_v1pdu->time))) { 
     413    noitL(nlerr, "send_trap: failed to insert copied sysUptime varbind\n"); 
     414    snmp_free_pdu(template_v2pdu); 
     415    return NULL; 
     416  } 
     417  var->next_variable = template_v2pdu->variables; 
     418  template_v2pdu->variables = var; 
     419 
     420  /* 
     421   * Append the other three conversion varbinds, 
     422   *  (snmpTrapAgentAddr, snmpTrapCommunity & snmpTrapEnterprise) 
     423   *  if they're not already present. 
     424   *  But don't bomb out completely if there are problems. 
     425   */ 
     426  var = find_varbind_in_list(template_v2pdu->variables, 
     427                             agentaddr_oid, agentaddr_oid_len); 
     428  if(!var && (template_v1pdu->agent_addr[0] 
     429              || template_v1pdu->agent_addr[1] 
     430              || template_v1pdu->agent_addr[2] 
     431              || template_v1pdu->agent_addr[3])) { 
     432    if(!snmp_varlist_add_variable(&(template_v2pdu->variables), 
     433                                  agentaddr_oid, agentaddr_oid_len, 
     434                                  ASN_IPADDRESS, 
     435                                  (u_char*)&(template_v1pdu->agent_addr),  
     436                                  sizeof(template_v1pdu->agent_addr))) 
     437      noitL(nlerr, "send_trap: failed to append snmpTrapAddr varbind\n"); 
     438  } 
     439  var = find_varbind_in_list(template_v2pdu->variables, 
     440                             community_oid, community_oid_len); 
     441  if(!var && template_v1pdu->community) { 
     442    if(!snmp_varlist_add_variable(&(template_v2pdu->variables), 
     443                                  community_oid, community_oid_len, 
     444                                  ASN_OCTET_STR, 
     445                                  template_v1pdu->community,  
     446                                  template_v1pdu->community_len)) 
     447      noitL(nlerr, "send_trap: failed to append snmpTrapCommunity varbind\n"); 
     448  } 
     449  var = find_varbind_in_list(template_v2pdu->variables, 
     450                             snmptrapenterprise_oid, 
     451                             snmptrapenterprise_oid_len); 
     452  if(!var &&  
     453     template_v1pdu->trap_type != SNMP_TRAP_ENTERPRISESPECIFIC) { 
     454    if(!snmp_varlist_add_variable(&(template_v2pdu->variables), 
     455                                  snmptrapenterprise_oid, 
     456                                  snmptrapenterprise_oid_len, 
     457                                  ASN_OBJECT_ID, 
     458                                  (u_char*)template_v1pdu->enterprise,  
     459                                  template_v1pdu->enterprise_length*sizeof(oid))) 
     460      noitL(nlerr, "send_trap: failed to append snmpEnterprise varbind\n"); 
     461  } 
     462  return template_v2pdu; 
     463} 
     464 
     465static int noit_snmp_oid_to_checkid(oid *o, int l, uuid_t checkid, char *out) { 
     466  int i; 
     467  char _uuid_str[UUID_STR_LEN+1], *cp, *uuid_str; 
     468 
     469  uuid_str = out ? out : _uuid_str; 
     470  if(l != reconnoiter_check_oid_len) { 
     471    noitL(nlerr, "unsupported (length) trap recieved\n"); 
     472    return -1; 
     473  } 
     474  if(netsnmp_oid_equals(o, 
     475                        reconnoiter_check_prefix_oid_len, 
     476                        reconnoiter_check_prefix_oid, 
     477                        reconnoiter_check_prefix_oid_len) != 0) { 
     478    noitL(nlerr, "unsupported (wrong namespace) trap recieved\n"); 
     479    return -1; 
     480  } 
     481  /* encode this as a uuid */ 
     482  cp = uuid_str; 
     483  for(i=0; 
     484      i < reconnoiter_check_oid_len - reconnoiter_check_prefix_oid_len; 
     485      i++) { 
     486    oid v = o[i + reconnoiter_check_prefix_oid_len]; 
     487    if(v < 0 || v > 0xffff) { 
     488      noitL(nlerr, "trap target oid [%ld] out of range\n", v); 
     489      return -1; 
     490    } 
     491    snprintf(cp, 5, "%04x", (unsigned short)(v & 0xffff)); 
     492    cp += 4; 
     493    /* hyphens after index 1,2,3,4 */ 
     494    if(i > 0 && i < 5) *cp++ = '-'; 
     495  } 
     496  if(uuid_parse(uuid_str, checkid) != 0) { 
     497    noitL(nlerr, "unexpected error decoding trap uuid '%s'\n", uuid_str); 
     498    return -1; 
     499  } 
     500  return 0; 
     501} 
     502 
     503#define isoid(a,b,c,d) (netsnmp_oid_equals(a,b,c,d) == 0) 
     504#define isoidprefix(a,b,c,d) (netsnmp_oid_equals(a,MIN(b,d),c,d) == 0) 
     505#define setstatus(st,soid,sv) \ 
     506  if(isoid(o,l,soid,reconnoiter_check_state_val_len)) current->st = sv 
     507 
     508static int 
     509noit_snmp_trapvars_to_stats(stats_t *current, netsnmp_variable_list *var) { 
     510  if(isoidprefix(var->name, var->name_length, reconnoiter_check_status_oid, 
     511                 reconnoiter_check_status_oid_len)) { 
     512    if(var->type == ASN_OBJECT_ID) { 
     513      if(isoid(var->name, var->name_length, 
     514               reconnoiter_check_state_oid, reconnoiter_check_state_oid_len)) { 
     515        oid *o = var->val.objid; 
     516        size_t l = var->val_len / sizeof(*o); 
     517        setstatus(state, reconnoiter_check_state_unknown_oid, NP_UNKNOWN); 
     518        else setstatus(state, reconnoiter_check_state_good_oid, NP_GOOD); 
     519        else setstatus(state, reconnoiter_check_state_bad_oid, NP_BAD); 
     520        else return -1; 
     521      } 
     522      else if(isoid(var->name, var->name_length, 
     523                    reconnoiter_check_available_oid, 
     524                    reconnoiter_check_available_oid_len)) { 
     525        oid *o = var->val.objid; 
     526        size_t l = var->val_len / sizeof(*o); 
     527        setstatus(available, reconnoiter_check_available_unknown_oid, NP_UNKNOWN); 
     528        else setstatus(available, reconnoiter_check_available_yes_oid, NP_AVAILABLE); 
     529        else setstatus(available, reconnoiter_check_available_no_oid, NP_UNAVAILABLE); 
     530        else return -1; 
     531      } 
     532      else { 
     533        /* We don't unerstand any other OBJECT_ID types */ 
     534        return -1; 
     535      } 
     536    } 
     537    else if(var->type == ASN_UNSIGNED) { 
     538      /* This is only for the duration (in ms) */ 
     539      if(isoid(var->name, var->name_length, 
     540               reconnoiter_check_duration_oid, 
     541               reconnoiter_check_duration_oid_len)) { 
     542        current->duration = *(var->val.integer); 
     543      } 
     544      else 
     545        return -1; 
     546    } 
     547    else if(var->type == ASN_OCTET_STR) { 
     548      /* This is only for the status message */ 
     549      if(isoid(var->name, var->name_length, 
     550               reconnoiter_check_status_msg_oid, 
     551               reconnoiter_check_status_msg_oid_len)) { 
     552        current->status = malloc(var->val_len + 1); 
     553        memcpy(current->status, var->val.string, var->val_len); 
     554        current->status[var->val_len] = '\0'; 
     555      } 
     556      else 
     557        return -1; 
     558    } 
     559    else { 
     560      /* I don't understand any other type of status message */ 
     561      return -1; 
     562    } 
     563  } 
     564  else if(isoidprefix(var->name, var->name_length, 
     565                      reconnoiter_metric_prefix_oid, 
     566                      reconnoiter_metric_prefix_oid_len)) { 
     567    /* decode the metric and store the value */ 
     568    int i, len; 
     569    u_int64_t u64; 
     570    double doubleVal; 
     571    char metric_name[128], buff[128], *cp; 
     572    if(var->name_length <= reconnoiter_metric_prefix_oid_len) return -1; 
     573    len = var->name[reconnoiter_metric_prefix_oid_len]; 
     574    if(var->name_length != (reconnoiter_metric_prefix_oid_len + 1 + len) || 
     575       len > sizeof(metric_name) - 1) { 
     576      noitL(nlerr, "snmp trap, malformed metric name\n"); 
     577      return -1; 
     578    } 
     579    for(i=0;i<len;i++) { 
     580      ((unsigned char *)metric_name)[i] = 
     581        (unsigned char)var->name[reconnoiter_metric_prefix_oid_len + 1 + i]; 
     582      if(!isprint(metric_name[i])) { 
     583        noitL(nlerr, "metric_name contains unprintable characters\n"); 
     584        return -1; 
     585      } 
     586    } 
     587    metric_name[i] = '\0'; 
     588    switch(var->type) { 
     589      case ASN_INTEGER: 
     590      case ASN_UINTEGER: 
     591      case ASN_TIMETICKS: 
     592      case ASN_INTEGER64: 
     593        noit_stats_set_metric(current, metric_name, 
     594                              METRIC_INT64, var->val.integer); 
     595        break; 
     596      case ASN_COUNTER64: 
     597        u64 = ((u_int64_t)var->val.counter64->high) << 32; 
     598        u64 |= var->val.counter64->low; 
     599        noit_stats_set_metric(current, metric_name, 
     600                              METRIC_UINT64, &u64); 
     601        break; 
     602      case ASN_OPAQUE_FLOAT: 
     603        doubleVal = (double)*var->val.floatVal; 
     604        noit_stats_set_metric(current, metric_name, 
     605                              METRIC_DOUBLE, &doubleVal); 
     606        break; 
     607      case ASN_OPAQUE_DOUBLE: 
     608        noit_stats_set_metric(current, metric_name, 
     609                              METRIC_DOUBLE, var->val.doubleVal); 
     610        break; 
     611      case ASN_OCTET_STR: 
     612        snprint_value(buff, sizeof(buff), var->name, var->name_length, var); 
     613        /* Advance passed the first space and use that unless there 
     614         * is no space or we have no more string left. 
     615         */ 
     616        cp = strchr(buff, ' '); 
     617        if(cp) { 
     618          char *ecp; 
     619          cp++; 
     620          if(*cp == '"') { 
     621            ecp = cp + strlen(cp) - 1; 
     622            if(*ecp == '"') { 
     623              cp++; *ecp = '\0'; 
     624            } 
     625          } 
     626        } 
     627        noit_stats_set_metric(current, metric_name, 
     628                              METRIC_STRING, (cp && *cp) ? cp : NULL); 
     629        break; 
     630      default: 
     631        noitL(nlerr, "snmp trap unsupport data type %d\n", var->type); 
     632    } 
     633    noitL(nldeb, "metric_name -> '%s'\n", metric_name); 
     634  } 
     635  else { 
     636    /* No idea what this is */ 
     637    return -1; 
     638  } 
     639  return 0; 
     640} 
     641static int noit_snmp_trapd_response(int operation, struct snmp_session *sp, 
     642                                    int reqid, struct snmp_pdu *pdu, 
     643                                    void *magic) { 
     644  /* the noit pieces */ 
     645  noit_check_t *check; 
     646  struct target_session *ts = magic; 
     647  snmp_mod_config_t *conf; 
     648  const char *community = NULL; 
     649  stats_t current; 
     650 
     651  /* parsing destination */ 
     652  char uuid_str[UUID_STR_LEN + 1]; 
     653  uuid_t checkid; 
     654 
     655  /* snmp oid parsing helper vars */ 
     656  netsnmp_pdu *newpdu = pdu; 
     657  netsnmp_variable_list *var; 
     658 
     659  conf = noit_module_get_userdata(ts->self); 
     660 
     661  if(pdu->version == SNMP_VERSION_1) 
     662    newpdu = convert_v1pdu_to_v2(pdu); 
     663  if(!newpdu || newpdu->version != SNMP_VERSION_2c) goto cleanup; 
     664 
     665  for(var = newpdu->variables; var != NULL; var = var->next_variable) { 
     666    if(netsnmp_oid_equals(var->name, var->name_length, 
     667                          snmptrap_oid, snmptrap_oid_len) == 0) 
     668      break; 
     669  } 
     670 
     671  if (!var || var->type != ASN_OBJECT_ID) { 
     672    noitL(nlerr, "unsupport trap (not a trap?) received\n"); 
     673    goto cleanup; 
     674  } 
     675 
     676  /* var is the oid on which we are trapping. 
     677   * It should be in the reconnoiter check prefix. 
     678   */ 
     679  if(noit_snmp_oid_to_checkid(var->val.objid, var->val_len/sizeof(oid), 
     680                              checkid, uuid_str)) { 
     681    goto cleanup; 
     682  } 
     683  noitL(nldeb, "recieved trap for %s\n", uuid_str); 
     684  check = noit_poller_lookup(checkid); 
     685  if(!check) { 
     686    noitL(nlerr, "trap received for non-existent check '%s'\n", uuid_str); 
     687    goto cleanup; 
     688  } 
     689  if(!noit_hash_retrieve(check->config, "community", strlen("community"), 
     690                         (void **)&community) && 
     691     !noit_hash_retrieve(conf->options, "community", strlen("community"), 
     692                         (void **)&community)) { 
     693    noitL(nlerr, "No community defined for check, dropping trap\n"); 
     694    goto cleanup; 
     695  } 
     696 
     697  if(strlen(community) != newpdu->community_len || 
     698     memcmp(community, newpdu->community, newpdu->community_len)) { 
     699    noitL(nlerr, "trap attempt with wrong community string\n"); 
     700    goto cleanup; 
     701  } 
     702 
     703  /* We have a check. The trap is authorized. Now, extract everything. */ 
     704  memset(&current, 0, sizeof(current)); 
     705  gettimeofday(&current.whence, NULL); 
     706 
     707  for(; var != NULL; var = var->next_variable) 
     708    noit_snmp_trapvars_to_stats(&current, var); 
     709  noit_check_set_stats(ts->self, check, &current); 
     710 
     711 cleanup: 
     712  if(newpdu != pdu) 
     713    snmp_free_pdu(newpdu); 
     714  return 0; 
    279715} 
    280716static int noit_snmp_asynch_response(int operation, struct snmp_session *sp, 
     
    384820 
    385821  check->flags |= NP_RUNNING; 
    386   ts = _get_target_session(check->target); 
     822  ts = _get_target_session(self, check->target); 
    387823  gettimeofday(&check->last_fire_time, NULL); 
    388824  if(!ts->refcnt) { 
     
    431867  else { 
    432868    ts->refcnt--; 
    433     noit_snmp_session_cleanse(ts); 
     869    noit_snmp_session_cleanse(ts); 
    434870    /* Error */ 
    435871    if(req) snmp_free_pdu(req); 
     
    448884} 
    449885 
    450 static int noit_snmp_config(noit_module_t *self, noit_hash_table *config) { 
    451   return 0; 
     886static int noit_snmptrap_initiate_check(noit_module_t *self, 
     887                                        noit_check_t *check, 
     888                                        int once, noit_check_t *cause) { 
     889  /* We don't do anything for snmptrap checks.  Not intuitive... but they 
     890   * never "run."  We accept input out-of-band via snmp traps. 
     891   */ 
     892  return 0; 
     893
     894 
     895static int noit_snmp_config(noit_module_t *self, noit_hash_table *options) { 
     896  snmp_mod_config_t *conf; 
     897  conf = noit_module_get_userdata(self); 
     898  if(conf) { 
     899    if(conf->options) { 
     900      noit_hash_destroy(conf->options, free, free); 
     901      free(conf->options); 
     902    } 
     903  } 
     904  else 
     905    conf = calloc(1, sizeof(*conf)); 
     906  conf->options = options; 
     907  noit_module_set_userdata(self, conf); 
     908  return 1; 
    452909} 
    453910static int noit_snmp_onload(noit_image_t *self) { 
    454   nlerr = noit_log_stream_find("error/snmp"); 
    455   nldeb = noit_log_stream_find("debug/snmp"); 
     911  if(!nlerr) nlerr = noit_log_stream_find("error/snmp"); 
     912  if(!nldeb) nldeb = noit_log_stream_find("debug/snmp"); 
    456913  if(!nlerr) nlerr = noit_stderr; 
    457914  if(!nldeb) nldeb = noit_debug; 
     
    459916  eventer_name_callback("noit_snmp/session_timeout", noit_snmp_session_timeout); 
    460917  eventer_name_callback("noit_snmp/handler", noit_snmp_handler); 
     918  return 0; 
     919} 
     920 
     921static int noit_snmptrap_onload(noit_image_t *self) { 
     922  if(!nlerr) nlerr = noit_log_stream_find("error/snmp"); 
     923  if(!nldeb) nldeb = noit_log_stream_find("debug/snmp"); 
     924  if(!nlerr) nlerr = noit_stderr; 
     925  if(!nldeb) nldeb = noit_debug; 
     926  eventer_name_callback("noit_snmp/session_timeout", noit_snmp_session_timeout); 
     927  eventer_name_callback("noit_snmp/handler", noit_snmp_handler); 
     928  return 0; 
     929} 
     930 
     931static int noit_snmp_init(noit_module_t *self) { 
     932  const char *opt; 
     933  snmp_mod_config_t *conf; 
     934 
     935  conf = noit_module_get_userdata(self); 
     936 
     937  if(!__snmp_initialize_once) { 
     938    register_mib_handlers(); 
     939    read_premib_configs(); 
     940    read_configs(); 
     941    init_snmp("noitd"); 
     942    __snmp_initialize_once = 1; 
     943  } 
     944 
     945  if(strcmp(self->hdr.name, "snmptrap") == 0) { 
     946    eventer_t newe; 
     947    int i, block = 0, fds = 0; 
     948    fd_set fdset; 
     949    struct timeval timeout = { 0, 0 }; 
     950    struct target_session *ts; 
     951    netsnmp_transport *transport; 
     952    netsnmp_session sess, *session = &sess; 
     953 
     954    if(!noit_hash_retrieve(conf->options, 
     955                           "snmptrapd_port", strlen("snmptrapd_port"), 
     956                           (void **)&opt)) 
     957      opt = "162"; 
     958 
     959    transport = netsnmp_transport_open_server("snmptrap", opt); 
     960    if(!transport) { 
     961      noitL(nlerr, "cannot open netsnmp transport for trap daemon\n"); 
     962      return -1; 
     963    } 
     964    ts = _get_target_session(self, "snmptrapd"); 
     965    snmp_sess_init(session); 
     966    session->peername = SNMP_DEFAULT_PEERNAME; 
     967    session->version = SNMP_DEFAULT_VERSION; 
     968    session->community_len = SNMP_DEFAULT_COMMUNITY_LEN; 
     969    session->retries = SNMP_DEFAULT_RETRIES; 
     970    session->timeout = SNMP_DEFAULT_TIMEOUT; 
     971    session->callback = noit_snmp_trapd_response; 
     972    session->callback_magic = (void *) ts; 
     973    session->authenticator = NULL; 
     974    session->isAuthoritative = SNMP_SESS_UNKNOWNAUTH; 
     975    ts->sess_handle = snmp_sess_add(session, transport, NULL, NULL); 
     976 
     977    FD_ZERO(&fdset); 
     978    snmp_sess_select_info(ts->sess_handle, &fds, &fdset, &timeout, &block); 
     979    assert(fds > 0); 
     980    for(i=0; i<fds; i++) { 
     981      if(FD_ISSET(i, &fdset)) { 
     982        ts->refcnt++; 
     983        ts->fd = i; 
     984        newe = eventer_alloc(); 
     985        newe->fd = ts->fd; 
     986        newe->callback = noit_snmp_handler; 
     987        newe->closure = ts; 
     988        newe->mask = EVENTER_READ | EVENTER_EXCEPTION; 
     989        eventer_add(newe); 
     990      } 
     991    } 
     992  } 
    461993  return 0; 
    462994} 
     
    4781010}; 
    4791011 
     1012#include "snmptrap.xmlh" 
     1013noit_module_t snmptrap = { 
     1014  { 
     1015    NOIT_MODULE_MAGIC, 
     1016    NOIT_MODULE_ABI_VERSION, 
     1017    "snmptrap", 
     1018    "SNMP trap collection", 
     1019    snmptrap_xml_description, 
     1020    noit_snmptrap_onload 
     1021  }, 
     1022  noit_snmp_config, 
     1023  noit_snmp_init, 
     1024  noit_snmptrap_initiate_check, 
     1025  NULL /* noit_snmp_cleanup */ 
     1026}; 
  • src/noit_defines.h

    rdbaf64b r374e7c3  
    4040} 
    4141 
     42#undef UUID_STR_LEN 
     43#define UUID_STR_LEN 36 
    4244#ifndef HAVE_UUID_UNPARSE_LOWER 
    4345/* Sigh, need to implement out own */