xref: /openbsd-src/libexec/snmpd/snmpd_metrics/util.c (revision 5e39b8099378bf76b55ebe1b7ea3a033c86608c7)
1 /*	$OpenBSD: util.c,v 1.1.1.1 2022/09/01 14:20:33 martijn 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 <ber.h>
25 #include <ctype.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <netdb.h>
30 #include <event.h>
31 
32 #include "snmpd.h"
33 
34 ssize_t
sendtofrom(int s,void * buf,size_t len,int flags,struct sockaddr * to,socklen_t tolen,struct sockaddr * from,socklen_t fromlen)35 sendtofrom(int s, void *buf, size_t len, int flags, struct sockaddr *to,
36     socklen_t tolen, struct sockaddr *from, socklen_t fromlen)
37 {
38 	struct iovec		 iov;
39 	struct msghdr		 msg;
40 	struct cmsghdr		*cmsg;
41 	struct in6_pktinfo	*pkt6;
42 	struct sockaddr_in	*in;
43 	struct sockaddr_in6	*in6;
44 	union {
45 		struct cmsghdr	hdr;
46 		char		inbuf[CMSG_SPACE(sizeof(struct in_addr))];
47 		char		in6buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
48 	} cmsgbuf;
49 
50 	bzero(&msg, sizeof(msg));
51 	bzero(&cmsgbuf, sizeof(cmsgbuf));
52 
53 	iov.iov_base = buf;
54 	iov.iov_len = len;
55 	msg.msg_iov = &iov;
56 	msg.msg_iovlen = 1;
57 	msg.msg_name = to;
58 	msg.msg_namelen = tolen;
59 	msg.msg_control = &cmsgbuf;
60 	msg.msg_controllen = sizeof(cmsgbuf);
61 
62 	cmsg = CMSG_FIRSTHDR(&msg);
63 	switch (to->sa_family) {
64 	case AF_INET:
65 		msg.msg_controllen = sizeof(cmsgbuf.inbuf);
66 		cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
67 		cmsg->cmsg_level = IPPROTO_IP;
68 		cmsg->cmsg_type = IP_SENDSRCADDR;
69 		in = (struct sockaddr_in *)from;
70 		memcpy(CMSG_DATA(cmsg), &in->sin_addr, sizeof(struct in_addr));
71 		break;
72 	case AF_INET6:
73 		msg.msg_controllen = sizeof(cmsgbuf.in6buf);
74 		cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
75 		cmsg->cmsg_level = IPPROTO_IPV6;
76 		cmsg->cmsg_type = IPV6_PKTINFO;
77 		in6 = (struct sockaddr_in6 *)from;
78 		pkt6 = (struct in6_pktinfo *)CMSG_DATA(cmsg);
79 		pkt6->ipi6_addr = in6->sin6_addr;
80 		break;
81 	}
82 
83 	return sendmsg(s, &msg, flags);
84 }
85 
86 ssize_t
recvfromto(int s,void * buf,size_t len,int flags,struct sockaddr * from,socklen_t * fromlen,struct sockaddr * to,socklen_t * tolen)87 recvfromto(int s, void *buf, size_t len, int flags, struct sockaddr *from,
88     socklen_t *fromlen, struct sockaddr *to, socklen_t *tolen)
89 {
90 	struct iovec		 iov;
91 	struct msghdr		 msg;
92 	struct cmsghdr		*cmsg;
93 	struct in6_pktinfo	*pkt6;
94 	struct sockaddr_in	*in;
95 	struct sockaddr_in6	*in6;
96 	ssize_t			 ret;
97 	union {
98 		struct cmsghdr hdr;
99 		char	buf[CMSG_SPACE(sizeof(struct sockaddr_storage))];
100 	} cmsgbuf;
101 
102 	bzero(&msg, sizeof(msg));
103 	bzero(&cmsgbuf.buf, sizeof(cmsgbuf.buf));
104 
105 	iov.iov_base = buf;
106 	iov.iov_len = len;
107 	msg.msg_iov = &iov;
108 	msg.msg_iovlen = 1;
109 	msg.msg_name = from;
110 	msg.msg_namelen = *fromlen;
111 	msg.msg_control = &cmsgbuf.buf;
112 	msg.msg_controllen = sizeof(cmsgbuf.buf);
113 
114 	if ((ret = recvmsg(s, &msg, flags)) == -1)
115 		return (-1);
116 
117 	*fromlen = from->sa_len;
118 	*tolen = 0;
119 
120 	if (getsockname(s, to, tolen) != 0)
121 		*tolen = 0;
122 
123 	for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
124 	    cmsg = CMSG_NXTHDR(&msg, cmsg)) {
125 		switch (from->sa_family) {
126 		case AF_INET:
127 			if (cmsg->cmsg_level == IPPROTO_IP &&
128 			    cmsg->cmsg_type == IP_RECVDSTADDR) {
129 				in = (struct sockaddr_in *)to;
130 				in->sin_family = AF_INET;
131 				in->sin_len = *tolen = sizeof(*in);
132 				memcpy(&in->sin_addr, CMSG_DATA(cmsg),
133 				    sizeof(struct in_addr));
134 			}
135 			break;
136 		case AF_INET6:
137 			if (cmsg->cmsg_level == IPPROTO_IPV6 &&
138 			    cmsg->cmsg_type == IPV6_PKTINFO) {
139 				in6 = (struct sockaddr_in6 *)to;
140 				in6->sin6_family = AF_INET6;
141 				in6->sin6_len = *tolen = sizeof(*in6);
142 				pkt6 = (struct in6_pktinfo *)CMSG_DATA(cmsg);
143 				memcpy(&in6->sin6_addr, &pkt6->ipi6_addr,
144 				    sizeof(struct in6_addr));
145 				if (IN6_IS_ADDR_LINKLOCAL(&in6->sin6_addr))
146 					in6->sin6_scope_id =
147 					    pkt6->ipi6_ifindex;
148 			}
149 			break;
150 		}
151 	}
152 
153 	return (ret);
154 }
155 
156 const char *
log_in6addr(const struct in6_addr * addr)157 log_in6addr(const struct in6_addr *addr)
158 {
159 	static char		buf[NI_MAXHOST];
160 	struct sockaddr_in6	sa_in6;
161 	u_int16_t		tmp16;
162 
163 	bzero(&sa_in6, sizeof(sa_in6));
164 	sa_in6.sin6_len = sizeof(sa_in6);
165 	sa_in6.sin6_family = AF_INET6;
166 	memcpy(&sa_in6.sin6_addr, addr, sizeof(sa_in6.sin6_addr));
167 
168 	/* XXX thanks, KAME, for this ugliness... adopted from route/show.c */
169 	if (IN6_IS_ADDR_LINKLOCAL(&sa_in6.sin6_addr) ||
170 	    IN6_IS_ADDR_MC_LINKLOCAL(&sa_in6.sin6_addr)) {
171 		memcpy(&tmp16, &sa_in6.sin6_addr.s6_addr[2], sizeof(tmp16));
172 		sa_in6.sin6_scope_id = ntohs(tmp16);
173 		sa_in6.sin6_addr.s6_addr[2] = 0;
174 		sa_in6.sin6_addr.s6_addr[3] = 0;
175 	}
176 
177 	return (print_host((struct sockaddr_storage *)&sa_in6, buf,
178 	    NI_MAXHOST));
179 }
180 
181 const char *
print_host(struct sockaddr_storage * ss,char * buf,size_t len)182 print_host(struct sockaddr_storage *ss, char *buf, size_t len)
183 {
184 	if (getnameinfo((struct sockaddr *)ss, ss->ss_len,
185 	    buf, len, NULL, 0, NI_NUMERICHOST) != 0) {
186 		buf[0] = '\0';
187 		return (NULL);
188 	}
189 	return (buf);
190 }
191 
192 char *
tohexstr(uint8_t * bstr,int len)193 tohexstr(uint8_t *bstr, int len)
194 {
195 #define MAXHEXSTRLEN		256
196 	static char hstr[2 * MAXHEXSTRLEN + 1];
197 	static const char hex[] = "0123456789abcdef";
198 	int i;
199 
200 	if (len > MAXHEXSTRLEN)
201 		len = MAXHEXSTRLEN;	/* truncate */
202 	for (i = 0; i < len; i++) {
203 		hstr[i + i] = hex[bstr[i] >> 4];
204 		hstr[i + i + 1] = hex[bstr[i] & 0x0f];
205 	}
206 	hstr[i + i] = '\0';
207 	return hstr;
208 }
209 
210 uint8_t *
fromhexstr(uint8_t * bstr,const char * hstr,size_t len)211 fromhexstr(uint8_t *bstr, const char *hstr, size_t len)
212 {
213 	size_t i;
214 	char hex[3];
215 
216 	if (len % 2 != 0)
217 		return NULL;
218 
219 	hex[2] = '\0';
220 	for (i = 0; i < len; i += 2) {
221 		if (!isxdigit(hstr[i]) || !isxdigit(hstr[i + 1]))
222 			return NULL;
223 		hex[0] = hstr[i];
224 		hex[1] = hstr[i + 1];
225 		bstr[i / 2] = strtol(hex, NULL, 16);
226 	}
227 
228 	return bstr;
229 }
230