1 /* $OpenBSD: trap.c,v 1.13 2008/10/09 14:14:40 reyk Exp $ */ 2 3 /* 4 * Copyright (c) 2008 Reyk Floeter <reyk@vantronix.net> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/queue.h> 20 #include <sys/param.h> 21 #include <sys/types.h> 22 #include <sys/stat.h> 23 #include <sys/socket.h> 24 #include <sys/un.h> 25 #include <sys/tree.h> 26 27 #include <net/if.h> 28 #include <netinet/in.h> 29 #include <arpa/inet.h> 30 31 #include <stdlib.h> 32 #include <stdio.h> 33 #include <errno.h> 34 #include <event.h> 35 #include <fcntl.h> 36 #include <string.h> 37 #include <unistd.h> 38 #include <pwd.h> 39 40 #include "snmpd.h" 41 #include "mib.h" 42 43 extern struct snmpd *env; 44 45 void 46 trap_init(void) 47 { 48 struct ber_oid trapoid = OID(MIB_coldStart); 49 50 /* 51 * Send a coldStart to notify that the daemon has been 52 * started and re-initialized. 53 */ 54 trap_send(&trapoid, NULL); 55 } 56 57 int 58 trap_imsg(struct imsgbuf *ibuf, pid_t pid) 59 { 60 struct imsg imsg; 61 int ret = -1, n, x = 0, state = 0; 62 int done = 0; 63 struct snmp_imsg *sm; 64 u_int32_t d; 65 u_int64_t l; 66 u_int8_t *c; 67 char ostr[SNMP_MAX_OID_LEN]; 68 struct ber_element *ber = NULL, *varbind = NULL, *a; 69 size_t len = 0; 70 struct ber_oid o; 71 72 while (!done) { 73 while (!done) { 74 if ((n = imsg_get(ibuf, &imsg)) == -1) 75 goto done; 76 if (n == 0) 77 break; 78 79 switch (imsg.hdr.type) { 80 case IMSG_SNMP_ELEMENT: 81 if (imsg.hdr.len < (IMSG_HEADER_SIZE + 82 sizeof(struct snmp_imsg))) 83 goto imsgdone; 84 85 sm = (struct snmp_imsg *)imsg.data; 86 87 if (!state++) { 88 /* First element must be the trap OID */ 89 if (sm->snmp_type != SNMP_NULL) 90 goto imsgdone; 91 ber_string2oid(sm->snmp_oid, &o); 92 break; 93 } 94 95 ber = ber_add_sequence(ber); 96 if (varbind == NULL) 97 varbind = ber; 98 a = ber_add_oidstring(ber, sm->snmp_oid); 99 100 switch (sm->snmp_type) { 101 case SNMP_OBJECT: 102 if (sm->snmp_len != sizeof(ostr)) 103 goto imsgdone; 104 bcopy(sm + 1, &ostr, sm->snmp_len); 105 a = ber_add_oidstring(a, ostr); 106 break; 107 case SNMP_BITSTRING: 108 case SNMP_OCTETSTRING: 109 case SNMP_IPADDR: 110 if ((sm->snmp_len < 1) || 111 (sm->snmp_len >= SNMPD_MAXSTRLEN)) 112 goto imsgdone; 113 c = (u_int8_t *)(sm + 1); 114 if (sm->snmp_type == SNMP_BITSTRING) 115 a = ber_add_bitstring(a, c, 116 sm->snmp_len); 117 else 118 a = ber_add_nstring(a, c, 119 sm->snmp_len); 120 break; 121 case SNMP_NULL: 122 a = ber_add_null(a); 123 break; 124 case SNMP_INTEGER32: 125 case SNMP_COUNTER32: 126 case SNMP_GAUGE32: 127 case SNMP_TIMETICKS: 128 case SNMP_OPAQUE: 129 case SNMP_UINTEGER32: 130 if (sm->snmp_len != sizeof(d)) 131 goto imsgdone; 132 bcopy(sm + 1, &d, sm->snmp_len); 133 a = ber_add_integer(a, d); 134 break; 135 case SNMP_COUNTER64: 136 if (sm->snmp_len != sizeof(l)) 137 goto imsgdone; 138 bcopy(sm + 1, &l, sm->snmp_len); 139 a = ber_add_integer(a, l); 140 break; 141 default: 142 log_debug("trap_imsg: illegal type %d", 143 sm->snmp_type); 144 imsg_free(&imsg); 145 goto imsgdone; 146 } 147 switch (sm->snmp_type) { 148 case SNMP_INTEGER32: 149 case SNMP_BITSTRING: 150 case SNMP_OCTETSTRING: 151 case SNMP_NULL: 152 case SNMP_OBJECT: 153 /* universal types */ 154 break; 155 default: 156 /* application-specific types */ 157 ber_set_header(a, BER_CLASS_APPLICATION, 158 sm->snmp_type); 159 break; 160 } 161 x++; 162 break; 163 case IMSG_SNMP_END: 164 done = 1; 165 break; 166 default: 167 log_debug("trap_imsg: illegal imsg %d", 168 imsg.hdr.type); 169 goto imsgdone; 170 } 171 imsg_free(&imsg); 172 } 173 if (done) 174 break; 175 if ((n = imsg_read(ibuf)) == -1) 176 goto done; 177 if (n == 0) 178 goto done; 179 } 180 181 if (varbind != NULL) 182 len = ber_calc_len(varbind); 183 log_debug("trap_imsg: from pid %u len %d elements %d", 184 pid, len, x); 185 trap_send(&o, varbind); 186 187 ret = 0; 188 imsgdone: 189 if (ret != 0) 190 imsg_free(&imsg); 191 done: 192 if (varbind != NULL) 193 ber_free_elements(varbind); 194 return (ret); 195 } 196 197 int 198 trap_send(struct ber_oid *oid, struct ber_element *elm) 199 { 200 int ret = 0, s; 201 struct address *tr; 202 struct ber_element *root, *b, *c, *trap; 203 struct ber ber; 204 char *cmn; 205 ssize_t len; 206 u_int8_t *ptr; 207 struct ber_oid uptime = OID(MIB_sysUpTime); 208 struct ber_oid trapoid = OID(MIB_snmpTrapOID); 209 char ostr[SNMP_MAX_OID_LEN]; 210 struct oid oa, ob; 211 212 if (TAILQ_EMPTY(&env->sc_trapreceivers)) 213 return (0); 214 215 smi_oidlen(&uptime); 216 smi_oidlen(&trapoid); 217 smi_oidlen(oid); 218 219 smi_oidstring(oid, ostr, sizeof(ostr)); 220 log_debug("trap_send: oid %s", ostr); 221 222 /* Setup OIDs to compare against the trap receiver MIB */ 223 bzero(&oa, sizeof(oa)); 224 bcopy(oid->bo_id, &oa.o_oid, sizeof(oa.o_oid)); 225 oa.o_oidlen = oid->bo_n; 226 bzero(&ob, sizeof(ob)); 227 ob.o_flags = OID_TABLE; 228 229 /* Add mandatory varbind elements */ 230 trap = ber_add_sequence(NULL); 231 c = ber_printf_elements(trap, "{Odt}{OO}", 232 &uptime, smi_getticks(), 233 BER_CLASS_APPLICATION, SNMP_T_TIMETICKS, 234 &trapoid, oid); 235 if (elm != NULL) 236 ber_link_elements(c, elm); 237 238 bzero(&ber, sizeof(ber)); 239 ber.fd = -1; 240 241 TAILQ_FOREACH(tr, &env->sc_trapreceivers, entry) { 242 if (tr->sa_oid != NULL && tr->sa_oid->bo_n) { 243 /* The trap receiver may want only a specified MIB */ 244 bcopy(&tr->sa_oid->bo_id, &ob.o_oid, 245 sizeof(ob.o_oid)); 246 ob.o_oidlen = tr->sa_oid->bo_n; 247 if (smi_oid_cmp(&oa, &ob) != 0) 248 continue; 249 } 250 251 if ((s = snmpd_socket_af(&tr->ss, htons(tr->port))) == -1) { 252 ret = -1; 253 goto done; 254 } 255 256 cmn = tr->sa_community != NULL ? 257 tr->sa_community : env->sc_trcommunity; 258 259 /* SNMP header */ 260 root = ber_add_sequence(NULL); 261 b = ber_printf_elements(root, "ds{tddd", 262 SNMP_V2, cmn, BER_CLASS_CONTEXT, SNMP_C_TRAPV2, 263 arc4random(), 0, 0); 264 ber_link_elements(b, trap); 265 266 #ifdef DEBUG 267 snmpe_debug_elements(root); 268 #endif 269 270 len = ber_write_elements(&ber, root); 271 if (ber_get_writebuf(&ber, (void *)&ptr) > 0 && 272 sendto(s, ptr, len, 0, (struct sockaddr *)&tr->ss, 273 tr->ss.ss_len) != -1) { 274 env->sc_stats.snmp_outpkts++; 275 ret++; 276 } 277 278 close(s); 279 ber_unlink_elements(b); 280 ber_free_elements(root); 281 } 282 283 done: 284 if (elm != NULL) 285 ber_unlink_elements(c); 286 ber_free_elements(trap); 287 ber_free(&ber); 288 289 return (ret); 290 } 291