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