xref: /openbsd-src/usr.sbin/snmpd/util.c (revision a9292d2a63fa67dc6b2075a718b776ad5d932d51)
1*a9292d2aSmartijn /*	$OpenBSD: util.c,v 1.14 2023/12/21 12:43:31 martijn Exp $	*/
2552ac9e7Sblambert /*
3552ac9e7Sblambert  * Copyright (c) 2014 Bret Stephen Lambert <blambert@openbsd.org>
4552ac9e7Sblambert  *
5552ac9e7Sblambert  * Permission to use, copy, modify, and distribute this software for any
6552ac9e7Sblambert  * purpose with or without fee is hereby granted, provided that the above
7552ac9e7Sblambert  * copyright notice and this permission notice appear in all copies.
8552ac9e7Sblambert  *
9552ac9e7Sblambert  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10552ac9e7Sblambert  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11552ac9e7Sblambert  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12552ac9e7Sblambert  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13552ac9e7Sblambert  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14552ac9e7Sblambert  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15552ac9e7Sblambert  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16552ac9e7Sblambert  */
17552ac9e7Sblambert 
18552ac9e7Sblambert #include <sys/socket.h>
19552ac9e7Sblambert 
20*a9292d2aSmartijn #include <netinet/in.h>
21552ac9e7Sblambert 
2273b5c081Smartijn #include <ctype.h>
2373b5c081Smartijn #include <stdlib.h>
24*a9292d2aSmartijn #include <stdint.h>
252685bdaeSreyk #include <string.h>
26*a9292d2aSmartijn #include <strings.h>
272685bdaeSreyk #include <netdb.h>
28552ac9e7Sblambert 
29552ac9e7Sblambert #include "snmpd.h"
30552ac9e7Sblambert 
31f005ecdcSjca ssize_t
sendtofrom(int s,void * buf,size_t len,int flags,struct sockaddr * to,socklen_t tolen,struct sockaddr * from,socklen_t fromlen)32f005ecdcSjca sendtofrom(int s, void *buf, size_t len, int flags, struct sockaddr *to,
33f005ecdcSjca     socklen_t tolen, struct sockaddr *from, socklen_t fromlen)
34f005ecdcSjca {
35f005ecdcSjca 	struct iovec		 iov;
36f005ecdcSjca 	struct msghdr		 msg;
37f005ecdcSjca 	struct cmsghdr		*cmsg;
38f005ecdcSjca 	struct in6_pktinfo	*pkt6;
39f005ecdcSjca 	struct sockaddr_in	*in;
40f005ecdcSjca 	struct sockaddr_in6	*in6;
41f005ecdcSjca 	union {
42f005ecdcSjca 		struct cmsghdr	hdr;
43f005ecdcSjca 		char		inbuf[CMSG_SPACE(sizeof(struct in_addr))];
44f005ecdcSjca 		char		in6buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
45f005ecdcSjca 	} cmsgbuf;
46f005ecdcSjca 
47f005ecdcSjca 	bzero(&msg, sizeof(msg));
48f005ecdcSjca 	bzero(&cmsgbuf, sizeof(cmsgbuf));
49f005ecdcSjca 
50f005ecdcSjca 	iov.iov_base = buf;
51f005ecdcSjca 	iov.iov_len = len;
52f005ecdcSjca 	msg.msg_iov = &iov;
53f005ecdcSjca 	msg.msg_iovlen = 1;
54f005ecdcSjca 	msg.msg_name = to;
55f005ecdcSjca 	msg.msg_namelen = tolen;
56f005ecdcSjca 	msg.msg_control = &cmsgbuf;
57f005ecdcSjca 	msg.msg_controllen = sizeof(cmsgbuf);
58f005ecdcSjca 
59f005ecdcSjca 	cmsg = CMSG_FIRSTHDR(&msg);
60f005ecdcSjca 	switch (to->sa_family) {
61f005ecdcSjca 	case AF_INET:
62f005ecdcSjca 		msg.msg_controllen = sizeof(cmsgbuf.inbuf);
63f005ecdcSjca 		cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
64f005ecdcSjca 		cmsg->cmsg_level = IPPROTO_IP;
65f005ecdcSjca 		cmsg->cmsg_type = IP_SENDSRCADDR;
66f005ecdcSjca 		in = (struct sockaddr_in *)from;
67f005ecdcSjca 		memcpy(CMSG_DATA(cmsg), &in->sin_addr, sizeof(struct in_addr));
68f005ecdcSjca 		break;
69f005ecdcSjca 	case AF_INET6:
70f005ecdcSjca 		msg.msg_controllen = sizeof(cmsgbuf.in6buf);
71f005ecdcSjca 		cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
72f005ecdcSjca 		cmsg->cmsg_level = IPPROTO_IPV6;
73f005ecdcSjca 		cmsg->cmsg_type = IPV6_PKTINFO;
74f005ecdcSjca 		in6 = (struct sockaddr_in6 *)from;
75f005ecdcSjca 		pkt6 = (struct in6_pktinfo *)CMSG_DATA(cmsg);
76f005ecdcSjca 		pkt6->ipi6_addr = in6->sin6_addr;
77f005ecdcSjca 		break;
78f005ecdcSjca 	}
79f005ecdcSjca 
80f005ecdcSjca 	return sendmsg(s, &msg, flags);
81f005ecdcSjca }
82f005ecdcSjca 
83f005ecdcSjca ssize_t
recvfromto(int s,void * buf,size_t len,int flags,struct sockaddr * from,socklen_t * fromlen,struct sockaddr * to,socklen_t * tolen)84f005ecdcSjca recvfromto(int s, void *buf, size_t len, int flags, struct sockaddr *from,
85f005ecdcSjca     socklen_t *fromlen, struct sockaddr *to, socklen_t *tolen)
86f005ecdcSjca {
87f005ecdcSjca 	struct iovec		 iov;
88f005ecdcSjca 	struct msghdr		 msg;
89f005ecdcSjca 	struct cmsghdr		*cmsg;
90f005ecdcSjca 	struct in6_pktinfo	*pkt6;
91f005ecdcSjca 	struct sockaddr_in	*in;
92f005ecdcSjca 	struct sockaddr_in6	*in6;
93f005ecdcSjca 	ssize_t			 ret;
94f005ecdcSjca 	union {
95f005ecdcSjca 		struct cmsghdr hdr;
96f005ecdcSjca 		char	buf[CMSG_SPACE(sizeof(struct sockaddr_storage))];
97f005ecdcSjca 	} cmsgbuf;
98f005ecdcSjca 
99f005ecdcSjca 	bzero(&msg, sizeof(msg));
100f005ecdcSjca 	bzero(&cmsgbuf.buf, sizeof(cmsgbuf.buf));
101f005ecdcSjca 
102f005ecdcSjca 	iov.iov_base = buf;
103f005ecdcSjca 	iov.iov_len = len;
104f005ecdcSjca 	msg.msg_iov = &iov;
105f005ecdcSjca 	msg.msg_iovlen = 1;
106f005ecdcSjca 	msg.msg_name = from;
107f005ecdcSjca 	msg.msg_namelen = *fromlen;
108f005ecdcSjca 	msg.msg_control = &cmsgbuf.buf;
109f005ecdcSjca 	msg.msg_controllen = sizeof(cmsgbuf.buf);
110f005ecdcSjca 
111f005ecdcSjca 	if ((ret = recvmsg(s, &msg, flags)) == -1)
112f005ecdcSjca 		return (-1);
113f005ecdcSjca 
114f005ecdcSjca 	*fromlen = from->sa_len;
115f005ecdcSjca 	*tolen = 0;
116f005ecdcSjca 
117f005ecdcSjca 	if (getsockname(s, to, tolen) != 0)
118f005ecdcSjca 		*tolen = 0;
119f005ecdcSjca 
120f005ecdcSjca 	for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
121f005ecdcSjca 	    cmsg = CMSG_NXTHDR(&msg, cmsg)) {
122f005ecdcSjca 		switch (from->sa_family) {
123f005ecdcSjca 		case AF_INET:
124f005ecdcSjca 			if (cmsg->cmsg_level == IPPROTO_IP &&
125f005ecdcSjca 			    cmsg->cmsg_type == IP_RECVDSTADDR) {
126f005ecdcSjca 				in = (struct sockaddr_in *)to;
127f005ecdcSjca 				in->sin_family = AF_INET;
128f005ecdcSjca 				in->sin_len = *tolen = sizeof(*in);
129f005ecdcSjca 				memcpy(&in->sin_addr, CMSG_DATA(cmsg),
130f005ecdcSjca 				    sizeof(struct in_addr));
131f005ecdcSjca 			}
132f005ecdcSjca 			break;
133f005ecdcSjca 		case AF_INET6:
134f005ecdcSjca 			if (cmsg->cmsg_level == IPPROTO_IPV6 &&
135f005ecdcSjca 			    cmsg->cmsg_type == IPV6_PKTINFO) {
136f005ecdcSjca 				in6 = (struct sockaddr_in6 *)to;
137f005ecdcSjca 				in6->sin6_family = AF_INET6;
138f005ecdcSjca 				in6->sin6_len = *tolen = sizeof(*in6);
139f005ecdcSjca 				pkt6 = (struct in6_pktinfo *)CMSG_DATA(cmsg);
140f005ecdcSjca 				memcpy(&in6->sin6_addr, &pkt6->ipi6_addr,
141f005ecdcSjca 				    sizeof(struct in6_addr));
142f005ecdcSjca 				if (IN6_IS_ADDR_LINKLOCAL(&in6->sin6_addr))
143f005ecdcSjca 					in6->sin6_scope_id =
144f005ecdcSjca 					    pkt6->ipi6_ifindex;
145f005ecdcSjca 			}
146f005ecdcSjca 			break;
147f005ecdcSjca 		}
148f005ecdcSjca 	}
149f005ecdcSjca 
150f005ecdcSjca 	return (ret);
151f005ecdcSjca }
152f005ecdcSjca 
1532685bdaeSreyk const char *
print_host(struct sockaddr_storage * ss,char * buf,size_t len)1542685bdaeSreyk print_host(struct sockaddr_storage *ss, char *buf, size_t len)
1552685bdaeSreyk {
1562685bdaeSreyk 	if (getnameinfo((struct sockaddr *)ss, ss->ss_len,
1572685bdaeSreyk 	    buf, len, NULL, 0, NI_NUMERICHOST) != 0) {
1582685bdaeSreyk 		buf[0] = '\0';
1592685bdaeSreyk 		return (NULL);
1602685bdaeSreyk 	}
1612685bdaeSreyk 	return (buf);
1622685bdaeSreyk }
16373b5c081Smartijn 
16473b5c081Smartijn char *
tohexstr(uint8_t * bstr,int len)16573b5c081Smartijn tohexstr(uint8_t *bstr, int len)
16673b5c081Smartijn {
16773b5c081Smartijn #define MAXHEXSTRLEN		256
16873b5c081Smartijn 	static char hstr[2 * MAXHEXSTRLEN + 1];
16973b5c081Smartijn 	static const char hex[] = "0123456789abcdef";
17073b5c081Smartijn 	int i;
17173b5c081Smartijn 
17273b5c081Smartijn 	if (len > MAXHEXSTRLEN)
17373b5c081Smartijn 		len = MAXHEXSTRLEN;	/* truncate */
17473b5c081Smartijn 	for (i = 0; i < len; i++) {
17573b5c081Smartijn 		hstr[i + i] = hex[bstr[i] >> 4];
17673b5c081Smartijn 		hstr[i + i + 1] = hex[bstr[i] & 0x0f];
17773b5c081Smartijn 	}
17873b5c081Smartijn 	hstr[i + i] = '\0';
17973b5c081Smartijn 	return hstr;
18073b5c081Smartijn }
18173b5c081Smartijn 
18273b5c081Smartijn uint8_t *
fromhexstr(uint8_t * bstr,const char * hstr,size_t len)18373b5c081Smartijn fromhexstr(uint8_t *bstr, const char *hstr, size_t len)
18473b5c081Smartijn {
18573b5c081Smartijn 	size_t i;
18673b5c081Smartijn 	char hex[3];
18773b5c081Smartijn 
18873b5c081Smartijn 	if (len % 2 != 0)
18973b5c081Smartijn 		return NULL;
19073b5c081Smartijn 
19173b5c081Smartijn 	hex[2] = '\0';
19273b5c081Smartijn 	for (i = 0; i < len; i += 2) {
19373b5c081Smartijn 		if (!isxdigit(hstr[i]) || !isxdigit(hstr[i + 1]))
19473b5c081Smartijn 			return NULL;
19573b5c081Smartijn 		hex[0] = hstr[i];
19673b5c081Smartijn 		hex[1] = hstr[i + 1];
19773b5c081Smartijn 		bstr[i / 2] = strtol(hex, NULL, 16);
19873b5c081Smartijn 	}
19973b5c081Smartijn 
20073b5c081Smartijn 	return bstr;
20173b5c081Smartijn }
202