xref: /openbsd/usr.sbin/relayd/util.c (revision 4cfece93)
1 /*	$OpenBSD: util.c,v 1.3 2019/09/15 19:23:29 rob Exp $	*/
2 
3 /*
4  * Copyright (c) 2006 - 2015 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/socket.h>
21 #include <sys/time.h>
22 
23 #include <stdio.h>
24 #include <string.h>
25 #include <time.h>
26 #include <netdb.h>
27 #include <ctype.h>
28 
29 #include "relayd.h"
30 
31 const char *
32 host_error(enum host_error he)
33 {
34 	switch (he) {
35 	case HCE_NONE:
36 		return ("none");
37 		break;
38 	case HCE_ABORT:
39 		return ("aborted");
40 		break;
41 	case HCE_INTERVAL_TIMEOUT:
42 		return ("interval timeout");
43 		break;
44 	case HCE_ICMP_OK:
45 		return ("icmp ok");
46 		break;
47 	case HCE_ICMP_READ_TIMEOUT:
48 		return ("icmp read timeout");
49 		break;
50 	case HCE_ICMP_WRITE_TIMEOUT:
51 		return ("icmp write timeout");
52 		break;
53 	case HCE_TCP_SOCKET_ERROR:
54 		return ("tcp socket error");
55 		break;
56 	case HCE_TCP_SOCKET_LIMIT:
57 		return ("tcp socket limit");
58 		break;
59 	case HCE_TCP_SOCKET_OPTION:
60 		return ("tcp socket option");
61 		break;
62 	case HCE_TCP_CONNECT_FAIL:
63 		return ("tcp connect failed");
64 		break;
65 	case HCE_TCP_CONNECT_TIMEOUT:
66 		return ("tcp connect timeout");
67 		break;
68 	case HCE_TCP_CONNECT_OK:
69 		return ("tcp connect ok");
70 		break;
71 	case HCE_TCP_WRITE_TIMEOUT:
72 		return ("tcp write timeout");
73 		break;
74 	case HCE_TCP_WRITE_FAIL:
75 		return ("tcp write failed");
76 		break;
77 	case HCE_TCP_READ_TIMEOUT:
78 		return ("tcp read timeout");
79 		break;
80 	case HCE_TCP_READ_FAIL:
81 		return ("tcp read failed");
82 		break;
83 	case HCE_SCRIPT_OK:
84 		return ("script ok");
85 		break;
86 	case HCE_SCRIPT_FAIL:
87 		return ("script failed");
88 		break;
89 	case HCE_TLS_CONNECT_OK:
90 		return ("tls connect ok");
91 		break;
92 	case HCE_TLS_CONNECT_FAIL:
93 		return ("tls connect failed");
94 		break;
95 	case HCE_TLS_CONNECT_TIMEOUT:
96 		return ("tls connect timeout");
97 		break;
98 	case HCE_TLS_CONNECT_ERROR:
99 		return ("tls connect error");
100 		break;
101 	case HCE_TLS_READ_TIMEOUT:
102 		return ("tls read timeout");
103 		break;
104 	case HCE_TLS_WRITE_TIMEOUT:
105 		return ("tls write timeout");
106 		break;
107 	case HCE_TLS_READ_ERROR:
108 		return ("tls read error");
109 		break;
110 	case HCE_TLS_WRITE_ERROR:
111 		return ("tls write error");
112 		break;
113 	case HCE_SEND_EXPECT_FAIL:
114 		return ("send/expect failed");
115 		break;
116 	case HCE_SEND_EXPECT_OK:
117 		return ("send/expect ok");
118 		break;
119 	case HCE_HTTP_CODE_ERROR:
120 		return ("http code malformed");
121 		break;
122 	case HCE_HTTP_CODE_FAIL:
123 		return ("http code mismatch");
124 		break;
125 	case HCE_HTTP_CODE_OK:
126 		return ("http code ok");
127 		break;
128 	case HCE_HTTP_DIGEST_ERROR:
129 		return ("http digest malformed");
130 		break;
131 	case HCE_HTTP_DIGEST_FAIL:
132 		return ("http digest mismatch");
133 		break;
134 	case HCE_HTTP_DIGEST_OK:
135 		return ("http digest ok");
136 		break;
137 	}
138 	/* NOTREACHED */
139 	return ("invalid");
140 }
141 
142 const char *
143 host_status(enum host_status status)
144 {
145 	switch (status) {
146 	case HOST_DOWN:
147 		return ("down");
148 	case HOST_UNKNOWN:
149 		return ("unknown");
150 	case HOST_UP:
151 		return ("up");
152 	};
153 	/* NOTREACHED */
154 	return ("invalid");
155 }
156 
157 const char *
158 table_check(enum table_check check)
159 {
160 	switch (check) {
161 	case CHECK_NOCHECK:
162 		return ("none");
163 	case CHECK_ICMP:
164 		return ("icmp");
165 	case CHECK_TCP:
166 		return ("tcp");
167 	case CHECK_HTTP_CODE:
168 		return ("http code");
169 	case CHECK_HTTP_DIGEST:
170 		return ("http digest");
171 	case CHECK_BINSEND_EXPECT:
172 	case CHECK_SEND_EXPECT:
173 		return ("send expect");
174 	case CHECK_SCRIPT:
175 		return ("script");
176 	};
177 	/* NOTREACHED */
178 	return ("invalid");
179 }
180 
181 #ifdef DEBUG
182 const char *
183 relay_state(enum relay_state state)
184 {
185 	switch (state) {
186 	case STATE_INIT:
187 		return ("init");
188 	case STATE_PENDING:
189 		return ("pending");
190 	case STATE_PRECONNECT:
191 		return ("preconnect");
192 	case STATE_CONNECTED:
193 		return ("connected");
194 	case STATE_CLOSED:
195 		return ("closed");
196 	case STATE_DONE:
197 		return ("done");
198 	};
199 	/* NOTREACHED */
200 	return ("invalid");
201 }
202 #endif
203 
204 const char *
205 print_availability(u_long cnt, u_long up)
206 {
207 	static char buf[BUFSIZ];
208 
209 	if (cnt == 0)
210 		return ("");
211 	bzero(buf, sizeof(buf));
212 	snprintf(buf, sizeof(buf), "%.2f%%", (double)up / cnt * 100);
213 	return (buf);
214 }
215 
216 const char *
217 print_host(struct sockaddr_storage *ss, char *buf, size_t len)
218 {
219 	if (getnameinfo((struct sockaddr *)ss, ss->ss_len,
220 	    buf, len, NULL, 0, NI_NUMERICHOST) != 0) {
221 		buf[0] = '\0';
222 		return (NULL);
223 	}
224 	return (buf);
225 }
226 
227 const char *
228 print_time(struct timeval *a, struct timeval *b, char *buf, size_t len)
229 {
230 	struct timeval		tv;
231 	u_long			h, sec, min;
232 
233 	timerclear(&tv);
234 	timersub(a, b, &tv);
235 	sec = tv.tv_sec % 60;
236 	min = tv.tv_sec / 60 % 60;
237 	h = tv.tv_sec / 60 / 60;
238 
239 	snprintf(buf, len, "%.2lu:%.2lu:%.2lu", h, min, sec);
240 	return (buf);
241 }
242 
243 const char *
244 printb_flags(const u_int32_t v, const char *bits)
245 {
246 	static char	 buf[2][BUFSIZ];
247 	static int	 idx = 0;
248 	int		 i, any = 0;
249 	char		 c, *p, *r;
250 
251 	p = r = buf[++idx % 2];
252 	bzero(p, BUFSIZ);
253 
254 	if (bits) {
255 		bits++;
256 		while ((i = *bits++)) {
257 			if (v & (1 << (i - 1))) {
258 				if (any) {
259 					*p++ = ',';
260 					*p++ = ' ';
261 				}
262 				any = 1;
263 				for (; (c = *bits) > 32; bits++) {
264 					if (c == '_')
265 						*p++ = ' ';
266 					else
267 						*p++ = tolower((u_char)c);
268 				}
269 			} else
270 				for (; *bits > 32; bits++)
271 					;
272 		}
273 	}
274 
275 	return (r);
276 }
277 
278 void
279 getmonotime(struct timeval *tv)
280 {
281 	struct timespec	 ts;
282 
283 	if (clock_gettime(CLOCK_MONOTONIC, &ts))
284 		fatal("clock_gettime");
285 
286 	TIMESPEC_TO_TIMEVAL(tv, &ts);
287 }
288 
289 struct ibuf *
290 string2binary(const char *string)
291 {
292 	unsigned long	 i, j, x;
293 	unsigned char	*binary = NULL;
294 	struct ibuf	*ibuf = NULL;
295 	char		 hex[3];
296 	int		 len;
297 
298 	if (strlen(string) % 2 != 0) {
299 		return NULL;
300 	}
301 
302 	binary = calloc(strlen(string), sizeof(unsigned char));
303 	if (binary == NULL) {
304 		return NULL;
305 	}
306 
307 	hex[2] = '\0';
308 	j = 0;
309 	for (i = 0; i < strlen(string); i++) {
310 		if (isxdigit(string[i]) == 0 || isxdigit(string[i+1]) == 0) {
311 			free(binary);
312 			return NULL;
313 		} else {
314 			hex[0] = string[i];
315 			hex[1] = string[i+1];
316 			x = strtoul(hex, NULL, 16);
317 			binary[j++] = (unsigned char)x;
318 			i++;
319 		}
320 	}
321 	len = strlen(string) / 2;
322 	if ((ibuf = ibuf_open(len)) == NULL ||
323 	    ibuf_add(ibuf, binary, len) == -1) {
324 		ibuf_free(ibuf);
325 		free(binary);
326 		return NULL;
327 	}
328 	free(binary);
329 	return ibuf;
330 }
331 
332 void
333 print_hex(uint8_t *buf, off_t offset, size_t length)
334 {
335 	unsigned int	 i;
336 
337 	if (log_getverbose() < 3 || !length)
338 		return;
339 
340 	for (i = 0; i < length; i++) {
341 		if (i && (i % 4) == 0) {
342 			if ((i % 32) == 0)
343 				print_debug("\n");
344 			else
345 				print_debug(" ");
346 		}
347 		print_debug("%02x", buf[offset + i]);
348 	}
349 	print_debug("\n");
350 }
351 
352 void
353 print_debug(const char *emsg, ...)
354 {
355 	va_list	 ap;
356 
357 	if (log_getverbose() > 2) {
358 		va_start(ap, emsg);
359 		vfprintf(stderr, emsg, ap);
360 		va_end(ap);
361 	}
362 }
363