diff options
author | syrinx <syrinx@FreeBSD.org> | 2010-12-20 17:13:14 +0000 |
---|---|---|
committer | syrinx <syrinx@FreeBSD.org> | 2010-12-20 17:13:14 +0000 |
commit | cdf73327e5ede68524c23f9fb281bbbd7c771b07 (patch) | |
tree | 5b7dd1db00389b1d0504f34a299b48339c9b9aac /contrib/bsnmp/snmpd | |
parent | 0f810ef0a25b4d64ffe05b47b5dfd30d73167b71 (diff) | |
download | FreeBSD-src-cdf73327e5ede68524c23f9fb281bbbd7c771b07.zip FreeBSD-src-cdf73327e5ede68524c23f9fb281bbbd7c771b07.tar.gz |
Bring in a SNMP module that allows configuration of SNMPv3 Notification targets.
Sponsored by: The FreeBSD Foundation
Reviewed by: philip
Approved by: philip
Diffstat (limited to 'contrib/bsnmp/snmpd')
-rw-r--r-- | contrib/bsnmp/snmpd/main.c | 14 | ||||
-rw-r--r-- | contrib/bsnmp/snmpd/snmpmod.3 | 163 | ||||
-rw-r--r-- | contrib/bsnmp/snmpd/snmpmod.h | 75 | ||||
-rw-r--r-- | contrib/bsnmp/snmpd/trap.c | 513 | ||||
-rw-r--r-- | contrib/bsnmp/snmpd/tree.def | 3 |
5 files changed, 731 insertions, 37 deletions
diff --git a/contrib/bsnmp/snmpd/main.c b/contrib/bsnmp/snmpd/main.c index e008bf7..c25fff2 100644 --- a/contrib/bsnmp/snmpd/main.c +++ b/contrib/bsnmp/snmpd/main.c @@ -5,6 +5,12 @@ * * Author: Harti Brandt <harti@freebsd.org> * + * Copyright (c) 2010 The FreeBSD Foundation + * All rights reserved. + * + * Portions of this software were developed by Shteryana Sotirova Shopova + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -98,6 +104,8 @@ struct snmp_engine snmpd_engine; /* snmpSerialNo */ int32_t snmp_serial_no; +struct snmpd_target_stats snmpd_target_stats; + /* search path for config files */ const char *syspath = PATH_SYSCONFIG; @@ -361,7 +369,7 @@ snmp_pdu_auth_user(struct snmp_pdu *pdu) * Check whether access to each of var bindings in the PDU is allowed based * on the user credentials against the configured User groups & VACM views. */ -static enum snmp_code +enum snmp_code snmp_pdu_auth_access(struct snmp_pdu *pdu, int32_t *ip) { const char *uname; @@ -1838,14 +1846,14 @@ main(int argc, char *argv[]) exit(1); } - snmp_send_trap(&oid_coldStart, (struct snmp_value *)NULL); - while ((m = TAILQ_FIRST(&modules_start)) != NULL) { m->flags &= ~LM_ONSTARTLIST; TAILQ_REMOVE(&modules_start, m, start); lm_start(m); } + snmp_send_trap(&oid_coldStart, (struct snmp_value *)NULL); + for (;;) { #ifndef USE_LIBBEGEMOT evEvent event; diff --git a/contrib/bsnmp/snmpd/snmpmod.3 b/contrib/bsnmp/snmpd/snmpmod.3 index a142069..38b3cf1 100644 --- a/contrib/bsnmp/snmpd/snmpmod.3 +++ b/contrib/bsnmp/snmpd/snmpmod.3 @@ -31,7 +31,7 @@ .\" .\" $Begemot: bsnmp/snmpd/snmpmod.3,v 1.14 2005/10/04 13:30:35 brandt_h Exp $ .\" -.Dd September 9, 2010 +.Dd December 19, 2010 .Dt SNMPMOD 3 .Os .Sh NAME @@ -83,6 +83,7 @@ .Nm snmp_output , .Nm snmp_send_port , .Nm snmp_send_trap , +.Nm snmp_pdu_auth_access .Nm string_save , .Nm string_commit , .Nm string_rollback , @@ -102,6 +103,7 @@ .Nm index_compare_off , .Nm index_append , .Nm index_append_off, +.Nm snmpd_usmstats, .Nm bsnmpd_get_usm_stats, .Nm bsnmpd_reset_usm_stats, .Nm usm_first_user, @@ -111,6 +113,25 @@ .Nm usm_delete_user, .Nm usm_flush_users, .Nm usm_user +.Nm snmpd_target_stat +.Nm bsnmpd_get_target_stats +.Nm target_first_address +.Nm target_next_address +.Nm target_new_address +.Nm target_activate_address +.Nm target_delete_address +.Nm target_first_param +.Nm target_next_param +.Nm target_new_param +.Nm target_delete_param +.Nm target_first_notify +.Nm target_next_notify +.Nm target_new_notify +.Nm target_delete_notify +.Nm target_flush_all +.Nm target_address +.Nm target_param +.Nm target_notify .Nd "SNMP daemon loadable module interface" .Sh LIBRARY Begemot SNMP library @@ -201,6 +222,8 @@ Begemot SNMP library .Fc .Ft void .Fn snmp_send_trap "const struct asn_oid *oid" "..." +.Ft enum snmp_code +.Fn snmp_pdu_auth_access "struct snmp_pdu *pdu" "int32_t *ip" .Ft int .Fn string_save "struct snmp_value *val" "struct snmp_context *ctx" "ssize_t req_size" "u_char **strp" .Ft void @@ -239,6 +262,7 @@ Begemot SNMP library .Fn index_append "struct asn_oid *dst" "u_int sub" "const struct asn_oid *src" .Ft void .Fn index_append_off "struct asn_oid *dst" "u_int sub" "const struct asn_oid *src" "u_int off" +.Vt extern struct snmpd_usmstat snmpd_usmstats ; .Ft struct snmpd_usmstat * .Fn bsnmpd_get_usm_stats "void" .Ft void @@ -256,6 +280,36 @@ Begemot SNMP library .Ft void .Fn usm_flush_users "void" .Vt extern struct usm_user *usm_user; +.Ft struct snmpd_target_stats * +.Fn bsnmpd_get_target_stats "void" +.Ft struct target_address * +.Fn target_first_address "void" +.Ft struct target_address * +.Fn target_next_address "struct target_address *" +.Ft struct target_address * +.Fn target_new_address "char *" +.Ft int +.Fn target_activate_address "struct target_address *" +.Ft int +.Fn target_delete_address "struct target_address *" +.Ft struct target_param * +.Fn target_first_param "void" +.Ft struct target_param * +.Fn target_next_param "struct target_param *" +.Ft struct target_param * +.Fn target_new_param "char *" +.Ft int +.Fn target_delete_param "struct target_param *" +.Ft struct target_notify * +.Fn target_first_notify "void" +.Ft struct target_notify * +.Fn target_next_notify "struct target_notify *" +.Ft struct target_notify * +.Fn target_new_notify "char *" +.Ft int +.Fn target_delete_notify "struct target_notify *" +.Ft void +.Fn target_flush_all "void" .Vt extern const struct asn_oid oid_usmUnknownEngineIDs; .Vt extern const struct asn_oid oid_usmNotInTimeWindows; .Sh DESCRIPTION @@ -603,7 +657,7 @@ struct usm_user { struct snmp_user suser; uint8_t user_engine_id[SNMP_ENGINE_ID_SIZ]; uint32_t user_engine_len; - char user_public[SNMP_USM_NAME_SIZ]; + char user_public[SNMP_ADM_STR32_SIZ]; uint32_t user_public_len; int32_t status; int32_t type; @@ -640,6 +694,103 @@ and or .Li NULL if an user with the specified name and engine id is not present in the list. +.Ss THE MANAGEMENT TARGET GROUP +The Management Target group holds target address information used when sending +SNMPv3 notifications. +.Pp +The scalar statistics of the Management Target group are held in the global +variable +.Va snmpd_target_stats : +.Bd -literal -offset indent +struct snmpd_target_stats { + uint32_t unavail_contexts; + uint32_t unknown_contexts; +}; +.Ed +.Fn bsnmpd_get_target_stats +returns a pointer to the global structure containing the statistics. +.Pp +Three global lists of configured management target addresses, parameters and +notifications respectively are maintained by the daemon. +.Bd -literal -offset indent +struct target_address { + char name[SNMP_ADM_STR32_SIZ]; + uint8_t address[SNMP_UDP_ADDR_SIZ]; + int32_t timeout; + int32_t retry; + char taglist[SNMP_TAG_SIZ]; + char paramname[SNMP_ADM_STR32_SIZ]; + int32_t type; + int32_t socket; + int32_t status; + SLIST_ENTRY(target_address) ta; +}; +.Ed +This structure represents a SNMPv3 Management Target address. Each time a SNMP +TRAP is send the daemon will send the Trap to all active Management Target +addresses in its global list. +.Bd -literal -offset indent +struct target_param { + char name[SNMP_ADM_STR32_SIZ]; + int32_t mpmodel; + int32_t sec_model; + char secname[SNMP_ADM_STR32_SIZ]; + enum snmp_usm_level sec_level; + int32_t type; + int32_t status; + SLIST_ENTRY(target_param) tp; +}; +.Ed +This structure represents the information used to generate SNMP messages to the +associated SNMPv3 Management Target addresses. +.Bd -literal -offset indent +struct target_notify { + char name[SNMP_ADM_STR32_SIZ]; + char taglist[SNMP_TAG_SIZ]; + int32_t notify_type; + int32_t type; + int32_t status; + SLIST_ENTRY(target_notify) tn; +}; +.Ed +This structure represents Notification Tag entries - SNMP notifications are sent +to the Target address for each entry in the Management Target Address list that +has a tag matching the specified tag in this structure. +.Pp +The daemon does not create or remove entries in the Management Target group +lists, it gives an interface to external loadable module(s) to manage the lists. +.Fn target_new_address +adds a target address entry, and +.Fn target_delete_address +deletes an existing entry from the target address list. +.Fn target_activate_address +creates a socket associated with the target address entry so that SNMP +notifications may actually be send to that target address. +.Fn target_first_address +will return a pointer to the first target address entry in the list, while +.Fn target_next_address +will return a pointer to the next target address of a given entry if one exists. +.Fn target_new_param +adds a target parameters' entry, and +.Fn target_delete_param +deletes an existing entry from the target parameters list. +.Fn target_first_param +will return a pointer to the first target parameters' entry in the list, while +.Fn target_next_param +will return a pointer to the next target parameters of a given entry if one +exists. +.Fn target_new_notify +adds a notification target entry, and +.Fn target_delete_notify +deletes an existing entry from the notification target list. +.Fn target_first_notify +will return a pointer to the first notification target entry in the list, while +.Fn target_next_notify +will return a pointer to the next notification target of a given entry if one +exists. +.Fn target_flush_all +is used to remove all configured data from the three global Management Target +Group lists. .Ss WELL KNOWN OIDS The global variable .Va oid_zeroDotZero @@ -840,6 +991,14 @@ The arguments are the identifying the trap and a NULL-terminated list of .Vt struct snmp_value pointers that are to be inserted into the trap binding list. +.Fn snmp_pdu_auth_access +verifies whether access to the object IDs contained in the +.Fa pdu + should be granted or denied, according to the configured View-Based Access +rules. +.Fa ip +contains the index of the first varbinding to which access was denied, or 0 if +access to all varbindings in the PDU is granted. .Ss SIMPLE ACTION SUPPORT For simple scalar variables that need no dependencies a number of support functions is available to handle the set, commit, rollback and get. diff --git a/contrib/bsnmp/snmpd/snmpmod.h b/contrib/bsnmp/snmpd/snmpmod.h index 379070c..9025366 100644 --- a/contrib/bsnmp/snmpd/snmpmod.h +++ b/contrib/bsnmp/snmpd/snmpmod.h @@ -5,6 +5,12 @@ * * Author: Harti Brandt <harti@freebsd.org> * + * Copyright (c) 2010 The FreeBSD Foundation + * All rights reserved. + * + * Portions of this software were developed by Shteryana Sotirova Shopova + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -455,6 +461,74 @@ struct vacm_context *vacm_add_context(char *, int32_t); void vacm_flush_contexts(int32_t); /* + * RFC 3413 SNMP Management Target & Notification MIB + */ + +struct snmpd_target_stats { + uint32_t unavail_contexts; + uint32_t unknown_contexts; +}; + +#define SNMP_UDP_ADDR_SIZ 6 +#define SNMP_TAG_SIZ (255 + 1) + +struct target_address { + char name[SNMP_ADM_STR32_SIZ]; + uint8_t address[SNMP_UDP_ADDR_SIZ]; + int32_t timeout; + int32_t retry; + char taglist[SNMP_TAG_SIZ]; + char paramname[SNMP_ADM_STR32_SIZ]; + int32_t type; + int32_t socket; + int32_t status; + SLIST_ENTRY(target_address) ta; +}; + +SLIST_HEAD(target_addresslist, target_address); + +struct target_param { + char name[SNMP_ADM_STR32_SIZ]; + int32_t mpmodel; + int32_t sec_model; + char secname[SNMP_ADM_STR32_SIZ]; + enum snmp_usm_level sec_level; + int32_t type; + int32_t status; + SLIST_ENTRY(target_param) tp; +}; + +SLIST_HEAD(target_paramlist, target_param); + +struct target_notify { + char name[SNMP_ADM_STR32_SIZ]; + char taglist[SNMP_TAG_SIZ]; + int32_t notify_type; + int32_t type; + int32_t status; + SLIST_ENTRY(target_notify) tn; +}; + +SLIST_HEAD(target_notifylist, target_notify); + +extern struct snmpd_target_stats snmpd_target_stats; +struct snmpd_target_stats *bsnmpd_get_target_stats(void); +struct target_address *target_first_address(void); +struct target_address *target_next_address(struct target_address *); +struct target_address *target_new_address(char *); +int target_activate_address(struct target_address *); +int target_delete_address(struct target_address *); +struct target_param *target_first_param(void); +struct target_param *target_next_param(struct target_param *); +struct target_param *target_new_param(char *); +int target_delete_param(struct target_param *); +struct target_notify *target_first_notify(void); +struct target_notify *target_next_notify(struct target_notify *); +struct target_notify *target_new_notify(char *); +int target_delete_notify (struct target_notify *); +void target_flush_all(void); + +/* * Well known OIDs */ extern const struct asn_oid oid_zeroDotZero; @@ -515,6 +589,7 @@ enum snmpd_input_err snmp_input_finish(struct snmp_pdu *, const u_char *, void snmp_output(struct snmp_pdu *, u_char *, size_t *, const char *); void snmp_send_port(void *, const struct asn_oid *, struct snmp_pdu *, const struct sockaddr *, socklen_t); +enum snmp_code snmp_pdu_auth_access(struct snmp_pdu *, int32_t *); /* sending traps */ void snmp_send_trap(const struct asn_oid *, ...); diff --git a/contrib/bsnmp/snmpd/trap.c b/contrib/bsnmp/snmpd/trap.c index 18164cf..d13f902 100644 --- a/contrib/bsnmp/snmpd/trap.c +++ b/contrib/bsnmp/snmpd/trap.c @@ -4,7 +4,13 @@ * All rights reserved. * * Author: Harti Brandt <harti@freebsd.org> - * + * + * Copyright (c) 2010 The FreeBSD Foundation + * All rights reserved. + * + * Portions of this software were developed by Shteryana Sotirova Shopova + * under sponsorship from the FreeBSD Foundation. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -34,6 +40,7 @@ #include <sys/queue.h> #include <sys/sysctl.h> #include <sys/un.h> +#include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <stdarg.h> @@ -52,6 +59,18 @@ struct trapsink_list trapsink_list = TAILQ_HEAD_INITIALIZER(trapsink_list); +/* List of target addresses */ +struct target_addresslist target_addresslist = + SLIST_HEAD_INITIALIZER(target_addresslist); + +/* List of target parameters */ +struct target_paramlist target_paramlist = + SLIST_HEAD_INITIALIZER(target_paramlist); + +/* List of notification targets */ +struct target_notifylist target_notifylist = + SLIST_HEAD_INITIALIZER(target_notifylist); + static const struct asn_oid oid_begemotTrapSinkTable = OIDX_begemotTrapSinkTable; static const struct asn_oid oid_sysUpTime = OIDX_sysUpTime; @@ -398,57 +417,152 @@ op_trapsink(struct snmp_context *ctx, struct snmp_value *value, return (SNMP_ERR_NOERROR); } +static void +snmp_create_v1_trap(struct snmp_pdu *pdu, char *com, + const struct asn_oid *trap_oid) +{ + memset(pdu, 0, sizeof(*pdu)); + strcpy(pdu->community, com); + + pdu->version = SNMP_V1; + pdu->type = SNMP_PDU_TRAP; + pdu->enterprise = systemg.object_id; + memcpy(pdu->agent_addr, snmpd.trap1addr, 4); + pdu->generic_trap = trap_oid->subs[trap_oid->len - 1] - 1; + pdu->specific_trap = 0; + pdu->time_stamp = get_ticks() - start_tick; + pdu->nbindings = 0; +} + +static void +snmp_create_v2_trap(struct snmp_pdu *pdu, char *com, + const struct asn_oid *trap_oid) +{ + memset(pdu, 0, sizeof(*pdu)); + strcpy(pdu->community, com); + + pdu->version = SNMP_V2c; + pdu->type = SNMP_PDU_TRAP2; + pdu->request_id = reqid_next(trap_reqid); + pdu->error_index = 0; + pdu->error_status = SNMP_ERR_NOERROR; + + pdu->bindings[0].var = oid_sysUpTime; + pdu->bindings[0].var.subs[pdu->bindings[0].var.len++] = 0; + pdu->bindings[0].syntax = SNMP_SYNTAX_TIMETICKS; + pdu->bindings[0].v.uint32 = get_ticks() - start_tick; + + pdu->bindings[1].var = oid_snmpTrapOID; + pdu->bindings[1].var.subs[pdu->bindings[1].var.len++] = 0; + pdu->bindings[1].syntax = SNMP_SYNTAX_OID; + pdu->bindings[1].v.oid = *trap_oid; + + pdu->nbindings = 2; +} + +static void +snmp_create_v3_trap(struct snmp_pdu *pdu, struct target_param *target, + const struct asn_oid *trap_oid) +{ + uint64_t etime; + struct usm_user *usmuser; + + memset(pdu, 0, sizeof(*pdu)); + + pdu->version = SNMP_V3; + pdu->type = SNMP_PDU_TRAP2; + pdu->request_id = reqid_next(trap_reqid); + pdu->error_index = 0; + pdu->error_status = SNMP_ERR_NOERROR; + + pdu->bindings[0].var = oid_sysUpTime; + pdu->bindings[0].var.subs[pdu->bindings[0].var.len++] = 0; + pdu->bindings[0].syntax = SNMP_SYNTAX_TIMETICKS; + pdu->bindings[0].v.uint32 = get_ticks() - start_tick; + + pdu->bindings[1].var = oid_snmpTrapOID; + pdu->bindings[1].var.subs[pdu->bindings[1].var.len++] = 0; + pdu->bindings[1].syntax = SNMP_SYNTAX_OID; + pdu->bindings[1].v.oid = *trap_oid; + + pdu->nbindings = 2; + + etime = (get_ticks() - start_tick) / 100ULL; + if (etime < INT32_MAX) + snmpd_engine.engine_time = etime; + else { + start_tick = get_ticks(); + set_snmpd_engine(); + snmpd_engine.engine_time = start_tick; + } + + memcpy(pdu->engine.engine_id, snmpd_engine.engine_id, + snmpd_engine.engine_len); + pdu->engine.engine_len = snmpd_engine.engine_len; + pdu->engine.engine_boots = snmpd_engine.engine_boots; + pdu->engine.engine_time = snmpd_engine.engine_time; + pdu->engine.max_msg_size = snmpd_engine.max_msg_size; + strlcpy(pdu->user.sec_name, target->secname, + sizeof(pdu->user.sec_name)); + pdu->security_model = target->sec_model; + + pdu->context_engine_len = snmpd_engine.engine_len; + memcpy(pdu->context_engine, snmpd_engine.engine_id, + snmpd_engine.engine_len); + + if (target->sec_model == SNMP_SECMODEL_USM && + target->sec_level != SNMP_noAuthNoPriv) { + usmuser = usm_find_user(pdu->engine.engine_id, + pdu->engine.engine_len, pdu->user.sec_name); + if (usmuser != NULL) { + pdu->user.auth_proto = usmuser->suser.auth_proto; + pdu->user.priv_proto = usmuser->suser.priv_proto; + memcpy(pdu->user.auth_key, usmuser->suser.auth_key, + sizeof(pdu->user.auth_key)); + memcpy(pdu->user.priv_key, usmuser->suser.priv_key, + sizeof(pdu->user.priv_key)); + } + snmp_pdu_init_secparams(pdu); + } +} + void snmp_send_trap(const struct asn_oid *trap_oid, ...) { struct snmp_pdu pdu; struct trapsink *t; const struct snmp_value *v; + struct target_notify *n; + struct target_address *ta; + struct target_param *tp; + va_list ap; u_char *sndbuf; + char *tag; size_t sndlen; ssize_t len; + int32_t ip; TAILQ_FOREACH(t, &trapsink_list, link) { if (t->status != TRAPSINK_ACTIVE) continue; - memset(&pdu, 0, sizeof(pdu)); - strcpy(pdu.community, t->comm); - if (t->version == TRAPSINK_V1) { - pdu.version = SNMP_V1; - pdu.type = SNMP_PDU_TRAP; - pdu.enterprise = systemg.object_id; - memcpy(pdu.agent_addr, snmpd.trap1addr, 4); - pdu.generic_trap = trap_oid->subs[trap_oid->len - 1] - 1; - pdu.specific_trap = 0; - pdu.time_stamp = get_ticks() - start_tick; - - pdu.nbindings = 0; - } else { - pdu.version = SNMP_V2c; - pdu.type = SNMP_PDU_TRAP2; - pdu.request_id = reqid_next(trap_reqid); - pdu.error_index = 0; - pdu.error_status = SNMP_ERR_NOERROR; - - pdu.bindings[0].var = oid_sysUpTime; - pdu.bindings[0].var.subs[pdu.bindings[0].var.len++] = 0; - pdu.bindings[0].syntax = SNMP_SYNTAX_TIMETICKS; - pdu.bindings[0].v.uint32 = get_ticks() - start_tick; - - pdu.bindings[1].var = oid_snmpTrapOID; - pdu.bindings[1].var.subs[pdu.bindings[1].var.len++] = 0; - pdu.bindings[1].syntax = SNMP_SYNTAX_OID; - pdu.bindings[1].v.oid = *trap_oid; - - pdu.nbindings = 2; - } + + if (t->version == TRAPSINK_V1) + snmp_create_v1_trap(&pdu, t->comm, trap_oid); + else + snmp_create_v2_trap(&pdu, t->comm, trap_oid); va_start(ap, trap_oid); while ((v = va_arg(ap, const struct snmp_value *)) != NULL) pdu.bindings[pdu.nbindings++] = *v; va_end(ap); + if (snmp_pdu_auth_access(&pdu, &ip) != SNMP_CODE_OK) { + syslog(LOG_DEBUG, "send trap to %s failed: no access", + t->comm); + continue; + } + if ((sndbuf = buf_alloc(1)) == NULL) { syslog(LOG_ERR, "trap send buffer: %m"); return; @@ -464,4 +578,339 @@ snmp_send_trap(const struct asn_oid *trap_oid, ...) free(sndbuf); } + + SLIST_FOREACH(n, &target_notifylist, tn) { + if (n->status != RowStatus_active || n->taglist[0] == '\0') + continue; + + SLIST_FOREACH(ta, &target_addresslist, ta) + if ((tag = strstr(ta->taglist, n->taglist)) != NULL && + (tag[strlen(n->taglist)] == ' ' || + tag[strlen(n->taglist)] == '\0' || + tag[strlen(n->taglist)] == '\t' || + tag[strlen(n->taglist)] == '\r' || + tag[strlen(n->taglist)] == '\n') && + ta->status == RowStatus_active) + break; + if (ta == NULL) + continue; + + SLIST_FOREACH(tp, &target_paramlist, tp) + if (strcmp(tp->name, ta->paramname) == 0 && + tp->status == 1) + break; + if (tp == NULL) + continue; + + switch (tp->mpmodel) { + case SNMP_MPM_SNMP_V1: + snmp_create_v1_trap(&pdu, tp->secname, trap_oid); + break; + + case SNMP_MPM_SNMP_V2c: + snmp_create_v2_trap(&pdu, tp->secname, trap_oid); + break; + + case SNMP_MPM_SNMP_V3: + snmp_create_v3_trap(&pdu, tp, trap_oid); + break; + + default: + continue; + } + + va_start(ap, trap_oid); + while ((v = va_arg(ap, const struct snmp_value *)) != NULL) + pdu.bindings[pdu.nbindings++] = *v; + va_end(ap); + + if (snmp_pdu_auth_access(&pdu, &ip) != SNMP_CODE_OK) { + syslog(LOG_DEBUG, "send trap to %s failed: no access", + t->comm); + continue; + } + + if ((sndbuf = buf_alloc(1)) == NULL) { + syslog(LOG_ERR, "trap send buffer: %m"); + return; + } + + snmp_output(&pdu, sndbuf, &sndlen, "TRAP"); + + if ((len = send(ta->socket, sndbuf, sndlen, 0)) == -1) + syslog(LOG_ERR, "send: %m"); + else if ((size_t)len != sndlen) + syslog(LOG_ERR, "send: short write %zu/%zu", + sndlen, (size_t)len); + + free(sndbuf); + } +} + +/* + * RFC 3413 SNMP Management Target MIB + */ +struct snmpd_target_stats * +bsnmpd_get_target_stats(void) +{ + return (&snmpd_target_stats); +} + +struct target_address * +target_first_address(void) +{ + return (SLIST_FIRST(&target_addresslist)); +} + +struct target_address * +target_next_address(struct target_address *addrs) +{ + if (addrs == NULL) + return (NULL); + + return (SLIST_NEXT(addrs, ta)); +} + +struct target_address * +target_new_address(char *aname) +{ + int cmp; + struct target_address *addrs, *temp, *prev; + + SLIST_FOREACH(addrs, &target_addresslist, ta) + if (strcmp(aname, addrs->name) == 0) + return (NULL); + + if ((addrs = (struct target_address *)malloc(sizeof(*addrs))) == NULL) + return (NULL); + + memset(addrs, 0, sizeof(*addrs)); + strlcpy(addrs->name, aname, sizeof(addrs->name)); + addrs->timeout = 150; + addrs->retry = 3; /* XXX */ + + if ((prev = SLIST_FIRST(&target_addresslist)) == NULL || + strcmp(aname, prev->name) < 0) { + SLIST_INSERT_HEAD(&target_addresslist, addrs, ta); + return (addrs); + } + + SLIST_FOREACH(temp, &target_addresslist, ta) { + if ((cmp = strcmp(aname, temp->name)) <= 0) + break; + prev = temp; + } + + if (temp == NULL || cmp < 0) + SLIST_INSERT_AFTER(prev, addrs, ta); + else if (cmp > 0) + SLIST_INSERT_AFTER(temp, addrs, ta); + else { + syslog(LOG_ERR, "Target address %s exists", addrs->name); + free(addrs); + return (NULL); + } + + return (addrs); +} + +int +target_activate_address(struct target_address *addrs) +{ + struct sockaddr_in sa; + + if ((addrs->socket = socket(PF_INET, SOCK_DGRAM, 0)) == -1) { + syslog(LOG_ERR, "socket(UDP): %m"); + return (SNMP_ERR_RES_UNAVAIL); + } + + (void)shutdown(addrs->socket, SHUT_RD); + sa.sin_len = sizeof(sa); + sa.sin_family = AF_INET; + + sa.sin_addr.s_addr = htonl((addrs->address[0] << 24) | + (addrs->address[1] << 16) | (addrs->address[2] << 8) | + (addrs->address[3] << 0)); + sa.sin_port = htons(addrs->address[4]) << 8 | + htons(addrs->address[5]) << 0; + + if (connect(addrs->socket, (struct sockaddr *)&sa, sa.sin_len) == -1) { + syslog(LOG_ERR, "connect(%s,%u): %m", + inet_ntoa(sa.sin_addr), ntohs(sa.sin_port)); + (void)close(addrs->socket); + return (SNMP_ERR_GENERR); + } + + addrs->status = RowStatus_active; + + return (SNMP_ERR_NOERROR); +} + +int +target_delete_address(struct target_address *addrs) +{ + SLIST_REMOVE(&target_addresslist, addrs, target_address, ta); + if (addrs->status == RowStatus_active) + close(addrs->socket); + free(addrs); + + return (0); +} + +struct target_param * +target_first_param(void) +{ + return (SLIST_FIRST(&target_paramlist)); +} + +struct target_param * +target_next_param(struct target_param *param) +{ + if (param == NULL) + return (NULL); + + return (SLIST_NEXT(param, tp)); +} + +struct target_param * +target_new_param(char *pname) +{ + int cmp; + struct target_param *param, *temp, *prev; + + SLIST_FOREACH(param, &target_paramlist, tp) + if (strcmp(pname, param->name) == 0) + return (NULL); + + if ((param = (struct target_param *)malloc(sizeof(*param))) == NULL) + return (NULL); + + memset(param, 0, sizeof(*param)); + strlcpy(param->name, pname, sizeof(param->name)); + + if ((prev = SLIST_FIRST(&target_paramlist)) == NULL || + strcmp(pname, prev->name) < 0) { + SLIST_INSERT_HEAD(&target_paramlist, param, tp); + return (param); + } + + SLIST_FOREACH(temp, &target_paramlist, tp) { + if ((cmp = strcmp(pname, temp->name)) <= 0) + break; + prev = temp; + } + + if (temp == NULL || cmp < 0) + SLIST_INSERT_AFTER(prev, param, tp); + else if (cmp > 0) + SLIST_INSERT_AFTER(temp, param, tp); + else { + syslog(LOG_ERR, "Target parameter %s exists", param->name); + free(param); + return (NULL); + } + + return (param); +} + +int +target_delete_param(struct target_param *param) +{ + SLIST_REMOVE(&target_paramlist, param, target_param, tp); + free(param); + + return (0); +} + +struct target_notify * +target_first_notify(void) +{ + return (SLIST_FIRST(&target_notifylist)); +} + +struct target_notify * +target_next_notify(struct target_notify *notify) +{ + if (notify == NULL) + return (NULL); + + return (SLIST_NEXT(notify, tn)); +} + +struct target_notify * +target_new_notify(char *nname) +{ + int cmp; + struct target_notify *notify, *temp, *prev; + + SLIST_FOREACH(notify, &target_notifylist, tn) + if (strcmp(nname, notify->name) == 0) + return (NULL); + + if ((notify = (struct target_notify *)malloc(sizeof(*notify))) == NULL) + return (NULL); + + memset(notify, 0, sizeof(*notify)); + strlcpy(notify->name, nname, sizeof(notify->name)); + + if ((prev = SLIST_FIRST(&target_notifylist)) == NULL || + strcmp(nname, prev->name) < 0) { + SLIST_INSERT_HEAD(&target_notifylist, notify, tn); + return (notify); + } + + SLIST_FOREACH(temp, &target_notifylist, tn) { + if ((cmp = strcmp(nname, temp->name)) <= 0) + break; + prev = temp; + } + + if (temp == NULL || cmp < 0) + SLIST_INSERT_AFTER(prev, notify, tn); + else if (cmp > 0) + SLIST_INSERT_AFTER(temp, notify, tn); + else { + syslog(LOG_ERR, "Notification target %s exists", notify->name); + free(notify); + return (NULL); + } + + return (notify); +} + +int +target_delete_notify(struct target_notify *notify) +{ + SLIST_REMOVE(&target_notifylist, notify, target_notify, tn); + free(notify); + + return (0); +} + +void +target_flush_all(void) +{ + struct target_address *addrs; + struct target_param *param; + struct target_notify *notify; + + while ((addrs = SLIST_FIRST(&target_addresslist)) != NULL) { + SLIST_REMOVE_HEAD(&target_addresslist, ta); + if (addrs->status == RowStatus_active) + close(addrs->socket); + free(addrs); + } + SLIST_INIT(&target_addresslist); + + while ((param = SLIST_FIRST(&target_paramlist)) != NULL) { + SLIST_REMOVE_HEAD(&target_paramlist, tp); + free(param); + } + SLIST_INIT(&target_paramlist); + + while ((notify = SLIST_FIRST(&target_notifylist)) != NULL) { + SLIST_REMOVE_HEAD(&target_notifylist, tn); + free(notify); + } + SLIST_INIT(&target_notifylist); } diff --git a/contrib/bsnmp/snmpd/tree.def b/contrib/bsnmp/snmpd/tree.def index 00672eb..f4d8579 100644 --- a/contrib/bsnmp/snmpd/tree.def +++ b/contrib/bsnmp/snmpd/tree.def @@ -30,6 +30,9 @@ # # System group and private Begemot SNMPd MIB. # + +include "tc.def" + (1 internet (2 mgmt (1 mibII |