1/* 2 * Copyright (c) 2001-2003 3 * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 4 * All rights reserved. 5 * 6 * Author: Harti Brandt <harti@freebsd.org> 7 * 8 * Copyright (c) 2010 The FreeBSD Foundation 9 * All rights reserved. 10 * 11 * Portions of this software were developed by Shteryana Sotirova Shopova 12 * under sponsorship from the FreeBSD Foundation. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions 16 * are met: 17 * 1. Redistributions of source code must retain the above copyright 18 * notice, this list of conditions and the following disclaimer. 19 * 2. Redistributions in binary form must reproduce the above copyright 20 * notice, this list of conditions and the following disclaimer in the 21 * documentation and/or other materials provided with the distribution. 22 * 23 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * $Begemot: bsnmp/snmpd/trap.c,v 1.9 2005/10/04 11:21:39 brandt_h Exp $ 36 * 37 * TrapSinkTable 38 */ 39#include <sys/types.h> 40#include <sys/queue.h> 41#include <sys/sysctl.h> 42#include <sys/un.h> 43#include <stdint.h> 44#include <stdio.h> 45#include <stdlib.h> 46#include <stdarg.h> 47#include <stdarg.h> 48#include <string.h> 49#include <ctype.h> 50#include <syslog.h> 51#include <unistd.h> 52#include <netinet/in.h> 53#include <arpa/inet.h> 54 55#include "snmpmod.h" 56#include "snmpd.h" 57#include "tree.h" 58#include "oid.h" 59 60struct trapsink_list trapsink_list = TAILQ_HEAD_INITIALIZER(trapsink_list); 61 62/* List of target addresses */ 63static struct target_addresslist target_addresslist = 64 SLIST_HEAD_INITIALIZER(target_addresslist); 65 66/* List of target parameters */ 67static struct target_paramlist target_paramlist = 68 SLIST_HEAD_INITIALIZER(target_paramlist); 69 70/* List of notification targets */ 71static struct target_notifylist target_notifylist = 72 SLIST_HEAD_INITIALIZER(target_notifylist); 73 74static const struct asn_oid oid_begemotTrapSinkTable = 75 OIDX_begemotTrapSinkTable; 76static const struct asn_oid oid_sysUpTime = OIDX_sysUpTime; 77static const struct asn_oid oid_snmpTrapOID = OIDX_snmpTrapOID; 78 79struct trapsink_dep { 80 struct snmp_dependency dep; 81 u_int set; 82 u_int status; 83 u_char comm[SNMP_COMMUNITY_MAXLEN + 1]; 84 u_int version; 85 u_int rb; 86 u_int rb_status; 87 u_int rb_version; 88 u_char rb_comm[SNMP_COMMUNITY_MAXLEN + 1]; 89}; 90enum { 91 TDEP_STATUS = 0x0001, 92 TDEP_COMM = 0x0002, 93 TDEP_VERSION = 0x0004, 94 95 TDEP_CREATE = 0x0001, 96 TDEP_MODIFY = 0x0002, 97 TDEP_DESTROY = 0x0004, 98}; 99 100static int 101trapsink_create(struct trapsink_dep *tdep) 102{ 103 struct trapsink *t; 104 struct sockaddr_in sa; 105 106 if ((t = malloc(sizeof(*t))) == NULL) 107 return (SNMP_ERR_RES_UNAVAIL); 108 109 t->index = tdep->dep.idx; 110 t->status = TRAPSINK_NOT_READY; 111 t->comm[0] = '\0'; 112 t->version = TRAPSINK_V2; 113 114 if ((t->socket = socket(PF_INET, SOCK_DGRAM, 0)) == -1) { 115 syslog(LOG_ERR, "socket(UDP): %m"); 116 free(t); 117 return (SNMP_ERR_RES_UNAVAIL); 118 } 119 (void)shutdown(t->socket, SHUT_RD); 120 memset(&sa, 0, sizeof(sa)); 121 sa.sin_len = sizeof(sa); 122 sa.sin_family = AF_INET; 123 sa.sin_addr.s_addr = htonl((t->index.subs[0] << 24) | 124 (t->index.subs[1] << 16) | (t->index.subs[2] << 8) | 125 (t->index.subs[3] << 0)); 126 sa.sin_port = htons(t->index.subs[4]); 127 128 if (connect(t->socket, (struct sockaddr *)&sa, sa.sin_len) == -1) { 129 syslog(LOG_ERR, "connect(%s,%u): %m", 130 inet_ntoa(sa.sin_addr), ntohs(sa.sin_port)); 131 (void)close(t->socket); 132 free(t); 133 return (SNMP_ERR_GENERR); 134 } 135 136 if (tdep->set & TDEP_VERSION) 137 t->version = tdep->version; 138 if (tdep->set & TDEP_COMM) 139 strcpy(t->comm, tdep->comm); 140 141 if (t->comm[0] != '\0') 142 t->status = TRAPSINK_NOT_IN_SERVICE; 143 144 /* look whether we should activate */ 145 if (tdep->status == 4) { 146 if (t->status == TRAPSINK_NOT_READY) { 147 if (t->socket != -1) 148 (void)close(t->socket); 149 free(t); 150 return (SNMP_ERR_INCONS_VALUE); 151 } 152 t->status = TRAPSINK_ACTIVE; 153 } 154 155 INSERT_OBJECT_OID(t, &trapsink_list); 156 157 tdep->rb |= TDEP_CREATE; 158 159 return (SNMP_ERR_NOERROR); 160} 161 162static void 163trapsink_free(struct trapsink *t) 164{ 165 TAILQ_REMOVE(&trapsink_list, t, link); 166 if (t->socket != -1) 167 (void)close(t->socket); 168 free(t); 169} 170 171static int 172trapsink_modify(struct trapsink *t, struct trapsink_dep *tdep) 173{ 174 tdep->rb_status = t->status; 175 tdep->rb_version = t->version; 176 strcpy(tdep->rb_comm, t->comm); 177 178 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 strlcpy(pdu->community, com, sizeof(pdu->community)); 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 strlcpy(pdu->community, com, sizeof(pdu->community)); 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 struct usm_user *usmuser; 468 469 memset(pdu, 0, sizeof(*pdu)); 470 471 pdu->version = SNMP_V3; 472 pdu->type = SNMP_PDU_TRAP2; 473 pdu->request_id = reqid_next(trap_reqid); 474 pdu->error_index = 0; 475 pdu->error_status = SNMP_ERR_NOERROR; 476 477 pdu->bindings[0].var = oid_sysUpTime; 478 pdu->bindings[0].var.subs[pdu->bindings[0].var.len++] = 0; 479 pdu->bindings[0].syntax = SNMP_SYNTAX_TIMETICKS; 480 pdu->bindings[0].v.uint32 = get_ticks() - start_tick; 481 482 pdu->bindings[1].var = oid_snmpTrapOID; 483 pdu->bindings[1].var.subs[pdu->bindings[1].var.len++] = 0; 484 pdu->bindings[1].syntax = SNMP_SYNTAX_OID; 485 pdu->bindings[1].v.oid = *trap_oid; 486 487 pdu->nbindings = 2; 488 489 update_snmpd_engine_time(); 490 491 memcpy(pdu->engine.engine_id, snmpd_engine.engine_id, 492 snmpd_engine.engine_len); 493 pdu->engine.engine_len = snmpd_engine.engine_len; 494 pdu->engine.engine_boots = snmpd_engine.engine_boots; 495 pdu->engine.engine_time = snmpd_engine.engine_time; 496 pdu->engine.max_msg_size = snmpd_engine.max_msg_size; 497 strlcpy(pdu->user.sec_name, target->secname, 498 sizeof(pdu->user.sec_name)); 499 pdu->security_model = target->sec_model; 500 501 pdu->context_engine_len = snmpd_engine.engine_len; 502 memcpy(pdu->context_engine, snmpd_engine.engine_id, 503 snmpd_engine.engine_len); 504 505 if (target->sec_model == SNMP_SECMODEL_USM && 506 target->sec_level != SNMP_noAuthNoPriv) { 507 usmuser = usm_find_user(pdu->engine.engine_id, 508 pdu->engine.engine_len, pdu->user.sec_name); 509 if (usmuser != NULL) { 510 pdu->user.auth_proto = usmuser->suser.auth_proto; 511 pdu->user.priv_proto = usmuser->suser.priv_proto; 512 memcpy(pdu->user.auth_key, usmuser->suser.auth_key, 513 sizeof(pdu->user.auth_key)); 514 memcpy(pdu->user.priv_key, usmuser->suser.priv_key, 515 sizeof(pdu->user.priv_key)); 516 } 517 snmp_pdu_init_secparams(pdu); 518 } 519} 520 521void 522snmp_send_trap(const struct asn_oid *trap_oid, ...) 523{ 524 struct snmp_pdu pdu; 525 struct trapsink *t; 526 const struct snmp_value *v; 527 struct target_notify *n; 528 struct target_address *ta; 529 struct target_param *tp; 530 531 va_list ap; 532 u_char *sndbuf; 533 char *tag; 534 size_t sndlen; 535 ssize_t len; 536 int32_t ip; 537 538 TAILQ_FOREACH(t, &trapsink_list, link) { 539 if (t->status != TRAPSINK_ACTIVE) 540 continue; 541 542 if (t->version == TRAPSINK_V1) 543 snmp_create_v1_trap(&pdu, t->comm, trap_oid); 544 else 545 snmp_create_v2_trap(&pdu, t->comm, trap_oid); 546 547 va_start(ap, trap_oid); 548 while ((v = va_arg(ap, const struct snmp_value *)) != NULL) 549 pdu.bindings[pdu.nbindings++] = *v; 550 va_end(ap); 551 552 if (snmp_pdu_auth_access(&pdu, &ip) != SNMP_CODE_OK) { 553 syslog(LOG_DEBUG, "send trap to %s failed: no access", 554 t->comm); 555 continue; 556 } 557 558 if ((sndbuf = buf_alloc(1)) == NULL) { 559 syslog(LOG_ERR, "trap send buffer: %m"); 560 return; 561 } 562 563 snmp_output(&pdu, sndbuf, &sndlen, "TRAP"); 564 565 if ((len = send(t->socket, sndbuf, sndlen, 0)) == -1) 566 syslog(LOG_ERR, "send: %m"); 567 else if ((size_t)len != sndlen) 568 syslog(LOG_ERR, "send: short write %zu/%zu", 569 sndlen, (size_t)len); 570 571 free(sndbuf); 572 } 573 574 SLIST_FOREACH(n, &target_notifylist, tn) { 575 if (n->status != RowStatus_active || n->taglist[0] == '\0') 576 continue; 577 578 SLIST_FOREACH(ta, &target_addresslist, ta) 579 if ((tag = strstr(ta->taglist, n->taglist)) != NULL && 580 (tag[strlen(n->taglist)] == ' ' || 581 tag[strlen(n->taglist)] == '\0' || 582 tag[strlen(n->taglist)] == '\t' || 583 tag[strlen(n->taglist)] == '\r' || 584 tag[strlen(n->taglist)] == '\n') && 585 ta->status == RowStatus_active) 586 break; 587 if (ta == NULL) 588 continue; 589 590 SLIST_FOREACH(tp, &target_paramlist, tp) 591 if (strcmp(tp->name, ta->paramname) == 0 && 592 tp->status == 1) 593 break; 594 if (tp == NULL) 595 continue; 596 597 switch (tp->mpmodel) { 598 case SNMP_MPM_SNMP_V1: 599 snmp_create_v1_trap(&pdu, tp->secname, trap_oid); 600 break; 601 602 case SNMP_MPM_SNMP_V2c: 603 snmp_create_v2_trap(&pdu, tp->secname, trap_oid); 604 break; 605 606 case SNMP_MPM_SNMP_V3: 607 snmp_create_v3_trap(&pdu, tp, trap_oid); 608 break; 609 610 default: 611 continue; 612 } 613 614 va_start(ap, trap_oid); 615 while ((v = va_arg(ap, const struct snmp_value *)) != NULL) 616 pdu.bindings[pdu.nbindings++] = *v; 617 va_end(ap); 618 619 if (snmp_pdu_auth_access(&pdu, &ip) != SNMP_CODE_OK) { 620 syslog(LOG_DEBUG, "send trap to %s failed: no access", 621 t->comm); 622 continue; 623 } 624 625 if ((sndbuf = buf_alloc(1)) == NULL) { 626 syslog(LOG_ERR, "trap send buffer: %m"); 627 return; 628 } 629 630 snmp_output(&pdu, sndbuf, &sndlen, "TRAP"); 631 632 if ((len = send(ta->socket, sndbuf, sndlen, 0)) == -1) 633 syslog(LOG_ERR, "send: %m"); 634 else if ((size_t)len != sndlen) 635 syslog(LOG_ERR, "send: short write %zu/%zu", 636 sndlen, (size_t)len); 637 638 free(sndbuf); 639 } 640} 641 642/* 643 * RFC 3413 SNMP Management Target MIB 644 */ 645struct snmpd_target_stats * 646bsnmpd_get_target_stats(void) 647{ 648 return (&snmpd_target_stats); 649} 650 651struct target_address * 652target_first_address(void) 653{ 654 return (SLIST_FIRST(&target_addresslist)); 655} 656 657struct target_address * 658target_next_address(struct target_address *addrs) 659{ 660 if (addrs == NULL) 661 return (NULL); 662 663 return (SLIST_NEXT(addrs, ta)); 664} 665 666struct target_address * 667target_new_address(char *aname) 668{ 669 int cmp; 670 struct target_address *addrs, *temp, *prev; 671 672 SLIST_FOREACH(addrs, &target_addresslist, ta) 673 if (strcmp(aname, addrs->name) == 0) 674 return (NULL); 675 676 if ((addrs = (struct target_address *)malloc(sizeof(*addrs))) == NULL) 677 return (NULL); 678 679 memset(addrs, 0, sizeof(*addrs)); 680 strlcpy(addrs->name, aname, sizeof(addrs->name)); 681 addrs->timeout = 150; 682 addrs->retry = 3; /* XXX */ 683 684 if ((prev = SLIST_FIRST(&target_addresslist)) == NULL || 685 strcmp(aname, prev->name) < 0) { 686 SLIST_INSERT_HEAD(&target_addresslist, addrs, ta); 687 return (addrs); 688 } 689 690 SLIST_FOREACH(temp, &target_addresslist, ta) { 691 if ((cmp = strcmp(aname, temp->name)) <= 0) 692 break; 693 prev = temp; 694 } 695 696 if (temp == NULL || cmp < 0) 697 SLIST_INSERT_AFTER(prev, addrs, ta); 698 else if (cmp > 0) 699 SLIST_INSERT_AFTER(temp, addrs, ta); 700 else { 701 syslog(LOG_ERR, "Target address %s exists", addrs->name); 702 free(addrs); 703 return (NULL); 704 } 705 706 return (addrs); 707} 708 709int 710target_activate_address(struct target_address *addrs) 711{ 712 struct sockaddr_in sa; 713 714 if ((addrs->socket = socket(PF_INET, SOCK_DGRAM, 0)) == -1) { 715 syslog(LOG_ERR, "socket(UDP): %m"); 716 return (SNMP_ERR_RES_UNAVAIL); 717 } 718 719 (void)shutdown(addrs->socket, SHUT_RD); 720 memset(&sa, 0, sizeof(sa)); 721 sa.sin_len = sizeof(sa); 722 sa.sin_family = AF_INET; 723 724 sa.sin_addr.s_addr = htonl((addrs->address[0] << 24) | 725 (addrs->address[1] << 16) | (addrs->address[2] << 8) | 726 (addrs->address[3] << 0)); 727 sa.sin_port = htons(addrs->address[4]) << 8 | 728 htons(addrs->address[5]) << 0; 729 730 if (connect(addrs->socket, (struct sockaddr *)&sa, sa.sin_len) == -1) { 731 syslog(LOG_ERR, "connect(%s,%u): %m", 732 inet_ntoa(sa.sin_addr), ntohs(sa.sin_port)); 733 (void)close(addrs->socket); 734 return (SNMP_ERR_GENERR); 735 } 736 737 addrs->status = RowStatus_active; 738 739 return (SNMP_ERR_NOERROR); 740} 741 742int 743target_delete_address(struct target_address *addrs) 744{ 745 SLIST_REMOVE(&target_addresslist, addrs, target_address, ta); 746 if (addrs->status == RowStatus_active) 747 close(addrs->socket); 748 free(addrs); 749 750 return (0); 751} 752 753struct target_param * 754target_first_param(void) 755{ 756 return (SLIST_FIRST(&target_paramlist)); 757} 758 759struct target_param * 760target_next_param(struct target_param *param) 761{ 762 if (param == NULL) 763 return (NULL); 764 765 return (SLIST_NEXT(param, tp)); 766} 767 768struct target_param * 769target_new_param(char *pname) 770{ 771 int cmp; 772 struct target_param *param, *temp, *prev; 773 774 SLIST_FOREACH(param, &target_paramlist, tp) 775 if (strcmp(pname, param->name) == 0) 776 return (NULL); 777 778 if ((param = (struct target_param *)malloc(sizeof(*param))) == NULL) 779 return (NULL); 780 781 memset(param, 0, sizeof(*param)); 782 strlcpy(param->name, pname, sizeof(param->name)); 783 784 if ((prev = SLIST_FIRST(&target_paramlist)) == NULL || 785 strcmp(pname, prev->name) < 0) { 786 SLIST_INSERT_HEAD(&target_paramlist, param, tp); 787 return (param); 788 } 789 790 SLIST_FOREACH(temp, &target_paramlist, tp) { 791 if ((cmp = strcmp(pname, temp->name)) <= 0) 792 break; 793 prev = temp; 794 } 795 796 if (temp == NULL || cmp < 0) 797 SLIST_INSERT_AFTER(prev, param, tp); 798 else if (cmp > 0) 799 SLIST_INSERT_AFTER(temp, param, tp); 800 else { 801 syslog(LOG_ERR, "Target parameter %s exists", param->name); 802 free(param); 803 return (NULL); 804 } 805 806 return (param); 807} 808 809int 810target_delete_param(struct target_param *param) 811{ 812 SLIST_REMOVE(&target_paramlist, param, target_param, tp); 813 free(param); 814 815 return (0); 816} 817 818struct target_notify * 819target_first_notify(void) 820{ 821 return (SLIST_FIRST(&target_notifylist)); 822} 823 824struct target_notify * 825target_next_notify(struct target_notify *notify) 826{ 827 if (notify == NULL) 828 return (NULL); 829 830 return (SLIST_NEXT(notify, tn)); 831} 832 833struct target_notify * 834target_new_notify(char *nname) 835{ 836 int cmp; 837 struct target_notify *notify, *temp, *prev; 838 839 SLIST_FOREACH(notify, &target_notifylist, tn) 840 if (strcmp(nname, notify->name) == 0) 841 return (NULL); 842 843 if ((notify = (struct target_notify *)malloc(sizeof(*notify))) == NULL) 844 return (NULL); 845 846 memset(notify, 0, sizeof(*notify)); 847 strlcpy(notify->name, nname, sizeof(notify->name)); 848 849 if ((prev = SLIST_FIRST(&target_notifylist)) == NULL || 850 strcmp(nname, prev->name) < 0) { 851 SLIST_INSERT_HEAD(&target_notifylist, notify, tn); 852 return (notify); 853 } 854 855 SLIST_FOREACH(temp, &target_notifylist, tn) { 856 if ((cmp = strcmp(nname, temp->name)) <= 0) 857 break; 858 prev = temp; 859 } 860 861 if (temp == NULL || cmp < 0) 862 SLIST_INSERT_AFTER(prev, notify, tn); 863 else if (cmp > 0) 864 SLIST_INSERT_AFTER(temp, notify, tn); 865 else { 866 syslog(LOG_ERR, "Notification target %s exists", notify->name); 867 free(notify); 868 return (NULL); 869 } 870 871 return (notify); 872} 873 874int 875target_delete_notify(struct target_notify *notify) 876{ 877 SLIST_REMOVE(&target_notifylist, notify, target_notify, tn); 878 free(notify); 879 880 return (0); 881} 882 883void 884target_flush_all(void) 885{ 886 struct target_address *addrs; 887 struct target_param *param; 888 struct target_notify *notify; 889 890 while ((addrs = SLIST_FIRST(&target_addresslist)) != NULL) { 891 SLIST_REMOVE_HEAD(&target_addresslist, ta); 892 if (addrs->status == RowStatus_active) 893 close(addrs->socket); 894 free(addrs); 895 } 896 SLIST_INIT(&target_addresslist); 897 898 while ((param = SLIST_FIRST(&target_paramlist)) != NULL) { 899 SLIST_REMOVE_HEAD(&target_paramlist, tp); 900 free(param); 901 } 902 SLIST_INIT(&target_paramlist); 903 904 while ((notify = SLIST_FIRST(&target_notifylist)) != NULL) { 905 SLIST_REMOVE_HEAD(&target_notifylist, tn); 906 free(notify); 907 } 908 SLIST_INIT(&target_notifylist); 909} 910