dvmrpctl.c revision 1.14
1/* $OpenBSD: dvmrpctl.c,v 1.14 2015/10/25 20:23:00 deraadt Exp $ */ 2 3/* 4 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org> 5 * Copyright (c) 2004, 2005, 2006 Esben Norby <norby@openbsd.org> 6 * Copyright (c) 2003 Henning Brauer <henning@openbsd.org> 7 * 8 * Permission to use, copy, modify, and distribute this software for any 9 * purpose with or without fee is hereby granted, provided that the above 10 * copyright notice and this permission notice appear in all copies. 11 * 12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 */ 20 21#include <sys/types.h> 22#include <sys/socket.h> 23#include <sys/un.h> 24#include <netinet/in.h> 25#include <netinet/ip_mroute.h> 26#include <arpa/inet.h> 27#include <net/if_types.h> 28 29#include <err.h> 30#include <errno.h> 31#include <stdio.h> 32#include <stdlib.h> 33#include <string.h> 34#include <unistd.h> 35 36#include "igmp.h" 37#include "dvmrp.h" 38#include "dvmrpd.h" 39#include "dvmrpe.h" 40#include "parser.h" 41#include "log.h" 42 43__dead void usage(void); 44int show_summary_msg(struct imsg *); 45int show_interface_msg(struct imsg *); 46int show_interface_detail_msg(struct imsg *); 47int show_igmp_msg(struct imsg *); 48const char *print_if_type(enum iface_type type); 49const char *print_nbr_state(int); 50const char *print_link(int); 51const char *fmt_timeframe(time_t t); 52const char *fmt_timeframe_core(time_t t); 53int show_nbr_msg(struct imsg *); 54const char *print_dvmrp_options(u_int8_t); 55int show_nbr_detail_msg(struct imsg *); 56int show_rib_msg(struct imsg *); 57int show_rib_detail_msg(struct imsg *); 58int show_mfc_msg(struct imsg *); 59int show_mfc_detail_msg(struct imsg *); 60const char * get_linkstate(uint8_t, int); 61 62struct imsgbuf *ibuf; 63 64__dead void 65usage(void) 66{ 67 extern char *__progname; 68 69 fprintf(stderr, "usage: %s command [argument ...]\n", __progname); 70 exit(1); 71} 72 73int 74main(int argc, char *argv[]) 75{ 76 struct sockaddr_un sun; 77 struct parse_result *res; 78 struct imsg imsg; 79 unsigned int ifidx = 0; 80 int ctl_sock; 81 int done = 0, verbose = 0; 82 int n; 83 84 /* parse options */ 85 if ((res = parse(argc - 1, argv + 1)) == NULL) 86 exit(1); 87 88 /* connect to dvmrpd control socket */ 89 if ((ctl_sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) 90 err(1, "socket"); 91 92 bzero(&sun, sizeof(sun)); 93 sun.sun_family = AF_UNIX; 94 strlcpy(sun.sun_path, DVMRPD_SOCKET, sizeof(sun.sun_path)); 95 if (connect(ctl_sock, (struct sockaddr *)&sun, sizeof(sun)) == -1) 96 err(1, "connect: %s", DVMRPD_SOCKET); 97 98 if (pledge("stdio", NULL) == -1) 99 err(1, "pledge"); 100 101 if ((ibuf = malloc(sizeof(struct imsgbuf))) == NULL) 102 fatal(NULL); 103 imsg_init(ibuf, ctl_sock); 104 done = 0; 105 106 /* process user request */ 107 switch (res->action) { 108 case NONE: 109 usage(); 110 /* NOTREACHED */ 111 case SHOW: 112 case SHOW_SUM: 113 imsg_compose(ibuf, IMSG_CTL_SHOW_SUM, 0, 0, -1, NULL, 0); 114 break; 115 case SHOW_IFACE: 116 printf("%-11s %-18s %-10s %-10s %-10s %-8s %s\n", 117 "Interface", "Address", "State", "ProbeTimer", "Linkstate", 118 "Uptime", "Groups"); 119 /* FALLTHROUGH */ 120 case SHOW_IFACE_DTAIL: 121 if (*res->ifname) { 122 ifidx = if_nametoindex(res->ifname); 123 if (ifidx == 0) 124 errx(1, "no such interface %s", res->ifname); 125 } 126 imsg_compose(ibuf, IMSG_CTL_SHOW_IFACE, 0, 0, -1, &ifidx, 127 sizeof(ifidx)); 128 break; 129 case SHOW_IGMP: 130 if (*res->ifname) { 131 ifidx = if_nametoindex(res->ifname); 132 if (ifidx == 0) 133 errx(1, "no such interface %s", res->ifname); 134 } 135 imsg_compose(ibuf, IMSG_CTL_SHOW_IGMP, 0, 0, -1, &ifidx, 136 sizeof(ifidx)); 137 break; 138 case SHOW_NBR: 139 printf("%-15s %-10s %-9s %-15s %-11s %-8s\n", "ID", "State", 140 "DeadTime", "Address", "Interface", "Uptime"); 141 /* FALLTHROUGH */ 142 case SHOW_NBR_DTAIL: 143 imsg_compose(ibuf, IMSG_CTL_SHOW_NBR, 0, 0, -1, NULL, 0); 144 break; 145 case SHOW_RIB: 146 printf("%-20s %-17s %-7s %-10s %-s\n", "Destination", "Nexthop", 147 "Cost", "Uptime", "Expire"); 148 /* FALLTHROUGH */ 149 case SHOW_RIB_DTAIL: 150 imsg_compose(ibuf, IMSG_CTL_SHOW_RIB, 0, 0, -1, NULL, 0); 151 break; 152 case SHOW_MFC: 153 printf("%-16s %-16s %-9s %-9s %-4s %-10s %-10s\n", "Group", 154 "Origin", "Incoming", "Outgoing", "TTL", "Uptime", 155 "Expire"); 156 /* FALLTHROUGH */ 157 case SHOW_MFC_DTAIL: 158 imsg_compose(ibuf, IMSG_CTL_SHOW_MFC, 0, 0, -1, NULL, 0); 159 break; 160 case LOG_VERBOSE: 161 verbose = 1; 162 /* FALLTHROUGH */ 163 case LOG_BRIEF: 164 imsg_compose(ibuf, IMSG_CTL_LOG_VERBOSE, 0, 0, -1, 165 &verbose, sizeof(verbose)); 166 printf("logging request sent.\n"); 167 done = 1; 168 break; 169 case RELOAD: 170 imsg_compose(ibuf, IMSG_CTL_RELOAD, 0, 0, -1, NULL, 0); 171 printf("reload request sent.\n"); 172 done = 1; 173 break; 174 } 175 176 while (ibuf->w.queued) 177 if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN) 178 err(1, "write error"); 179 180 while (!done) { 181 if ((n = imsg_read(ibuf)) == -1) 182 errx(1, "imsg_read error"); 183 if (n == 0) 184 errx(1, "pipe closed"); 185 186 while (!done) { 187 if ((n = imsg_get(ibuf, &imsg)) == -1) 188 errx(1, "imsg_get error"); 189 if (n == 0) 190 break; 191 switch (res->action) { 192 case SHOW: 193 case SHOW_SUM: 194 done = show_summary_msg(&imsg); 195 break; 196 case SHOW_IFACE: 197 done = show_interface_msg(&imsg); 198 break; 199 case SHOW_IFACE_DTAIL: 200 done = show_interface_detail_msg(&imsg); 201 break; 202 case SHOW_IGMP: 203 done = show_igmp_msg(&imsg); 204 break; 205 case SHOW_NBR: 206 done = show_nbr_msg(&imsg); 207 break; 208 case SHOW_NBR_DTAIL: 209 done = show_nbr_detail_msg(&imsg); 210 break; 211 case SHOW_RIB: 212 done = show_rib_msg(&imsg); 213 break; 214 case SHOW_RIB_DTAIL: 215 done = show_rib_detail_msg(&imsg); 216 break; 217 case SHOW_MFC: 218 done = show_mfc_msg(&imsg); 219 break; 220 case SHOW_MFC_DTAIL: 221 done = show_mfc_detail_msg(&imsg); 222 break; 223 case NONE: 224 case LOG_VERBOSE: 225 case LOG_BRIEF: 226 case RELOAD: 227 break; 228 } 229 imsg_free(&imsg); 230 } 231 } 232 close(ctl_sock); 233 free(ibuf); 234 235 return (0); 236} 237 238int 239show_summary_msg(struct imsg *imsg) 240{ 241 struct ctl_sum *sum; 242 243 switch (imsg->hdr.type) { 244 case IMSG_CTL_SHOW_SUM: 245 sum = imsg->data; 246 printf("Router ID: %s\n", inet_ntoa(sum->rtr_id)); 247 printf("Hold time is %d sec(s)\n", sum->hold_time); 248 break; 249 case IMSG_CTL_END: 250 printf("\n"); 251 return (1); 252 default: 253 break; 254 } 255 256 return (0); 257} 258 259int 260show_interface_msg(struct imsg *imsg) 261{ 262 struct ctl_iface *iface; 263 char *netid; 264 265 switch (imsg->hdr.type) { 266 case IMSG_CTL_SHOW_IFACE: 267 iface = imsg->data; 268 269 if (asprintf(&netid, "%s/%d", inet_ntoa(iface->addr), 270 mask2prefixlen(iface->mask.s_addr)) == -1) 271 err(1, NULL); 272 printf("%-11s %-18s %-10s %-10s %-10s %-8s %5d\n", 273 iface->name, netid, if_state_name(iface->state), 274 iface->probe_timer == 0 ? "00:00:00" : 275 fmt_timeframe_core(iface->probe_timer), 276 get_linkstate(iface->if_type, iface->linkstate), 277 iface->uptime == 0 ? "00:00:00" : 278 fmt_timeframe_core(iface->uptime), iface->group_cnt); 279 free(netid); 280 break; 281 case IMSG_CTL_END: 282 printf("\n"); 283 return (1); 284 default: 285 break; 286 } 287 288 return (0); 289} 290 291int 292show_interface_detail_msg(struct imsg *imsg) 293{ 294 struct ctl_iface *iface; 295 296 switch (imsg->hdr.type) { 297 case IMSG_CTL_SHOW_IFACE: 298 iface = imsg->data; 299 300 printf("\n"); 301 printf("Interface %s, line protocol is %s\n", 302 iface->name, print_link(iface->flags)); 303 printf(" Internet address %s/%d\n", 304 inet_ntoa(iface->addr), 305 mask2prefixlen(iface->mask.s_addr)); 306 printf(" Linkstate %s\n", 307 get_linkstate(iface->if_type, iface->linkstate)); 308 printf(" Network type %s, cost: %d\n", 309 if_type_name(iface->type), iface->metric); 310 printf(" State %s, querier ", if_state_name(iface->state)); 311 if (iface->state == IF_STA_QUERIER) 312 printf("%s\n", inet_ntoa(iface->addr)); 313 else 314 printf("%s\n", inet_ntoa(iface->querier)); 315 printf(" Generation ID %d\n", iface->gen_id); 316 printf(" Timer intervals configured, " 317 "probe %d, dead %d\n", iface->probe_interval, 318 iface->dead_interval); 319 if (iface->passive) 320 printf(" Passive interface (No Hellos)\n"); 321 else if (iface->probe_timer < 0) 322 printf(" Hello timer not running\n"); 323 else 324 printf(" Hello timer due in %s\n", 325 fmt_timeframe_core(iface->probe_timer)); 326 printf(" Uptime %s\n", iface->uptime == 0 ? 327 "00:00:00" : fmt_timeframe_core(iface->uptime)); 328 printf(" Adjacent neighbor count is " 329 "%d\n", iface->adj_cnt); 330 break; 331 case IMSG_CTL_END: 332 printf("\n"); 333 return (1); 334 default: 335 break; 336 } 337 338 return (0); 339} 340 341int 342show_igmp_msg(struct imsg *imsg) 343{ 344 struct ctl_iface *iface; 345 struct ctl_group *group; 346 char *netid; 347 348 switch (imsg->hdr.type) { 349 case IMSG_CTL_SHOW_IFACE: 350 iface = imsg->data; 351 if (asprintf(&netid, "%s/%d", inet_ntoa(iface->addr), 352 mask2prefixlen(iface->mask.s_addr)) == -1) 353 err(1, NULL); 354 printf("\nInterface %s, address %s, state %s, groups %d\n", 355 iface->name, netid, if_state_name(iface->state), 356 iface->group_cnt); 357 free(netid); 358 printf(" %-16s %-10s %-10s %-10s\n", "Group", "State", 359 "DeadTimer", "Uptime"); 360 break; 361 case IMSG_CTL_SHOW_IGMP: 362 group = imsg->data; 363 printf(" %-16s %-10s %-10s %-10s\n", inet_ntoa(group->addr), 364 group_state_name(group->state), 365 group->dead_timer == 0 ? "00:00:00" : 366 fmt_timeframe_core(group->dead_timer), 367 group->uptime == 0 ? "00:00:00" : 368 fmt_timeframe_core(group->uptime)); 369 break; 370 case IMSG_CTL_END: 371 printf("\n"); 372 return (1); 373 default: 374 break; 375 } 376 377 return (0); 378} 379 380const char * 381print_if_type(enum iface_type type) 382{ 383 switch (type) { 384 case IF_TYPE_POINTOPOINT: 385 return ("POINTOPOINT"); 386 case IF_TYPE_BROADCAST: 387 return ("BROADCAST"); 388 default: 389 return ("UNKNOWN"); 390 } 391} 392 393const char * 394print_nbr_state(int state) 395{ 396 switch (state) { 397 case NBR_STA_DOWN: 398 return ("DOWN"); 399 case NBR_STA_1_WAY: 400 return ("1-WAY"); 401 case NBR_STA_2_WAY: 402 return ("2-WAY"); 403 default: 404 return ("UNKNOWN"); 405 } 406} 407 408const char * 409print_link(int state) 410{ 411 if (state & IFF_UP) 412 return ("UP"); 413 else 414 return ("DOWN"); 415} 416 417#define TF_BUFS 8 418#define TF_LEN 9 419 420const char * 421fmt_timeframe(time_t t) 422{ 423 if (t == 0) 424 return ("Never"); 425 else 426 return (fmt_timeframe_core(time(NULL) - t)); 427} 428 429const char * 430fmt_timeframe_core(time_t t) 431{ 432 char *buf; 433 static char tfbuf[TF_BUFS][TF_LEN]; /* ring buffer */ 434 static int idx = 0; 435 unsigned int sec, min, hrs, day; 436 unsigned long long week; 437 438 if (t == 0) 439 return ("Stopped"); 440 441 buf = tfbuf[idx++]; 442 if (idx == TF_BUFS) 443 idx = 0; 444 445 week = t; 446 447 sec = week % 60; 448 week /= 60; 449 min = week % 60; 450 week /= 60; 451 hrs = week % 24; 452 week /= 24; 453 day = week % 7; 454 week /= 7; 455 456 if (week > 0) 457 snprintf(buf, TF_LEN, "%02lluw%01ud%02uh", week, day, hrs); 458 else if (day > 0) 459 snprintf(buf, TF_LEN, "%01ud%02uh%02um", day, hrs, min); 460 else 461 snprintf(buf, TF_LEN, "%02u:%02u:%02u", hrs, min, sec); 462 463 return (buf); 464} 465 466/* prototype defined in dvmrpd.h and shared with the kroute.c version */ 467u_int8_t 468mask2prefixlen(in_addr_t ina) 469{ 470 if (ina == 0) 471 return (0); 472 else 473 return (33 - ffs(ntohl(ina))); 474} 475 476int 477show_nbr_msg(struct imsg *imsg) 478{ 479 struct ctl_nbr *nbr; 480 481 switch (imsg->hdr.type) { 482 case IMSG_CTL_SHOW_NBR: 483 nbr = imsg->data; 484 printf("%-15s %-10s %-10s", inet_ntoa(nbr->id), 485 print_nbr_state(nbr->state), 486 fmt_timeframe_core(nbr->dead_timer)); 487 printf("%-15s %-11s %s\n", inet_ntoa(nbr->addr), 488 nbr->name, fmt_timeframe_core(nbr->uptime)); 489 break; 490 case IMSG_CTL_END: 491 printf("\n"); 492 return (1); 493 default: 494 break; 495 } 496 497 return (0); 498} 499 500const char * 501print_dvmrp_options(u_int8_t opts) 502{ 503 static char optbuf[32]; 504 505 snprintf(optbuf, sizeof(optbuf), "*|*|%s|%s|%s|%s|%s|%s", 506 opts & DVMRP_CAP_NETMASK ? "N" : "-", 507 opts & DVMRP_CAP_SNMP ? "S" : "-", 508 opts & DVMRP_CAP_MTRACE ? "M" : "-", 509 opts & DVMRP_CAP_GENID ? "G" : "-", 510 opts & DVMRP_CAP_PRUNE ? "P" : "-", 511 opts & DVMRP_CAP_LEAF ? "L" : "-"); 512 return (optbuf); 513} 514 515int 516show_nbr_detail_msg(struct imsg *imsg) 517{ 518 struct ctl_nbr *nbr; 519 520 switch (imsg->hdr.type) { 521 case IMSG_CTL_SHOW_NBR: 522 nbr = imsg->data; 523 break; 524 case IMSG_CTL_END: 525 printf("\n"); 526 return (1); 527 default: 528 break; 529 } 530 531 return (0); 532} 533 534int 535show_rib_msg(struct imsg *imsg) 536{ 537 struct ctl_rt *rt; 538 char *dstnet; 539 540 switch (imsg->hdr.type) { 541 case IMSG_CTL_SHOW_RIB: 542 rt = imsg->data; 543 if (asprintf(&dstnet, "%s/%d", inet_ntoa(rt->prefix), 544 rt->prefixlen) == -1) 545 err(1, NULL); 546 547 printf("%-20s %-17s %-7d %-9s %9s\n", dstnet, 548 inet_ntoa(rt->nexthop), 549 rt->cost, rt->uptime == 0 ? "-" : 550 fmt_timeframe_core(rt->uptime), 551 rt->expire == 0 ? "00:00:00" : 552 fmt_timeframe_core(rt->expire)); 553 free(dstnet); 554 555 break; 556 case IMSG_CTL_END: 557 printf("\n"); 558 return (1); 559 default: 560 break; 561 } 562 563 return (0); 564} 565 566int 567show_rib_detail_msg(struct imsg *imsg) 568{ 569 570 switch (imsg->hdr.type) { 571 case IMSG_CTL_SHOW_RIB: 572 break; 573 case IMSG_CTL_END: 574 printf("\n"); 575 return (1); 576 default: 577 break; 578 } 579 580 return (0); 581} 582 583int 584show_mfc_msg(struct imsg *imsg) 585{ 586 char iname[IF_NAMESIZE]; 587 char oname[IF_NAMESIZE] = "-"; 588 struct ctl_mfc *mfc; 589 int i; 590 591 592 switch (imsg->hdr.type) { 593 case IMSG_CTL_SHOW_MFC: 594 mfc = imsg->data; 595 if_indextoname(mfc->ifindex, iname); 596 597 /* search for first entry with ttl > 0 */ 598 for (i = 0; i < MAXVIFS; i++) { 599 if (mfc->ttls[i] > 0) { 600 if_indextoname(i, oname); 601 i++; 602 break; 603 } 604 } 605 606 /* display first entry with uptime */ 607 printf("%-16s ", inet_ntoa(mfc->group)); 608 printf("%-16s %-9s %-9s %-4d %-10s %-10s\n", 609 inet_ntoa(mfc->origin), iname, oname, mfc->ttls[i - 1], 610 mfc->uptime == 0 ? "-" : fmt_timeframe_core(mfc->uptime), 611 mfc->expire == 0 ? "-" : fmt_timeframe_core(mfc->expire)); 612 613 /* display remaining entries with ttl > 0 */ 614 for (; i < MAXVIFS; i++) { 615 if (mfc->ttls[i] > 0) { 616 if_indextoname(i, oname); 617 printf("%43s %-9s %-4d\n", " ", oname, 618 mfc->ttls[i]); 619 } 620 } 621 break; 622 case IMSG_CTL_END: 623 printf("\n"); 624 return (1); 625 default: 626 break; 627 } 628 629 return (0); 630} 631 632int 633show_mfc_detail_msg(struct imsg *imsg) 634{ 635 636 switch (imsg->hdr.type) { 637 case IMSG_CTL_SHOW_MFC: 638 break; 639 case IMSG_CTL_END: 640 printf("\n"); 641 return (1); 642 default: 643 break; 644 } 645 646 return (0); 647} 648 649const struct if_status_description 650 if_status_descriptions[] = LINK_STATE_DESCRIPTIONS; 651 652const char * 653get_linkstate(uint8_t if_type, int link_state) 654{ 655 const struct if_status_description *p; 656 static char buf[8]; 657 658 for (p = if_status_descriptions; p->ifs_string != NULL; p++) { 659 if (LINK_STATE_DESC_MATCH(p, if_type, link_state)) 660 return (p->ifs_string); 661 } 662 snprintf(buf, sizeof(buf), "[#%d]", link_state); 663 return (buf); 664} 665