/contrib/bsnmp/snmpd/trap.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 917 lines · 717 code · 152 blank · 48 comment · 196 complexity · 39144a5d0fe1c86d7ed609ab7fcd4fb9 MD5 · raw file

  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. #include "snmpmod.h"
  55. #include "snmpd.h"
  56. #include "tree.h"
  57. #include "oid.h"
  58. struct trapsink_list trapsink_list = TAILQ_HEAD_INITIALIZER(trapsink_list);
  59. /* List of target addresses */
  60. struct target_addresslist target_addresslist =
  61. SLIST_HEAD_INITIALIZER(target_addresslist);
  62. /* List of target parameters */
  63. struct target_paramlist target_paramlist =
  64. SLIST_HEAD_INITIALIZER(target_paramlist);
  65. /* List of notification targets */
  66. struct target_notifylist target_notifylist =
  67. SLIST_HEAD_INITIALIZER(target_notifylist);
  68. static const struct asn_oid oid_begemotTrapSinkTable =
  69. OIDX_begemotTrapSinkTable;
  70. static const struct asn_oid oid_sysUpTime = OIDX_sysUpTime;
  71. static const struct asn_oid oid_snmpTrapOID = OIDX_snmpTrapOID;
  72. struct trapsink_dep {
  73. struct snmp_dependency dep;
  74. u_int set;
  75. u_int status;
  76. u_char comm[SNMP_COMMUNITY_MAXLEN + 1];
  77. u_int version;
  78. u_int rb;
  79. u_int rb_status;
  80. u_int rb_version;
  81. u_char rb_comm[SNMP_COMMUNITY_MAXLEN + 1];
  82. };
  83. enum {
  84. TDEP_STATUS = 0x0001,
  85. TDEP_COMM = 0x0002,
  86. TDEP_VERSION = 0x0004,
  87. TDEP_CREATE = 0x0001,
  88. TDEP_MODIFY = 0x0002,
  89. TDEP_DESTROY = 0x0004,
  90. };
  91. static int
  92. trapsink_create(struct trapsink_dep *tdep)
  93. {
  94. struct trapsink *t;
  95. struct sockaddr_in sa;
  96. if ((t = malloc(sizeof(*t))) == NULL)
  97. return (SNMP_ERR_RES_UNAVAIL);
  98. t->index = tdep->dep.idx;
  99. t->status = TRAPSINK_NOT_READY;
  100. t->comm[0] = '\0';
  101. t->version = TRAPSINK_V2;
  102. if ((t->socket = socket(PF_INET, SOCK_DGRAM, 0)) == -1) {
  103. syslog(LOG_ERR, "socket(UDP): %m");
  104. free(t);
  105. return (SNMP_ERR_RES_UNAVAIL);
  106. }
  107. (void)shutdown(t->socket, SHUT_RD);
  108. memset(&sa, 0, sizeof(sa));
  109. sa.sin_len = sizeof(sa);
  110. sa.sin_family = AF_INET;
  111. sa.sin_addr.s_addr = htonl((t->index.subs[0] << 24) |
  112. (t->index.subs[1] << 16) | (t->index.subs[2] << 8) |
  113. (t->index.subs[3] << 0));
  114. sa.sin_port = htons(t->index.subs[4]);
  115. if (connect(t->socket, (struct sockaddr *)&sa, sa.sin_len) == -1) {
  116. syslog(LOG_ERR, "connect(%s,%u): %m",
  117. inet_ntoa(sa.sin_addr), ntohs(sa.sin_port));
  118. (void)close(t->socket);
  119. free(t);
  120. return (SNMP_ERR_GENERR);
  121. }
  122. if (tdep->set & TDEP_VERSION)
  123. t->version = tdep->version;
  124. if (tdep->set & TDEP_COMM)
  125. strcpy(t->comm, tdep->comm);
  126. if (t->comm[0] != '\0')
  127. t->status = TRAPSINK_NOT_IN_SERVICE;
  128. /* look whether we should activate */
  129. if (tdep->status == 4) {
  130. if (t->status == TRAPSINK_NOT_READY) {
  131. if (t->socket != -1)
  132. (void)close(t->socket);
  133. free(t);
  134. return (SNMP_ERR_INCONS_VALUE);
  135. }
  136. t->status = TRAPSINK_ACTIVE;
  137. }
  138. INSERT_OBJECT_OID(t, &trapsink_list);
  139. tdep->rb |= TDEP_CREATE;
  140. return (SNMP_ERR_NOERROR);
  141. }
  142. static void
  143. trapsink_free(struct trapsink *t)
  144. {
  145. TAILQ_REMOVE(&trapsink_list, t, link);
  146. if (t->socket != -1)
  147. (void)close(t->socket);
  148. free(t);
  149. }
  150. static int
  151. trapsink_modify(struct trapsink *t, struct trapsink_dep *tdep)
  152. {
  153. tdep->rb_status = t->status;
  154. tdep->rb_version = t->version;
  155. strcpy(tdep->rb_comm, t->comm);
  156. if (tdep->set & TDEP_STATUS) {
  157. /* if we are active and should move to not_in_service do
  158. * this first */
  159. if (tdep->status == 2 && tdep->rb_status == TRAPSINK_ACTIVE) {
  160. t->status = TRAPSINK_NOT_IN_SERVICE;
  161. tdep->rb |= TDEP_MODIFY;
  162. }
  163. }
  164. if (tdep->set & TDEP_VERSION)
  165. t->version = tdep->version;
  166. if (tdep->set & TDEP_COMM)
  167. strcpy(t->comm, tdep->comm);
  168. if (tdep->set & TDEP_STATUS) {
  169. /* if we were inactive and should go active - do this now */
  170. if (tdep->status == 1 && tdep->rb_status != TRAPSINK_ACTIVE) {
  171. if (t->comm[0] == '\0') {
  172. t->status = tdep->rb_status;
  173. t->version = tdep->rb_version;
  174. strcpy(t->comm, tdep->rb_comm);
  175. return (SNMP_ERR_INCONS_VALUE);
  176. }
  177. t->status = TRAPSINK_ACTIVE;
  178. tdep->rb |= TDEP_MODIFY;
  179. }
  180. }
  181. return (SNMP_ERR_NOERROR);
  182. }
  183. static int
  184. trapsink_unmodify(struct trapsink *t, struct trapsink_dep *tdep)
  185. {
  186. if (tdep->set & TDEP_STATUS)
  187. t->status = tdep->rb_status;
  188. if (tdep->set & TDEP_VERSION)
  189. t->version = tdep->rb_version;
  190. if (tdep->set & TDEP_COMM)
  191. strcpy(t->comm, tdep->rb_comm);
  192. return (SNMP_ERR_NOERROR);
  193. }
  194. static int
  195. trapsink_destroy(struct snmp_context *ctx __unused, struct trapsink *t,
  196. struct trapsink_dep *tdep)
  197. {
  198. t->status = TRAPSINK_DESTROY;
  199. tdep->rb_status = t->status;
  200. tdep->rb |= TDEP_DESTROY;
  201. return (SNMP_ERR_NOERROR);
  202. }
  203. static int
  204. trapsink_undestroy(struct trapsink *t, struct trapsink_dep *tdep)
  205. {
  206. t->status = tdep->rb_status;
  207. return (SNMP_ERR_NOERROR);
  208. }
  209. static int
  210. trapsink_dep(struct snmp_context *ctx, struct snmp_dependency *dep,
  211. enum snmp_depop op)
  212. {
  213. struct trapsink_dep *tdep = (struct trapsink_dep *)dep;
  214. struct trapsink *t;
  215. t = FIND_OBJECT_OID(&trapsink_list, &dep->idx, 0);
  216. switch (op) {
  217. case SNMP_DEPOP_COMMIT:
  218. if (tdep->set & TDEP_STATUS) {
  219. switch (tdep->status) {
  220. case 1:
  221. case 2:
  222. if (t == NULL)
  223. return (SNMP_ERR_INCONS_VALUE);
  224. return (trapsink_modify(t, tdep));
  225. case 4:
  226. case 5:
  227. if (t != NULL)
  228. return (SNMP_ERR_INCONS_VALUE);
  229. return (trapsink_create(tdep));
  230. case 6:
  231. if (t == NULL)
  232. return (SNMP_ERR_NOERROR);
  233. return (trapsink_destroy(ctx, t, tdep));
  234. }
  235. } else if (tdep->set != 0)
  236. return (trapsink_modify(t, tdep));
  237. return (SNMP_ERR_NOERROR);
  238. case SNMP_DEPOP_ROLLBACK:
  239. if (tdep->rb & TDEP_CREATE) {
  240. trapsink_free(t);
  241. return (SNMP_ERR_NOERROR);
  242. }
  243. if (tdep->rb & TDEP_MODIFY)
  244. return (trapsink_unmodify(t, tdep));
  245. if(tdep->rb & TDEP_DESTROY)
  246. return (trapsink_undestroy(t, tdep));
  247. return (SNMP_ERR_NOERROR);
  248. case SNMP_DEPOP_FINISH:
  249. if ((tdep->rb & TDEP_DESTROY) && t != NULL &&
  250. ctx->code == SNMP_RET_OK)
  251. trapsink_free(t);
  252. return (SNMP_ERR_NOERROR);
  253. }
  254. abort();
  255. }
  256. int
  257. op_trapsink(struct snmp_context *ctx, struct snmp_value *value,
  258. u_int sub, u_int iidx, enum snmp_op op)
  259. {
  260. struct trapsink *t;
  261. u_char ipa[4];
  262. int32_t port;
  263. struct asn_oid idx;
  264. struct trapsink_dep *tdep;
  265. u_char *p;
  266. t = NULL; /* gcc */
  267. switch (op) {
  268. case SNMP_OP_GETNEXT:
  269. if ((t = NEXT_OBJECT_OID(&trapsink_list, &value->var, sub)) == NULL)
  270. return (SNMP_ERR_NOSUCHNAME);
  271. index_append(&value->var, sub, &t->index);
  272. break;
  273. case SNMP_OP_GET:
  274. if ((t = FIND_OBJECT_OID(&trapsink_list, &value->var, sub)) == NULL)
  275. return (SNMP_ERR_NOSUCHNAME);
  276. break;
  277. case SNMP_OP_SET:
  278. if (index_decode(&value->var, sub, iidx, ipa, &port) ||
  279. port == 0 || port > 65535)
  280. return (SNMP_ERR_NO_CREATION);
  281. t = FIND_OBJECT_OID(&trapsink_list, &value->var, sub);
  282. asn_slice_oid(&idx, &value->var, sub, value->var.len);
  283. tdep = (struct trapsink_dep *)snmp_dep_lookup(ctx,
  284. &oid_begemotTrapSinkTable, &idx,
  285. sizeof(*tdep), trapsink_dep);
  286. if (tdep == NULL)
  287. return (SNMP_ERR_RES_UNAVAIL);
  288. switch (value->var.subs[sub - 1]) {
  289. case LEAF_begemotTrapSinkStatus:
  290. if (tdep->set & TDEP_STATUS)
  291. return (SNMP_ERR_INCONS_VALUE);
  292. switch (value->v.integer) {
  293. case 1:
  294. case 2:
  295. if (t == NULL)
  296. return (SNMP_ERR_INCONS_VALUE);
  297. break;
  298. case 4:
  299. case 5:
  300. if (t != NULL)
  301. return (SNMP_ERR_INCONS_VALUE);
  302. break;
  303. case 6:
  304. break;
  305. default:
  306. return (SNMP_ERR_WRONG_VALUE);
  307. }
  308. tdep->status = value->v.integer;
  309. tdep->set |= TDEP_STATUS;
  310. return (SNMP_ERR_NOERROR);
  311. case LEAF_begemotTrapSinkComm:
  312. if (tdep->set & TDEP_COMM)
  313. return (SNMP_ERR_INCONS_VALUE);
  314. if (value->v.octetstring.len == 0 ||
  315. value->v.octetstring.len > SNMP_COMMUNITY_MAXLEN)
  316. return (SNMP_ERR_WRONG_VALUE);
  317. for (p = value->v.octetstring.octets;
  318. p < value->v.octetstring.octets + value->v.octetstring.len;
  319. p++) {
  320. if (!isascii(*p) || !isprint(*p))
  321. return (SNMP_ERR_WRONG_VALUE);
  322. }
  323. tdep->set |= TDEP_COMM;
  324. strncpy(tdep->comm, value->v.octetstring.octets,
  325. value->v.octetstring.len);
  326. tdep->comm[value->v.octetstring.len] = '\0';
  327. return (SNMP_ERR_NOERROR);
  328. case LEAF_begemotTrapSinkVersion:
  329. if (tdep->set & TDEP_VERSION)
  330. return (SNMP_ERR_INCONS_VALUE);
  331. if (value->v.integer != TRAPSINK_V1 &&
  332. value->v.integer != TRAPSINK_V2)
  333. return (SNMP_ERR_WRONG_VALUE);
  334. tdep->version = value->v.integer;
  335. tdep->set |= TDEP_VERSION;
  336. return (SNMP_ERR_NOERROR);
  337. }
  338. if (t == NULL)
  339. return (SNMP_ERR_INCONS_NAME);
  340. else
  341. return (SNMP_ERR_NOT_WRITEABLE);
  342. case SNMP_OP_ROLLBACK:
  343. case SNMP_OP_COMMIT:
  344. return (SNMP_ERR_NOERROR);
  345. }
  346. switch (value->var.subs[sub - 1]) {
  347. case LEAF_begemotTrapSinkStatus:
  348. value->v.integer = t->status;
  349. break;
  350. case LEAF_begemotTrapSinkComm:
  351. return (string_get(value, t->comm, -1));
  352. case LEAF_begemotTrapSinkVersion:
  353. value->v.integer = t->version;
  354. break;
  355. }
  356. return (SNMP_ERR_NOERROR);
  357. }
  358. static void
  359. snmp_create_v1_trap(struct snmp_pdu *pdu, char *com,
  360. const struct asn_oid *trap_oid)
  361. {
  362. memset(pdu, 0, sizeof(*pdu));
  363. strcpy(pdu->community, com);
  364. pdu->version = SNMP_V1;
  365. pdu->type = SNMP_PDU_TRAP;
  366. pdu->enterprise = systemg.object_id;
  367. memcpy(pdu->agent_addr, snmpd.trap1addr, 4);
  368. pdu->generic_trap = trap_oid->subs[trap_oid->len - 1] - 1;
  369. pdu->specific_trap = 0;
  370. pdu->time_stamp = get_ticks() - start_tick;
  371. pdu->nbindings = 0;
  372. }
  373. static void
  374. snmp_create_v2_trap(struct snmp_pdu *pdu, char *com,
  375. const struct asn_oid *trap_oid)
  376. {
  377. memset(pdu, 0, sizeof(*pdu));
  378. strcpy(pdu->community, com);
  379. pdu->version = SNMP_V2c;
  380. pdu->type = SNMP_PDU_TRAP2;
  381. pdu->request_id = reqid_next(trap_reqid);
  382. pdu->error_index = 0;
  383. pdu->error_status = SNMP_ERR_NOERROR;
  384. pdu->bindings[0].var = oid_sysUpTime;
  385. pdu->bindings[0].var.subs[pdu->bindings[0].var.len++] = 0;
  386. pdu->bindings[0].syntax = SNMP_SYNTAX_TIMETICKS;
  387. pdu->bindings[0].v.uint32 = get_ticks() - start_tick;
  388. pdu->bindings[1].var = oid_snmpTrapOID;
  389. pdu->bindings[1].var.subs[pdu->bindings[1].var.len++] = 0;
  390. pdu->bindings[1].syntax = SNMP_SYNTAX_OID;
  391. pdu->bindings[1].v.oid = *trap_oid;
  392. pdu->nbindings = 2;
  393. }
  394. static void
  395. snmp_create_v3_trap(struct snmp_pdu *pdu, struct target_param *target,
  396. const struct asn_oid *trap_oid)
  397. {
  398. uint64_t etime;
  399. struct usm_user *usmuser;
  400. memset(pdu, 0, sizeof(*pdu));
  401. pdu->version = SNMP_V3;
  402. pdu->type = SNMP_PDU_TRAP2;
  403. pdu->request_id = reqid_next(trap_reqid);
  404. pdu->error_index = 0;
  405. pdu->error_status = SNMP_ERR_NOERROR;
  406. pdu->bindings[0].var = oid_sysUpTime;
  407. pdu->bindings[0].var.subs[pdu->bindings[0].var.len++] = 0;
  408. pdu->bindings[0].syntax = SNMP_SYNTAX_TIMETICKS;
  409. pdu->bindings[0].v.uint32 = get_ticks() - start_tick;
  410. pdu->bindings[1].var = oid_snmpTrapOID;
  411. pdu->bindings[1].var.subs[pdu->bindings[1].var.len++] = 0;
  412. pdu->bindings[1].syntax = SNMP_SYNTAX_OID;
  413. pdu->bindings[1].v.oid = *trap_oid;
  414. pdu->nbindings = 2;
  415. etime = (get_ticks() - start_tick) / 100ULL;
  416. if (etime < INT32_MAX)
  417. snmpd_engine.engine_time = etime;
  418. else {
  419. start_tick = get_ticks();
  420. set_snmpd_engine();
  421. snmpd_engine.engine_time = start_tick;
  422. }
  423. memcpy(pdu->engine.engine_id, snmpd_engine.engine_id,
  424. snmpd_engine.engine_len);
  425. pdu->engine.engine_len = snmpd_engine.engine_len;
  426. pdu->engine.engine_boots = snmpd_engine.engine_boots;
  427. pdu->engine.engine_time = snmpd_engine.engine_time;
  428. pdu->engine.max_msg_size = snmpd_engine.max_msg_size;
  429. strlcpy(pdu->user.sec_name, target->secname,
  430. sizeof(pdu->user.sec_name));
  431. pdu->security_model = target->sec_model;
  432. pdu->context_engine_len = snmpd_engine.engine_len;
  433. memcpy(pdu->context_engine, snmpd_engine.engine_id,
  434. snmpd_engine.engine_len);
  435. if (target->sec_model == SNMP_SECMODEL_USM &&
  436. target->sec_level != SNMP_noAuthNoPriv) {
  437. usmuser = usm_find_user(pdu->engine.engine_id,
  438. pdu->engine.engine_len, pdu->user.sec_name);
  439. if (usmuser != NULL) {
  440. pdu->user.auth_proto = usmuser->suser.auth_proto;
  441. pdu->user.priv_proto = usmuser->suser.priv_proto;
  442. memcpy(pdu->user.auth_key, usmuser->suser.auth_key,
  443. sizeof(pdu->user.auth_key));
  444. memcpy(pdu->user.priv_key, usmuser->suser.priv_key,
  445. sizeof(pdu->user.priv_key));
  446. }
  447. snmp_pdu_init_secparams(pdu);
  448. }
  449. }
  450. void
  451. snmp_send_trap(const struct asn_oid *trap_oid, ...)
  452. {
  453. struct snmp_pdu pdu;
  454. struct trapsink *t;
  455. const struct snmp_value *v;
  456. struct target_notify *n;
  457. struct target_address *ta;
  458. struct target_param *tp;
  459. va_list ap;
  460. u_char *sndbuf;
  461. char *tag;
  462. size_t sndlen;
  463. ssize_t len;
  464. int32_t ip;
  465. TAILQ_FOREACH(t, &trapsink_list, link) {
  466. if (t->status != TRAPSINK_ACTIVE)
  467. continue;
  468. if (t->version == TRAPSINK_V1)
  469. snmp_create_v1_trap(&pdu, t->comm, trap_oid);
  470. else
  471. snmp_create_v2_trap(&pdu, t->comm, trap_oid);
  472. va_start(ap, trap_oid);
  473. while ((v = va_arg(ap, const struct snmp_value *)) != NULL)
  474. pdu.bindings[pdu.nbindings++] = *v;
  475. va_end(ap);
  476. if (snmp_pdu_auth_access(&pdu, &ip) != SNMP_CODE_OK) {
  477. syslog(LOG_DEBUG, "send trap to %s failed: no access",
  478. t->comm);
  479. continue;
  480. }
  481. if ((sndbuf = buf_alloc(1)) == NULL) {
  482. syslog(LOG_ERR, "trap send buffer: %m");
  483. return;
  484. }
  485. snmp_output(&pdu, sndbuf, &sndlen, "TRAP");
  486. if ((len = send(t->socket, sndbuf, sndlen, 0)) == -1)
  487. syslog(LOG_ERR, "send: %m");
  488. else if ((size_t)len != sndlen)
  489. syslog(LOG_ERR, "send: short write %zu/%zu",
  490. sndlen, (size_t)len);
  491. free(sndbuf);
  492. }
  493. SLIST_FOREACH(n, &target_notifylist, tn) {
  494. if (n->status != RowStatus_active || n->taglist[0] == '\0')
  495. continue;
  496. SLIST_FOREACH(ta, &target_addresslist, ta)
  497. if ((tag = strstr(ta->taglist, n->taglist)) != NULL &&
  498. (tag[strlen(n->taglist)] == ' ' ||
  499. tag[strlen(n->taglist)] == '\0' ||
  500. tag[strlen(n->taglist)] == '\t' ||
  501. tag[strlen(n->taglist)] == '\r' ||
  502. tag[strlen(n->taglist)] == '\n') &&
  503. ta->status == RowStatus_active)
  504. break;
  505. if (ta == NULL)
  506. continue;
  507. SLIST_FOREACH(tp, &target_paramlist, tp)
  508. if (strcmp(tp->name, ta->paramname) == 0 &&
  509. tp->status == 1)
  510. break;
  511. if (tp == NULL)
  512. continue;
  513. switch (tp->mpmodel) {
  514. case SNMP_MPM_SNMP_V1:
  515. snmp_create_v1_trap(&pdu, tp->secname, trap_oid);
  516. break;
  517. case SNMP_MPM_SNMP_V2c:
  518. snmp_create_v2_trap(&pdu, tp->secname, trap_oid);
  519. break;
  520. case SNMP_MPM_SNMP_V3:
  521. snmp_create_v3_trap(&pdu, tp, trap_oid);
  522. break;
  523. default:
  524. continue;
  525. }
  526. va_start(ap, trap_oid);
  527. while ((v = va_arg(ap, const struct snmp_value *)) != NULL)
  528. pdu.bindings[pdu.nbindings++] = *v;
  529. va_end(ap);
  530. if (snmp_pdu_auth_access(&pdu, &ip) != SNMP_CODE_OK) {
  531. syslog(LOG_DEBUG, "send trap to %s failed: no access",
  532. t->comm);
  533. continue;
  534. }
  535. if ((sndbuf = buf_alloc(1)) == NULL) {
  536. syslog(LOG_ERR, "trap send buffer: %m");
  537. return;
  538. }
  539. snmp_output(&pdu, sndbuf, &sndlen, "TRAP");
  540. if ((len = send(ta->socket, sndbuf, sndlen, 0)) == -1)
  541. syslog(LOG_ERR, "send: %m");
  542. else if ((size_t)len != sndlen)
  543. syslog(LOG_ERR, "send: short write %zu/%zu",
  544. sndlen, (size_t)len);
  545. free(sndbuf);
  546. }
  547. }
  548. /*
  549. * RFC 3413 SNMP Management Target MIB
  550. */
  551. struct snmpd_target_stats *
  552. bsnmpd_get_target_stats(void)
  553. {
  554. return (&snmpd_target_stats);
  555. }
  556. struct target_address *
  557. target_first_address(void)
  558. {
  559. return (SLIST_FIRST(&target_addresslist));
  560. }
  561. struct target_address *
  562. target_next_address(struct target_address *addrs)
  563. {
  564. if (addrs == NULL)
  565. return (NULL);
  566. return (SLIST_NEXT(addrs, ta));
  567. }
  568. struct target_address *
  569. target_new_address(char *aname)
  570. {
  571. int cmp;
  572. struct target_address *addrs, *temp, *prev;
  573. SLIST_FOREACH(addrs, &target_addresslist, ta)
  574. if (strcmp(aname, addrs->name) == 0)
  575. return (NULL);
  576. if ((addrs = (struct target_address *)malloc(sizeof(*addrs))) == NULL)
  577. return (NULL);
  578. memset(addrs, 0, sizeof(*addrs));
  579. strlcpy(addrs->name, aname, sizeof(addrs->name));
  580. addrs->timeout = 150;
  581. addrs->retry = 3; /* XXX */
  582. if ((prev = SLIST_FIRST(&target_addresslist)) == NULL ||
  583. strcmp(aname, prev->name) < 0) {
  584. SLIST_INSERT_HEAD(&target_addresslist, addrs, ta);
  585. return (addrs);
  586. }
  587. SLIST_FOREACH(temp, &target_addresslist, ta) {
  588. if ((cmp = strcmp(aname, temp->name)) <= 0)
  589. break;
  590. prev = temp;
  591. }
  592. if (temp == NULL || cmp < 0)
  593. SLIST_INSERT_AFTER(prev, addrs, ta);
  594. else if (cmp > 0)
  595. SLIST_INSERT_AFTER(temp, addrs, ta);
  596. else {
  597. syslog(LOG_ERR, "Target address %s exists", addrs->name);
  598. free(addrs);
  599. return (NULL);
  600. }
  601. return (addrs);
  602. }
  603. int
  604. target_activate_address(struct target_address *addrs)
  605. {
  606. struct sockaddr_in sa;
  607. if ((addrs->socket = socket(PF_INET, SOCK_DGRAM, 0)) == -1) {
  608. syslog(LOG_ERR, "socket(UDP): %m");
  609. return (SNMP_ERR_RES_UNAVAIL);
  610. }
  611. (void)shutdown(addrs->socket, SHUT_RD);
  612. memset(&sa, 0, sizeof(sa));
  613. sa.sin_len = sizeof(sa);
  614. sa.sin_family = AF_INET;
  615. sa.sin_addr.s_addr = htonl((addrs->address[0] << 24) |
  616. (addrs->address[1] << 16) | (addrs->address[2] << 8) |
  617. (addrs->address[3] << 0));
  618. sa.sin_port = htons(addrs->address[4]) << 8 |
  619. htons(addrs->address[5]) << 0;
  620. if (connect(addrs->socket, (struct sockaddr *)&sa, sa.sin_len) == -1) {
  621. syslog(LOG_ERR, "connect(%s,%u): %m",
  622. inet_ntoa(sa.sin_addr), ntohs(sa.sin_port));
  623. (void)close(addrs->socket);
  624. return (SNMP_ERR_GENERR);
  625. }
  626. addrs->status = RowStatus_active;
  627. return (SNMP_ERR_NOERROR);
  628. }
  629. int
  630. target_delete_address(struct target_address *addrs)
  631. {
  632. SLIST_REMOVE(&target_addresslist, addrs, target_address, ta);
  633. if (addrs->status == RowStatus_active)
  634. close(addrs->socket);
  635. free(addrs);
  636. return (0);
  637. }
  638. struct target_param *
  639. target_first_param(void)
  640. {
  641. return (SLIST_FIRST(&target_paramlist));
  642. }
  643. struct target_param *
  644. target_next_param(struct target_param *param)
  645. {
  646. if (param == NULL)
  647. return (NULL);
  648. return (SLIST_NEXT(param, tp));
  649. }
  650. struct target_param *
  651. target_new_param(char *pname)
  652. {
  653. int cmp;
  654. struct target_param *param, *temp, *prev;
  655. SLIST_FOREACH(param, &target_paramlist, tp)
  656. if (strcmp(pname, param->name) == 0)
  657. return (NULL);
  658. if ((param = (struct target_param *)malloc(sizeof(*param))) == NULL)
  659. return (NULL);
  660. memset(param, 0, sizeof(*param));
  661. strlcpy(param->name, pname, sizeof(param->name));
  662. if ((prev = SLIST_FIRST(&target_paramlist)) == NULL ||
  663. strcmp(pname, prev->name) < 0) {
  664. SLIST_INSERT_HEAD(&target_paramlist, param, tp);
  665. return (param);
  666. }
  667. SLIST_FOREACH(temp, &target_paramlist, tp) {
  668. if ((cmp = strcmp(pname, temp->name)) <= 0)
  669. break;
  670. prev = temp;
  671. }
  672. if (temp == NULL || cmp < 0)
  673. SLIST_INSERT_AFTER(prev, param, tp);
  674. else if (cmp > 0)
  675. SLIST_INSERT_AFTER(temp, param, tp);
  676. else {
  677. syslog(LOG_ERR, "Target parameter %s exists", param->name);
  678. free(param);
  679. return (NULL);
  680. }
  681. return (param);
  682. }
  683. int
  684. target_delete_param(struct target_param *param)
  685. {
  686. SLIST_REMOVE(&target_paramlist, param, target_param, tp);
  687. free(param);
  688. return (0);
  689. }
  690. struct target_notify *
  691. target_first_notify(void)
  692. {
  693. return (SLIST_FIRST(&target_notifylist));
  694. }
  695. struct target_notify *
  696. target_next_notify(struct target_notify *notify)
  697. {
  698. if (notify == NULL)
  699. return (NULL);
  700. return (SLIST_NEXT(notify, tn));
  701. }
  702. struct target_notify *
  703. target_new_notify(char *nname)
  704. {
  705. int cmp;
  706. struct target_notify *notify, *temp, *prev;
  707. SLIST_FOREACH(notify, &target_notifylist, tn)
  708. if (strcmp(nname, notify->name) == 0)
  709. return (NULL);
  710. if ((notify = (struct target_notify *)malloc(sizeof(*notify))) == NULL)
  711. return (NULL);
  712. memset(notify, 0, sizeof(*notify));
  713. strlcpy(notify->name, nname, sizeof(notify->name));
  714. if ((prev = SLIST_FIRST(&target_notifylist)) == NULL ||
  715. strcmp(nname, prev->name) < 0) {
  716. SLIST_INSERT_HEAD(&target_notifylist, notify, tn);
  717. return (notify);
  718. }
  719. SLIST_FOREACH(temp, &target_notifylist, tn) {
  720. if ((cmp = strcmp(nname, temp->name)) <= 0)
  721. break;
  722. prev = temp;
  723. }
  724. if (temp == NULL || cmp < 0)
  725. SLIST_INSERT_AFTER(prev, notify, tn);
  726. else if (cmp > 0)
  727. SLIST_INSERT_AFTER(temp, notify, tn);
  728. else {
  729. syslog(LOG_ERR, "Notification target %s exists", notify->name);
  730. free(notify);
  731. return (NULL);
  732. }
  733. return (notify);
  734. }
  735. int
  736. target_delete_notify(struct target_notify *notify)
  737. {
  738. SLIST_REMOVE(&target_notifylist, notify, target_notify, tn);
  739. free(notify);
  740. return (0);
  741. }
  742. void
  743. target_flush_all(void)
  744. {
  745. struct target_address *addrs;
  746. struct target_param *param;
  747. struct target_notify *notify;
  748. while ((addrs = SLIST_FIRST(&target_addresslist)) != NULL) {
  749. SLIST_REMOVE_HEAD(&target_addresslist, ta);
  750. if (addrs->status == RowStatus_active)
  751. close(addrs->socket);
  752. free(addrs);
  753. }
  754. SLIST_INIT(&target_addresslist);
  755. while ((param = SLIST_FIRST(&target_paramlist)) != NULL) {
  756. SLIST_REMOVE_HEAD(&target_paramlist, tp);
  757. free(param);
  758. }
  759. SLIST_INIT(&target_paramlist);
  760. while ((notify = SLIST_FIRST(&target_notifylist)) != NULL) {
  761. SLIST_REMOVE_HEAD(&target_notifylist, tn);
  762. free(notify);
  763. }
  764. SLIST_INIT(&target_notifylist);
  765. }