GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/relayctl/relayctl.c Lines: 0 253 0.0 %
Date: 2017-11-07 Branches: 0 160 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: relayctl.c,v 1.57 2016/09/03 14:44:21 reyk Exp $	*/
2
3
/*
4
 * Copyright (c) 2007 - 2013 Reyk Floeter <reyk@openbsd.org>
5
 * Copyright (c) 2006 Pierre-Yves Ritschard <pyr@openbsd.org>
6
 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
7
 * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
8
 * Copyright (c) 2003 Henning Brauer <henning@openbsd.org>
9
 *
10
 * Permission to use, copy, modify, and distribute this software for any
11
 * purpose with or without fee is hereby granted, provided that the above
12
 * copyright notice and this permission notice appear in all copies.
13
 *
14
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
15
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
16
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
17
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
20
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21
 */
22
23
#include <sys/types.h>
24
#include <sys/socket.h>
25
#include <sys/time.h>
26
#include <sys/queue.h>
27
#include <sys/un.h>
28
29
#include <arpa/inet.h>
30
31
#include <stdio.h>
32
#include <stdlib.h>
33
#include <err.h>
34
#include <errno.h>
35
#include <limits.h>
36
#include <string.h>
37
#include <unistd.h>
38
#include <time.h>
39
#include <imsg.h>
40
41
#include "relayd.h"
42
#include "parser.h"
43
44
__dead void	 usage(void);
45
int		 show_summary_msg(struct imsg *, int);
46
int		 show_session_msg(struct imsg *);
47
int		 show_command_output(struct imsg *);
48
char		*print_rdr_status(int);
49
char		*print_host_status(int, int);
50
char		*print_table_status(int, int);
51
char		*print_relay_status(int);
52
void		 print_statistics(struct ctl_stats[PROC_MAX_INSTANCES + 1]);
53
54
struct imsgname {
55
	int type;
56
	char *name;
57
	void (*func)(struct imsg *);
58
};
59
60
struct imsgname *monitor_lookup(u_int8_t);
61
void		 monitor_host_status(struct imsg *);
62
void		 monitor_id(struct imsg *);
63
int		 monitor(struct imsg *);
64
65
struct imsgname imsgs[] = {
66
	{ IMSG_HOST_STATUS,		"host_status",	monitor_host_status },
67
	{ IMSG_CTL_RDR_DISABLE,		"ctl_rdr_disable",	monitor_id },
68
	{ IMSG_CTL_RDR_ENABLE,		"ctl_rdr_enable",	monitor_id },
69
	{ IMSG_CTL_TABLE_DISABLE,	"ctl_table_disable",	monitor_id },
70
	{ IMSG_CTL_TABLE_ENABLE,	"ctl_table_enable",	monitor_id },
71
	{ IMSG_CTL_HOST_DISABLE,	"ctl_host_disable",	monitor_id },
72
	{ IMSG_CTL_HOST_ENABLE,		"ctl_host_enable",	monitor_id },
73
	{ IMSG_CTL_TABLE_CHANGED,	"ctl_table_changed",	monitor_id },
74
	{ IMSG_CTL_PULL_RULESET,	"ctl_pull_ruleset",	monitor_id },
75
	{ IMSG_CTL_PUSH_RULESET,	"ctl_push_ruleset",	monitor_id },
76
	{ IMSG_SYNC,			"sync",			NULL },
77
	{ 0,				NULL,			NULL }
78
};
79
struct imsgname imsgunknown = {
80
	-1,				"<unknown>",		NULL
81
};
82
83
struct imsgbuf	*ibuf;
84
int error = 0;
85
86
__dead void
87
usage(void)
88
{
89
	extern char *__progname;
90
91
	fprintf(stderr, "usage: %s command [argument ...]\n", __progname);
92
	exit(1);
93
}
94
95
int
96
main(int argc, char *argv[])
97
{
98
	struct sockaddr_un	 sun;
99
	struct parse_result	*res;
100
	struct imsg		 imsg;
101
	int			 ctl_sock;
102
	int			 done = 0;
103
	int			 n, verbose = 0;
104
105
	/* parse options */
106
	if ((res = parse(argc - 1, argv + 1)) == NULL)
107
		exit(1);
108
109
	/* connect to relayd control socket */
110
	if ((ctl_sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
111
		err(1, "socket");
112
113
	bzero(&sun, sizeof(sun));
114
	sun.sun_family = AF_UNIX;
115
	(void)strlcpy(sun.sun_path, RELAYD_SOCKET, sizeof(sun.sun_path));
116
 reconnect:
117
	if (connect(ctl_sock, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
118
		/* Keep retrying if running in monitor mode */
119
		if (res->action == MONITOR &&
120
		    (errno == ENOENT || errno == ECONNREFUSED)) {
121
			usleep(100);
122
			goto reconnect;
123
		}
124
		err(1, "connect: %s", RELAYD_SOCKET);
125
	}
126
127
	if (pledge("stdio flock rpath cpath wpath", NULL) == -1)
128
		err(1, "pledge");
129
130
	if ((ibuf = malloc(sizeof(struct imsgbuf))) == NULL)
131
		err(1, NULL);
132
	imsg_init(ibuf, ctl_sock);
133
	done = 0;
134
135
	/* process user request */
136
	switch (res->action) {
137
	case NONE:
138
		usage();
139
		/* not reached */
140
	case SHOW_SUM:
141
	case SHOW_HOSTS:
142
	case SHOW_RDRS:
143
	case SHOW_RELAYS:
144
	case SHOW_ROUTERS:
145
		imsg_compose(ibuf, IMSG_CTL_SHOW_SUM, 0, 0, -1, NULL, 0);
146
		printf("%-4s\t%-8s\t%-24s\t%-7s\tStatus\n",
147
		    "Id", "Type", "Name", "Avlblty");
148
		break;
149
	case SHOW_SESSIONS:
150
		imsg_compose(ibuf, IMSG_CTL_SESSION, 0, 0, -1, NULL, 0);
151
		break;
152
	case RDR_ENABLE:
153
		imsg_compose(ibuf, IMSG_CTL_RDR_ENABLE, 0, 0, -1,
154
		    &res->id, sizeof(res->id));
155
		break;
156
	case RDR_DISABLE:
157
		imsg_compose(ibuf, IMSG_CTL_RDR_DISABLE, 0, 0, -1,
158
		    &res->id, sizeof(res->id));
159
		break;
160
	case TABLE_ENABLE:
161
		imsg_compose(ibuf, IMSG_CTL_TABLE_ENABLE, 0, 0, -1,
162
		    &res->id, sizeof(res->id));
163
		break;
164
	case TABLE_DISABLE:
165
		imsg_compose(ibuf, IMSG_CTL_TABLE_DISABLE, 0, 0, -1,
166
		    &res->id, sizeof(res->id));
167
		break;
168
	case HOST_ENABLE:
169
		imsg_compose(ibuf, IMSG_CTL_HOST_ENABLE, 0, 0, -1,
170
		    &res->id, sizeof(res->id));
171
		break;
172
	case HOST_DISABLE:
173
		imsg_compose(ibuf, IMSG_CTL_HOST_DISABLE, 0, 0, -1,
174
		    &res->id, sizeof(res->id));
175
		break;
176
	case SHUTDOWN:
177
		imsg_compose(ibuf, IMSG_CTL_SHUTDOWN, 0, 0, -1, NULL, 0);
178
		break;
179
	case POLL:
180
		imsg_compose(ibuf, IMSG_CTL_POLL, 0, 0, -1, NULL, 0);
181
		break;
182
	case LOAD:
183
		imsg_compose(ibuf, IMSG_CTL_RELOAD, 0, 0, -1,
184
		    res->path, strlen(res->path));
185
		done = 1;
186
		break;
187
	case RELOAD:
188
		imsg_compose(ibuf, IMSG_CTL_RELOAD, 0, 0, -1, NULL, 0);
189
		done = 1;
190
		break;
191
	case MONITOR:
192
		imsg_compose(ibuf, IMSG_CTL_NOTIFY, 0, 0, -1, NULL, 0);
193
		break;
194
	case LOG_VERBOSE:
195
		verbose = 2;
196
		/* FALLTHROUGH */
197
	case LOG_BRIEF:
198
		imsg_compose(ibuf, IMSG_CTL_VERBOSE, 0, 0, -1,
199
		    &verbose, sizeof(verbose));
200
		printf("logging request sent.\n");
201
		done = 1;
202
		break;
203
	}
204
205
	while (ibuf->w.queued)
206
		if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN)
207
			err(1, "write error");
208
209
	while (!done) {
210
		if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN)
211
			errx(1, "imsg_read error");
212
		if (n == 0)
213
			errx(1, "pipe closed");
214
215
		while (!done) {
216
			if ((n = imsg_get(ibuf, &imsg)) == -1)
217
				errx(1, "imsg_get error");
218
			if (n == 0)
219
				break;
220
			switch (res->action) {
221
			case SHOW_SUM:
222
			case SHOW_HOSTS:
223
			case SHOW_RDRS:
224
			case SHOW_RELAYS:
225
			case SHOW_ROUTERS:
226
				done = show_summary_msg(&imsg, res->action);
227
				break;
228
			case SHOW_SESSIONS:
229
				done = show_session_msg(&imsg);
230
				break;
231
			case RDR_DISABLE:
232
			case RDR_ENABLE:
233
			case TABLE_DISABLE:
234
			case TABLE_ENABLE:
235
			case HOST_DISABLE:
236
			case HOST_ENABLE:
237
			case POLL:
238
			case SHUTDOWN:
239
				done = show_command_output(&imsg);
240
				break;
241
			case NONE:
242
			case LOG_VERBOSE:
243
			case LOG_BRIEF:
244
			case RELOAD:
245
			case LOAD:
246
				break;
247
			case MONITOR:
248
				done = monitor(&imsg);
249
				break;
250
			}
251
			imsg_free(&imsg);
252
		}
253
	}
254
	close(ctl_sock);
255
	free(ibuf);
256
257
	return (error ? 1 : 0);
258
}
259
260
struct imsgname *
261
monitor_lookup(u_int8_t type)
262
{
263
	int i;
264
265
	for (i = 0; imsgs[i].name != NULL; i++)
266
		if (imsgs[i].type == type)
267
			return (&imsgs[i]);
268
	return (&imsgunknown);
269
}
270
271
void
272
monitor_host_status(struct imsg *imsg)
273
{
274
	struct ctl_status	 cs;
275
276
	memcpy(&cs, imsg->data, sizeof(cs));
277
	printf("\tid: %u\n", cs.id);
278
	printf("\tstate: ");
279
	switch (cs.up) {
280
	case HOST_UP:
281
		printf("up\n");
282
		break;
283
	case HOST_DOWN:
284
		printf("down\n");
285
		break;
286
	default:
287
		printf("unknown\n");
288
		break;
289
	}
290
}
291
292
void
293
monitor_id(struct imsg *imsg)
294
{
295
	struct ctl_id		 id;
296
297
	memcpy(&id, imsg->data, sizeof(id));
298
	printf("\tid: %u\n", id.id);
299
	if (strlen(id.name))
300
		printf("\tname: %s\n", id.name);
301
}
302
303
int
304
monitor(struct imsg *imsg)
305
{
306
	time_t			 now;
307
	int			 done = 0;
308
	struct imsgname		*imn;
309
310
	now = time(NULL);
311
312
	imn = monitor_lookup(imsg->hdr.type);
313
	printf("%s: imsg type %u len %u peerid %u pid %d\n", imn->name,
314
	    imsg->hdr.type, imsg->hdr.len, imsg->hdr.peerid, imsg->hdr.pid);
315
	printf("\ttimestamp: %lld, %s", (long long)now, ctime(&now));
316
	if (imn->type == -1)
317
		done = 1;
318
	if (imn->func != NULL)
319
		(*imn->func)(imsg);
320
321
	return (done);
322
}
323
324
int
325
show_summary_msg(struct imsg *imsg, int type)
326
{
327
	struct rdr		*rdr;
328
	struct table		*table;
329
	struct host		*host;
330
	struct relay		*rlay;
331
	struct router		*rt;
332
	struct netroute		*nr;
333
	struct ctl_stats	 stats[PROC_MAX_INSTANCES];
334
	char			 name[HOST_NAME_MAX+1];
335
336
	switch (imsg->hdr.type) {
337
	case IMSG_CTL_RDR:
338
		if (!(type == SHOW_SUM || type == SHOW_RDRS))
339
			break;
340
		rdr = imsg->data;
341
		printf("%-4u\t%-8s\t%-24s\t%-7s\t%s\n",
342
		    rdr->conf.id, "redirect", rdr->conf.name, "",
343
		    print_rdr_status(rdr->conf.flags));
344
		break;
345
	case IMSG_CTL_TABLE:
346
		if (!(type == SHOW_SUM || type == SHOW_HOSTS))
347
			break;
348
		table = imsg->data;
349
		printf("%-4u\t%-8s\t%-24s\t%-7s\t%s\n",
350
		    table->conf.id, "table", table->conf.name, "",
351
		    print_table_status(table->up, table->conf.flags));
352
		break;
353
	case IMSG_CTL_HOST:
354
		if (!(type == SHOW_SUM || type == SHOW_HOSTS))
355
			break;
356
		host = imsg->data;
357
		if (host->conf.parentid)
358
			snprintf(name, sizeof(name), "%s parent %u",
359
			    host->conf.name, host->conf.parentid);
360
		else
361
			strlcpy(name, host->conf.name, sizeof(name));
362
		printf("%-4u\t%-8s\t%-24s\t%-7s\t%s\n",
363
		    host->conf.id, "host", name,
364
		    print_availability(host->check_cnt, host->up_cnt),
365
		    print_host_status(host->up, host->flags));
366
		if (type == SHOW_HOSTS && host->check_cnt) {
367
			printf("\t%8s\ttotal: %lu/%lu checks",
368
			    "", host->up_cnt, host->check_cnt);
369
			if (host->retry_cnt)
370
				printf(", %d retries", host->retry_cnt);
371
			if (host->he && host->up == HOST_DOWN)
372
				printf(", error: %s", host_error(host->he));
373
			printf("\n");
374
		}
375
		break;
376
	case IMSG_CTL_RELAY:
377
		if (!(type == SHOW_SUM || type == SHOW_RELAYS))
378
			break;
379
		rlay = imsg->data;
380
		printf("%-4u\t%-8s\t%-24s\t%-7s\t%s\n",
381
		    rlay->rl_conf.id, "relay", rlay->rl_conf.name, "",
382
		    print_relay_status(rlay->rl_conf.flags));
383
		break;
384
	case IMSG_CTL_RDR_STATS:
385
		if (type != SHOW_RDRS)
386
			break;
387
		bcopy(imsg->data, &stats[0], sizeof(stats[0]));
388
		stats[1].id = EMPTY_ID;
389
		print_statistics(stats);
390
		break;
391
	case IMSG_CTL_RELAY_STATS:
392
		if (type != SHOW_RELAYS)
393
			break;
394
		bcopy(imsg->data, &stats, sizeof(stats));
395
		print_statistics(stats);
396
		break;
397
	case IMSG_CTL_ROUTER:
398
		if (!(type == SHOW_SUM || type == SHOW_ROUTERS))
399
			break;
400
		rt = imsg->data;
401
		printf("%-4u\t%-8s\t%-24s\t%-7s\t%s\n",
402
		    rt->rt_conf.id, "router", rt->rt_conf.name, "",
403
		    print_relay_status(rt->rt_conf.flags));
404
		if (type != SHOW_ROUTERS)
405
			break;
406
		if (rt->rt_conf.rtable)
407
			printf("\t%8s\trtable: %d\n", "", rt->rt_conf.rtable);
408
		if (strlen(rt->rt_conf.label))
409
			printf("\t%8s\trtlabel: %s\n", "", rt->rt_conf.label);
410
		break;
411
	case IMSG_CTL_NETROUTE:
412
		if (type != SHOW_ROUTERS)
413
			break;
414
		nr = imsg->data;
415
		(void)print_host(&nr->nr_conf.ss, name, sizeof(name));
416
		printf("\t%8s\troute: %s/%d\n",
417
		    "", name, nr->nr_conf.prefixlen);
418
		break;
419
	case IMSG_CTL_END:
420
		return (1);
421
	default:
422
		errx(1, "wrong message in summary: %u", imsg->hdr.type);
423
		break;
424
	}
425
	return (0);
426
}
427
428
int
429
show_session_msg(struct imsg *imsg)
430
{
431
	struct rsession		*con;
432
	char			 a[128], b[128];
433
	struct timeval		 tv_now;
434
435
	switch (imsg->hdr.type) {
436
	case IMSG_CTL_SESSION:
437
		con = imsg->data;
438
439
		(void)print_host(&con->se_in.ss, a, sizeof(a));
440
		(void)print_host(&con->se_out.ss, b, sizeof(b));
441
		printf("session %u:%u %s:%u -> %s:%u\t%s\n",
442
		    imsg->hdr.peerid, con->se_id,
443
		    a, ntohs(con->se_in.port), b, ntohs(con->se_out.port),
444
		    con->se_done ? "DONE" : "RUNNING");
445
446
		getmonotime(&tv_now);
447
		print_time(&tv_now, &con->se_tv_start, a, sizeof(a));
448
		print_time(&tv_now, &con->se_tv_last, b, sizeof(b));
449
		printf("\tage %s, idle %s, relay %u, pid %u",
450
		    a, b, con->se_relayid, con->se_pid);
451
		/* XXX grab tagname instead of tag id */
452
		if (con->se_tag)
453
			printf(", tag (id) %u", con->se_tag);
454
		printf("\n");
455
		break;
456
	case IMSG_CTL_END:
457
		return (1);
458
	default:
459
		errx(1, "wrong message in session: %u", imsg->hdr.type);
460
		break;
461
	}
462
	return (0);
463
}
464
465
int
466
show_command_output(struct imsg *imsg)
467
{
468
	switch (imsg->hdr.type) {
469
	case IMSG_CTL_OK:
470
		printf("command succeeded\n");
471
		break;
472
	case IMSG_CTL_FAIL:
473
		printf("command failed\n");
474
		error++;
475
		break;
476
	default:
477
		errx(1, "wrong message in summary: %u", imsg->hdr.type);
478
	}
479
	return (1);
480
}
481
482
char *
483
print_rdr_status(int flags)
484
{
485
	if (flags & F_DISABLE) {
486
		return ("disabled");
487
	} else if (flags & F_DOWN) {
488
		return ("down");
489
	} else if (flags & F_BACKUP) {
490
		return ("active (using backup table)");
491
	} else
492
		return ("active");
493
}
494
495
char *
496
print_table_status(int up, int fl)
497
{
498
	static char buf[1024];
499
500
	bzero(buf, sizeof(buf));
501
502
	if (fl & F_DISABLE) {
503
		snprintf(buf, sizeof(buf) - 1, "disabled");
504
	} else if (!up) {
505
		snprintf(buf, sizeof(buf) - 1, "empty");
506
	} else
507
		snprintf(buf, sizeof(buf) - 1, "active (%d hosts)", up);
508
	return (buf);
509
}
510
511
char *
512
print_host_status(int status, int fl)
513
{
514
	if (fl & F_DISABLE)
515
		return ("disabled");
516
517
	switch (status) {
518
	case HOST_DOWN:
519
		return ("down");
520
	case HOST_UNKNOWN:
521
		return ("unknown");
522
	case HOST_UP:
523
		return ("up");
524
	default:
525
		errx(1, "invalid status: %d", status);
526
	}
527
}
528
529
char *
530
print_relay_status(int flags)
531
{
532
	if (flags & F_DISABLE) {
533
		return ("disabled");
534
	} else
535
		return ("active");
536
}
537
538
void
539
print_statistics(struct ctl_stats stats[PROC_MAX_INSTANCES + 1])
540
{
541
	struct ctl_stats	 crs;
542
	int			 i;
543
544
	bzero(&crs, sizeof(crs));
545
	crs.interval = stats[0].interval;
546
	for (i = 0; stats[i].id != EMPTY_ID; i++) {
547
		crs.cnt += stats[i].cnt;
548
		crs.last += stats[i].last;
549
		crs.avg += stats[i].avg;
550
		crs.last_hour += stats[i].last_hour;
551
		crs.avg_hour += stats[i].avg_hour;
552
		crs.last_day += stats[i].last_day;
553
		crs.avg_day += stats[i].avg_day;
554
	}
555
	if (crs.cnt == 0)
556
		return;
557
	printf("\t%8s\ttotal: %llu sessions\n"
558
	    "\t%8s\tlast: %u/%llus %u/h %u/d sessions\n"
559
	    "\t%8s\taverage: %u/%llus %u/h %u/d sessions\n",
560
	    "", crs.cnt,
561
	    "", crs.last, crs.interval,
562
	    crs.last_hour, crs.last_day,
563
	    "", crs.avg, crs.interval,
564
	    crs.avg_hour, crs.avg_day);
565
}