summaryrefslogtreecommitdiff
path: root/usr.sbin/snmpd/trap.c
blob: c68ada5fb0bc53a5c520699e2f5eb7e6114c6dc3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
/*	$OpenBSD: trap.c,v 1.43 2024/02/06 15:36:11 martijn Exp $	*/

/*
 * Copyright (c) 2008 Reyk Floeter <reyk@openbsd.org>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <sys/queue.h>
#include <sys/socket.h>

#include <ber.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#include "log.h"
#include "mib.h"
#include "smi.h"
#include "snmp.h"
#include "snmpd.h"

void
trap_init(void)
{
	/*
	 * Send a coldStart to notify that the daemon has been
	 * started and re-initialized.
	 */
	trap_send(&OID(MIB_coldStart), NULL);
}

int
trap_send(struct ber_oid *oid, struct ber_element *elm)
{
	struct trap_address	*tr;
	struct ber_element	*vblist, *trap;
	struct			 ber_oid uptime = OID(MIB_sysUpTime, 0);
	struct			 ber_oid trapoid = OID(MIB_snmpTrapOID, 0);
	char			 ostr[SNMP_MAX_OID_STRLEN];
	struct snmp_message	*msg;
	int			 r;

	if (TAILQ_EMPTY(&snmpd_env->sc_trapreceivers))
		return (0);

	mib_oid2string(oid, ostr, sizeof(ostr), snmpd_env->sc_oidfmt);
	log_debug("trap_send: oid %s", ostr);

	/* Add mandatory varbind elements */
	trap = ober_add_sequence(NULL);
	vblist = ober_printf_elements(trap, "{Odt}{OO}",
	    &uptime, smi_getticks(),
	    BER_CLASS_APPLICATION, SNMP_T_TIMETICKS,
	    &trapoid, oid);
	if (elm != NULL)
		ober_link_elements(vblist, elm);

	TAILQ_FOREACH(tr, &snmpd_env->sc_trapreceivers, entry) {
		if (tr->ta_oid.bo_n) {
			/* The trap receiver may want only a specified MIB */
			r = ober_oid_cmp(oid, &tr->ta_oid);
			if (r != 0 && r != 2)
				continue;
		}

		if ((msg = calloc(1, sizeof(*msg))) == NULL)
			fatal("malloc");
		msg->sm_sock = snmpd_socket_af(&tr->ta_ss, SOCK_DGRAM);
		if (msg->sm_sock == -1) {
			log_warn("socket");
			free(msg);
			continue;
		}
		memcpy(&(msg->sm_ss), &(tr->ta_ss), sizeof(msg->sm_ss));
		msg->sm_slen = tr->ta_ss.ss_len;
		if (tr->ta_sslocal.ss_family != 0) {
			memcpy(&(msg->sm_local_ss), &(tr->ta_sslocal),
			    sizeof(msg->sm_local_ss));
			msg->sm_local_slen = tr->ta_sslocal.ss_len;
		}
		msg->sm_version = tr->ta_version;
		msg->sm_pdutype = SNMP_C_TRAPV2;
		ober_set_application(&msg->sm_ber, smi_application);
		msg->sm_request = arc4random();
		if ((msg->sm_varbindresp = ober_dup(trap->be_sub)) == NULL)
			fatal("malloc");

		switch (msg->sm_version) {
		case SNMP_V2:
			(void)strlcpy(msg->sm_community, tr->ta_community,
			    sizeof(msg->sm_community));
			break;
		case SNMP_V3:
			msg->sm_msgid = msg->sm_request & INT32_MAX;
			msg->sm_max_msg_size = READ_BUF_SIZE;
			msg->sm_flags = tr->ta_seclevel != -1 ?
			    tr->ta_seclevel : snmpd_env->sc_min_seclevel;
			msg->sm_secmodel = SNMP_SEC_USM;
			msg->sm_engine_time = snmpd_engine_time();
			msg->sm_engine_boots = snmpd_env->sc_engine_boots;
			memcpy(msg->sm_ctxengineid, snmpd_env->sc_engineid,
			    snmpd_env->sc_engineid_len);
			msg->sm_ctxengineid_len =
			    snmpd_env->sc_engineid_len;
			(void)strlcpy(msg->sm_username, tr->ta_usmusername,
			    sizeof(msg->sm_username));
			msg->sm_user = tr->ta_usmuser;
			arc4random_buf(msg->sm_salt, sizeof(msg->sm_salt));
			break;
		}

		snmpe_response(msg);
	}
	ober_free_elements(trap);

	return 0;
}