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