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