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