xref: /openbsd-src/usr.sbin/relayd/util.c (revision 479c151d3429b7cfa6228ee428d945620629789d)
1*479c151dSjsg /*	$OpenBSD: util.c,v 1.5 2024/09/20 02:00:46 jsg Exp $	*/
27fb21699Sreyk 
37fb21699Sreyk /*
47fb21699Sreyk  * Copyright (c) 2006 - 2015 Reyk Floeter <reyk@openbsd.org>
57fb21699Sreyk  *
67fb21699Sreyk  * Permission to use, copy, modify, and distribute this software for any
77fb21699Sreyk  * purpose with or without fee is hereby granted, provided that the above
87fb21699Sreyk  * copyright notice and this permission notice appear in all copies.
97fb21699Sreyk  *
107fb21699Sreyk  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
117fb21699Sreyk  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
127fb21699Sreyk  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
137fb21699Sreyk  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
147fb21699Sreyk  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
157fb21699Sreyk  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
167fb21699Sreyk  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
177fb21699Sreyk  */
187fb21699Sreyk 
197fb21699Sreyk #include <sys/types.h>
207fb21699Sreyk #include <sys/socket.h>
217fb21699Sreyk #include <sys/time.h>
227fb21699Sreyk 
237fb21699Sreyk #include <stdio.h>
247fb21699Sreyk #include <string.h>
257fb21699Sreyk #include <time.h>
267fb21699Sreyk #include <netdb.h>
277fb21699Sreyk #include <ctype.h>
287fb21699Sreyk 
297fb21699Sreyk #include "relayd.h"
307fb21699Sreyk 
317fb21699Sreyk const char *
327fb21699Sreyk host_error(enum host_error he)
337fb21699Sreyk {
347fb21699Sreyk 	switch (he) {
357fb21699Sreyk 	case HCE_NONE:
367fb21699Sreyk 		return ("none");
377fb21699Sreyk 		break;
387fb21699Sreyk 	case HCE_ABORT:
397fb21699Sreyk 		return ("aborted");
407fb21699Sreyk 		break;
417fb21699Sreyk 	case HCE_INTERVAL_TIMEOUT:
427fb21699Sreyk 		return ("interval timeout");
437fb21699Sreyk 		break;
447fb21699Sreyk 	case HCE_ICMP_OK:
457fb21699Sreyk 		return ("icmp ok");
467fb21699Sreyk 		break;
477fb21699Sreyk 	case HCE_ICMP_READ_TIMEOUT:
487fb21699Sreyk 		return ("icmp read timeout");
497fb21699Sreyk 		break;
507fb21699Sreyk 	case HCE_ICMP_WRITE_TIMEOUT:
517fb21699Sreyk 		return ("icmp write timeout");
527fb21699Sreyk 		break;
537fb21699Sreyk 	case HCE_TCP_SOCKET_ERROR:
547fb21699Sreyk 		return ("tcp socket error");
557fb21699Sreyk 		break;
567fb21699Sreyk 	case HCE_TCP_SOCKET_LIMIT:
577fb21699Sreyk 		return ("tcp socket limit");
587fb21699Sreyk 		break;
597fb21699Sreyk 	case HCE_TCP_SOCKET_OPTION:
607fb21699Sreyk 		return ("tcp socket option");
617fb21699Sreyk 		break;
627fb21699Sreyk 	case HCE_TCP_CONNECT_FAIL:
637fb21699Sreyk 		return ("tcp connect failed");
647fb21699Sreyk 		break;
657fb21699Sreyk 	case HCE_TCP_CONNECT_TIMEOUT:
667fb21699Sreyk 		return ("tcp connect timeout");
677fb21699Sreyk 		break;
687fb21699Sreyk 	case HCE_TCP_CONNECT_OK:
697fb21699Sreyk 		return ("tcp connect ok");
707fb21699Sreyk 		break;
717fb21699Sreyk 	case HCE_TCP_WRITE_TIMEOUT:
727fb21699Sreyk 		return ("tcp write timeout");
737fb21699Sreyk 		break;
747fb21699Sreyk 	case HCE_TCP_WRITE_FAIL:
757fb21699Sreyk 		return ("tcp write failed");
767fb21699Sreyk 		break;
777fb21699Sreyk 	case HCE_TCP_READ_TIMEOUT:
787fb21699Sreyk 		return ("tcp read timeout");
797fb21699Sreyk 		break;
807fb21699Sreyk 	case HCE_TCP_READ_FAIL:
817fb21699Sreyk 		return ("tcp read failed");
827fb21699Sreyk 		break;
837fb21699Sreyk 	case HCE_SCRIPT_OK:
847fb21699Sreyk 		return ("script ok");
857fb21699Sreyk 		break;
867fb21699Sreyk 	case HCE_SCRIPT_FAIL:
877fb21699Sreyk 		return ("script failed");
887fb21699Sreyk 		break;
897fb21699Sreyk 	case HCE_TLS_CONNECT_OK:
907fb21699Sreyk 		return ("tls connect ok");
917fb21699Sreyk 		break;
927fb21699Sreyk 	case HCE_TLS_CONNECT_FAIL:
937fb21699Sreyk 		return ("tls connect failed");
947fb21699Sreyk 		break;
957fb21699Sreyk 	case HCE_TLS_CONNECT_TIMEOUT:
967fb21699Sreyk 		return ("tls connect timeout");
977fb21699Sreyk 		break;
987fb21699Sreyk 	case HCE_TLS_CONNECT_ERROR:
997fb21699Sreyk 		return ("tls connect error");
1007fb21699Sreyk 		break;
1017fb21699Sreyk 	case HCE_TLS_READ_TIMEOUT:
1027fb21699Sreyk 		return ("tls read timeout");
1037fb21699Sreyk 		break;
1047fb21699Sreyk 	case HCE_TLS_WRITE_TIMEOUT:
1057fb21699Sreyk 		return ("tls write timeout");
1067fb21699Sreyk 		break;
1077fb21699Sreyk 	case HCE_TLS_READ_ERROR:
1087fb21699Sreyk 		return ("tls read error");
1097fb21699Sreyk 		break;
1107fb21699Sreyk 	case HCE_TLS_WRITE_ERROR:
1117fb21699Sreyk 		return ("tls write error");
1127fb21699Sreyk 		break;
1137fb21699Sreyk 	case HCE_SEND_EXPECT_FAIL:
1147fb21699Sreyk 		return ("send/expect failed");
1157fb21699Sreyk 		break;
1167fb21699Sreyk 	case HCE_SEND_EXPECT_OK:
1177fb21699Sreyk 		return ("send/expect ok");
1187fb21699Sreyk 		break;
1197fb21699Sreyk 	case HCE_HTTP_CODE_ERROR:
1207fb21699Sreyk 		return ("http code malformed");
1217fb21699Sreyk 		break;
1227fb21699Sreyk 	case HCE_HTTP_CODE_FAIL:
1237fb21699Sreyk 		return ("http code mismatch");
1247fb21699Sreyk 		break;
1257fb21699Sreyk 	case HCE_HTTP_CODE_OK:
1267fb21699Sreyk 		return ("http code ok");
1277fb21699Sreyk 		break;
1287fb21699Sreyk 	case HCE_HTTP_DIGEST_ERROR:
1297fb21699Sreyk 		return ("http digest malformed");
1307fb21699Sreyk 		break;
1317fb21699Sreyk 	case HCE_HTTP_DIGEST_FAIL:
1327fb21699Sreyk 		return ("http digest mismatch");
1337fb21699Sreyk 		break;
1347fb21699Sreyk 	case HCE_HTTP_DIGEST_OK:
1357fb21699Sreyk 		return ("http digest ok");
1367fb21699Sreyk 		break;
1377fb21699Sreyk 	}
1387fb21699Sreyk 	/* NOTREACHED */
1397fb21699Sreyk 	return ("invalid");
1407fb21699Sreyk }
1417fb21699Sreyk 
1427fb21699Sreyk const char *
1437fb21699Sreyk host_status(enum host_status status)
1447fb21699Sreyk {
1457fb21699Sreyk 	switch (status) {
1467fb21699Sreyk 	case HOST_DOWN:
1477fb21699Sreyk 		return ("down");
1487fb21699Sreyk 	case HOST_UNKNOWN:
1497fb21699Sreyk 		return ("unknown");
1507fb21699Sreyk 	case HOST_UP:
1517fb21699Sreyk 		return ("up");
152*479c151dSjsg 	}
1537fb21699Sreyk 	/* NOTREACHED */
1547fb21699Sreyk 	return ("invalid");
1557fb21699Sreyk }
1567fb21699Sreyk 
1577fb21699Sreyk const char *
1587fb21699Sreyk table_check(enum table_check check)
1597fb21699Sreyk {
1607fb21699Sreyk 	switch (check) {
1617fb21699Sreyk 	case CHECK_NOCHECK:
1627fb21699Sreyk 		return ("none");
1637fb21699Sreyk 	case CHECK_ICMP:
1647fb21699Sreyk 		return ("icmp");
1657fb21699Sreyk 	case CHECK_TCP:
1667fb21699Sreyk 		return ("tcp");
1677fb21699Sreyk 	case CHECK_HTTP_CODE:
1687fb21699Sreyk 		return ("http code");
1697fb21699Sreyk 	case CHECK_HTTP_DIGEST:
1707fb21699Sreyk 		return ("http digest");
1713f229715Srob 	case CHECK_BINSEND_EXPECT:
1727fb21699Sreyk 	case CHECK_SEND_EXPECT:
1737fb21699Sreyk 		return ("send expect");
1747fb21699Sreyk 	case CHECK_SCRIPT:
1757fb21699Sreyk 		return ("script");
176*479c151dSjsg 	}
1777fb21699Sreyk 	/* NOTREACHED */
1787fb21699Sreyk 	return ("invalid");
1797fb21699Sreyk }
1807fb21699Sreyk 
18165f47834Sreyk #ifdef DEBUG
18265f47834Sreyk const char *
18365f47834Sreyk relay_state(enum relay_state state)
18465f47834Sreyk {
18565f47834Sreyk 	switch (state) {
18665f47834Sreyk 	case STATE_INIT:
18765f47834Sreyk 		return ("init");
18865f47834Sreyk 	case STATE_PENDING:
18965f47834Sreyk 		return ("pending");
19065f47834Sreyk 	case STATE_PRECONNECT:
19165f47834Sreyk 		return ("preconnect");
19265f47834Sreyk 	case STATE_CONNECTED:
19365f47834Sreyk 		return ("connected");
19465f47834Sreyk 	case STATE_CLOSED:
19565f47834Sreyk 		return ("closed");
19665f47834Sreyk 	case STATE_DONE:
19765f47834Sreyk 		return ("done");
198*479c151dSjsg 	}
19965f47834Sreyk 	/* NOTREACHED */
20065f47834Sreyk 	return ("invalid");
20165f47834Sreyk }
20265f47834Sreyk #endif
20365f47834Sreyk 
2047fb21699Sreyk const char *
2057fb21699Sreyk print_availability(u_long cnt, u_long up)
2067fb21699Sreyk {
2077fb21699Sreyk 	static char buf[BUFSIZ];
2087fb21699Sreyk 
2097fb21699Sreyk 	if (cnt == 0)
2107fb21699Sreyk 		return ("");
2117fb21699Sreyk 	bzero(buf, sizeof(buf));
2127fb21699Sreyk 	snprintf(buf, sizeof(buf), "%.2f%%", (double)up / cnt * 100);
2137fb21699Sreyk 	return (buf);
2147fb21699Sreyk }
2157fb21699Sreyk 
2167fb21699Sreyk const char *
2177fb21699Sreyk print_host(struct sockaddr_storage *ss, char *buf, size_t len)
2187fb21699Sreyk {
2197fb21699Sreyk 	if (getnameinfo((struct sockaddr *)ss, ss->ss_len,
2207fb21699Sreyk 	    buf, len, NULL, 0, NI_NUMERICHOST) != 0) {
2217fb21699Sreyk 		buf[0] = '\0';
2227fb21699Sreyk 		return (NULL);
2237fb21699Sreyk 	}
2247fb21699Sreyk 	return (buf);
2257fb21699Sreyk }
2267fb21699Sreyk 
2277fb21699Sreyk const char *
2287fb21699Sreyk print_time(struct timeval *a, struct timeval *b, char *buf, size_t len)
2297fb21699Sreyk {
2307fb21699Sreyk 	struct timeval		tv;
2317fb21699Sreyk 	u_long			h, sec, min;
2327fb21699Sreyk 
2337fb21699Sreyk 	timerclear(&tv);
2347fb21699Sreyk 	timersub(a, b, &tv);
2357fb21699Sreyk 	sec = tv.tv_sec % 60;
2367fb21699Sreyk 	min = tv.tv_sec / 60 % 60;
2377fb21699Sreyk 	h = tv.tv_sec / 60 / 60;
2387fb21699Sreyk 
2397fb21699Sreyk 	snprintf(buf, len, "%.2lu:%.2lu:%.2lu", h, min, sec);
2407fb21699Sreyk 	return (buf);
2417fb21699Sreyk }
2427fb21699Sreyk 
2437fb21699Sreyk const char *
2447fb21699Sreyk printb_flags(const u_int32_t v, const char *bits)
2457fb21699Sreyk {
2467fb21699Sreyk 	static char	 buf[2][BUFSIZ];
2477fb21699Sreyk 	static int	 idx = 0;
2487fb21699Sreyk 	int		 i, any = 0;
2497fb21699Sreyk 	char		 c, *p, *r;
2507fb21699Sreyk 
2517fb21699Sreyk 	p = r = buf[++idx % 2];
2527fb21699Sreyk 	bzero(p, BUFSIZ);
2537fb21699Sreyk 
2547fb21699Sreyk 	if (bits) {
2557fb21699Sreyk 		bits++;
2567fb21699Sreyk 		while ((i = *bits++)) {
2577fb21699Sreyk 			if (v & (1 << (i - 1))) {
2587fb21699Sreyk 				if (any) {
2597fb21699Sreyk 					*p++ = ',';
2607fb21699Sreyk 					*p++ = ' ';
2617fb21699Sreyk 				}
2627fb21699Sreyk 				any = 1;
2637fb21699Sreyk 				for (; (c = *bits) > 32; bits++) {
2647fb21699Sreyk 					if (c == '_')
2657fb21699Sreyk 						*p++ = ' ';
2667fb21699Sreyk 					else
2677fb21699Sreyk 						*p++ = tolower((u_char)c);
2687fb21699Sreyk 				}
2697fb21699Sreyk 			} else
2707fb21699Sreyk 				for (; *bits > 32; bits++)
2717fb21699Sreyk 					;
2727fb21699Sreyk 		}
2737fb21699Sreyk 	}
2747fb21699Sreyk 
2757fb21699Sreyk 	return (r);
2767fb21699Sreyk }
2777fb21699Sreyk 
2787fb21699Sreyk void
2797fb21699Sreyk getmonotime(struct timeval *tv)
2807fb21699Sreyk {
2817fb21699Sreyk 	struct timespec	 ts;
2827fb21699Sreyk 
2837fb21699Sreyk 	if (clock_gettime(CLOCK_MONOTONIC, &ts))
2847fb21699Sreyk 		fatal("clock_gettime");
2857fb21699Sreyk 
2867fb21699Sreyk 	TIMESPEC_TO_TIMEVAL(tv, &ts);
2877fb21699Sreyk }
2883f229715Srob 
2893f229715Srob struct ibuf *
2903f229715Srob string2binary(const char *string)
2913f229715Srob {
2923f229715Srob 	struct ibuf	*ibuf = NULL;
293b5355054Sclaudio 	unsigned char	 ch, r;
294b5355054Sclaudio 	size_t		 i, len;
2953f229715Srob 
296b5355054Sclaudio 	len = strlen(string);
297b5355054Sclaudio 	if (len % 2 != 0)
298b5355054Sclaudio 		goto fail;
299b5355054Sclaudio 	if ((ibuf = ibuf_open(len / 2)) == NULL)
300b5355054Sclaudio 		goto fail;
301b5355054Sclaudio 
302b5355054Sclaudio 	while (*string) {
303b5355054Sclaudio 		r = 0;
304b5355054Sclaudio 		for (i = 0; i < 2; i++) {
305b5355054Sclaudio 			ch = string[i];
306b5355054Sclaudio 			if (isdigit(ch))
307b5355054Sclaudio 				ch -= '0';
308b5355054Sclaudio 			else if (islower(ch))
309b5355054Sclaudio 				ch -= ('a' - 10);
310b5355054Sclaudio 			else if (isupper(ch))
311b5355054Sclaudio 				ch -= ('A' - 10);
312b5355054Sclaudio 			else
313b5355054Sclaudio 				goto fail;
314b5355054Sclaudio 			if (ch > 0xf)
315b5355054Sclaudio 				goto fail;
316b5355054Sclaudio 			r = r << 4 | ch;
317b5355054Sclaudio 		}
318b5355054Sclaudio 		if (ibuf_add_n8(ibuf, r) == -1)
319b5355054Sclaudio 			goto fail;
320b5355054Sclaudio 		string += 2;
3213f229715Srob 	}
3223f229715Srob 
3233f229715Srob 	return ibuf;
324b5355054Sclaudio 
325b5355054Sclaudio fail:
326b5355054Sclaudio 	ibuf_free(ibuf);
327b5355054Sclaudio 	return NULL;
3283f229715Srob }
3293f229715Srob 
3303f229715Srob void
3313f229715Srob print_hex(uint8_t *buf, off_t offset, size_t length)
3323f229715Srob {
3333f229715Srob 	unsigned int	 i;
3343f229715Srob 
3353f229715Srob 	if (log_getverbose() < 3 || !length)
3363f229715Srob 		return;
3373f229715Srob 
3383f229715Srob 	for (i = 0; i < length; i++) {
3393f229715Srob 		if (i && (i % 4) == 0) {
3403f229715Srob 			if ((i % 32) == 0)
3413f229715Srob 				print_debug("\n");
3423f229715Srob 			else
3433f229715Srob 				print_debug(" ");
3443f229715Srob 		}
3453f229715Srob 		print_debug("%02x", buf[offset + i]);
3463f229715Srob 	}
3473f229715Srob 	print_debug("\n");
3483f229715Srob }
3493f229715Srob 
3503f229715Srob void
3513f229715Srob print_debug(const char *emsg, ...)
3523f229715Srob {
3533f229715Srob 	va_list	 ap;
3543f229715Srob 
3553f229715Srob 	if (log_getverbose() > 2) {
3563f229715Srob 		va_start(ap, emsg);
3573f229715Srob 		vfprintf(stderr, emsg, ap);
3583f229715Srob 		va_end(ap);
3593f229715Srob 	}
3603f229715Srob }
361