trap.c revision 292815
1109001Sbenno/* 2109001Sbenno * Copyright (c) 2001-2003 3109001Sbenno * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 4109001Sbenno * All rights reserved. 5109001Sbenno * 6109001Sbenno * Author: Harti Brandt <harti@freebsd.org> 7109001Sbenno * 8109001Sbenno * Copyright (c) 2010 The FreeBSD Foundation 9109001Sbenno * All rights reserved. 10109001Sbenno * 11109001Sbenno * Portions of this software were developed by Shteryana Sotirova Shopova 12109001Sbenno * under sponsorship from the FreeBSD Foundation. 13109001Sbenno * 14109001Sbenno * Redistribution and use in source and binary forms, with or without 15109001Sbenno * modification, are permitted provided that the following conditions 16109001Sbenno * are met: 17109001Sbenno * 1. Redistributions of source code must retain the above copyright 18109001Sbenno * notice, this list of conditions and the following disclaimer. 19109001Sbenno * 2. Redistributions in binary form must reproduce the above copyright 20109001Sbenno * notice, this list of conditions and the following disclaimer in the 21109001Sbenno * documentation and/or other materials provided with the distribution. 22109001Sbenno * 23109001Sbenno * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 24109001Sbenno * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25109001Sbenno * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26109001Sbenno * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 27109001Sbenno * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28109001Sbenno * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29109001Sbenno * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30109001Sbenno * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31131102Sgrehan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32109001Sbenno * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33109001Sbenno * SUCH DAMAGE. 34109001Sbenno * 35109001Sbenno * $Begemot: bsnmp/snmpd/trap.c,v 1.9 2005/10/04 11:21:39 brandt_h Exp $ 36109001Sbenno * 37109001Sbenno * TrapSinkTable 38183882Snwhitehorn */ 39186128Snwhitehorn#include <sys/types.h> 40109001Sbenno#include <sys/queue.h> 41119291Simp#include <sys/sysctl.h> 42119291Simp#include <sys/un.h> 43119291Simp#include <stdint.h> 44109001Sbenno#include <stdio.h> 45109001Sbenno#include <stdlib.h> 46109001Sbenno#include <stdarg.h> 47109001Sbenno#include <stdarg.h> 48109001Sbenno#include <string.h> 49183882Snwhitehorn#include <ctype.h> 50186128Snwhitehorn#include <syslog.h> 51186128Snwhitehorn#include <unistd.h> 52109001Sbenno#include <netinet/in.h> 53109001Sbenno#include <arpa/inet.h> 54109001Sbenno 55109001Sbenno#include "snmpmod.h" 56109001Sbenno#include "snmpd.h" 57109001Sbenno#include "tree.h" 58109001Sbenno#include "oid.h" 59109001Sbenno 60109001Sbennostruct trapsink_list trapsink_list = TAILQ_HEAD_INITIALIZER(trapsink_list); 61109001Sbenno 62109001Sbenno/* List of target addresses */ 63109001Sbennostatic struct target_addresslist target_addresslist = 64109001Sbenno SLIST_HEAD_INITIALIZER(target_addresslist); 65109001Sbenno 66109001Sbenno/* List of target parameters */ 67109001Sbennostatic struct target_paramlist target_paramlist = 68109001Sbenno SLIST_HEAD_INITIALIZER(target_paramlist); 69109001Sbenno 70109001Sbenno/* List of notification targets */ 71109001Sbennostatic struct target_notifylist target_notifylist = 72109001Sbenno SLIST_HEAD_INITIALIZER(target_notifylist); 73109001Sbenno 74109001Sbennostatic const struct asn_oid oid_begemotTrapSinkTable = 75109001Sbenno OIDX_begemotTrapSinkTable; 76186128Snwhitehornstatic const struct asn_oid oid_sysUpTime = OIDX_sysUpTime; 77109001Sbennostatic const struct asn_oid oid_snmpTrapOID = OIDX_snmpTrapOID; 78183882Snwhitehorn 79183882Snwhitehornstruct trapsink_dep { 80183882Snwhitehorn struct snmp_dependency dep; 81109001Sbenno u_int set; 82109001Sbenno u_int status; 83109001Sbenno u_char comm[SNMP_COMMUNITY_MAXLEN + 1]; 84154079Sjhb u_int version; 85109001Sbenno u_int rb; 86186128Snwhitehorn u_int rb_status; 87186128Snwhitehorn u_int rb_version; 88186128Snwhitehorn u_char rb_comm[SNMP_COMMUNITY_MAXLEN + 1]; 89186128Snwhitehorn}; 90186128Snwhitehornenum { 91186128Snwhitehorn TDEP_STATUS = 0x0001, 92186128Snwhitehorn TDEP_COMM = 0x0002, 93186128Snwhitehorn TDEP_VERSION = 0x0004, 94186128Snwhitehorn 95186128Snwhitehorn TDEP_CREATE = 0x0001, 96186128Snwhitehorn TDEP_MODIFY = 0x0002, 97186128Snwhitehorn TDEP_DESTROY = 0x0004, 98154079Sjhb}; 99186128Snwhitehorn 100109001Sbennostatic int 101109001Sbennotrapsink_create(struct trapsink_dep *tdep) 102109001Sbenno{ 103109001Sbenno struct trapsink *t; 104109001Sbenno struct sockaddr_in sa; 105109001Sbenno 106109001Sbenno if ((t = malloc(sizeof(*t))) == NULL) 107109001Sbenno return (SNMP_ERR_RES_UNAVAIL); 108109001Sbenno 109109001Sbenno t->index = tdep->dep.idx; 110183882Snwhitehorn t->status = TRAPSINK_NOT_READY; 111183882Snwhitehorn t->comm[0] = '\0'; 112109001Sbenno t->version = TRAPSINK_V2; 113109001Sbenno 114183882Snwhitehorn if ((t->socket = socket(PF_INET, SOCK_DGRAM, 0)) == -1) { 115183882Snwhitehorn syslog(LOG_ERR, "socket(UDP): %m"); 116109001Sbenno free(t); 117109001Sbenno return (SNMP_ERR_RES_UNAVAIL); 118109001Sbenno } 119109001Sbenno (void)shutdown(t->socket, SHUT_RD); 120109001Sbenno memset(&sa, 0, sizeof(sa)); 121186128Snwhitehorn sa.sin_len = sizeof(sa); 122186128Snwhitehorn sa.sin_family = AF_INET; 123186128Snwhitehorn sa.sin_addr.s_addr = htonl((t->index.subs[0] << 24) | 124186128Snwhitehorn (t->index.subs[1] << 16) | (t->index.subs[2] << 8) | 125186128Snwhitehorn (t->index.subs[3] << 0)); 126186128Snwhitehorn sa.sin_port = htons(t->index.subs[4]); 127186128Snwhitehorn 128186128Snwhitehorn if (connect(t->socket, (struct sockaddr *)&sa, sa.sin_len) == -1) { 129186128Snwhitehorn syslog(LOG_ERR, "connect(%s,%u): %m", 130109001Sbenno inet_ntoa(sa.sin_addr), ntohs(sa.sin_port)); 131109001Sbenno (void)close(t->socket); 132109001Sbenno free(t); 133109001Sbenno return (SNMP_ERR_GENERR); 134109001Sbenno } 135109001Sbenno 136183882Snwhitehorn if (tdep->set & TDEP_VERSION) 137186128Snwhitehorn t->version = tdep->version; 138183882Snwhitehorn if (tdep->set & TDEP_COMM) 139183882Snwhitehorn strcpy(t->comm, tdep->comm); 140183882Snwhitehorn 141183882Snwhitehorn if (t->comm[0] != '\0') 142183882Snwhitehorn t->status = TRAPSINK_NOT_IN_SERVICE; 143183882Snwhitehorn 144183882Snwhitehorn /* look whether we should activate */ 145186128Snwhitehorn if (tdep->status == 4) { 146186128Snwhitehorn if (t->status == TRAPSINK_NOT_READY) { 147186128Snwhitehorn if (t->socket != -1) 148186128Snwhitehorn (void)close(t->socket); 149186128Snwhitehorn free(t); 150186128Snwhitehorn return (SNMP_ERR_INCONS_VALUE); 151186128Snwhitehorn } 152186128Snwhitehorn t->status = TRAPSINK_ACTIVE; 153186128Snwhitehorn } 154186128Snwhitehorn 155186128Snwhitehorn INSERT_OBJECT_OID(t, &trapsink_list); 156186128Snwhitehorn 157186128Snwhitehorn tdep->rb |= TDEP_CREATE; 158186128Snwhitehorn 159186128Snwhitehorn return (SNMP_ERR_NOERROR); 160186128Snwhitehorn} 161186128Snwhitehorn 162186128Snwhitehornstatic void 163186128Snwhitehorntrapsink_free(struct trapsink *t) 164186128Snwhitehorn{ 165186128Snwhitehorn TAILQ_REMOVE(&trapsink_list, t, link); 166186128Snwhitehorn if (t->socket != -1) 167186128Snwhitehorn (void)close(t->socket); 168186128Snwhitehorn free(t); 169186128Snwhitehorn} 170186128Snwhitehorn 171186128Snwhitehornstatic int 172186128Snwhitehorntrapsink_modify(struct trapsink *t, struct trapsink_dep *tdep) 173186128Snwhitehorn{ 174186128Snwhitehorn tdep->rb_status = t->status; 175186128Snwhitehorn tdep->rb_version = t->version; 176186128Snwhitehorn strcpy(tdep->rb_comm, t->comm); 177186128Snwhitehorn 178186128Snwhitehorn if (tdep->set & TDEP_STATUS) { 179 /* if we are active and should move to not_in_service do 180 * this first */ 181 if (tdep->status == 2 && tdep->rb_status == TRAPSINK_ACTIVE) { 182 t->status = TRAPSINK_NOT_IN_SERVICE; 183 tdep->rb |= TDEP_MODIFY; 184 } 185 } 186 187 if (tdep->set & TDEP_VERSION) 188 t->version = tdep->version; 189 if (tdep->set & TDEP_COMM) 190 strcpy(t->comm, tdep->comm); 191 192 if (tdep->set & TDEP_STATUS) { 193 /* if we were inactive and should go active - do this now */ 194 if (tdep->status == 1 && tdep->rb_status != TRAPSINK_ACTIVE) { 195 if (t->comm[0] == '\0') { 196 t->status = tdep->rb_status; 197 t->version = tdep->rb_version; 198 strcpy(t->comm, tdep->rb_comm); 199 return (SNMP_ERR_INCONS_VALUE); 200 } 201 t->status = TRAPSINK_ACTIVE; 202 tdep->rb |= TDEP_MODIFY; 203 } 204 } 205 return (SNMP_ERR_NOERROR); 206} 207 208static int 209trapsink_unmodify(struct trapsink *t, struct trapsink_dep *tdep) 210{ 211 if (tdep->set & TDEP_STATUS) 212 t->status = tdep->rb_status; 213 if (tdep->set & TDEP_VERSION) 214 t->version = tdep->rb_version; 215 if (tdep->set & TDEP_COMM) 216 strcpy(t->comm, tdep->rb_comm); 217 218 return (SNMP_ERR_NOERROR); 219} 220 221static int 222trapsink_destroy(struct snmp_context *ctx __unused, struct trapsink *t, 223 struct trapsink_dep *tdep) 224{ 225 t->status = TRAPSINK_DESTROY; 226 tdep->rb_status = t->status; 227 tdep->rb |= TDEP_DESTROY; 228 return (SNMP_ERR_NOERROR); 229} 230 231static int 232trapsink_undestroy(struct trapsink *t, struct trapsink_dep *tdep) 233{ 234 t->status = tdep->rb_status; 235 return (SNMP_ERR_NOERROR); 236} 237 238static int 239trapsink_dep(struct snmp_context *ctx, struct snmp_dependency *dep, 240 enum snmp_depop op) 241{ 242 struct trapsink_dep *tdep = (struct trapsink_dep *)dep; 243 struct trapsink *t; 244 245 t = FIND_OBJECT_OID(&trapsink_list, &dep->idx, 0); 246 247 switch (op) { 248 249 case SNMP_DEPOP_COMMIT: 250 if (tdep->set & TDEP_STATUS) { 251 switch (tdep->status) { 252 253 case 1: 254 case 2: 255 if (t == NULL) 256 return (SNMP_ERR_INCONS_VALUE); 257 return (trapsink_modify(t, tdep)); 258 259 case 4: 260 case 5: 261 if (t != NULL) 262 return (SNMP_ERR_INCONS_VALUE); 263 return (trapsink_create(tdep)); 264 265 case 6: 266 if (t == NULL) 267 return (SNMP_ERR_NOERROR); 268 return (trapsink_destroy(ctx, t, tdep)); 269 } 270 } else if (tdep->set != 0) 271 return (trapsink_modify(t, tdep)); 272 273 return (SNMP_ERR_NOERROR); 274 275 case SNMP_DEPOP_ROLLBACK: 276 if (tdep->rb & TDEP_CREATE) { 277 trapsink_free(t); 278 return (SNMP_ERR_NOERROR); 279 } 280 if (tdep->rb & TDEP_MODIFY) 281 return (trapsink_unmodify(t, tdep)); 282 if(tdep->rb & TDEP_DESTROY) 283 return (trapsink_undestroy(t, tdep)); 284 return (SNMP_ERR_NOERROR); 285 286 case SNMP_DEPOP_FINISH: 287 if ((tdep->rb & TDEP_DESTROY) && t != NULL && 288 ctx->code == SNMP_RET_OK) 289 trapsink_free(t); 290 return (SNMP_ERR_NOERROR); 291 } 292 abort(); 293} 294 295int 296op_trapsink(struct snmp_context *ctx, struct snmp_value *value, 297 u_int sub, u_int iidx, enum snmp_op op) 298{ 299 struct trapsink *t; 300 u_char ipa[4]; 301 int32_t port; 302 struct asn_oid idx; 303 struct trapsink_dep *tdep; 304 u_char *p; 305 306 t = NULL; /* gcc */ 307 308 switch (op) { 309 310 case SNMP_OP_GETNEXT: 311 if ((t = NEXT_OBJECT_OID(&trapsink_list, &value->var, sub)) == NULL) 312 return (SNMP_ERR_NOSUCHNAME); 313 index_append(&value->var, sub, &t->index); 314 break; 315 316 case SNMP_OP_GET: 317 if ((t = FIND_OBJECT_OID(&trapsink_list, &value->var, sub)) == NULL) 318 return (SNMP_ERR_NOSUCHNAME); 319 break; 320 321 case SNMP_OP_SET: 322 if (index_decode(&value->var, sub, iidx, ipa, &port) || 323 port == 0 || port > 65535) 324 return (SNMP_ERR_NO_CREATION); 325 t = FIND_OBJECT_OID(&trapsink_list, &value->var, sub); 326 327 asn_slice_oid(&idx, &value->var, sub, value->var.len); 328 329 tdep = (struct trapsink_dep *)snmp_dep_lookup(ctx, 330 &oid_begemotTrapSinkTable, &idx, 331 sizeof(*tdep), trapsink_dep); 332 if (tdep == NULL) 333 return (SNMP_ERR_RES_UNAVAIL); 334 335 switch (value->var.subs[sub - 1]) { 336 337 case LEAF_begemotTrapSinkStatus: 338 if (tdep->set & TDEP_STATUS) 339 return (SNMP_ERR_INCONS_VALUE); 340 switch (value->v.integer) { 341 342 case 1: 343 case 2: 344 if (t == NULL) 345 return (SNMP_ERR_INCONS_VALUE); 346 break; 347 348 case 4: 349 case 5: 350 if (t != NULL) 351 return (SNMP_ERR_INCONS_VALUE); 352 break; 353 354 case 6: 355 break; 356 357 default: 358 return (SNMP_ERR_WRONG_VALUE); 359 } 360 tdep->status = value->v.integer; 361 tdep->set |= TDEP_STATUS; 362 return (SNMP_ERR_NOERROR); 363 364 case LEAF_begemotTrapSinkComm: 365 if (tdep->set & TDEP_COMM) 366 return (SNMP_ERR_INCONS_VALUE); 367 if (value->v.octetstring.len == 0 || 368 value->v.octetstring.len > SNMP_COMMUNITY_MAXLEN) 369 return (SNMP_ERR_WRONG_VALUE); 370 for (p = value->v.octetstring.octets; 371 p < value->v.octetstring.octets + value->v.octetstring.len; 372 p++) { 373 if (!isascii(*p) || !isprint(*p)) 374 return (SNMP_ERR_WRONG_VALUE); 375 } 376 tdep->set |= TDEP_COMM; 377 strncpy(tdep->comm, value->v.octetstring.octets, 378 value->v.octetstring.len); 379 tdep->comm[value->v.octetstring.len] = '\0'; 380 return (SNMP_ERR_NOERROR); 381 382 case LEAF_begemotTrapSinkVersion: 383 if (tdep->set & TDEP_VERSION) 384 return (SNMP_ERR_INCONS_VALUE); 385 if (value->v.integer != TRAPSINK_V1 && 386 value->v.integer != TRAPSINK_V2) 387 return (SNMP_ERR_WRONG_VALUE); 388 tdep->version = value->v.integer; 389 tdep->set |= TDEP_VERSION; 390 return (SNMP_ERR_NOERROR); 391 } 392 if (t == NULL) 393 return (SNMP_ERR_INCONS_NAME); 394 else 395 return (SNMP_ERR_NOT_WRITEABLE); 396 397 398 case SNMP_OP_ROLLBACK: 399 case SNMP_OP_COMMIT: 400 return (SNMP_ERR_NOERROR); 401 } 402 403 switch (value->var.subs[sub - 1]) { 404 405 case LEAF_begemotTrapSinkStatus: 406 value->v.integer = t->status; 407 break; 408 409 case LEAF_begemotTrapSinkComm: 410 return (string_get(value, t->comm, -1)); 411 412 case LEAF_begemotTrapSinkVersion: 413 value->v.integer = t->version; 414 break; 415 416 } 417 return (SNMP_ERR_NOERROR); 418} 419 420static void 421snmp_create_v1_trap(struct snmp_pdu *pdu, char *com, 422 const struct asn_oid *trap_oid) 423{ 424 memset(pdu, 0, sizeof(*pdu)); 425 strcpy(pdu->community, com); 426 427 pdu->version = SNMP_V1; 428 pdu->type = SNMP_PDU_TRAP; 429 pdu->enterprise = systemg.object_id; 430 memcpy(pdu->agent_addr, snmpd.trap1addr, 4); 431 pdu->generic_trap = trap_oid->subs[trap_oid->len - 1] - 1; 432 pdu->specific_trap = 0; 433 pdu->time_stamp = get_ticks() - start_tick; 434 pdu->nbindings = 0; 435} 436 437static void 438snmp_create_v2_trap(struct snmp_pdu *pdu, char *com, 439 const struct asn_oid *trap_oid) 440{ 441 memset(pdu, 0, sizeof(*pdu)); 442 strcpy(pdu->community, com); 443 444 pdu->version = SNMP_V2c; 445 pdu->type = SNMP_PDU_TRAP2; 446 pdu->request_id = reqid_next(trap_reqid); 447 pdu->error_index = 0; 448 pdu->error_status = SNMP_ERR_NOERROR; 449 450 pdu->bindings[0].var = oid_sysUpTime; 451 pdu->bindings[0].var.subs[pdu->bindings[0].var.len++] = 0; 452 pdu->bindings[0].syntax = SNMP_SYNTAX_TIMETICKS; 453 pdu->bindings[0].v.uint32 = get_ticks() - start_tick; 454 455 pdu->bindings[1].var = oid_snmpTrapOID; 456 pdu->bindings[1].var.subs[pdu->bindings[1].var.len++] = 0; 457 pdu->bindings[1].syntax = SNMP_SYNTAX_OID; 458 pdu->bindings[1].v.oid = *trap_oid; 459 460 pdu->nbindings = 2; 461} 462 463static void 464snmp_create_v3_trap(struct snmp_pdu *pdu, struct target_param *target, 465 const struct asn_oid *trap_oid) 466{ 467 uint64_t etime; 468 struct usm_user *usmuser; 469 470 memset(pdu, 0, sizeof(*pdu)); 471 472 pdu->version = SNMP_V3; 473 pdu->type = SNMP_PDU_TRAP2; 474 pdu->request_id = reqid_next(trap_reqid); 475 pdu->error_index = 0; 476 pdu->error_status = SNMP_ERR_NOERROR; 477 478 pdu->bindings[0].var = oid_sysUpTime; 479 pdu->bindings[0].var.subs[pdu->bindings[0].var.len++] = 0; 480 pdu->bindings[0].syntax = SNMP_SYNTAX_TIMETICKS; 481 pdu->bindings[0].v.uint32 = get_ticks() - start_tick; 482 483 pdu->bindings[1].var = oid_snmpTrapOID; 484 pdu->bindings[1].var.subs[pdu->bindings[1].var.len++] = 0; 485 pdu->bindings[1].syntax = SNMP_SYNTAX_OID; 486 pdu->bindings[1].v.oid = *trap_oid; 487 488 pdu->nbindings = 2; 489 490 etime = (get_ticks() - start_tick) / 100ULL; 491 if (etime < INT32_MAX) 492 snmpd_engine.engine_time = etime; 493 else { 494 start_tick = get_ticks(); 495 set_snmpd_engine(); 496 snmpd_engine.engine_time = start_tick; 497 } 498 499 memcpy(pdu->engine.engine_id, snmpd_engine.engine_id, 500 snmpd_engine.engine_len); 501 pdu->engine.engine_len = snmpd_engine.engine_len; 502 pdu->engine.engine_boots = snmpd_engine.engine_boots; 503 pdu->engine.engine_time = snmpd_engine.engine_time; 504 pdu->engine.max_msg_size = snmpd_engine.max_msg_size; 505 strlcpy(pdu->user.sec_name, target->secname, 506 sizeof(pdu->user.sec_name)); 507 pdu->security_model = target->sec_model; 508 509 pdu->context_engine_len = snmpd_engine.engine_len; 510 memcpy(pdu->context_engine, snmpd_engine.engine_id, 511 snmpd_engine.engine_len); 512 513 if (target->sec_model == SNMP_SECMODEL_USM && 514 target->sec_level != SNMP_noAuthNoPriv) { 515 usmuser = usm_find_user(pdu->engine.engine_id, 516 pdu->engine.engine_len, pdu->user.sec_name); 517 if (usmuser != NULL) { 518 pdu->user.auth_proto = usmuser->suser.auth_proto; 519 pdu->user.priv_proto = usmuser->suser.priv_proto; 520 memcpy(pdu->user.auth_key, usmuser->suser.auth_key, 521 sizeof(pdu->user.auth_key)); 522 memcpy(pdu->user.priv_key, usmuser->suser.priv_key, 523 sizeof(pdu->user.priv_key)); 524 } 525 snmp_pdu_init_secparams(pdu); 526 } 527} 528 529void 530snmp_send_trap(const struct asn_oid *trap_oid, ...) 531{ 532 struct snmp_pdu pdu; 533 struct trapsink *t; 534 const struct snmp_value *v; 535 struct target_notify *n; 536 struct target_address *ta; 537 struct target_param *tp; 538 539 va_list ap; 540 u_char *sndbuf; 541 char *tag; 542 size_t sndlen; 543 ssize_t len; 544 int32_t ip; 545 546 TAILQ_FOREACH(t, &trapsink_list, link) { 547 if (t->status != TRAPSINK_ACTIVE) 548 continue; 549 550 if (t->version == TRAPSINK_V1) 551 snmp_create_v1_trap(&pdu, t->comm, trap_oid); 552 else 553 snmp_create_v2_trap(&pdu, t->comm, trap_oid); 554 555 va_start(ap, trap_oid); 556 while ((v = va_arg(ap, const struct snmp_value *)) != NULL) 557 pdu.bindings[pdu.nbindings++] = *v; 558 va_end(ap); 559 560 if (snmp_pdu_auth_access(&pdu, &ip) != SNMP_CODE_OK) { 561 syslog(LOG_DEBUG, "send trap to %s failed: no access", 562 t->comm); 563 continue; 564 } 565 566 if ((sndbuf = buf_alloc(1)) == NULL) { 567 syslog(LOG_ERR, "trap send buffer: %m"); 568 return; 569 } 570 571 snmp_output(&pdu, sndbuf, &sndlen, "TRAP"); 572 573 if ((len = send(t->socket, sndbuf, sndlen, 0)) == -1) 574 syslog(LOG_ERR, "send: %m"); 575 else if ((size_t)len != sndlen) 576 syslog(LOG_ERR, "send: short write %zu/%zu", 577 sndlen, (size_t)len); 578 579 free(sndbuf); 580 } 581 582 SLIST_FOREACH(n, &target_notifylist, tn) { 583 if (n->status != RowStatus_active || n->taglist[0] == '\0') 584 continue; 585 586 SLIST_FOREACH(ta, &target_addresslist, ta) 587 if ((tag = strstr(ta->taglist, n->taglist)) != NULL && 588 (tag[strlen(n->taglist)] == ' ' || 589 tag[strlen(n->taglist)] == '\0' || 590 tag[strlen(n->taglist)] == '\t' || 591 tag[strlen(n->taglist)] == '\r' || 592 tag[strlen(n->taglist)] == '\n') && 593 ta->status == RowStatus_active) 594 break; 595 if (ta == NULL) 596 continue; 597 598 SLIST_FOREACH(tp, &target_paramlist, tp) 599 if (strcmp(tp->name, ta->paramname) == 0 && 600 tp->status == 1) 601 break; 602 if (tp == NULL) 603 continue; 604 605 switch (tp->mpmodel) { 606 case SNMP_MPM_SNMP_V1: 607 snmp_create_v1_trap(&pdu, tp->secname, trap_oid); 608 break; 609 610 case SNMP_MPM_SNMP_V2c: 611 snmp_create_v2_trap(&pdu, tp->secname, trap_oid); 612 break; 613 614 case SNMP_MPM_SNMP_V3: 615 snmp_create_v3_trap(&pdu, tp, trap_oid); 616 break; 617 618 default: 619 continue; 620 } 621 622 va_start(ap, trap_oid); 623 while ((v = va_arg(ap, const struct snmp_value *)) != NULL) 624 pdu.bindings[pdu.nbindings++] = *v; 625 va_end(ap); 626 627 if (snmp_pdu_auth_access(&pdu, &ip) != SNMP_CODE_OK) { 628 syslog(LOG_DEBUG, "send trap to %s failed: no access", 629 t->comm); 630 continue; 631 } 632 633 if ((sndbuf = buf_alloc(1)) == NULL) { 634 syslog(LOG_ERR, "trap send buffer: %m"); 635 return; 636 } 637 638 snmp_output(&pdu, sndbuf, &sndlen, "TRAP"); 639 640 if ((len = send(ta->socket, sndbuf, sndlen, 0)) == -1) 641 syslog(LOG_ERR, "send: %m"); 642 else if ((size_t)len != sndlen) 643 syslog(LOG_ERR, "send: short write %zu/%zu", 644 sndlen, (size_t)len); 645 646 free(sndbuf); 647 } 648} 649 650/* 651 * RFC 3413 SNMP Management Target MIB 652 */ 653struct snmpd_target_stats * 654bsnmpd_get_target_stats(void) 655{ 656 return (&snmpd_target_stats); 657} 658 659struct target_address * 660target_first_address(void) 661{ 662 return (SLIST_FIRST(&target_addresslist)); 663} 664 665struct target_address * 666target_next_address(struct target_address *addrs) 667{ 668 if (addrs == NULL) 669 return (NULL); 670 671 return (SLIST_NEXT(addrs, ta)); 672} 673 674struct target_address * 675target_new_address(char *aname) 676{ 677 int cmp; 678 struct target_address *addrs, *temp, *prev; 679 680 SLIST_FOREACH(addrs, &target_addresslist, ta) 681 if (strcmp(aname, addrs->name) == 0) 682 return (NULL); 683 684 if ((addrs = (struct target_address *)malloc(sizeof(*addrs))) == NULL) 685 return (NULL); 686 687 memset(addrs, 0, sizeof(*addrs)); 688 strlcpy(addrs->name, aname, sizeof(addrs->name)); 689 addrs->timeout = 150; 690 addrs->retry = 3; /* XXX */ 691 692 if ((prev = SLIST_FIRST(&target_addresslist)) == NULL || 693 strcmp(aname, prev->name) < 0) { 694 SLIST_INSERT_HEAD(&target_addresslist, addrs, ta); 695 return (addrs); 696 } 697 698 SLIST_FOREACH(temp, &target_addresslist, ta) { 699 if ((cmp = strcmp(aname, temp->name)) <= 0) 700 break; 701 prev = temp; 702 } 703 704 if (temp == NULL || cmp < 0) 705 SLIST_INSERT_AFTER(prev, addrs, ta); 706 else if (cmp > 0) 707 SLIST_INSERT_AFTER(temp, addrs, ta); 708 else { 709 syslog(LOG_ERR, "Target address %s exists", addrs->name); 710 free(addrs); 711 return (NULL); 712 } 713 714 return (addrs); 715} 716 717int 718target_activate_address(struct target_address *addrs) 719{ 720 struct sockaddr_in sa; 721 722 if ((addrs->socket = socket(PF_INET, SOCK_DGRAM, 0)) == -1) { 723 syslog(LOG_ERR, "socket(UDP): %m"); 724 return (SNMP_ERR_RES_UNAVAIL); 725 } 726 727 (void)shutdown(addrs->socket, SHUT_RD); 728 memset(&sa, 0, sizeof(sa)); 729 sa.sin_len = sizeof(sa); 730 sa.sin_family = AF_INET; 731 732 sa.sin_addr.s_addr = htonl((addrs->address[0] << 24) | 733 (addrs->address[1] << 16) | (addrs->address[2] << 8) | 734 (addrs->address[3] << 0)); 735 sa.sin_port = htons(addrs->address[4]) << 8 | 736 htons(addrs->address[5]) << 0; 737 738 if (connect(addrs->socket, (struct sockaddr *)&sa, sa.sin_len) == -1) { 739 syslog(LOG_ERR, "connect(%s,%u): %m", 740 inet_ntoa(sa.sin_addr), ntohs(sa.sin_port)); 741 (void)close(addrs->socket); 742 return (SNMP_ERR_GENERR); 743 } 744 745 addrs->status = RowStatus_active; 746 747 return (SNMP_ERR_NOERROR); 748} 749 750int 751target_delete_address(struct target_address *addrs) 752{ 753 SLIST_REMOVE(&target_addresslist, addrs, target_address, ta); 754 if (addrs->status == RowStatus_active) 755 close(addrs->socket); 756 free(addrs); 757 758 return (0); 759} 760 761struct target_param * 762target_first_param(void) 763{ 764 return (SLIST_FIRST(&target_paramlist)); 765} 766 767struct target_param * 768target_next_param(struct target_param *param) 769{ 770 if (param == NULL) 771 return (NULL); 772 773 return (SLIST_NEXT(param, tp)); 774} 775 776struct target_param * 777target_new_param(char *pname) 778{ 779 int cmp; 780 struct target_param *param, *temp, *prev; 781 782 SLIST_FOREACH(param, &target_paramlist, tp) 783 if (strcmp(pname, param->name) == 0) 784 return (NULL); 785 786 if ((param = (struct target_param *)malloc(sizeof(*param))) == NULL) 787 return (NULL); 788 789 memset(param, 0, sizeof(*param)); 790 strlcpy(param->name, pname, sizeof(param->name)); 791 792 if ((prev = SLIST_FIRST(&target_paramlist)) == NULL || 793 strcmp(pname, prev->name) < 0) { 794 SLIST_INSERT_HEAD(&target_paramlist, param, tp); 795 return (param); 796 } 797 798 SLIST_FOREACH(temp, &target_paramlist, tp) { 799 if ((cmp = strcmp(pname, temp->name)) <= 0) 800 break; 801 prev = temp; 802 } 803 804 if (temp == NULL || cmp < 0) 805 SLIST_INSERT_AFTER(prev, param, tp); 806 else if (cmp > 0) 807 SLIST_INSERT_AFTER(temp, param, tp); 808 else { 809 syslog(LOG_ERR, "Target parameter %s exists", param->name); 810 free(param); 811 return (NULL); 812 } 813 814 return (param); 815} 816 817int 818target_delete_param(struct target_param *param) 819{ 820 SLIST_REMOVE(&target_paramlist, param, target_param, tp); 821 free(param); 822 823 return (0); 824} 825 826struct target_notify * 827target_first_notify(void) 828{ 829 return (SLIST_FIRST(&target_notifylist)); 830} 831 832struct target_notify * 833target_next_notify(struct target_notify *notify) 834{ 835 if (notify == NULL) 836 return (NULL); 837 838 return (SLIST_NEXT(notify, tn)); 839} 840 841struct target_notify * 842target_new_notify(char *nname) 843{ 844 int cmp; 845 struct target_notify *notify, *temp, *prev; 846 847 SLIST_FOREACH(notify, &target_notifylist, tn) 848 if (strcmp(nname, notify->name) == 0) 849 return (NULL); 850 851 if ((notify = (struct target_notify *)malloc(sizeof(*notify))) == NULL) 852 return (NULL); 853 854 memset(notify, 0, sizeof(*notify)); 855 strlcpy(notify->name, nname, sizeof(notify->name)); 856 857 if ((prev = SLIST_FIRST(&target_notifylist)) == NULL || 858 strcmp(nname, prev->name) < 0) { 859 SLIST_INSERT_HEAD(&target_notifylist, notify, tn); 860 return (notify); 861 } 862 863 SLIST_FOREACH(temp, &target_notifylist, tn) { 864 if ((cmp = strcmp(nname, temp->name)) <= 0) 865 break; 866 prev = temp; 867 } 868 869 if (temp == NULL || cmp < 0) 870 SLIST_INSERT_AFTER(prev, notify, tn); 871 else if (cmp > 0) 872 SLIST_INSERT_AFTER(temp, notify, tn); 873 else { 874 syslog(LOG_ERR, "Notification target %s exists", notify->name); 875 free(notify); 876 return (NULL); 877 } 878 879 return (notify); 880} 881 882int 883target_delete_notify(struct target_notify *notify) 884{ 885 SLIST_REMOVE(&target_notifylist, notify, target_notify, tn); 886 free(notify); 887 888 return (0); 889} 890 891void 892target_flush_all(void) 893{ 894 struct target_address *addrs; 895 struct target_param *param; 896 struct target_notify *notify; 897 898 while ((addrs = SLIST_FIRST(&target_addresslist)) != NULL) { 899 SLIST_REMOVE_HEAD(&target_addresslist, ta); 900 if (addrs->status == RowStatus_active) 901 close(addrs->socket); 902 free(addrs); 903 } 904 SLIST_INIT(&target_addresslist); 905 906 while ((param = SLIST_FIRST(&target_paramlist)) != NULL) { 907 SLIST_REMOVE_HEAD(&target_paramlist, tp); 908 free(param); 909 } 910 SLIST_INIT(&target_paramlist); 911 912 while ((notify = SLIST_FIRST(&target_notifylist)) != NULL) { 913 SLIST_REMOVE_HEAD(&target_notifylist, tn); 914 free(notify); 915 } 916 SLIST_INIT(&target_notifylist); 917} 918