1*5e39b809Smartijn /* $OpenBSD: util.c,v 1.1.1.1 2022/09/01 14:20:33 martijn Exp $ */
2*5e39b809Smartijn /*
3*5e39b809Smartijn * Copyright (c) 2014 Bret Stephen Lambert <blambert@openbsd.org>
4*5e39b809Smartijn *
5*5e39b809Smartijn * Permission to use, copy, modify, and distribute this software for any
6*5e39b809Smartijn * purpose with or without fee is hereby granted, provided that the above
7*5e39b809Smartijn * copyright notice and this permission notice appear in all copies.
8*5e39b809Smartijn *
9*5e39b809Smartijn * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10*5e39b809Smartijn * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11*5e39b809Smartijn * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12*5e39b809Smartijn * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13*5e39b809Smartijn * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14*5e39b809Smartijn * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15*5e39b809Smartijn * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16*5e39b809Smartijn */
17*5e39b809Smartijn
18*5e39b809Smartijn #include <sys/types.h>
19*5e39b809Smartijn #include <sys/queue.h>
20*5e39b809Smartijn #include <sys/socket.h>
21*5e39b809Smartijn
22*5e39b809Smartijn #include <net/if.h>
23*5e39b809Smartijn
24*5e39b809Smartijn #include <ber.h>
25*5e39b809Smartijn #include <ctype.h>
26*5e39b809Smartijn #include <stdio.h>
27*5e39b809Smartijn #include <stdlib.h>
28*5e39b809Smartijn #include <string.h>
29*5e39b809Smartijn #include <netdb.h>
30*5e39b809Smartijn #include <event.h>
31*5e39b809Smartijn
32*5e39b809Smartijn #include "snmpd.h"
33*5e39b809Smartijn
34*5e39b809Smartijn 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*5e39b809Smartijn sendtofrom(int s, void *buf, size_t len, int flags, struct sockaddr *to,
36*5e39b809Smartijn socklen_t tolen, struct sockaddr *from, socklen_t fromlen)
37*5e39b809Smartijn {
38*5e39b809Smartijn struct iovec iov;
39*5e39b809Smartijn struct msghdr msg;
40*5e39b809Smartijn struct cmsghdr *cmsg;
41*5e39b809Smartijn struct in6_pktinfo *pkt6;
42*5e39b809Smartijn struct sockaddr_in *in;
43*5e39b809Smartijn struct sockaddr_in6 *in6;
44*5e39b809Smartijn union {
45*5e39b809Smartijn struct cmsghdr hdr;
46*5e39b809Smartijn char inbuf[CMSG_SPACE(sizeof(struct in_addr))];
47*5e39b809Smartijn char in6buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
48*5e39b809Smartijn } cmsgbuf;
49*5e39b809Smartijn
50*5e39b809Smartijn bzero(&msg, sizeof(msg));
51*5e39b809Smartijn bzero(&cmsgbuf, sizeof(cmsgbuf));
52*5e39b809Smartijn
53*5e39b809Smartijn iov.iov_base = buf;
54*5e39b809Smartijn iov.iov_len = len;
55*5e39b809Smartijn msg.msg_iov = &iov;
56*5e39b809Smartijn msg.msg_iovlen = 1;
57*5e39b809Smartijn msg.msg_name = to;
58*5e39b809Smartijn msg.msg_namelen = tolen;
59*5e39b809Smartijn msg.msg_control = &cmsgbuf;
60*5e39b809Smartijn msg.msg_controllen = sizeof(cmsgbuf);
61*5e39b809Smartijn
62*5e39b809Smartijn cmsg = CMSG_FIRSTHDR(&msg);
63*5e39b809Smartijn switch (to->sa_family) {
64*5e39b809Smartijn case AF_INET:
65*5e39b809Smartijn msg.msg_controllen = sizeof(cmsgbuf.inbuf);
66*5e39b809Smartijn cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
67*5e39b809Smartijn cmsg->cmsg_level = IPPROTO_IP;
68*5e39b809Smartijn cmsg->cmsg_type = IP_SENDSRCADDR;
69*5e39b809Smartijn in = (struct sockaddr_in *)from;
70*5e39b809Smartijn memcpy(CMSG_DATA(cmsg), &in->sin_addr, sizeof(struct in_addr));
71*5e39b809Smartijn break;
72*5e39b809Smartijn case AF_INET6:
73*5e39b809Smartijn msg.msg_controllen = sizeof(cmsgbuf.in6buf);
74*5e39b809Smartijn cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
75*5e39b809Smartijn cmsg->cmsg_level = IPPROTO_IPV6;
76*5e39b809Smartijn cmsg->cmsg_type = IPV6_PKTINFO;
77*5e39b809Smartijn in6 = (struct sockaddr_in6 *)from;
78*5e39b809Smartijn pkt6 = (struct in6_pktinfo *)CMSG_DATA(cmsg);
79*5e39b809Smartijn pkt6->ipi6_addr = in6->sin6_addr;
80*5e39b809Smartijn break;
81*5e39b809Smartijn }
82*5e39b809Smartijn
83*5e39b809Smartijn return sendmsg(s, &msg, flags);
84*5e39b809Smartijn }
85*5e39b809Smartijn
86*5e39b809Smartijn 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*5e39b809Smartijn recvfromto(int s, void *buf, size_t len, int flags, struct sockaddr *from,
88*5e39b809Smartijn socklen_t *fromlen, struct sockaddr *to, socklen_t *tolen)
89*5e39b809Smartijn {
90*5e39b809Smartijn struct iovec iov;
91*5e39b809Smartijn struct msghdr msg;
92*5e39b809Smartijn struct cmsghdr *cmsg;
93*5e39b809Smartijn struct in6_pktinfo *pkt6;
94*5e39b809Smartijn struct sockaddr_in *in;
95*5e39b809Smartijn struct sockaddr_in6 *in6;
96*5e39b809Smartijn ssize_t ret;
97*5e39b809Smartijn union {
98*5e39b809Smartijn struct cmsghdr hdr;
99*5e39b809Smartijn char buf[CMSG_SPACE(sizeof(struct sockaddr_storage))];
100*5e39b809Smartijn } cmsgbuf;
101*5e39b809Smartijn
102*5e39b809Smartijn bzero(&msg, sizeof(msg));
103*5e39b809Smartijn bzero(&cmsgbuf.buf, sizeof(cmsgbuf.buf));
104*5e39b809Smartijn
105*5e39b809Smartijn iov.iov_base = buf;
106*5e39b809Smartijn iov.iov_len = len;
107*5e39b809Smartijn msg.msg_iov = &iov;
108*5e39b809Smartijn msg.msg_iovlen = 1;
109*5e39b809Smartijn msg.msg_name = from;
110*5e39b809Smartijn msg.msg_namelen = *fromlen;
111*5e39b809Smartijn msg.msg_control = &cmsgbuf.buf;
112*5e39b809Smartijn msg.msg_controllen = sizeof(cmsgbuf.buf);
113*5e39b809Smartijn
114*5e39b809Smartijn if ((ret = recvmsg(s, &msg, flags)) == -1)
115*5e39b809Smartijn return (-1);
116*5e39b809Smartijn
117*5e39b809Smartijn *fromlen = from->sa_len;
118*5e39b809Smartijn *tolen = 0;
119*5e39b809Smartijn
120*5e39b809Smartijn if (getsockname(s, to, tolen) != 0)
121*5e39b809Smartijn *tolen = 0;
122*5e39b809Smartijn
123*5e39b809Smartijn for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
124*5e39b809Smartijn cmsg = CMSG_NXTHDR(&msg, cmsg)) {
125*5e39b809Smartijn switch (from->sa_family) {
126*5e39b809Smartijn case AF_INET:
127*5e39b809Smartijn if (cmsg->cmsg_level == IPPROTO_IP &&
128*5e39b809Smartijn cmsg->cmsg_type == IP_RECVDSTADDR) {
129*5e39b809Smartijn in = (struct sockaddr_in *)to;
130*5e39b809Smartijn in->sin_family = AF_INET;
131*5e39b809Smartijn in->sin_len = *tolen = sizeof(*in);
132*5e39b809Smartijn memcpy(&in->sin_addr, CMSG_DATA(cmsg),
133*5e39b809Smartijn sizeof(struct in_addr));
134*5e39b809Smartijn }
135*5e39b809Smartijn break;
136*5e39b809Smartijn case AF_INET6:
137*5e39b809Smartijn if (cmsg->cmsg_level == IPPROTO_IPV6 &&
138*5e39b809Smartijn cmsg->cmsg_type == IPV6_PKTINFO) {
139*5e39b809Smartijn in6 = (struct sockaddr_in6 *)to;
140*5e39b809Smartijn in6->sin6_family = AF_INET6;
141*5e39b809Smartijn in6->sin6_len = *tolen = sizeof(*in6);
142*5e39b809Smartijn pkt6 = (struct in6_pktinfo *)CMSG_DATA(cmsg);
143*5e39b809Smartijn memcpy(&in6->sin6_addr, &pkt6->ipi6_addr,
144*5e39b809Smartijn sizeof(struct in6_addr));
145*5e39b809Smartijn if (IN6_IS_ADDR_LINKLOCAL(&in6->sin6_addr))
146*5e39b809Smartijn in6->sin6_scope_id =
147*5e39b809Smartijn pkt6->ipi6_ifindex;
148*5e39b809Smartijn }
149*5e39b809Smartijn break;
150*5e39b809Smartijn }
151*5e39b809Smartijn }
152*5e39b809Smartijn
153*5e39b809Smartijn return (ret);
154*5e39b809Smartijn }
155*5e39b809Smartijn
156*5e39b809Smartijn const char *
log_in6addr(const struct in6_addr * addr)157*5e39b809Smartijn log_in6addr(const struct in6_addr *addr)
158*5e39b809Smartijn {
159*5e39b809Smartijn static char buf[NI_MAXHOST];
160*5e39b809Smartijn struct sockaddr_in6 sa_in6;
161*5e39b809Smartijn u_int16_t tmp16;
162*5e39b809Smartijn
163*5e39b809Smartijn bzero(&sa_in6, sizeof(sa_in6));
164*5e39b809Smartijn sa_in6.sin6_len = sizeof(sa_in6);
165*5e39b809Smartijn sa_in6.sin6_family = AF_INET6;
166*5e39b809Smartijn memcpy(&sa_in6.sin6_addr, addr, sizeof(sa_in6.sin6_addr));
167*5e39b809Smartijn
168*5e39b809Smartijn /* XXX thanks, KAME, for this ugliness... adopted from route/show.c */
169*5e39b809Smartijn if (IN6_IS_ADDR_LINKLOCAL(&sa_in6.sin6_addr) ||
170*5e39b809Smartijn IN6_IS_ADDR_MC_LINKLOCAL(&sa_in6.sin6_addr)) {
171*5e39b809Smartijn memcpy(&tmp16, &sa_in6.sin6_addr.s6_addr[2], sizeof(tmp16));
172*5e39b809Smartijn sa_in6.sin6_scope_id = ntohs(tmp16);
173*5e39b809Smartijn sa_in6.sin6_addr.s6_addr[2] = 0;
174*5e39b809Smartijn sa_in6.sin6_addr.s6_addr[3] = 0;
175*5e39b809Smartijn }
176*5e39b809Smartijn
177*5e39b809Smartijn return (print_host((struct sockaddr_storage *)&sa_in6, buf,
178*5e39b809Smartijn NI_MAXHOST));
179*5e39b809Smartijn }
180*5e39b809Smartijn
181*5e39b809Smartijn const char *
print_host(struct sockaddr_storage * ss,char * buf,size_t len)182*5e39b809Smartijn print_host(struct sockaddr_storage *ss, char *buf, size_t len)
183*5e39b809Smartijn {
184*5e39b809Smartijn if (getnameinfo((struct sockaddr *)ss, ss->ss_len,
185*5e39b809Smartijn buf, len, NULL, 0, NI_NUMERICHOST) != 0) {
186*5e39b809Smartijn buf[0] = '\0';
187*5e39b809Smartijn return (NULL);
188*5e39b809Smartijn }
189*5e39b809Smartijn return (buf);
190*5e39b809Smartijn }
191*5e39b809Smartijn
192*5e39b809Smartijn char *
tohexstr(uint8_t * bstr,int len)193*5e39b809Smartijn tohexstr(uint8_t *bstr, int len)
194*5e39b809Smartijn {
195*5e39b809Smartijn #define MAXHEXSTRLEN 256
196*5e39b809Smartijn static char hstr[2 * MAXHEXSTRLEN + 1];
197*5e39b809Smartijn static const char hex[] = "0123456789abcdef";
198*5e39b809Smartijn int i;
199*5e39b809Smartijn
200*5e39b809Smartijn if (len > MAXHEXSTRLEN)
201*5e39b809Smartijn len = MAXHEXSTRLEN; /* truncate */
202*5e39b809Smartijn for (i = 0; i < len; i++) {
203*5e39b809Smartijn hstr[i + i] = hex[bstr[i] >> 4];
204*5e39b809Smartijn hstr[i + i + 1] = hex[bstr[i] & 0x0f];
205*5e39b809Smartijn }
206*5e39b809Smartijn hstr[i + i] = '\0';
207*5e39b809Smartijn return hstr;
208*5e39b809Smartijn }
209*5e39b809Smartijn
210*5e39b809Smartijn uint8_t *
fromhexstr(uint8_t * bstr,const char * hstr,size_t len)211*5e39b809Smartijn fromhexstr(uint8_t *bstr, const char *hstr, size_t len)
212*5e39b809Smartijn {
213*5e39b809Smartijn size_t i;
214*5e39b809Smartijn char hex[3];
215*5e39b809Smartijn
216*5e39b809Smartijn if (len % 2 != 0)
217*5e39b809Smartijn return NULL;
218*5e39b809Smartijn
219*5e39b809Smartijn hex[2] = '\0';
220*5e39b809Smartijn for (i = 0; i < len; i += 2) {
221*5e39b809Smartijn if (!isxdigit(hstr[i]) || !isxdigit(hstr[i + 1]))
222*5e39b809Smartijn return NULL;
223*5e39b809Smartijn hex[0] = hstr[i];
224*5e39b809Smartijn hex[1] = hstr[i + 1];
225*5e39b809Smartijn bstr[i / 2] = strtol(hex, NULL, 16);
226*5e39b809Smartijn }
227*5e39b809Smartijn
228*5e39b809Smartijn return bstr;
229*5e39b809Smartijn }
230