1 /* $OpenBSD: ripctl.c,v 1.17 2016/08/02 16:05:32 jca Exp $ 2 * 3 * Copyright (c) 2006 Michele Marchetto <mydecay@openbeer.it> 4 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org> 5 * Copyright (c) 2004, 2005 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 <arpa/inet.h> 26 #include <net/if_media.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 "rip.h" 37 #include "ripd.h" 38 #include "ripe.h" 39 #include "parser.h" 40 41 __dead void usage(void); 42 const char *fmt_timeframe_core(time_t); 43 const char *get_linkstate(uint8_t, int); 44 int show_interface_msg(struct imsg *); 45 uint64_t get_ifms_type(uint8_t); 46 int show_rib_msg(struct imsg *); 47 int show_nbr_msg(struct imsg *); 48 void show_fib_head(void); 49 int show_fib_msg(struct imsg *); 50 void show_interface_head(void); 51 int show_fib_interface_msg(struct imsg *); 52 const char *get_media_descr(uint64_t); 53 void print_baudrate(uint64_t); 54 55 struct imsgbuf *ibuf; 56 57 __dead void 58 usage(void) 59 { 60 extern char *__progname; 61 62 fprintf(stderr, "usage: %s [-s socket] command [argument ...]\n", 63 __progname); 64 exit(1); 65 } 66 67 int 68 main(int argc, char *argv[]) 69 { 70 struct sockaddr_un sun; 71 struct parse_result *res; 72 struct imsg imsg; 73 unsigned int ifidx = 0; 74 int ctl_sock; 75 int done = 0, verbose = 0; 76 int n; 77 int ch; 78 char *sockname = RIPD_SOCKET; 79 80 while ((ch = getopt(argc, argv, "s:")) != -1) { 81 switch (ch) { 82 case 's': 83 sockname = optarg; 84 break; 85 default: 86 usage(); 87 /* NOTREACHED */ 88 } 89 } 90 91 argc -= optind; 92 argv += optind; 93 94 /* parse options */ 95 if ((res = parse(argc, argv)) == NULL) 96 exit(1); 97 98 /* connect to ripd control socket */ 99 if ((ctl_sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) 100 err(1, "socket"); 101 102 bzero(&sun, sizeof(sun)); 103 sun.sun_family = AF_UNIX; 104 strlcpy(sun.sun_path, sockname, sizeof(sun.sun_path)); 105 if (connect(ctl_sock, (struct sockaddr *)&sun, sizeof(sun)) == -1) 106 err(1, "connect: %s", sockname); 107 108 if (pledge("stdio", NULL) == -1) 109 err(1, "pledge"); 110 111 if ((ibuf = malloc(sizeof(struct imsgbuf))) == NULL) 112 err(1, NULL); 113 imsg_init(ibuf, ctl_sock); 114 done = 0; 115 116 /* process user request */ 117 switch (res->action) { 118 case NONE: 119 usage(); 120 /* not reached */ 121 case SHOW: 122 case SHOW_IFACE: 123 printf("%-11s %-18s %-10s %-10s %-8s\n", 124 "Interface", "Address", "State", "Linkstate", 125 "Uptime"); 126 if (*res->ifname) { 127 ifidx = if_nametoindex(res->ifname); 128 if (ifidx == 0) 129 errx(1, "no such interface %s", res->ifname); 130 } 131 imsg_compose(ibuf, IMSG_CTL_SHOW_INTERFACE, 0, 0, -1, 132 &ifidx, sizeof(ifidx)); 133 break; 134 case SHOW_NBR: 135 printf("%-15s %-15s %-15s %-9s %-10s\n", "ID", 136 "State", "Address", "Iface", "Uptime"); 137 imsg_compose(ibuf, IMSG_CTL_SHOW_NBR, 0, 0, -1, NULL, 0); 138 break; 139 case SHOW_RIB: 140 printf("%-20s %-17s %-7s\n", "Destination", 141 "Nexthop", "Cost"); 142 imsg_compose(ibuf, IMSG_CTL_SHOW_RIB, 0, 0, -1, NULL, 0); 143 break; 144 case SHOW_FIB: 145 if (!res->addr.s_addr) 146 imsg_compose(ibuf, IMSG_CTL_KROUTE, 0, 0, -1, 147 &res->flags, sizeof(res->flags)); 148 else 149 imsg_compose(ibuf, IMSG_CTL_KROUTE_ADDR, 0, 0, -1, 150 &res->addr, sizeof(res->addr)); 151 show_fib_head(); 152 break; 153 case SHOW_FIB_IFACE: 154 if (*res->ifname) 155 imsg_compose(ibuf, IMSG_CTL_IFINFO, 0, 0, -1, 156 res->ifname, sizeof(res->ifname)); 157 else 158 imsg_compose(ibuf, IMSG_CTL_IFINFO, 0, 0, -1, NULL, 0); 159 show_interface_head(); 160 break; 161 case FIB: 162 errx(1, "fib couple|decouple"); 163 break; 164 case FIB_COUPLE: 165 imsg_compose(ibuf, IMSG_CTL_FIB_COUPLE, 0, 0, -1, NULL, 0); 166 printf("couple request sent.\n"); 167 done = 1; 168 break; 169 case FIB_DECOUPLE: 170 imsg_compose(ibuf, IMSG_CTL_FIB_DECOUPLE, 0, 0, -1, NULL, 0); 171 printf("decouple request sent.\n"); 172 done = 1; 173 break; 174 case LOG_VERBOSE: 175 verbose = 1; 176 /* FALLTHROUGH */ 177 case LOG_BRIEF: 178 imsg_compose(ibuf, IMSG_CTL_LOG_VERBOSE, 0, 0, -1, 179 &verbose, sizeof(verbose)); 180 printf("logging request sent.\n"); 181 done = 1; 182 break; 183 case RELOAD: 184 imsg_compose(ibuf, IMSG_CTL_RELOAD, 0, 0, -1, NULL, 0); 185 printf("reload request sent.\n"); 186 done = 1; 187 break; 188 } 189 190 while (ibuf->w.queued) 191 if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN) 192 err(1, "write error"); 193 194 while (!done) { 195 if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) 196 errx(1, "imsg_read error"); 197 if (n == 0) 198 errx(1, "pipe closed"); 199 200 while (!done) { 201 if ((n = imsg_get(ibuf, &imsg)) == -1) 202 errx(1, "imsg_get error"); 203 if (n == 0) 204 break; 205 switch (res->action) { 206 case SHOW: 207 case SHOW_IFACE: 208 done = show_interface_msg(&imsg); 209 break; 210 case SHOW_NBR: 211 done = show_nbr_msg(&imsg); 212 break; 213 case SHOW_RIB: 214 done = show_rib_msg(&imsg); 215 break; 216 case SHOW_FIB: 217 done = show_fib_msg(&imsg); 218 break; 219 case SHOW_FIB_IFACE: 220 done = show_fib_interface_msg(&imsg); 221 break; 222 case NONE: 223 case FIB: 224 case FIB_COUPLE: 225 case FIB_DECOUPLE: 226 case LOG_VERBOSE: 227 case LOG_BRIEF: 228 case RELOAD: 229 break; 230 } 231 imsg_free(&imsg); 232 } 233 } 234 close(ctl_sock); 235 free(ibuf); 236 237 return (0); 238 } 239 240 uint64_t 241 get_ifms_type(uint8_t if_type) 242 { 243 switch (if_type) { 244 case IFT_ETHER: 245 return (IFM_ETHER); 246 break; 247 case IFT_FDDI: 248 return (IFM_FDDI); 249 break; 250 case IFT_CARP: 251 return (IFM_CARP); 252 break; 253 default: 254 return (0); 255 break; 256 } 257 } 258 259 #define TF_BUFS 8 260 #define TF_LEN 9 261 262 const char * 263 fmt_timeframe_core(time_t t) 264 { 265 char *buf; 266 static char tfbuf[TF_BUFS][TF_LEN]; /* ring buffer */ 267 static int idx = 0; 268 unsigned int sec, min, hrs, day; 269 unsigned long long week; 270 271 if (t == 0) 272 return ("Stopped"); 273 274 buf = tfbuf[idx++]; 275 if (idx == TF_BUFS) 276 idx = 0; 277 278 week = t; 279 280 sec = week % 60; 281 week /= 60; 282 min = week % 60; 283 week /= 60; 284 hrs = week % 24; 285 week /= 24; 286 day = week % 7; 287 week /= 7; 288 289 if (week > 0) 290 snprintf(buf, TF_LEN, "%02lluw%01ud%02uh", week, day, hrs); 291 else if (day > 0) 292 snprintf(buf, TF_LEN, "%01ud%02uh%02um", day, hrs, min); 293 else 294 snprintf(buf, TF_LEN, "%02u:%02u:%02u", hrs, min, sec); 295 296 return (buf); 297 } 298 299 /* prototype defined in ripd.h and shared with the kroute.c version */ 300 u_int8_t 301 mask2prefixlen(in_addr_t ina) 302 { 303 if (ina == 0) 304 return (0); 305 else 306 return (33 - ffs(ntohl(ina))); 307 } 308 309 int 310 show_interface_msg(struct imsg *imsg) 311 { 312 struct ctl_iface *iface; 313 char *netid; 314 315 switch (imsg->hdr.type) { 316 case IMSG_CTL_SHOW_IFACE: 317 iface = imsg->data; 318 319 if (asprintf(&netid, "%s/%d", inet_ntoa(iface->addr), 320 mask2prefixlen(iface->mask.s_addr)) == -1) 321 err(1, NULL); 322 printf("%-11s %-18s %-10s %-10s %-8s\n", 323 iface->name, netid, if_state_name(iface->state), 324 get_linkstate(iface->if_type, iface->linkstate), 325 iface->uptime == 0 ? "00:00:00" : 326 fmt_timeframe_core(iface->uptime)); 327 free(netid); 328 break; 329 case IMSG_CTL_END: 330 printf("\n"); 331 return (1); 332 default: 333 break; 334 } 335 336 return (0); 337 } 338 339 int 340 show_rib_msg(struct imsg *imsg) 341 { 342 struct ctl_rt *rt; 343 char *dstnet; 344 345 switch (imsg->hdr.type) { 346 case IMSG_CTL_SHOW_RIB: 347 rt = imsg->data; 348 if (asprintf(&dstnet, "%s/%d", inet_ntoa(rt->prefix), 349 mask2prefixlen(rt->netmask.s_addr)) == -1) 350 err(1, NULL); 351 352 printf("%-20s %-17s %-7d\n", dstnet, 353 inet_ntoa(rt->nexthop), 354 rt->metric); 355 free(dstnet); 356 357 break; 358 case IMSG_CTL_END: 359 printf("\n"); 360 return (1); 361 default: 362 break; 363 } 364 365 return (0); 366 } 367 368 int 369 show_nbr_msg(struct imsg *imsg) 370 { 371 struct ctl_nbr *nbr; 372 char *state; 373 374 switch (imsg->hdr.type) { 375 case IMSG_CTL_SHOW_NBR: 376 nbr = imsg->data; 377 if (asprintf(&state, "%s/%s", nbr_state_name(nbr->nbr_state), 378 if_state_name(nbr->iface_state)) == -1) 379 err(1, NULL); 380 printf("%-15s %-16s", inet_ntoa(nbr->id), 381 state); 382 printf("%-15s %-10s", inet_ntoa(nbr->addr), nbr->name); 383 printf("%-15s\n", nbr->uptime == 0 ? "-" : 384 fmt_timeframe_core(nbr->uptime)); 385 free(state); 386 break; 387 case IMSG_CTL_END: 388 printf("\n"); 389 return (1); 390 default: 391 break; 392 } 393 394 return (0); 395 } 396 397 void 398 show_fib_head(void) 399 { 400 printf("flags: * = valid, R = RIP, C = Connected, S = Static\n"); 401 printf("%-6s %-20s %-17s\n", "Flags", "Destination", "Nexthop"); 402 } 403 404 int 405 show_fib_msg(struct imsg *imsg) 406 { 407 struct kroute *k; 408 char *p; 409 410 switch (imsg->hdr.type) { 411 case IMSG_CTL_KROUTE: 412 if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(struct kroute)) 413 errx(1, "wrong imsg len"); 414 k = imsg->data; 415 416 if (k->flags & F_DOWN) 417 printf(" "); 418 else 419 printf("*"); 420 421 if (k->flags & F_RIPD_INSERTED) 422 printf("R"); 423 else if (k->flags & F_CONNECTED) 424 printf("C"); 425 else if (k->flags & F_STATIC) 426 printf("S"); 427 else 428 printf(" "); 429 430 printf(" "); 431 if (asprintf(&p, "%s/%u", inet_ntoa(k->prefix), 432 mask2prefixlen(k->netmask.s_addr)) == -1) 433 err(1, NULL); 434 printf("%-20s ", p); 435 free(p); 436 437 if (k->nexthop.s_addr) 438 printf("%s", inet_ntoa(k->nexthop)); 439 else if (k->flags & F_CONNECTED) 440 printf("link#%u", k->ifindex); 441 printf("\n"); 442 443 break; 444 case IMSG_CTL_END: 445 printf("\n"); 446 return (1); 447 default: 448 break; 449 } 450 451 return (0); 452 } 453 454 void 455 show_interface_head(void) 456 { 457 printf("%-15s%-15s%s\n", "Interface", "Flags", 458 "Link state"); 459 } 460 461 int 462 show_fib_interface_msg(struct imsg *imsg) 463 { 464 struct kif *k; 465 uint64_t ifms_type; 466 467 switch (imsg->hdr.type) { 468 case IMSG_CTL_IFINFO: 469 k = imsg->data; 470 printf("%-15s", k->ifname); 471 printf("%-15s", k->flags & IFF_UP ? "UP" : ""); 472 ifms_type = get_ifms_type(k->if_type); 473 if (ifms_type) 474 printf("%s, ", get_media_descr(ifms_type)); 475 476 printf("%s", get_linkstate(k->if_type, k->link_state)); 477 478 if (k->link_state != LINK_STATE_DOWN && k->baudrate > 0) { 479 printf(", "); 480 print_baudrate(k->baudrate); 481 } 482 printf("\n"); 483 break; 484 case IMSG_CTL_END: 485 printf("\n"); 486 return (1); 487 default: 488 break; 489 } 490 491 return (0); 492 } 493 494 const struct if_status_description 495 if_status_descriptions[] = LINK_STATE_DESCRIPTIONS; 496 const struct ifmedia_description 497 ifm_type_descriptions[] = IFM_TYPE_DESCRIPTIONS; 498 499 const char * 500 get_media_descr(uint64_t media_type) 501 { 502 const struct ifmedia_description *p; 503 504 for (p = ifm_type_descriptions; p->ifmt_string != NULL; p++) 505 if (media_type == p->ifmt_word) 506 return (p->ifmt_string); 507 508 return ("unknown"); 509 } 510 511 const char * 512 get_linkstate(uint8_t if_type, int link_state) 513 { 514 const struct if_status_description *p; 515 static char buf[8]; 516 517 for (p = if_status_descriptions; p->ifs_string != NULL; p++) { 518 if (LINK_STATE_DESC_MATCH(p, if_type, link_state)) 519 return (p->ifs_string); 520 } 521 snprintf(buf, sizeof(buf), "[#%d]", link_state); 522 return (buf); 523 } 524 525 void 526 print_baudrate(uint64_t baudrate) 527 { 528 if (baudrate > IF_Gbps(1)) 529 printf("%llu GBit/s", baudrate / IF_Gbps(1)); 530 else if (baudrate > IF_Mbps(1)) 531 printf("%llu MBit/s", baudrate / IF_Mbps(1)); 532 else if (baudrate > IF_Kbps(1)) 533 printf("%llu KBit/s", baudrate / IF_Kbps(1)); 534 else 535 printf("%llu Bit/s", baudrate); 536 } 537