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