1 /** 2 * @file 3 * SNMPv1 traps implementation. 4 */ 5 6 /* 7 * Copyright (c) 2001-2004 Swedish Institute of Computer Science. 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without modification, 11 * are permitted provided that the following conditions are met: 12 * 13 * 1. Redistributions of source code must retain the above copyright notice, 14 * this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright notice, 16 * this list of conditions and the following disclaimer in the documentation 17 * and/or other materials provided with the distribution. 18 * 3. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 22 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 23 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 24 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 26 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 29 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 30 * OF SUCH DAMAGE. 31 * 32 * This file is part of the lwIP TCP/IP stack. 33 * 34 * Author: Martin Hentschel 35 * Christiaan Simons <christiaan.simons@axon.tv> 36 * 37 */ 38 39 #include "lwip/apps/snmp_opts.h" 40 41 #if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ 42 43 #include <string.h> 44 45 #include "lwip/snmp.h" 46 #include "lwip/sys.h" 47 #include "lwip/apps/snmp.h" 48 #include "lwip/apps/snmp_core.h" 49 #include "snmp_msg.h" 50 #include "snmp_asn1.h" 51 #include "snmp_core_priv.h" 52 53 struct snmp_msg_trap 54 { 55 /* source enterprise ID (sysObjectID) */ 56 const struct snmp_obj_id *enterprise; 57 /* source IP address, raw network order format */ 58 ip_addr_t sip; 59 /* generic trap code */ 60 u32_t gen_trap; 61 /* specific trap code */ 62 u32_t spc_trap; 63 /* timestamp */ 64 u32_t ts; 65 /* snmp_version */ 66 u32_t snmp_version; 67 68 /* output trap lengths used in ASN encoding */ 69 /* encoding pdu length */ 70 u16_t pdulen; 71 /* encoding community length */ 72 u16_t comlen; 73 /* encoding sequence length */ 74 u16_t seqlen; 75 /* encoding varbinds sequence length */ 76 u16_t vbseqlen; 77 }; 78 79 static u16_t snmp_trap_varbind_sum(struct snmp_msg_trap *trap, struct snmp_varbind *varbinds); 80 static u16_t snmp_trap_header_sum(struct snmp_msg_trap *trap, u16_t vb_len); 81 static void snmp_trap_header_enc(struct snmp_msg_trap *trap, struct snmp_pbuf_stream *pbuf_stream); 82 static void snmp_trap_varbind_enc(struct snmp_msg_trap *trap, struct snmp_pbuf_stream *pbuf_stream, struct snmp_varbind *varbinds); 83 84 /** Agent community string for sending traps */ 85 extern const char *snmp_community_trap; 86 87 void* snmp_traps_handle; 88 89 struct snmp_trap_dst 90 { 91 /* destination IP address in network order */ 92 ip_addr_t dip; 93 /* set to 0 when disabled, >0 when enabled */ 94 u8_t enable; 95 }; 96 static struct snmp_trap_dst trap_dst[SNMP_TRAP_DESTINATIONS]; 97 98 static u8_t snmp_auth_traps_enabled = 0; 99 100 /** 101 * @ingroup snmp_traps 102 * Sets enable switch for this trap destination. 103 * @param dst_idx index in 0 .. SNMP_TRAP_DESTINATIONS-1 104 * @param enable switch if 0 destination is disabled >0 enabled. 105 */ 106 void 107 snmp_trap_dst_enable(u8_t dst_idx, u8_t enable) 108 { 109 if (dst_idx < SNMP_TRAP_DESTINATIONS) { 110 trap_dst[dst_idx].enable = enable; 111 } 112 } 113 114 /** 115 * @ingroup snmp_traps 116 * Sets IPv4 address for this trap destination. 117 * @param dst_idx index in 0 .. SNMP_TRAP_DESTINATIONS-1 118 * @param dst IPv4 address in host order. 119 */ 120 void 121 snmp_trap_dst_ip_set(u8_t dst_idx, const ip_addr_t *dst) 122 { 123 if (dst_idx < SNMP_TRAP_DESTINATIONS) { 124 ip_addr_set(&trap_dst[dst_idx].dip, dst); 125 } 126 } 127 128 /** 129 * @ingroup snmp_traps 130 * Enable/disable authentication traps 131 */ 132 void 133 snmp_set_auth_traps_enabled(u8_t enable) 134 { 135 snmp_auth_traps_enabled = enable; 136 } 137 138 /** 139 * @ingroup snmp_traps 140 * Get authentication traps enabled state 141 */ 142 u8_t 143 snmp_get_auth_traps_enabled(void) 144 { 145 return snmp_auth_traps_enabled; 146 } 147 148 149 /** 150 * @ingroup snmp_traps 151 * Sends a generic or enterprise specific trap message. 152 * 153 * @param eoid points to enterprise object identifier 154 * @param generic_trap is the trap code 155 * @param specific_trap used for enterprise traps when generic_trap == 6 156 * @param varbinds linked list of varbinds to be sent 157 * @return ERR_OK when success, ERR_MEM if we're out of memory 158 * 159 * @note the use of the enterprise identifier field 160 * is per RFC1215. 161 * Use .iso.org.dod.internet.mgmt.mib-2.snmp for generic traps 162 * and .iso.org.dod.internet.private.enterprises.yourenterprise 163 * (sysObjectID) for specific traps. 164 */ 165 err_t 166 snmp_send_trap(const struct snmp_obj_id* eoid, s32_t generic_trap, s32_t specific_trap, struct snmp_varbind *varbinds) 167 { 168 struct snmp_msg_trap trap_msg; 169 struct snmp_trap_dst *td; 170 struct pbuf *p; 171 u16_t i, tot_len; 172 err_t err = ERR_OK; 173 174 trap_msg.snmp_version = 0; 175 176 for (i = 0, td = &trap_dst[0]; i < SNMP_TRAP_DESTINATIONS; i++, td++) { 177 if ((td->enable != 0) && !ip_addr_isany(&td->dip)) { 178 /* lookup current source address for this dst */ 179 if (snmp_get_local_ip_for_dst(snmp_traps_handle, &td->dip, &trap_msg.sip)) { 180 if (eoid == NULL) { 181 trap_msg.enterprise = snmp_get_device_enterprise_oid(); 182 } else { 183 trap_msg.enterprise = eoid; 184 } 185 186 trap_msg.gen_trap = generic_trap; 187 if (generic_trap == SNMP_GENTRAP_ENTERPRISE_SPECIFIC) { 188 trap_msg.spc_trap = specific_trap; 189 } else { 190 trap_msg.spc_trap = 0; 191 } 192 193 MIB2_COPY_SYSUPTIME_TO(&trap_msg.ts); 194 195 /* pass 0, calculate length fields */ 196 tot_len = snmp_trap_varbind_sum(&trap_msg, varbinds); 197 tot_len = snmp_trap_header_sum(&trap_msg, tot_len); 198 199 /* allocate pbuf(s) */ 200 p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_RAM); 201 if (p != NULL) { 202 struct snmp_pbuf_stream pbuf_stream; 203 snmp_pbuf_stream_init(&pbuf_stream, p, 0, tot_len); 204 205 /* pass 1, encode packet ino the pbuf(s) */ 206 snmp_trap_header_enc(&trap_msg, &pbuf_stream); 207 snmp_trap_varbind_enc(&trap_msg, &pbuf_stream, varbinds); 208 209 snmp_stats.outtraps++; 210 snmp_stats.outpkts++; 211 212 /** send to the TRAP destination */ 213 snmp_sendto(snmp_traps_handle, p, &td->dip, SNMP_TRAP_PORT); 214 pbuf_free(p); 215 } else { 216 err = ERR_MEM; 217 } 218 } else { 219 /* routing error */ 220 err = ERR_RTE; 221 } 222 } 223 } 224 return err; 225 } 226 227 /** 228 * @ingroup snmp_traps 229 * Send generic SNMP trap 230 */ 231 err_t 232 snmp_send_trap_generic(s32_t generic_trap) 233 { 234 static const struct snmp_obj_id oid = { 7, { 1, 3, 6, 1, 2, 1, 11 } }; 235 return snmp_send_trap(&oid, generic_trap, 0, NULL); 236 } 237 238 /** 239 * @ingroup snmp_traps 240 * Send specific SNMP trap with variable bindings 241 */ 242 err_t 243 snmp_send_trap_specific(s32_t specific_trap, struct snmp_varbind *varbinds) 244 { 245 return snmp_send_trap(NULL, SNMP_GENTRAP_ENTERPRISE_SPECIFIC, specific_trap, varbinds); 246 } 247 248 /** 249 * @ingroup snmp_traps 250 * Send coldstart trap 251 */ 252 void 253 snmp_coldstart_trap(void) 254 { 255 snmp_send_trap_generic(SNMP_GENTRAP_COLDSTART); 256 } 257 258 /** 259 * @ingroup snmp_traps 260 * Send authentication failure trap (used internally by agent) 261 */ 262 void 263 snmp_authfail_trap(void) 264 { 265 if (snmp_auth_traps_enabled != 0) { 266 snmp_send_trap_generic(SNMP_GENTRAP_AUTH_FAILURE); 267 } 268 } 269 270 static u16_t 271 snmp_trap_varbind_sum(struct snmp_msg_trap *trap, struct snmp_varbind *varbinds) 272 { 273 struct snmp_varbind *varbind; 274 u16_t tot_len; 275 u8_t tot_len_len; 276 277 tot_len = 0; 278 varbind = varbinds; 279 while (varbind != NULL) { 280 struct snmp_varbind_len len; 281 282 if (snmp_varbind_length(varbind, &len) == ERR_OK) { 283 tot_len += 1 + len.vb_len_len + len.vb_value_len; 284 } 285 286 varbind = varbind->next; 287 } 288 289 trap->vbseqlen = tot_len; 290 snmp_asn1_enc_length_cnt(trap->vbseqlen, &tot_len_len); 291 tot_len += 1 + tot_len_len; 292 293 return tot_len; 294 } 295 296 /** 297 * Sums trap header field lengths from tail to head and 298 * returns trap_header_lengths for second encoding pass. 299 * 300 * @param trap Trap message 301 * @param vb_len varbind-list length 302 * @return the required length for encoding the trap header 303 */ 304 static u16_t 305 snmp_trap_header_sum(struct snmp_msg_trap *trap, u16_t vb_len) 306 { 307 u16_t tot_len; 308 u16_t len; 309 u8_t lenlen; 310 311 tot_len = vb_len; 312 313 snmp_asn1_enc_u32t_cnt(trap->ts, &len); 314 snmp_asn1_enc_length_cnt(len, &lenlen); 315 tot_len += 1 + len + lenlen; 316 317 snmp_asn1_enc_s32t_cnt(trap->spc_trap, &len); 318 snmp_asn1_enc_length_cnt(len, &lenlen); 319 tot_len += 1 + len + lenlen; 320 321 snmp_asn1_enc_s32t_cnt(trap->gen_trap, &len); 322 snmp_asn1_enc_length_cnt(len, &lenlen); 323 tot_len += 1 + len + lenlen; 324 325 if (IP_IS_V6_VAL(trap->sip)) { 326 #if LWIP_IPV6 327 len = sizeof(ip_2_ip6(&trap->sip)->addr); 328 #endif 329 } else { 330 #if LWIP_IPV4 331 len = sizeof(ip_2_ip4(&trap->sip)->addr); 332 #endif 333 } 334 snmp_asn1_enc_length_cnt(len, &lenlen); 335 tot_len += 1 + len + lenlen; 336 337 snmp_asn1_enc_oid_cnt(trap->enterprise->id, trap->enterprise->len, &len); 338 snmp_asn1_enc_length_cnt(len, &lenlen); 339 tot_len += 1 + len + lenlen; 340 341 trap->pdulen = tot_len; 342 snmp_asn1_enc_length_cnt(trap->pdulen, &lenlen); 343 tot_len += 1 + lenlen; 344 345 trap->comlen = (u16_t)LWIP_MIN(strlen(snmp_community_trap), 0xFFFF); 346 snmp_asn1_enc_length_cnt(trap->comlen, &lenlen); 347 tot_len += 1 + lenlen + trap->comlen; 348 349 snmp_asn1_enc_s32t_cnt(trap->snmp_version, &len); 350 snmp_asn1_enc_length_cnt(len, &lenlen); 351 tot_len += 1 + len + lenlen; 352 353 trap->seqlen = tot_len; 354 snmp_asn1_enc_length_cnt(trap->seqlen, &lenlen); 355 tot_len += 1 + lenlen; 356 357 return tot_len; 358 } 359 360 static void 361 snmp_trap_varbind_enc(struct snmp_msg_trap *trap, struct snmp_pbuf_stream *pbuf_stream, struct snmp_varbind *varbinds) 362 { 363 struct snmp_asn1_tlv tlv; 364 struct snmp_varbind *varbind; 365 366 varbind = varbinds; 367 368 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 0, trap->vbseqlen); 369 snmp_ans1_enc_tlv(pbuf_stream, &tlv); 370 371 while (varbind != NULL) { 372 snmp_append_outbound_varbind(pbuf_stream, varbind); 373 374 varbind = varbind->next; 375 } 376 } 377 378 /** 379 * Encodes trap header from head to tail. 380 */ 381 static void 382 snmp_trap_header_enc(struct snmp_msg_trap *trap, struct snmp_pbuf_stream *pbuf_stream) 383 { 384 struct snmp_asn1_tlv tlv; 385 386 /* 'Message' sequence */ 387 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 0, trap->seqlen); 388 snmp_ans1_enc_tlv(pbuf_stream, &tlv); 389 390 /* version */ 391 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0); 392 snmp_asn1_enc_s32t_cnt(trap->snmp_version, &tlv.value_len); 393 snmp_ans1_enc_tlv(pbuf_stream, &tlv); 394 snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, trap->snmp_version); 395 396 /* community */ 397 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, trap->comlen); 398 snmp_ans1_enc_tlv(pbuf_stream, &tlv); 399 snmp_asn1_enc_raw(pbuf_stream, (const u8_t *)snmp_community_trap, trap->comlen); 400 401 /* 'PDU' sequence */ 402 SNMP_ASN1_SET_TLV_PARAMS(tlv, (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_TRAP), 0, trap->pdulen); 403 snmp_ans1_enc_tlv(pbuf_stream, &tlv); 404 405 /* object ID */ 406 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OBJECT_ID, 0, 0); 407 snmp_asn1_enc_oid_cnt(trap->enterprise->id, trap->enterprise->len, &tlv.value_len); 408 snmp_ans1_enc_tlv(pbuf_stream, &tlv); 409 snmp_asn1_enc_oid(pbuf_stream, trap->enterprise->id, trap->enterprise->len); 410 411 /* IP addr */ 412 if (IP_IS_V6_VAL(trap->sip)) { 413 #if LWIP_IPV6 414 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_IPADDR, 0, sizeof(ip_2_ip6(&trap->sip)->addr)); 415 snmp_ans1_enc_tlv(pbuf_stream, &tlv); 416 snmp_asn1_enc_raw(pbuf_stream, (const u8_t *)&ip_2_ip6(&trap->sip)->addr, sizeof(ip_2_ip6(&trap->sip)->addr)); 417 #endif 418 } else { 419 #if LWIP_IPV4 420 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_IPADDR, 0, sizeof(ip_2_ip4(&trap->sip)->addr)); 421 snmp_ans1_enc_tlv(pbuf_stream, &tlv); 422 snmp_asn1_enc_raw(pbuf_stream, (const u8_t *)&ip_2_ip4(&trap->sip)->addr, sizeof(ip_2_ip4(&trap->sip)->addr)); 423 #endif 424 } 425 426 /* trap length */ 427 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0); 428 snmp_asn1_enc_s32t_cnt(trap->gen_trap, &tlv.value_len); 429 snmp_ans1_enc_tlv(pbuf_stream, &tlv); 430 snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, trap->gen_trap); 431 432 /* specific trap */ 433 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0); 434 snmp_asn1_enc_s32t_cnt(trap->spc_trap, &tlv.value_len); 435 snmp_ans1_enc_tlv(pbuf_stream, &tlv); 436 snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, trap->spc_trap); 437 438 /* timestamp */ 439 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_TIMETICKS, 0, 0); 440 snmp_asn1_enc_s32t_cnt(trap->ts, &tlv.value_len); 441 snmp_ans1_enc_tlv(pbuf_stream, &tlv); 442 snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, trap->ts); 443 } 444 445 #endif /* LWIP_SNMP */ 446