/src/openiked-portable/iked/util.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* $OpenBSD: util.c,v 1.43 2023/07/28 11:23:03 claudio Exp $ */ |
2 | | |
3 | | /* |
4 | | * Copyright (c) 2021 Tobias Heider <tobhe@openbsd.org> |
5 | | * Copyright (c) 2010-2013 Reyk Floeter <reyk@openbsd.org> |
6 | | * |
7 | | * Permission to use, copy, modify, and distribute this software for any |
8 | | * purpose with or without fee is hereby granted, provided that the above |
9 | | * copyright notice and this permission notice appear in all copies. |
10 | | * |
11 | | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
12 | | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
13 | | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
14 | | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
15 | | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
16 | | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
17 | | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
18 | | */ |
19 | | |
20 | | #include <sys/types.h> |
21 | | #include <sys/queue.h> |
22 | | #include <sys/socket.h> |
23 | | #include <sys/uio.h> |
24 | | |
25 | | #include <netinet/in.h> |
26 | | #include <netinet/ip_ipsp.h> |
27 | | |
28 | | #include <netdb.h> |
29 | | #include <stdio.h> |
30 | | #include <stdlib.h> |
31 | | #include <unistd.h> |
32 | | #include <string.h> |
33 | | #include <errno.h> |
34 | | #include <limits.h> |
35 | | #include <fcntl.h> |
36 | | #include <ctype.h> |
37 | | #include <event.h> |
38 | | |
39 | | #include "iked.h" |
40 | | #include "ikev2.h" |
41 | | |
42 | | int |
43 | | socket_af(struct sockaddr *sa, in_port_t port) |
44 | 0 | { |
45 | 0 | errno = 0; |
46 | 0 | switch (sa->sa_family) { |
47 | 0 | case AF_INET: |
48 | 0 | ((struct sockaddr_in *)sa)->sin_port = port; |
49 | | #ifdef HAVE_SOCKADDR_SA_LEN |
50 | | ((struct sockaddr_in *)sa)->sin_len = |
51 | | sizeof(struct sockaddr_in); |
52 | | #endif |
53 | 0 | break; |
54 | 0 | case AF_INET6: |
55 | 0 | ((struct sockaddr_in6 *)sa)->sin6_port = port; |
56 | | #ifdef HAVE_SOCKADDR_SA_LEN |
57 | | ((struct sockaddr_in6 *)sa)->sin6_len = |
58 | | sizeof(struct sockaddr_in6); |
59 | | #endif |
60 | 0 | break; |
61 | 0 | default: |
62 | 0 | errno = EPFNOSUPPORT; |
63 | 0 | return (-1); |
64 | 0 | } |
65 | | |
66 | 0 | return (0); |
67 | 0 | } |
68 | | |
69 | | in_port_t |
70 | | socket_getport(struct sockaddr *sa) |
71 | 20.1k | { |
72 | 20.1k | switch (sa->sa_family) { |
73 | 17.4k | case AF_INET: |
74 | 17.4k | return (ntohs(((struct sockaddr_in *)sa)->sin_port)); |
75 | 2.68k | case AF_INET6: |
76 | 2.68k | return (ntohs(((struct sockaddr_in6 *)sa)->sin6_port)); |
77 | 0 | default: |
78 | 0 | return (0); |
79 | 20.1k | } |
80 | | |
81 | | /* NOTREACHED */ |
82 | 0 | return (0); |
83 | 20.1k | } |
84 | | |
85 | | int |
86 | | socket_setport(struct sockaddr *sa, in_port_t port) |
87 | 0 | { |
88 | 0 | switch (sa->sa_family) { |
89 | 0 | case AF_INET: |
90 | 0 | ((struct sockaddr_in *)sa)->sin_port = htons(port); |
91 | 0 | break; |
92 | 0 | case AF_INET6: |
93 | 0 | ((struct sockaddr_in6 *)sa)->sin6_port = htons(port); |
94 | 0 | break; |
95 | 0 | default: |
96 | 0 | return (-1); |
97 | 0 | } |
98 | 0 | return (0); |
99 | 0 | } |
100 | | |
101 | | int |
102 | | socket_getaddr(int s, struct sockaddr_storage *ss) |
103 | 0 | { |
104 | 0 | socklen_t sslen = sizeof(*ss); |
105 | |
|
106 | 0 | return (getsockname(s, (struct sockaddr *)ss, &sslen)); |
107 | 0 | } |
108 | | |
109 | | int |
110 | | socket_bypass(int s, struct sockaddr *sa) |
111 | 0 | { |
112 | | #if defined(__OpenBSD__) |
113 | | int v, *a; |
114 | | int a4[] = { |
115 | | IPPROTO_IP, |
116 | | IP_AUTH_LEVEL, |
117 | | IP_ESP_TRANS_LEVEL, |
118 | | IP_ESP_NETWORK_LEVEL, |
119 | | #ifdef IPV6_IPCOMP_LEVEL |
120 | | IP_IPCOMP_LEVEL |
121 | | #endif |
122 | | }; |
123 | | int a6[] = { |
124 | | IPPROTO_IPV6, |
125 | | IPV6_AUTH_LEVEL, |
126 | | IPV6_ESP_TRANS_LEVEL, |
127 | | IPV6_ESP_NETWORK_LEVEL, |
128 | | #ifdef IPV6_IPCOMP_LEVEL |
129 | | IPV6_IPCOMP_LEVEL |
130 | | #endif |
131 | | }; |
132 | | |
133 | | switch (sa->sa_family) { |
134 | | case AF_INET: |
135 | | a = a4; |
136 | | break; |
137 | | case AF_INET6: |
138 | | a = a6; |
139 | | break; |
140 | | default: |
141 | | log_warn("%s: invalid address family", __func__); |
142 | | return (-1); |
143 | | } |
144 | | |
145 | | v = IPSEC_LEVEL_BYPASS; |
146 | | if (setsockopt(s, a[0], a[1], &v, sizeof(v)) == -1) { |
147 | | log_warn("%s: AUTH_LEVEL", __func__); |
148 | | return (-1); |
149 | | } |
150 | | if (setsockopt(s, a[0], a[2], &v, sizeof(v)) == -1) { |
151 | | log_warn("%s: ESP_TRANS_LEVEL", __func__); |
152 | | return (-1); |
153 | | } |
154 | | if (setsockopt(s, a[0], a[3], &v, sizeof(v)) == -1) { |
155 | | log_warn("%s: ESP_NETWORK_LEVEL", __func__); |
156 | | return (-1); |
157 | | } |
158 | | #ifdef IP_IPCOMP_LEVEL |
159 | | if (setsockopt(s, a[0], a[4], &v, sizeof(v)) == -1) { |
160 | | log_warn("%s: IPCOMP_LEVEL", __func__); |
161 | | return (-1); |
162 | | } |
163 | | #endif |
164 | | #else /* __OpenBSD__ */ |
165 | 0 | int *a; |
166 | 0 | int a4[] = { |
167 | 0 | IPPROTO_IP, |
168 | 0 | IP_IPSEC_POLICY |
169 | 0 | }; |
170 | 0 | int a6[] = { |
171 | 0 | IPPROTO_IPV6, |
172 | 0 | IPV6_IPSEC_POLICY, |
173 | 0 | }; |
174 | 0 | struct sadb_x_policy pol = { |
175 | 0 | SADB_UPDATE, |
176 | 0 | SADB_EXT_SENSITIVITY, |
177 | 0 | IPSEC_POLICY_BYPASS, |
178 | 0 | 0, 0, 0, 0 |
179 | 0 | }; |
180 | |
|
181 | 0 | switch (sa->sa_family) { |
182 | 0 | case AF_INET: |
183 | 0 | a = a4; |
184 | 0 | break; |
185 | 0 | case AF_INET6: |
186 | 0 | a = a6; |
187 | 0 | break; |
188 | 0 | default: |
189 | 0 | log_warn("%s: invalid address family", __func__); |
190 | 0 | return (-1); |
191 | 0 | } |
192 | | |
193 | 0 | pol.sadb_x_policy_dir = IPSEC_DIR_INBOUND; |
194 | 0 | if (setsockopt(s, a[0], a[1], &pol, sizeof(pol)) == -1) { |
195 | 0 | log_warn("%s: IPSEC_DIR_INBOUND", __func__); |
196 | 0 | return (-1); |
197 | 0 | } |
198 | 0 | pol.sadb_x_policy_dir = IPSEC_DIR_OUTBOUND; |
199 | 0 | if (setsockopt(s, a[0], a[1], &pol, sizeof(pol)) == -1) { |
200 | 0 | log_warn("%s: IPSEC_DIR_OUTBOUND", __func__); |
201 | 0 | return (-1); |
202 | 0 | } |
203 | 0 | #endif /* !__OpenBSD__ */ |
204 | | |
205 | 0 | return (0); |
206 | 0 | } |
207 | | |
208 | | int |
209 | | udp_bind(struct sockaddr *sa, in_port_t port) |
210 | 0 | { |
211 | 0 | int s, val; |
212 | |
|
213 | 0 | if (socket_af(sa, port) == -1) { |
214 | 0 | log_warn("%s: failed to set UDP port", __func__); |
215 | 0 | return (-1); |
216 | 0 | } |
217 | | |
218 | 0 | if ((s = socket(sa->sa_family, |
219 | 0 | SOCK_DGRAM | SOCK_NONBLOCK, IPPROTO_UDP)) == -1) { |
220 | 0 | log_warn("%s: failed to get UDP socket", __func__); |
221 | 0 | return (-1); |
222 | 0 | } |
223 | | |
224 | | /* Skip IPsec processing (don't encrypt) for IKE messages */ |
225 | 0 | if (socket_bypass(s, sa) == -1) { |
226 | 0 | log_warn("%s: failed to bypass IPsec on IKE socket", |
227 | 0 | __func__); |
228 | 0 | goto bad; |
229 | 0 | } |
230 | | |
231 | 0 | val = 1; |
232 | 0 | if (setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &val, sizeof(int)) == -1) { |
233 | 0 | log_warn("%s: failed to set reuseport", __func__); |
234 | 0 | goto bad; |
235 | 0 | } |
236 | 0 | val = 1; |
237 | 0 | if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(int)) == -1) { |
238 | 0 | log_warn("%s: failed to set reuseaddr", __func__); |
239 | 0 | goto bad; |
240 | 0 | } |
241 | | |
242 | 0 | if (sa->sa_family == AF_INET) { |
243 | 0 | #if defined(IP_RECVORIGDSTADDR) |
244 | 0 | val = 1; |
245 | 0 | if (setsockopt(s, IPPROTO_IP, IP_RECVORIGDSTADDR, |
246 | 0 | &val, sizeof(int)) == -1) { |
247 | 0 | log_warn("%s: failed to set IPv4 packet info", |
248 | 0 | __func__); |
249 | 0 | goto bad; |
250 | 0 | } |
251 | | #elif defined(IP_RECVDSTADDR) |
252 | | val = 1; |
253 | | if (setsockopt(s, IPPROTO_IP, IP_RECVDSTADDR, |
254 | | &val, sizeof(int)) == -1) { |
255 | | log_warn("%s: failed to set IPv4 packet info", |
256 | | __func__); |
257 | | goto bad; |
258 | | } |
259 | | #endif |
260 | 0 | } else { |
261 | 0 | #ifdef IPV6_RECVPKTINFO |
262 | 0 | val = 1; |
263 | 0 | if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO, |
264 | 0 | &val, sizeof(int)) == -1) { |
265 | 0 | log_warn("%s: failed to set IPv6 packet info", |
266 | 0 | __func__); |
267 | 0 | goto bad; |
268 | 0 | } |
269 | 0 | #endif |
270 | 0 | } |
271 | | |
272 | 0 | if (bind(s, sa, SA_LEN(sa)) == -1) { |
273 | 0 | log_warn("%s: failed to bind UDP socket", __func__); |
274 | 0 | goto bad; |
275 | 0 | } |
276 | | |
277 | 0 | return (s); |
278 | 0 | bad: |
279 | 0 | close(s); |
280 | 0 | return (-1); |
281 | 0 | } |
282 | | |
283 | | int |
284 | | sockaddr_cmp(struct sockaddr *a, struct sockaddr *b, int prefixlen) |
285 | 0 | { |
286 | 0 | struct sockaddr_in *a4, *b4; |
287 | 0 | struct sockaddr_in6 *a6, *b6; |
288 | 0 | uint32_t av[4], bv[4], mv[4]; |
289 | |
|
290 | 0 | if (a->sa_family == AF_UNSPEC || b->sa_family == AF_UNSPEC) |
291 | 0 | return (0); |
292 | 0 | else if (a->sa_family > b->sa_family) |
293 | 0 | return (1); |
294 | 0 | else if (a->sa_family < b->sa_family) |
295 | 0 | return (-1); |
296 | | |
297 | 0 | if (prefixlen == -1) |
298 | 0 | memset(&mv, 0xff, sizeof(mv)); |
299 | |
|
300 | 0 | switch (a->sa_family) { |
301 | 0 | case AF_INET: |
302 | 0 | a4 = (struct sockaddr_in *)a; |
303 | 0 | b4 = (struct sockaddr_in *)b; |
304 | |
|
305 | 0 | av[0] = a4->sin_addr.s_addr; |
306 | 0 | bv[0] = b4->sin_addr.s_addr; |
307 | 0 | if (prefixlen != -1) |
308 | 0 | mv[0] = prefixlen2mask(prefixlen); |
309 | |
|
310 | 0 | if ((av[0] & mv[0]) > (bv[0] & mv[0])) |
311 | 0 | return (1); |
312 | 0 | if ((av[0] & mv[0]) < (bv[0] & mv[0])) |
313 | 0 | return (-1); |
314 | 0 | break; |
315 | 0 | case AF_INET6: |
316 | 0 | a6 = (struct sockaddr_in6 *)a; |
317 | 0 | b6 = (struct sockaddr_in6 *)b; |
318 | |
|
319 | 0 | memcpy(&av, &a6->sin6_addr.s6_addr, 16); |
320 | 0 | memcpy(&bv, &b6->sin6_addr.s6_addr, 16); |
321 | 0 | if (prefixlen != -1) |
322 | 0 | prefixlen2mask6(prefixlen, mv); |
323 | |
|
324 | 0 | if ((av[3] & mv[3]) > (bv[3] & mv[3])) |
325 | 0 | return (1); |
326 | 0 | if ((av[3] & mv[3]) < (bv[3] & mv[3])) |
327 | 0 | return (-1); |
328 | 0 | if ((av[2] & mv[2]) > (bv[2] & mv[2])) |
329 | 0 | return (1); |
330 | 0 | if ((av[2] & mv[2]) < (bv[2] & mv[2])) |
331 | 0 | return (-1); |
332 | 0 | if ((av[1] & mv[1]) > (bv[1] & mv[1])) |
333 | 0 | return (1); |
334 | 0 | if ((av[1] & mv[1]) < (bv[1] & mv[1])) |
335 | 0 | return (-1); |
336 | 0 | if ((av[0] & mv[0]) > (bv[0] & mv[0])) |
337 | 0 | return (1); |
338 | 0 | if ((av[0] & mv[0]) < (bv[0] & mv[0])) |
339 | 0 | return (-1); |
340 | 0 | break; |
341 | 0 | } |
342 | | |
343 | 0 | return (0); |
344 | 0 | } |
345 | | |
346 | | ssize_t |
347 | | sendtofrom(int s, void *buf, size_t len, int flags, struct sockaddr *to, |
348 | | socklen_t tolen, struct sockaddr *from, socklen_t fromlen) |
349 | 0 | { |
350 | 0 | struct iovec iov; |
351 | 0 | struct msghdr msg; |
352 | 0 | struct cmsghdr *cmsg; |
353 | | #ifdef IP_SENDSRCADDR |
354 | | struct sockaddr_in *in; |
355 | | #endif |
356 | 0 | #ifdef IPV6_PKTINFO |
357 | 0 | struct in6_pktinfo *pkt6; |
358 | 0 | struct sockaddr_in6 *in6; |
359 | 0 | #endif |
360 | 0 | union { |
361 | 0 | struct cmsghdr hdr; |
362 | 0 | char inbuf[CMSG_SPACE(sizeof(struct in_addr))]; |
363 | 0 | char in6buf[CMSG_SPACE(sizeof(struct in6_pktinfo))]; |
364 | 0 | } cmsgbuf; |
365 | |
|
366 | 0 | bzero(&msg, sizeof(msg)); |
367 | 0 | bzero(&cmsgbuf, sizeof(cmsgbuf)); |
368 | |
|
369 | 0 | iov.iov_base = buf; |
370 | 0 | iov.iov_len = len; |
371 | 0 | msg.msg_iov = &iov; |
372 | 0 | msg.msg_iovlen = 1; |
373 | 0 | msg.msg_name = to; |
374 | 0 | msg.msg_namelen = tolen; |
375 | 0 | msg.msg_controllen = 0; |
376 | |
|
377 | 0 | switch (to->sa_family) { |
378 | 0 | case AF_INET: |
379 | | #ifdef IP_SENDSRCADDR |
380 | | in = (struct sockaddr_in *)from; |
381 | | if (in->sin_addr.s_addr == INADDR_ANY) |
382 | | break; |
383 | | msg.msg_control = &cmsgbuf; |
384 | | msg.msg_controllen += sizeof(cmsgbuf.inbuf); |
385 | | cmsg = CMSG_FIRSTHDR(&msg); |
386 | | cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr)); |
387 | | cmsg->cmsg_level = IPPROTO_IP; |
388 | | cmsg->cmsg_type = IP_SENDSRCADDR; |
389 | | memcpy(CMSG_DATA(cmsg), &in->sin_addr, sizeof(struct in_addr)); |
390 | | #endif |
391 | 0 | break; |
392 | 0 | case AF_INET6: |
393 | 0 | #ifdef IPV6_PKTINFO |
394 | 0 | msg.msg_control = &cmsgbuf; |
395 | 0 | msg.msg_controllen += sizeof(cmsgbuf.in6buf); |
396 | 0 | cmsg = CMSG_FIRSTHDR(&msg); |
397 | 0 | cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); |
398 | 0 | cmsg->cmsg_level = IPPROTO_IPV6; |
399 | 0 | cmsg->cmsg_type = IPV6_PKTINFO; |
400 | 0 | in6 = (struct sockaddr_in6 *)from; |
401 | 0 | pkt6 = (struct in6_pktinfo *)CMSG_DATA(cmsg); |
402 | 0 | pkt6->ipi6_addr = in6->sin6_addr; |
403 | 0 | #endif |
404 | 0 | break; |
405 | 0 | } |
406 | | |
407 | 0 | return sendmsg(s, &msg, flags); |
408 | 0 | } |
409 | | |
410 | | ssize_t |
411 | | recvfromto(int s, void *buf, size_t len, int flags, struct sockaddr *from, |
412 | | socklen_t *fromlen, struct sockaddr *to, socklen_t *tolen) |
413 | 0 | { |
414 | 0 | struct iovec iov; |
415 | 0 | struct msghdr msg; |
416 | 0 | struct cmsghdr *cmsg; |
417 | | #if !defined(IP_RECVORIGDSTADDR) && defined(IP_RECVDSTADDR) |
418 | | struct sockaddr_in *in; |
419 | | #endif |
420 | 0 | #ifdef IPV6_PKTINFO |
421 | 0 | struct in6_pktinfo *pkt6; |
422 | 0 | struct sockaddr_in6 *in6; |
423 | 0 | #endif |
424 | 0 | ssize_t ret; |
425 | 0 | union { |
426 | 0 | struct cmsghdr hdr; |
427 | 0 | char buf[CMSG_SPACE(sizeof(struct sockaddr_storage))]; |
428 | 0 | } cmsgbuf; |
429 | |
|
430 | 0 | bzero(&msg, sizeof(msg)); |
431 | 0 | bzero(&cmsgbuf.buf, sizeof(cmsgbuf.buf)); |
432 | |
|
433 | 0 | iov.iov_base = buf; |
434 | 0 | iov.iov_len = len; |
435 | 0 | msg.msg_iov = &iov; |
436 | 0 | msg.msg_iovlen = 1; |
437 | 0 | msg.msg_name = from; |
438 | 0 | msg.msg_namelen = *fromlen; |
439 | 0 | msg.msg_control = &cmsgbuf.buf; |
440 | 0 | msg.msg_controllen = sizeof(cmsgbuf.buf); |
441 | |
|
442 | 0 | if ((ret = recvmsg(s, &msg, flags)) == -1) |
443 | 0 | return (-1); |
444 | | |
445 | 0 | *fromlen = SA_LEN(from); |
446 | |
|
447 | 0 | if (getsockname(s, to, tolen) != 0) |
448 | 0 | *tolen = 0; |
449 | |
|
450 | 0 | for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; |
451 | 0 | cmsg = CMSG_NXTHDR(&msg, cmsg)) { |
452 | 0 | switch (from->sa_family) { |
453 | 0 | case AF_INET: |
454 | 0 | #if defined(IP_RECVORIGDSTADDR) |
455 | 0 | if (cmsg->cmsg_level == IPPROTO_IP && |
456 | 0 | cmsg->cmsg_type == IP_RECVORIGDSTADDR) { |
457 | 0 | memcpy(to, CMSG_DATA(cmsg), |
458 | 0 | sizeof(struct sockaddr_in)); |
459 | 0 | } |
460 | | #elif defined(IP_RECVDSTADDR) |
461 | | if (cmsg->cmsg_level == IPPROTO_IP && |
462 | | cmsg->cmsg_type == IP_RECVDSTADDR) { |
463 | | in = (struct sockaddr_in *)to; |
464 | | in->sin_family = AF_INET; |
465 | | #ifdef HAVE_SOCKADDR_SA_LEN |
466 | | in->sin_len = *tolen = sizeof(*in); |
467 | | #endif |
468 | | memcpy(&in->sin_addr, CMSG_DATA(cmsg), |
469 | | sizeof(struct in_addr)); |
470 | | } |
471 | | #endif /* defined(IP_RECVDSTADDR) */ |
472 | 0 | break; |
473 | 0 | case AF_INET6: |
474 | 0 | #ifdef IPV6_PKTINFO |
475 | 0 | if (cmsg->cmsg_level == IPPROTO_IPV6 && |
476 | 0 | cmsg->cmsg_type == IPV6_PKTINFO) { |
477 | 0 | in6 = (struct sockaddr_in6 *)to; |
478 | 0 | in6->sin6_family = AF_INET6; |
479 | | #ifdef HAVE_SOCKADDR_SA_LEN |
480 | | in6->sin6_len = *tolen = sizeof(*in6); |
481 | | #endif |
482 | 0 | pkt6 = (struct in6_pktinfo *)CMSG_DATA(cmsg); |
483 | 0 | memcpy(&in6->sin6_addr, &pkt6->ipi6_addr, |
484 | 0 | sizeof(struct in6_addr)); |
485 | 0 | if (IN6_IS_ADDR_LINKLOCAL(&in6->sin6_addr)) |
486 | 0 | in6->sin6_scope_id = |
487 | 0 | pkt6->ipi6_ifindex; |
488 | 0 | } |
489 | 0 | #endif |
490 | 0 | break; |
491 | 0 | } |
492 | 0 | } |
493 | | |
494 | 0 | return (ret); |
495 | 0 | } |
496 | | |
497 | | const char * |
498 | | print_spi(uint64_t spi, int size) |
499 | 43.5k | { |
500 | 43.5k | static char buf[IKED_CYCLE_BUFFERS][32]; |
501 | 43.5k | static int i = 0; |
502 | 43.5k | char *ptr; |
503 | | |
504 | 43.5k | ptr = buf[i]; |
505 | | |
506 | 43.5k | switch (size) { |
507 | 0 | case 2: |
508 | 0 | snprintf(ptr, 32, "0x%04x", (uint16_t)spi); |
509 | 0 | break; |
510 | 421 | case 4: |
511 | 421 | snprintf(ptr, 32, "0x%08x", (uint32_t)spi); |
512 | 421 | break; |
513 | 32.4k | case 8: |
514 | 32.4k | snprintf(ptr, 32, "0x%016llx", (long long unsigned)spi); |
515 | 32.4k | break; |
516 | 10.6k | default: |
517 | 10.6k | snprintf(ptr, 32, "%llu", (long long unsigned)spi); |
518 | 10.6k | break; |
519 | 43.5k | } |
520 | | |
521 | 43.5k | if (++i >= IKED_CYCLE_BUFFERS) |
522 | 5.43k | i = 0; |
523 | | |
524 | 43.5k | return (ptr); |
525 | 43.5k | } |
526 | | |
527 | | const char * |
528 | | print_map(unsigned int type, struct iked_constmap *map) |
529 | 935k | { |
530 | 935k | unsigned int i; |
531 | 935k | static char buf[IKED_CYCLE_BUFFERS][32]; |
532 | 935k | static int idx = 0; |
533 | 935k | const char *name = NULL; |
534 | | |
535 | 935k | if (idx >= IKED_CYCLE_BUFFERS) |
536 | 116k | idx = 0; |
537 | 935k | bzero(buf[idx], sizeof(buf[idx])); |
538 | | |
539 | 19.0M | for (i = 0; map[i].cm_name != NULL; i++) { |
540 | 18.1M | if (map[i].cm_type == type) |
541 | 651k | name = map[i].cm_name; |
542 | 18.1M | } |
543 | | |
544 | 935k | if (name == NULL) |
545 | 284k | snprintf(buf[idx], sizeof(buf[idx]), "<UNKNOWN:%u>", type); |
546 | 651k | else |
547 | 651k | strlcpy(buf[idx], name, sizeof(buf[idx])); |
548 | | |
549 | 935k | return (buf[idx++]); |
550 | 935k | } |
551 | | |
552 | | void |
553 | | lc_idtype(char *str) |
554 | 0 | { |
555 | 0 | for (; *str != '\0' && *str != '/'; str++) |
556 | 0 | *str = tolower((unsigned char)*str); |
557 | 0 | } |
558 | | |
559 | | void |
560 | | print_hex(const uint8_t *buf, off_t offset, size_t length) |
561 | 198k | { |
562 | 198k | unsigned int i; |
563 | | |
564 | 198k | if (log_getverbose() < 3 || !length) |
565 | 198k | return; |
566 | | |
567 | 0 | for (i = 0; i < length; i++) { |
568 | 0 | if (i && (i % 4) == 0) { |
569 | 0 | if ((i % 32) == 0) |
570 | 0 | print_debug("\n"); |
571 | 0 | else |
572 | 0 | print_debug(" "); |
573 | 0 | } |
574 | 0 | print_debug("%02x", buf[offset + i]); |
575 | 0 | } |
576 | 0 | print_debug("\n"); |
577 | 0 | } |
578 | | |
579 | | void |
580 | | print_hexval(const uint8_t *buf, off_t offset, size_t length) |
581 | 0 | { |
582 | 0 | unsigned int i; |
583 | |
|
584 | 0 | if (log_getverbose() < 2 || !length) |
585 | 0 | return; |
586 | | |
587 | 0 | print_debug("0x"); |
588 | 0 | for (i = 0; i < length; i++) |
589 | 0 | print_debug("%02x", buf[offset + i]); |
590 | 0 | print_debug("\n"); |
591 | 0 | } |
592 | | |
593 | | void |
594 | | print_hexbuf(struct ibuf *ibuf) |
595 | 0 | { |
596 | 0 | print_hex(ibuf_data(ibuf), 0, ibuf_size(ibuf)); |
597 | 0 | } |
598 | | |
599 | | const char * |
600 | | print_bits(unsigned short v, unsigned char *bits) |
601 | 0 | { |
602 | 0 | static char buf[IKED_CYCLE_BUFFERS][BUFSIZ]; |
603 | 0 | static int idx = 0; |
604 | 0 | unsigned int i, any = 0, j = 0; |
605 | 0 | unsigned char c; |
606 | |
|
607 | 0 | if (!bits) |
608 | 0 | return (""); |
609 | | |
610 | 0 | if (++idx >= IKED_CYCLE_BUFFERS) |
611 | 0 | idx = 0; |
612 | |
|
613 | 0 | bzero(buf[idx], sizeof(buf[idx])); |
614 | |
|
615 | 0 | bits++; |
616 | 0 | while ((i = *bits++)) { |
617 | 0 | if (v & (1 << (i-1))) { |
618 | 0 | if (any) { |
619 | 0 | buf[idx][j++] = ','; |
620 | 0 | if (j >= sizeof(buf[idx])) |
621 | 0 | return (buf[idx]); |
622 | 0 | } |
623 | 0 | any = 1; |
624 | 0 | for (; (c = *bits) > 32; bits++) { |
625 | 0 | buf[idx][j++] = tolower((unsigned char)c); |
626 | 0 | if (j >= sizeof(buf[idx])) |
627 | 0 | return (buf[idx]); |
628 | 0 | } |
629 | 0 | } else |
630 | 0 | for (; *bits > 32; bits++) |
631 | 0 | ; |
632 | 0 | } |
633 | | |
634 | 0 | return (buf[idx]); |
635 | 0 | } |
636 | | |
637 | | uint8_t |
638 | | mask2prefixlen(struct sockaddr *sa) |
639 | 0 | { |
640 | 0 | struct sockaddr_in *sa_in = (struct sockaddr_in *)sa; |
641 | 0 | in_addr_t ina = sa_in->sin_addr.s_addr; |
642 | |
|
643 | 0 | if (ina == 0) |
644 | 0 | return (0); |
645 | 0 | else |
646 | 0 | return (33 - ffs(ntohl(ina))); |
647 | 0 | } |
648 | | |
649 | | uint8_t |
650 | | mask2prefixlen6(struct sockaddr *sa) |
651 | 0 | { |
652 | 0 | struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)sa; |
653 | 0 | uint8_t *ap, *ep; |
654 | 0 | unsigned int l = 0; |
655 | | |
656 | | /* |
657 | | * sin6_len is the size of the sockaddr so substract the offset of |
658 | | * the possibly truncated sin6_addr struct. |
659 | | */ |
660 | 0 | ap = (uint8_t *)&sa_in6->sin6_addr; |
661 | 0 | ep = (uint8_t *)sa_in6 + SA_LEN(sa); |
662 | 0 | for (; ap < ep; ap++) { |
663 | | /* this "beauty" is adopted from sbin/route/show.c ... */ |
664 | 0 | switch (*ap) { |
665 | 0 | case 0xff: |
666 | 0 | l += 8; |
667 | 0 | break; |
668 | 0 | case 0xfe: |
669 | 0 | l += 7; |
670 | 0 | goto done; |
671 | 0 | case 0xfc: |
672 | 0 | l += 6; |
673 | 0 | goto done; |
674 | 0 | case 0xf8: |
675 | 0 | l += 5; |
676 | 0 | goto done; |
677 | 0 | case 0xf0: |
678 | 0 | l += 4; |
679 | 0 | goto done; |
680 | 0 | case 0xe0: |
681 | 0 | l += 3; |
682 | 0 | goto done; |
683 | 0 | case 0xc0: |
684 | 0 | l += 2; |
685 | 0 | goto done; |
686 | 0 | case 0x80: |
687 | 0 | l += 1; |
688 | 0 | goto done; |
689 | 0 | case 0x00: |
690 | 0 | goto done; |
691 | 0 | default: |
692 | 0 | fatalx("non contiguous inet6 netmask"); |
693 | 0 | } |
694 | 0 | } |
695 | | |
696 | 0 | done: |
697 | 0 | if (l > sizeof(struct in6_addr) * 8) |
698 | 0 | fatalx("%s: prefixlen %d out of bound", __func__, l); |
699 | 0 | return (l); |
700 | 0 | } |
701 | | |
702 | | uint32_t |
703 | | prefixlen2mask(uint8_t prefixlen) |
704 | 0 | { |
705 | 0 | if (prefixlen == 0) |
706 | 0 | return (0); |
707 | | |
708 | 0 | if (prefixlen > 32) |
709 | 0 | prefixlen = 32; |
710 | |
|
711 | 0 | return (htonl(0xffffffff << (32 - prefixlen))); |
712 | 0 | } |
713 | | |
714 | | struct in6_addr * |
715 | | prefixlen2mask6(uint8_t prefixlen, uint32_t *mask) |
716 | 0 | { |
717 | 0 | static struct in6_addr s6; |
718 | 0 | int i; |
719 | |
|
720 | 0 | if (prefixlen > 128) |
721 | 0 | prefixlen = 128; |
722 | |
|
723 | 0 | bzero(&s6, sizeof(s6)); |
724 | 0 | for (i = 0; i < prefixlen / 8; i++) |
725 | 0 | s6.s6_addr[i] = 0xff; |
726 | 0 | i = prefixlen % 8; |
727 | 0 | if (i) |
728 | 0 | s6.s6_addr[prefixlen / 8] = 0xff00 >> i; |
729 | |
|
730 | 0 | memcpy(mask, &s6, sizeof(s6)); |
731 | |
|
732 | 0 | return (&s6); |
733 | 0 | } |
734 | | |
735 | | const char * |
736 | | print_addr(void *addr) |
737 | 20.1k | { |
738 | 20.1k | static char sbuf[IKED_CYCLE_BUFFERS][NI_MAXHOST + 7]; |
739 | 20.1k | static int idx; |
740 | 20.1k | struct sockaddr *sa = addr; |
741 | 20.1k | char *buf; |
742 | 20.1k | size_t len; |
743 | 20.1k | char pbuf[7]; |
744 | 20.1k | in_port_t port; |
745 | | |
746 | 20.1k | buf = sbuf[idx]; |
747 | 20.1k | len = sizeof(sbuf[idx]); |
748 | 20.1k | if (++idx >= IKED_CYCLE_BUFFERS) |
749 | 2.52k | idx = 0; |
750 | | |
751 | 20.1k | if (sa->sa_family == AF_UNSPEC) { |
752 | 0 | strlcpy(buf, "any", len); |
753 | 0 | return (buf); |
754 | 0 | } |
755 | | |
756 | 20.1k | if (getnameinfo(sa, SA_LEN(sa), |
757 | 20.1k | buf, len, NULL, 0, NI_NUMERICHOST) != 0) { |
758 | 0 | strlcpy(buf, "unknown", len); |
759 | 0 | return (buf); |
760 | 0 | } |
761 | | |
762 | 20.1k | if ((port = socket_getport(sa)) != 0) { |
763 | 0 | snprintf(pbuf, sizeof(pbuf), ":%d", port); |
764 | 0 | (void)strlcat(buf, pbuf, len); |
765 | 0 | } |
766 | | |
767 | 20.1k | return (buf); |
768 | 20.1k | } |
769 | | |
770 | | char * |
771 | | get_string(uint8_t *ptr, size_t len) |
772 | 0 | { |
773 | 0 | size_t i; |
774 | |
|
775 | 0 | for (i = 0; i < len; i++) |
776 | 0 | if (!isprint(ptr[i])) |
777 | 0 | break; |
778 | |
|
779 | 0 | return strndup(ptr, i); |
780 | 0 | } |
781 | | |
782 | | const char * |
783 | | print_proto(uint8_t proto) |
784 | 0 | { |
785 | 0 | struct protoent *p; |
786 | 0 | static char buf[IKED_CYCLE_BUFFERS][BUFSIZ]; |
787 | 0 | static int idx = 0; |
788 | |
|
789 | 0 | if (idx >= IKED_CYCLE_BUFFERS) |
790 | 0 | idx = 0; |
791 | |
|
792 | 0 | if ((p = getprotobynumber(proto)) != NULL) |
793 | 0 | strlcpy(buf[idx], p->p_name, sizeof(buf[idx])); |
794 | 0 | else |
795 | 0 | snprintf(buf[idx], sizeof(buf), "%u", proto); |
796 | | |
797 | |
|
798 | 0 | return (buf[idx++]); |
799 | 0 | } |
800 | | |
801 | | int |
802 | | expand_string(char *label, size_t len, const char *srch, const char *repl) |
803 | 0 | { |
804 | 0 | char *tmp; |
805 | 0 | char *p, *q; |
806 | |
|
807 | 0 | if ((tmp = calloc(1, len)) == NULL) { |
808 | 0 | log_debug("%s: calloc", __func__); |
809 | 0 | return (-1); |
810 | 0 | } |
811 | 0 | p = label; |
812 | 0 | while ((q = strstr(p, srch)) != NULL) { |
813 | 0 | *q = '\0'; |
814 | 0 | if ((strlcat(tmp, p, len) >= len) || |
815 | 0 | (strlcat(tmp, repl, len) >= len)) { |
816 | 0 | log_debug("%s: string too long", __func__); |
817 | 0 | free(tmp); |
818 | 0 | return (-1); |
819 | 0 | } |
820 | 0 | q += strlen(srch); |
821 | 0 | p = q; |
822 | 0 | } |
823 | 0 | if (strlcat(tmp, p, len) >= len) { |
824 | 0 | log_debug("%s: string too long", __func__); |
825 | 0 | free(tmp); |
826 | 0 | return (-1); |
827 | 0 | } |
828 | 0 | strlcpy(label, tmp, len); /* always fits */ |
829 | 0 | free(tmp); |
830 | |
|
831 | 0 | return (0); |
832 | 0 | } |
833 | | |
834 | | uint8_t * |
835 | | string2unicode(const char *ascii, size_t *outlen) |
836 | 0 | { |
837 | 0 | uint8_t *uc = NULL; |
838 | 0 | size_t i, len = strlen(ascii); |
839 | |
|
840 | 0 | if ((uc = calloc(1, (len * 2) + 2)) == NULL) |
841 | 0 | return (NULL); |
842 | | |
843 | 0 | for (i = 0; i < len; i++) { |
844 | | /* XXX what about the byte order? */ |
845 | 0 | uc[i * 2] = ascii[i]; |
846 | 0 | } |
847 | 0 | *outlen = len * 2; |
848 | |
|
849 | 0 | return (uc); |
850 | 0 | } |
851 | | |
852 | | void |
853 | | print_debug(const char *emsg, ...) |
854 | 0 | { |
855 | 0 | va_list ap; |
856 | |
|
857 | 0 | if (log_getverbose() > 2) { |
858 | 0 | va_start(ap, emsg); |
859 | 0 | vfprintf(stderr, emsg, ap); |
860 | 0 | va_end(ap); |
861 | 0 | } |
862 | 0 | } |
863 | | |
864 | | void |
865 | | print_verbose(const char *emsg, ...) |
866 | 0 | { |
867 | 0 | va_list ap; |
868 | |
|
869 | 0 | if (log_getverbose()) { |
870 | 0 | va_start(ap, emsg); |
871 | 0 | vfprintf(stderr, emsg, ap); |
872 | 0 | va_end(ap); |
873 | 0 | } |
874 | 0 | } |