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