1 /* $OpenBSD: ospfctl.c,v 1.73 2024/11/21 13:38:14 claudio Exp $ */ 2 3 /* 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 "ospf.h" 37 #include "ospfd.h" 38 #include "ospfctl.h" 39 #include "ospfe.h" 40 #include "parser.h" 41 42 __dead void usage(void); 43 44 int show(struct imsg *, struct parse_result *); 45 46 struct imsgbuf *ibuf; 47 const struct output *output = &show_output; 48 49 __dead void 50 usage(void) 51 { 52 extern char *__progname; 53 54 fprintf(stderr, "usage: %s [-s socket] command [argument ...]\n", 55 __progname); 56 exit(1); 57 } 58 59 int 60 main(int argc, char *argv[]) 61 { 62 struct sockaddr_un sun; 63 struct parse_result *res; 64 struct imsg imsg; 65 unsigned int ifidx = 0; 66 int ctl_sock, r; 67 int done = 0; 68 int n, verbose = 0; 69 int ch; 70 char *sockname; 71 72 r = getrtable(); 73 if (asprintf(&sockname, "%s.%d", OSPFD_SOCKET, r) == -1) 74 err(1, "asprintf"); 75 76 while ((ch = getopt(argc, argv, "s:")) != -1) { 77 switch (ch) { 78 case 's': 79 sockname = optarg; 80 break; 81 default: 82 usage(); 83 /* NOTREACHED */ 84 } 85 } 86 argc -= optind; 87 argv += optind; 88 89 /* parse options */ 90 if ((res = parse(argc, argv)) == NULL) 91 exit(1); 92 93 /* connect to ospfd control socket */ 94 if ((ctl_sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) 95 err(1, "socket"); 96 97 bzero(&sun, sizeof(sun)); 98 sun.sun_family = AF_UNIX; 99 strlcpy(sun.sun_path, sockname, sizeof(sun.sun_path)); 100 101 if (connect(ctl_sock, (struct sockaddr *)&sun, sizeof(sun)) == -1) 102 err(1, "connect: %s", sockname); 103 104 if (pledge("stdio", NULL) == -1) 105 err(1, "pledge"); 106 107 if ((ibuf = malloc(sizeof(struct imsgbuf))) == NULL) 108 err(1, NULL); 109 if (imsgbuf_init(ibuf, ctl_sock) == -1) 110 err(1, NULL); 111 done = 0; 112 113 /* process user request */ 114 switch (res->action) { 115 case NONE: 116 usage(); 117 /* not reached */ 118 case SHOW: 119 case SHOW_SUM: 120 imsg_compose(ibuf, IMSG_CTL_SHOW_SUM, 0, 0, -1, NULL, 0); 121 break; 122 case SHOW_IFACE: 123 case SHOW_IFACE_DTAIL: 124 if (*res->ifname) { 125 ifidx = if_nametoindex(res->ifname); 126 if (ifidx == 0) 127 errx(1, "no such interface %s", res->ifname); 128 } 129 imsg_compose(ibuf, IMSG_CTL_SHOW_INTERFACE, 0, 0, -1, 130 &ifidx, sizeof(ifidx)); 131 break; 132 case SHOW_NBR: 133 case SHOW_NBR_DTAIL: 134 imsg_compose(ibuf, IMSG_CTL_SHOW_NBR, 0, 0, -1, NULL, 0); 135 break; 136 case SHOW_DB: 137 imsg_compose(ibuf, IMSG_CTL_SHOW_DATABASE, 0, 0, -1, NULL, 0); 138 break; 139 case SHOW_DBBYAREA: 140 imsg_compose(ibuf, IMSG_CTL_SHOW_DATABASE, 0, 0, -1, 141 &res->addr, sizeof(res->addr)); 142 break; 143 case SHOW_DBEXT: 144 imsg_compose(ibuf, IMSG_CTL_SHOW_DB_EXT, 0, 0, -1, NULL, 0); 145 break; 146 case SHOW_DBNET: 147 imsg_compose(ibuf, IMSG_CTL_SHOW_DB_NET, 0, 0, -1, NULL, 0); 148 break; 149 case SHOW_DBRTR: 150 imsg_compose(ibuf, IMSG_CTL_SHOW_DB_RTR, 0, 0, -1, NULL, 0); 151 break; 152 case SHOW_DBSELF: 153 imsg_compose(ibuf, IMSG_CTL_SHOW_DB_SELF, 0, 0, -1, NULL, 0); 154 break; 155 case SHOW_DBSUM: 156 imsg_compose(ibuf, IMSG_CTL_SHOW_DB_SUM, 0, 0, -1, NULL, 0); 157 break; 158 case SHOW_DBASBR: 159 imsg_compose(ibuf, IMSG_CTL_SHOW_DB_ASBR, 0, 0, -1, NULL, 0); 160 break; 161 case SHOW_DBOPAQ: 162 imsg_compose(ibuf, IMSG_CTL_SHOW_DB_OPAQ, 0, 0, -1, NULL, 0); 163 break; 164 case SHOW_RIB: 165 case SHOW_RIB_DTAIL: 166 imsg_compose(ibuf, IMSG_CTL_SHOW_RIB, 0, 0, -1, NULL, 0); 167 break; 168 case SHOW_FIB: 169 if (!res->addr.s_addr) 170 imsg_compose(ibuf, IMSG_CTL_KROUTE, 0, 0, -1, 171 &res->flags, sizeof(res->flags)); 172 else 173 imsg_compose(ibuf, IMSG_CTL_KROUTE_ADDR, 0, 0, -1, 174 &res->addr, sizeof(res->addr)); 175 break; 176 case SHOW_FIB_IFACE: 177 if (*res->ifname) 178 imsg_compose(ibuf, IMSG_CTL_IFINFO, 0, 0, -1, 179 res->ifname, sizeof(res->ifname)); 180 else 181 imsg_compose(ibuf, IMSG_CTL_IFINFO, 0, 0, -1, NULL, 0); 182 break; 183 case FIB: 184 errx(1, "fib couple|decouple"); 185 break; 186 case FIB_COUPLE: 187 imsg_compose(ibuf, IMSG_CTL_FIB_COUPLE, 0, 0, -1, NULL, 0); 188 printf("couple request sent.\n"); 189 done = 1; 190 break; 191 case FIB_DECOUPLE: 192 imsg_compose(ibuf, IMSG_CTL_FIB_DECOUPLE, 0, 0, -1, NULL, 0); 193 printf("decouple request sent.\n"); 194 done = 1; 195 break; 196 case FIB_RELOAD: 197 imsg_compose(ibuf, IMSG_CTL_FIB_RELOAD, 0, 0, -1, NULL, 0); 198 printf("reload request sent.\n"); 199 done = 1; 200 break; 201 case LOG_VERBOSE: 202 verbose = 1; 203 /* FALLTHROUGH */ 204 case LOG_BRIEF: 205 imsg_compose(ibuf, IMSG_CTL_LOG_VERBOSE, 0, 0, -1, 206 &verbose, sizeof(verbose)); 207 printf("logging request sent.\n"); 208 done = 1; 209 break; 210 case RELOAD: 211 imsg_compose(ibuf, IMSG_CTL_RELOAD, 0, 0, -1, NULL, 0); 212 printf("reload request sent.\n"); 213 done = 1; 214 break; 215 } 216 217 if (imsgbuf_flush(ibuf) == -1) 218 err(1, "write error"); 219 220 /* no output for certain commands such as log verbose */ 221 if (!done) { 222 output->head(res); 223 224 while (!done) { 225 if ((n = imsgbuf_read(ibuf)) == -1) 226 err(1, "read error"); 227 if (n == 0) 228 errx(1, "pipe closed"); 229 230 while (!done) { 231 if ((n = imsg_get(ibuf, &imsg)) == -1) 232 errx(1, "imsg_get error"); 233 if (n == 0) 234 break; 235 236 done = show(&imsg, res); 237 imsg_free(&imsg); 238 } 239 } 240 241 output->tail(); 242 } 243 244 close(ctl_sock); 245 free(ibuf); 246 247 return (0); 248 } 249 250 int 251 show(struct imsg *imsg, struct parse_result *res) 252 { 253 struct ctl_sum *sum; 254 struct ctl_sum_area *sumarea; 255 struct ctl_iface *ctliface; 256 struct ctl_nbr *nbr; 257 struct ctl_rt *rt; 258 struct kroute *k; 259 struct kif *kif; 260 static struct in_addr area_id; 261 struct area *area; 262 static u_int8_t lasttype; 263 static char ifname[IF_NAMESIZE]; 264 struct iface *iface; 265 struct lsa *lsa; 266 struct lsa_hdr *lsa_hdr; 267 268 switch (imsg->hdr.type) { 269 case IMSG_CTL_SHOW_SUM: 270 sum = imsg->data; 271 output->summary(sum); 272 break; 273 case IMSG_CTL_SHOW_SUM_AREA: 274 sumarea = imsg->data; 275 output->summary_area(sumarea); 276 break; 277 case IMSG_CTL_SHOW_INTERFACE: 278 ctliface = imsg->data; 279 if(res->action == SHOW_IFACE_DTAIL) 280 output->interface(ctliface, 1); 281 else 282 output->interface(ctliface, 0); 283 break; 284 case IMSG_CTL_SHOW_NBR: 285 nbr = imsg->data; 286 if(res->action == SHOW_NBR_DTAIL) 287 output->neighbor(nbr, 1); 288 else 289 output->neighbor(nbr, 0); 290 break; 291 case IMSG_CTL_SHOW_RIB: 292 rt = imsg->data; 293 if(res->action == SHOW_RIB_DTAIL) 294 output->rib(rt, 1); 295 else 296 output->rib(rt, 0); 297 break; 298 case IMSG_CTL_KROUTE: 299 if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(struct kroute)) 300 errx(1, "wrong imsg len"); 301 k = imsg->data; 302 output->fib(k); 303 break; 304 case IMSG_CTL_IFINFO: 305 kif = imsg->data; 306 output->fib_interface(kif); 307 break; 308 case IMSG_CTL_SHOW_DB_EXT: 309 case IMSG_CTL_SHOW_DB_NET: 310 case IMSG_CTL_SHOW_DB_RTR: 311 case IMSG_CTL_SHOW_DB_SUM: 312 case IMSG_CTL_SHOW_DB_ASBR: 313 case IMSG_CTL_SHOW_DB_OPAQ: 314 lsa = imsg->data; 315 output->db(lsa, area_id, lasttype, ifname); 316 lasttype = lsa->hdr.type; 317 break; 318 case IMSG_CTL_SHOW_DATABASE: 319 case IMSG_CTL_SHOW_DB_SELF: 320 lsa_hdr = imsg->data; 321 output->db_simple(lsa_hdr, area_id, lasttype, ifname); 322 lasttype = lsa_hdr->type; 323 break; 324 case IMSG_CTL_AREA: 325 area = imsg->data; 326 area_id = area->id; 327 lasttype = 0; 328 break; 329 case IMSG_CTL_IFACE: 330 iface = imsg->data; 331 strlcpy(ifname, iface->name, sizeof(ifname)); 332 lasttype = 0; 333 break; 334 case IMSG_CTL_END: 335 return (1); 336 default: 337 warnx("unknown imsg %d received", imsg->hdr.type); 338 break; 339 } 340 341 return (0); 342 } 343 344 uint64_t 345 get_ifms_type(uint8_t if_type) 346 { 347 switch (if_type) { 348 case IFT_ETHER: 349 return (IFM_ETHER); 350 case IFT_FDDI: 351 return (IFM_FDDI); 352 case IFT_CARP: 353 return (IFM_CARP); 354 case IFT_PPP: 355 return (IFM_TDM); 356 default: 357 return (0); 358 } 359 } 360 361 const char * 362 print_link(int state) 363 { 364 if (state & IFF_UP) 365 return ("UP"); 366 else 367 return ("DOWN"); 368 } 369 370 #define TF_BUFS 8 371 #define TF_LEN 9 372 373 const char * 374 fmt_timeframe_core(time_t t) 375 { 376 char *buf; 377 static char tfbuf[TF_BUFS][TF_LEN];/* ring buffer */ 378 static int idx = 0; 379 unsigned int sec, min, hrs, day; 380 unsigned long long week; 381 382 if (t == 0) 383 return ("00:00:00"); 384 385 buf = tfbuf[idx++]; 386 if (idx == TF_BUFS) 387 idx = 0; 388 389 week = t; 390 391 sec = week % 60; 392 week /= 60; 393 min = week % 60; 394 week /= 60; 395 hrs = week % 24; 396 week /= 24; 397 day = week % 7; 398 week /= 7; 399 400 if (week > 0) 401 snprintf(buf, TF_LEN, "%02lluw%01ud%02uh", week, day, hrs); 402 else if (day > 0) 403 snprintf(buf, TF_LEN, "%01ud%02uh%02um", day, hrs, min); 404 else 405 snprintf(buf, TF_LEN, "%02u:%02u:%02u", hrs, min, sec); 406 407 return (buf); 408 } 409 410 const char * 411 log_id(u_int32_t id) 412 { 413 static char buf[48]; 414 struct in_addr addr; 415 416 addr.s_addr = id; 417 418 if (inet_ntop(AF_INET, &addr, buf, sizeof(buf)) == NULL) 419 return ("?"); 420 else 421 return (buf); 422 } 423 424 const char * 425 log_adv_rtr(u_int32_t adv_rtr) 426 { 427 static char buf[48]; 428 struct in_addr addr; 429 430 addr.s_addr = adv_rtr; 431 432 if (inet_ntop(AF_INET, &addr, buf, sizeof(buf)) == NULL) 433 return ("?"); 434 else 435 return (buf); 436 } 437 438 /* prototype defined in ospfd.h and shared with the kroute.c version */ 439 u_int8_t 440 mask2prefixlen(in_addr_t ina) 441 { 442 if (ina == 0) 443 return (0); 444 else 445 return (33 - ffs(ntohl(ina))); 446 } 447 448 char * 449 print_ls_type(u_int8_t type) 450 { 451 switch (type) { 452 case LSA_TYPE_ROUTER: 453 return ("Router"); 454 case LSA_TYPE_NETWORK: 455 return ("Network"); 456 case LSA_TYPE_SUM_NETWORK: 457 return ("Summary (Network)"); 458 case LSA_TYPE_SUM_ROUTER: 459 return ("Summary (Router)"); 460 case LSA_TYPE_EXTERNAL: 461 return ("AS External"); 462 case LSA_TYPE_LINK_OPAQ: 463 return ("Type-9 Opaque"); 464 case LSA_TYPE_AREA_OPAQ: 465 return ("Type-10 Opaque"); 466 case LSA_TYPE_AS_OPAQ: 467 return ("Type-11 Opaque"); 468 default: 469 return ("Unknown"); 470 } 471 } 472 473 char * 474 print_rtr_link_type(u_int8_t type) 475 { 476 switch (type) { 477 case LINK_TYPE_POINTTOPOINT: 478 return ("Point-to-Point"); 479 case LINK_TYPE_TRANSIT_NET: 480 return ("Transit Network"); 481 case LINK_TYPE_STUB_NET: 482 return ("Stub Network"); 483 case LINK_TYPE_VIRTUAL: 484 return ("Virtual Link"); 485 default: 486 return ("Unknown"); 487 } 488 } 489 490 const char * 491 print_ospf_flags(u_int8_t opts) 492 { 493 static char optbuf[32]; 494 495 snprintf(optbuf, sizeof(optbuf), "*|*|*|*|*|%s|%s|%s", 496 opts & OSPF_RTR_V ? "V" : "-", 497 opts & OSPF_RTR_E ? "E" : "-", 498 opts & OSPF_RTR_B ? "B" : "-"); 499 return (optbuf); 500 } 501 502 const char * 503 print_ospf_options(u_int8_t opts) 504 { 505 static char optbuf[32]; 506 507 snprintf(optbuf, sizeof(optbuf), "%s|%s|%s|%s|%s|%s|%s|%s", 508 opts & OSPF_OPTION_DN ? "DN" : "-", 509 opts & OSPF_OPTION_O ? "O" : "-", 510 opts & OSPF_OPTION_DC ? "DC" : "-", 511 opts & OSPF_OPTION_EA ? "EA" : "-", 512 opts & OSPF_OPTION_NP ? "N/P" : "-", 513 opts & OSPF_OPTION_MC ? "MC" : "-", 514 opts & OSPF_OPTION_E ? "E" : "-", 515 opts & OSPF_OPTION_MT ? "MT" : "-"); 516 return (optbuf); 517 } 518 519 const char * 520 print_ospf_rtr_flags(u_int8_t opts) 521 { 522 static char optbuf[32]; 523 524 snprintf(optbuf, sizeof(optbuf), "%s%s%s", 525 opts & OSPF_RTR_E ? "AS" : "", 526 opts & OSPF_RTR_E && opts & OSPF_RTR_B ? "+" : "", 527 opts & OSPF_RTR_B ? "ABR" : ""); 528 return (optbuf); 529 } 530 531 const struct if_status_description 532 if_status_descriptions[] = LINK_STATE_DESCRIPTIONS; 533 const struct ifmedia_description 534 ifm_type_descriptions[] = IFM_TYPE_DESCRIPTIONS; 535 536 const char * 537 get_media_descr(uint64_t media_type) 538 { 539 const struct ifmedia_description *p; 540 541 for (p = ifm_type_descriptions; p->ifmt_string != NULL; p++) 542 if (media_type == p->ifmt_word) 543 return (p->ifmt_string); 544 545 return ("unknown"); 546 } 547 548 const char * 549 get_linkstate(uint8_t if_type, int link_state) 550 { 551 const struct if_status_description *p; 552 static char buf[8]; 553 554 for (p = if_status_descriptions; p->ifs_string != NULL; p++) { 555 if (LINK_STATE_DESC_MATCH(p, if_type, link_state)) 556 return (p->ifs_string); 557 } 558 snprintf(buf, sizeof(buf), "[#%d]", link_state); 559 return (buf); 560 } 561 562 const char * 563 print_baudrate(u_int64_t baudrate) 564 { 565 static char buf[32]; 566 567 if (baudrate > IF_Gbps(1)) 568 snprintf(buf, sizeof(buf), "%llu GBit/s", baudrate / IF_Gbps(1)); 569 else if (baudrate > IF_Mbps(1)) 570 snprintf(buf, sizeof(buf), "%llu MBit/s", baudrate / IF_Mbps(1)); 571 else if (baudrate > IF_Kbps(1)) 572 snprintf(buf, sizeof(buf), "%llu KBit/s", baudrate / IF_Kbps(1)); 573 else 574 snprintf(buf, sizeof(buf), "%llu Bit/s", baudrate); 575 return (buf); 576 } 577