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