GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/snmpd/util.c Lines: 0 144 0.0 %
Date: 2017-11-07 Branches: 0 78 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: util.c,v 1.7 2017/01/09 14:49: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
/*
34
 * Convert variable bindings from AgentX to SNMP dialect.
35
 */
36
int
37
varbind_convert(struct agentx_pdu *pdu, struct agentx_varbind_hdr *vbhdr,
38
    struct ber_element **varbind, struct ber_element **iter)
39
{
40
	struct ber_oid			 oid;
41
	u_int32_t			 d;
42
	u_int64_t			 l;
43
	int				 slen;
44
	char				*str;
45
	struct ber_element		*a;
46
	int				 ret = AGENTX_ERR_NONE;
47
48
	if (snmp_agentx_read_oid(pdu, (struct snmp_oid *)&oid) == -1) {
49
		ret = AGENTX_ERR_PARSE_ERROR;
50
		goto done;
51
	}
52
53
	*iter = ber_add_sequence(*iter);
54
	if (*varbind == NULL)
55
		*varbind = *iter;
56
57
	a = ber_add_oid(*iter, &oid);
58
59
	switch (vbhdr->type) {
60
	case AGENTX_NO_SUCH_OBJECT:
61
	case AGENTX_NO_SUCH_INSTANCE:
62
	case AGENTX_END_OF_MIB_VIEW:
63
	case AGENTX_NULL:
64
		a = ber_add_null(a);
65
		break;
66
67
	case AGENTX_IP_ADDRESS:
68
	case AGENTX_OPAQUE:
69
	case AGENTX_OCTET_STRING:
70
		str = snmp_agentx_read_octetstr(pdu, &slen);
71
		if (str == NULL) {
72
			ret = AGENTX_ERR_PARSE_ERROR;
73
			goto done;
74
		}
75
		a = ber_add_nstring(a, str, slen);
76
		break;
77
78
	case AGENTX_OBJECT_IDENTIFIER:
79
		if (snmp_agentx_read_oid(pdu,
80
		    (struct snmp_oid *)&oid) == -1) {
81
			ret = AGENTX_ERR_PARSE_ERROR;
82
			goto done;
83
		}
84
		a = ber_add_oid(a, &oid);
85
		break;
86
87
	case AGENTX_INTEGER:
88
	case AGENTX_COUNTER32:
89
	case AGENTX_GAUGE32:
90
	case AGENTX_TIME_TICKS:
91
		if (snmp_agentx_read_int(pdu, &d) == -1) {
92
			ret = AGENTX_ERR_PARSE_ERROR;
93
			goto done;
94
		}
95
		a = ber_add_integer(a, d);
96
		break;
97
98
	case AGENTX_COUNTER64:
99
		if (snmp_agentx_read_int64(pdu, &l) == -1) {
100
			ret = AGENTX_ERR_PARSE_ERROR;
101
			goto done;
102
		}
103
		a = ber_add_integer(a, l);
104
		break;
105
106
	default:
107
		log_debug("unknown data type '%i'", vbhdr->type);
108
		ret = AGENTX_ERR_PARSE_ERROR;
109
		goto done;
110
	}
111
112
	/* AgentX types correspond to BER types */
113
	switch (vbhdr->type) {
114
	case BER_TYPE_INTEGER:
115
	case BER_TYPE_BITSTRING:
116
	case BER_TYPE_OCTETSTRING:
117
	case BER_TYPE_NULL:
118
	case BER_TYPE_OBJECT:
119
		/* universal types */
120
		break;
121
122
	/* Convert AgentX error types to SNMP error types */
123
	case AGENTX_NO_SUCH_OBJECT:
124
		ber_set_header(a, BER_CLASS_CONTEXT, 0);
125
		break;
126
	case AGENTX_NO_SUCH_INSTANCE:
127
		ber_set_header(a, BER_CLASS_CONTEXT, 1);
128
		break;
129
130
	case AGENTX_COUNTER32:
131
		ber_set_header(a, BER_CLASS_APPLICATION, SNMP_COUNTER32);
132
		break;
133
134
	case AGENTX_GAUGE32:
135
		ber_set_header(a, BER_CLASS_APPLICATION, SNMP_GAUGE32);
136
		break;
137
138
	case AGENTX_COUNTER64:
139
		ber_set_header(a, BER_CLASS_APPLICATION, SNMP_COUNTER64);
140
		break;
141
142
	case AGENTX_IP_ADDRESS:
143
		/* application 0 implicit 4-byte octet string per SNMPv2-SMI */
144
		break;
145
146
	default:
147
		/* application-specific types */
148
		ber_set_header(a, BER_CLASS_APPLICATION, vbhdr->type);
149
		break;
150
	}
151
 done:
152
	return (ret);
153
}
154
155
ssize_t
156
sendtofrom(int s, void *buf, size_t len, int flags, struct sockaddr *to,
157
    socklen_t tolen, struct sockaddr *from, socklen_t fromlen)
158
{
159
	struct iovec		 iov;
160
	struct msghdr		 msg;
161
	struct cmsghdr		*cmsg;
162
	struct in6_pktinfo	*pkt6;
163
	struct sockaddr_in	*in;
164
	struct sockaddr_in6	*in6;
165
	union {
166
		struct cmsghdr	hdr;
167
		char		inbuf[CMSG_SPACE(sizeof(struct in_addr))];
168
		char		in6buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
169
	} cmsgbuf;
170
171
	bzero(&msg, sizeof(msg));
172
	bzero(&cmsgbuf, sizeof(cmsgbuf));
173
174
	iov.iov_base = buf;
175
	iov.iov_len = len;
176
	msg.msg_iov = &iov;
177
	msg.msg_iovlen = 1;
178
	msg.msg_name = to;
179
	msg.msg_namelen = tolen;
180
	msg.msg_control = &cmsgbuf;
181
	msg.msg_controllen = sizeof(cmsgbuf);
182
183
	cmsg = CMSG_FIRSTHDR(&msg);
184
	switch (to->sa_family) {
185
	case AF_INET:
186
		msg.msg_controllen = sizeof(cmsgbuf.inbuf);
187
		cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
188
		cmsg->cmsg_level = IPPROTO_IP;
189
		cmsg->cmsg_type = IP_SENDSRCADDR;
190
		in = (struct sockaddr_in *)from;
191
		memcpy(CMSG_DATA(cmsg), &in->sin_addr, sizeof(struct in_addr));
192
		break;
193
	case AF_INET6:
194
		msg.msg_controllen = sizeof(cmsgbuf.in6buf);
195
		cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
196
		cmsg->cmsg_level = IPPROTO_IPV6;
197
		cmsg->cmsg_type = IPV6_PKTINFO;
198
		in6 = (struct sockaddr_in6 *)from;
199
		pkt6 = (struct in6_pktinfo *)CMSG_DATA(cmsg);
200
		pkt6->ipi6_addr = in6->sin6_addr;
201
		break;
202
	}
203
204
	return sendmsg(s, &msg, flags);
205
}
206
207
ssize_t
208
recvfromto(int s, void *buf, size_t len, int flags, struct sockaddr *from,
209
    socklen_t *fromlen, struct sockaddr *to, socklen_t *tolen)
210
{
211
	struct iovec		 iov;
212
	struct msghdr		 msg;
213
	struct cmsghdr		*cmsg;
214
	struct in6_pktinfo	*pkt6;
215
	struct sockaddr_in	*in;
216
	struct sockaddr_in6	*in6;
217
	ssize_t			 ret;
218
	union {
219
		struct cmsghdr hdr;
220
		char	buf[CMSG_SPACE(sizeof(struct sockaddr_storage))];
221
	} cmsgbuf;
222
223
	bzero(&msg, sizeof(msg));
224
	bzero(&cmsgbuf.buf, sizeof(cmsgbuf.buf));
225
226
	iov.iov_base = buf;
227
	iov.iov_len = len;
228
	msg.msg_iov = &iov;
229
	msg.msg_iovlen = 1;
230
	msg.msg_name = from;
231
	msg.msg_namelen = *fromlen;
232
	msg.msg_control = &cmsgbuf.buf;
233
	msg.msg_controllen = sizeof(cmsgbuf.buf);
234
235
	if ((ret = recvmsg(s, &msg, flags)) == -1)
236
		return (-1);
237
238
	*fromlen = from->sa_len;
239
	*tolen = 0;
240
241
	if (getsockname(s, to, tolen) != 0)
242
		*tolen = 0;
243
244
	for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
245
	    cmsg = CMSG_NXTHDR(&msg, cmsg)) {
246
		switch (from->sa_family) {
247
		case AF_INET:
248
			if (cmsg->cmsg_level == IPPROTO_IP &&
249
			    cmsg->cmsg_type == IP_RECVDSTADDR) {
250
				in = (struct sockaddr_in *)to;
251
				in->sin_family = AF_INET;
252
				in->sin_len = *tolen = sizeof(*in);
253
				memcpy(&in->sin_addr, CMSG_DATA(cmsg),
254
				    sizeof(struct in_addr));
255
			}
256
			break;
257
		case AF_INET6:
258
			if (cmsg->cmsg_level == IPPROTO_IPV6 &&
259
			    cmsg->cmsg_type == IPV6_PKTINFO) {
260
				in6 = (struct sockaddr_in6 *)to;
261
				in6->sin6_family = AF_INET6;
262
				in6->sin6_len = *tolen = sizeof(*in6);
263
				pkt6 = (struct in6_pktinfo *)CMSG_DATA(cmsg);
264
				memcpy(&in6->sin6_addr, &pkt6->ipi6_addr,
265
				    sizeof(struct in6_addr));
266
				if (IN6_IS_ADDR_LINKLOCAL(&in6->sin6_addr))
267
					in6->sin6_scope_id =
268
					    pkt6->ipi6_ifindex;
269
			}
270
			break;
271
		}
272
	}
273
274
	return (ret);
275
}
276
277
void
278
print_debug(const char *emsg, ...)
279
{
280
	va_list	 ap;
281
282
	if (log_getverbose() > 2) {
283
		va_start(ap, emsg);
284
		vfprintf(stderr, emsg, ap);
285
		va_end(ap);
286
	}
287
}
288
289
void
290
print_verbose(const char *emsg, ...)
291
{
292
	va_list	 ap;
293
294
	if (log_getverbose()) {
295
		va_start(ap, emsg);
296
		vfprintf(stderr, emsg, ap);
297
		va_end(ap);
298
	}
299
}
300
301
const char *
302
log_in6addr(const struct in6_addr *addr)
303
{
304
	static char		buf[NI_MAXHOST];
305
	struct sockaddr_in6	sa_in6;
306
	u_int16_t		tmp16;
307
308
	bzero(&sa_in6, sizeof(sa_in6));
309
	sa_in6.sin6_len = sizeof(sa_in6);
310
	sa_in6.sin6_family = AF_INET6;
311
	memcpy(&sa_in6.sin6_addr, addr, sizeof(sa_in6.sin6_addr));
312
313
	/* XXX thanks, KAME, for this ugliness... adopted from route/show.c */
314
	if (IN6_IS_ADDR_LINKLOCAL(&sa_in6.sin6_addr) ||
315
	    IN6_IS_ADDR_MC_LINKLOCAL(&sa_in6.sin6_addr)) {
316
		memcpy(&tmp16, &sa_in6.sin6_addr.s6_addr[2], sizeof(tmp16));
317
		sa_in6.sin6_scope_id = ntohs(tmp16);
318
		sa_in6.sin6_addr.s6_addr[2] = 0;
319
		sa_in6.sin6_addr.s6_addr[3] = 0;
320
	}
321
322
	return (print_host((struct sockaddr_storage *)&sa_in6, buf,
323
	    NI_MAXHOST));
324
}
325
326
const char *
327
print_host(struct sockaddr_storage *ss, char *buf, size_t len)
328
{
329
	if (getnameinfo((struct sockaddr *)ss, ss->ss_len,
330
	    buf, len, NULL, 0, NI_NUMERICHOST) != 0) {
331
		buf[0] = '\0';
332
		return (NULL);
333
	}
334
	return (buf);
335
}