xref: /openbsd-src/usr.sbin/snmpd/trap.c (revision 1a8dbaac879b9f3335ad7fb25429ce63ac1d6bac)
1 /*	$OpenBSD: trap.c,v 1.36 2020/09/06 15:51:28 martijn Exp $	*/
2 
3 /*
4  * Copyright (c) 2008 Reyk Floeter <reyk@openbsd.org>
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/types.h>
21 #include <sys/stat.h>
22 #include <sys/socket.h>
23 #include <sys/un.h>
24 #include <sys/tree.h>
25 
26 #include <net/if.h>
27 #include <netinet/in.h>
28 #include <arpa/inet.h>
29 
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <errno.h>
33 #include <event.h>
34 #include <fcntl.h>
35 #include <string.h>
36 #include <unistd.h>
37 #include <pwd.h>
38 
39 #include "snmpd.h"
40 #include "mib.h"
41 
42 void
43 trap_init(void)
44 {
45 	struct ber_oid	 trapoid = OID(MIB_coldStart);
46 
47 	/*
48 	 * Send a coldStart to notify that the daemon has been
49 	 * started and re-initialized.
50 	 */
51 	trap_send(&trapoid, NULL);
52 }
53 
54 int
55 trap_send(struct ber_oid *oid, struct ber_element *elm)
56 {
57 	int			 ret = 0, s;
58 	struct trap_address	*tr;
59 	struct ber_element	*root, *b, *c, *trap;
60 	struct ber		 ber;
61 	char			*cmn;
62 	ssize_t			 len;
63 	u_int8_t		*ptr;
64 	struct			 ber_oid uptime = OID(MIB_sysUpTime);
65 	struct			 ber_oid trapoid = OID(MIB_snmpTrapOID);
66 	char			 ostr[SNMP_MAX_OID_STRLEN];
67 	struct oid		 oa, ob;
68 
69 	if (TAILQ_EMPTY(&snmpd_env->sc_trapreceivers))
70 		return (0);
71 
72 	smi_scalar_oidlen(&uptime);
73 	smi_scalar_oidlen(&trapoid);
74 	smi_scalar_oidlen(oid);
75 
76 	smi_oid2string(oid, ostr, sizeof(ostr), 0);
77 	log_debug("trap_send: oid %s", ostr);
78 
79 	/* Setup OIDs to compare against the trap receiver MIB */
80 	bzero(&oa, sizeof(oa));
81 	bcopy(oid->bo_id, &oa.o_oid, sizeof(oa.o_oid));
82 	oa.o_oidlen = oid->bo_n;
83 	bzero(&ob, sizeof(ob));
84 	ob.o_flags = OID_TABLE;
85 
86 	/* Add mandatory varbind elements */
87 	trap = ober_add_sequence(NULL);
88 	c = ober_printf_elements(trap, "{Odt}{OO}",
89 	    &uptime, smi_getticks(),
90 	    BER_CLASS_APPLICATION, SNMP_T_TIMETICKS,
91 	    &trapoid, oid);
92 	if (elm != NULL)
93 		ober_link_elements(c, elm);
94 
95 	bzero(&ber, sizeof(ber));
96 
97 	TAILQ_FOREACH(tr, &snmpd_env->sc_trapreceivers, entry) {
98 		if (tr->sa_oid != NULL && tr->sa_oid->bo_n) {
99 			/* The trap receiver may want only a specified MIB */
100 			bcopy(&tr->sa_oid->bo_id, &ob.o_oid,
101 			    sizeof(ob.o_oid));
102 			ob.o_oidlen = tr->sa_oid->bo_n;
103 			if (smi_oid_cmp(&oa, &ob) != 0)
104 				continue;
105 		}
106 
107 		if ((s = snmpd_socket_af(&tr->ss, SOCK_DGRAM)) == -1) {
108 			ret = -1;
109 			goto done;
110 		}
111 		if (tr->ss_local.ss_family != 0) {
112 			if (bind(s, (struct sockaddr *)&(tr->ss_local),
113 			    tr->ss_local.ss_len) == -1) {
114 				ret = -1;
115 				goto done;
116 			}
117 		}
118 
119 		cmn = tr->sa_community != NULL ?
120 		    tr->sa_community : snmpd_env->sc_trcommunity;
121 
122 		/* SNMP header */
123 		root = ober_add_sequence(NULL);
124 		b = ober_printf_elements(root, "ds{tddd",
125 		    SNMP_V2, cmn, BER_CLASS_CONTEXT, SNMP_C_TRAPV2,
126 		    arc4random(), 0, 0);
127 		ober_link_elements(b, trap);
128 
129 #ifdef DEBUG
130 		smi_debug_elements(root);
131 #endif
132 		len = ober_write_elements(&ber, root);
133 		if (ober_get_writebuf(&ber, (void *)&ptr) > 0 &&
134 		    sendto(s, ptr, len, 0, (struct sockaddr *)&tr->ss,
135 		    tr->ss.ss_len) != -1) {
136 			snmpd_env->sc_stats.snmp_outpkts++;
137 			ret++;
138 		}
139 
140 		close(s);
141 		ober_unlink_elements(b);
142 		ober_free_elements(root);
143 	}
144 
145  done:
146 	ober_free_elements(trap);
147 	ober_free(&ber);
148 
149 	return (ret);
150 }
151