xref: /openbsd-src/usr.sbin/snmpd/util.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1 /*	$OpenBSD: util.c,v 1.5 2015/11/21 13:06:22 reyk Exp $	*/
2 /*
3  * Copyright (c) 2014 Bret Stephen Lambert <blambert@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/types.h>
19 #include <sys/queue.h>
20 #include <sys/socket.h>
21 
22 #include <net/if.h>
23 
24 #include <stdio.h>
25 #include <string.h>
26 #include <netdb.h>
27 #include <event.h>
28 
29 #include "ber.h"
30 #include "snmp.h"
31 #include "snmpd.h"
32 
33 /* log.c */
34 extern int	 debug;
35 extern int	 verbose;
36 
37 /*
38  * Convert variable bindings from AgentX to SNMP dialect.
39  */
40 int
41 varbind_convert(struct agentx_pdu *pdu, struct agentx_varbind_hdr *vbhdr,
42     struct ber_element **varbind, struct ber_element **iter)
43 {
44 	struct ber_oid			 oid;
45 	u_int32_t			 d;
46 	u_int64_t			 l;
47 	int				 slen;
48 	char				*str;
49 	struct ber_element		*a;
50 	int				 ret = AGENTX_ERR_NONE;
51 
52 	if (snmp_agentx_read_oid(pdu, (struct snmp_oid *)&oid) == -1) {
53 		ret = AGENTX_ERR_PARSE_ERROR;
54 		goto done;
55 	}
56 
57 	*iter = ber_add_sequence(*iter);
58 	if (*varbind == NULL)
59 		*varbind = *iter;
60 
61 	a = ber_add_oid(*iter, &oid);
62 
63 	switch (vbhdr->type) {
64 	case AGENTX_NO_SUCH_OBJECT:
65 	case AGENTX_NO_SUCH_INSTANCE:
66 	case AGENTX_END_OF_MIB_VIEW:
67 	case AGENTX_NULL:
68 		a = ber_add_null(a);
69 		break;
70 
71 	case AGENTX_IP_ADDRESS:
72 	case AGENTX_OPAQUE:
73 	case AGENTX_OCTET_STRING:
74 		str = snmp_agentx_read_octetstr(pdu, &slen);
75 		if (str == NULL) {
76 			ret = AGENTX_ERR_PARSE_ERROR;
77 			goto done;
78 		}
79 		a = ber_add_nstring(a, str, slen);
80 		break;
81 
82 	case AGENTX_OBJECT_IDENTIFIER:
83 		if (snmp_agentx_read_oid(pdu,
84 		    (struct snmp_oid *)&oid) == -1) {
85 			ret = AGENTX_ERR_PARSE_ERROR;
86 			goto done;
87 		}
88 		a = ber_add_oid(a, &oid);
89 		break;
90 
91 	case AGENTX_INTEGER:
92 	case AGENTX_COUNTER32:
93 	case AGENTX_GAUGE32:
94 	case AGENTX_TIME_TICKS:
95 		if (snmp_agentx_read_int(pdu, &d) == -1) {
96 			ret = AGENTX_ERR_PARSE_ERROR;
97 			goto done;
98 		}
99 		a = ber_add_integer(a, d);
100 		break;
101 
102 	case AGENTX_COUNTER64:
103 		if (snmp_agentx_read_int64(pdu, &l) == -1) {
104 			ret = AGENTX_ERR_PARSE_ERROR;
105 			goto done;
106 		}
107 		a = ber_add_integer(a, l);
108 		break;
109 
110 	default:
111 		log_debug("unknown data type '%i'", vbhdr->type);
112 		ret = AGENTX_ERR_PARSE_ERROR;
113 		goto done;
114 	}
115 
116 	/* AgentX types correspond to BER types */
117 	switch (vbhdr->type) {
118 	case BER_TYPE_INTEGER:
119 	case BER_TYPE_BITSTRING:
120 	case BER_TYPE_OCTETSTRING:
121 	case BER_TYPE_NULL:
122 	case BER_TYPE_OBJECT:
123 		/* universal types */
124 		break;
125 
126 	/* Convert AgentX error types to SNMP error types */
127 	case AGENTX_NO_SUCH_OBJECT:
128 		ber_set_header(a, BER_CLASS_CONTEXT, 0);
129 		break;
130 	case AGENTX_NO_SUCH_INSTANCE:
131 		ber_set_header(a, BER_CLASS_CONTEXT, 1);
132 		break;
133 
134 	case AGENTX_COUNTER32:
135 		ber_set_header(a, BER_CLASS_APPLICATION, SNMP_COUNTER32);
136 		break;
137 
138 	case AGENTX_GAUGE32:
139 		ber_set_header(a, BER_CLASS_APPLICATION, SNMP_GAUGE32);
140 		break;
141 
142 	case AGENTX_COUNTER64:
143 		ber_set_header(a, BER_CLASS_APPLICATION, SNMP_COUNTER64);
144 		break;
145 
146 	case AGENTX_IP_ADDRESS:
147 		/* application 0 implicit 4-byte octet string per SNMPv2-SMI */
148 		break;
149 
150 	default:
151 		/* application-specific types */
152 		ber_set_header(a, BER_CLASS_APPLICATION, vbhdr->type);
153 		break;
154 	}
155  done:
156 	return (ret);
157 }
158 
159 void
160 print_debug(const char *emsg, ...)
161 {
162 	va_list	 ap;
163 
164 	if (debug && verbose > 2) {
165 		va_start(ap, emsg);
166 		vfprintf(stderr, emsg, ap);
167 		va_end(ap);
168 	}
169 }
170 
171 void
172 print_verbose(const char *emsg, ...)
173 {
174 	va_list	 ap;
175 
176 	if (verbose) {
177 		va_start(ap, emsg);
178 		vfprintf(stderr, emsg, ap);
179 		va_end(ap);
180 	}
181 }
182 
183 const char *
184 log_in6addr(const struct in6_addr *addr)
185 {
186 	static char		buf[NI_MAXHOST];
187 	struct sockaddr_in6	sa_in6;
188 	u_int16_t		tmp16;
189 
190 	bzero(&sa_in6, sizeof(sa_in6));
191 	sa_in6.sin6_len = sizeof(sa_in6);
192 	sa_in6.sin6_family = AF_INET6;
193 	memcpy(&sa_in6.sin6_addr, addr, sizeof(sa_in6.sin6_addr));
194 
195 	/* XXX thanks, KAME, for this ugliness... adopted from route/show.c */
196 	if (IN6_IS_ADDR_LINKLOCAL(&sa_in6.sin6_addr) ||
197 	    IN6_IS_ADDR_MC_LINKLOCAL(&sa_in6.sin6_addr)) {
198 		memcpy(&tmp16, &sa_in6.sin6_addr.s6_addr[2], sizeof(tmp16));
199 		sa_in6.sin6_scope_id = ntohs(tmp16);
200 		sa_in6.sin6_addr.s6_addr[2] = 0;
201 		sa_in6.sin6_addr.s6_addr[3] = 0;
202 	}
203 
204 	return (print_host((struct sockaddr_storage *)&sa_in6, buf,
205 	    NI_MAXHOST));
206 }
207 
208 const char *
209 print_host(struct sockaddr_storage *ss, char *buf, size_t len)
210 {
211 	if (getnameinfo((struct sockaddr *)ss, ss->ss_len,
212 	    buf, len, NULL, 0, NI_NUMERICHOST) != 0) {
213 		buf[0] = '\0';
214 		return (NULL);
215 	}
216 	return (buf);
217 }
218