ospfctl.c revision 1.67
1/* $OpenBSD: ospfctl.c,v 1.67 2020/05/18 17:52:18 denis 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 44int show(struct imsg *, struct parse_result *); 45 46struct imsgbuf *ibuf; 47const struct output *output = &show_output; 48 49__dead void 50usage(void) 51{ 52 extern char *__progname; 53 54 fprintf(stderr, "usage: %s [-s socket] command [argument ...]\n", 55 __progname); 56 exit(1); 57} 58 59int 60main(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 imsg_init(ibuf, ctl_sock); 110 done = 0; 111 112 /* process user request */ 113 switch (res->action) { 114 case NONE: 115 usage(); 116 /* not reached */ 117 case SHOW: 118 case SHOW_SUM: 119 imsg_compose(ibuf, IMSG_CTL_SHOW_SUM, 0, 0, -1, NULL, 0); 120 break; 121 case SHOW_IFACE: 122 case SHOW_IFACE_DTAIL: 123 if (*res->ifname) { 124 ifidx = if_nametoindex(res->ifname); 125 if (ifidx == 0) 126 errx(1, "no such interface %s", res->ifname); 127 } 128 imsg_compose(ibuf, IMSG_CTL_SHOW_INTERFACE, 0, 0, -1, 129 &ifidx, sizeof(ifidx)); 130 break; 131 case SHOW_NBR: 132 case SHOW_NBR_DTAIL: 133 imsg_compose(ibuf, IMSG_CTL_SHOW_NBR, 0, 0, -1, NULL, 0); 134 break; 135 case SHOW_DB: 136 imsg_compose(ibuf, IMSG_CTL_SHOW_DATABASE, 0, 0, -1, NULL, 0); 137 break; 138 case SHOW_DBBYAREA: 139 imsg_compose(ibuf, IMSG_CTL_SHOW_DATABASE, 0, 0, -1, 140 &res->addr, sizeof(res->addr)); 141 break; 142 case SHOW_DBEXT: 143 imsg_compose(ibuf, IMSG_CTL_SHOW_DB_EXT, 0, 0, -1, NULL, 0); 144 break; 145 case SHOW_DBNET: 146 imsg_compose(ibuf, IMSG_CTL_SHOW_DB_NET, 0, 0, -1, NULL, 0); 147 break; 148 case SHOW_DBRTR: 149 imsg_compose(ibuf, IMSG_CTL_SHOW_DB_RTR, 0, 0, -1, NULL, 0); 150 break; 151 case SHOW_DBSELF: 152 imsg_compose(ibuf, IMSG_CTL_SHOW_DB_SELF, 0, 0, -1, NULL, 0); 153 break; 154 case SHOW_DBSUM: 155 imsg_compose(ibuf, IMSG_CTL_SHOW_DB_SUM, 0, 0, -1, NULL, 0); 156 break; 157 case SHOW_DBASBR: 158 imsg_compose(ibuf, IMSG_CTL_SHOW_DB_ASBR, 0, 0, -1, NULL, 0); 159 break; 160 case SHOW_DBOPAQ: 161 imsg_compose(ibuf, IMSG_CTL_SHOW_DB_OPAQ, 0, 0, -1, NULL, 0); 162 break; 163 case SHOW_RIB: 164 case SHOW_RIB_DTAIL: 165 imsg_compose(ibuf, IMSG_CTL_SHOW_RIB, 0, 0, -1, NULL, 0); 166 break; 167 case SHOW_FIB: 168 if (!res->addr.s_addr) 169 imsg_compose(ibuf, IMSG_CTL_KROUTE, 0, 0, -1, 170 &res->flags, sizeof(res->flags)); 171 else 172 imsg_compose(ibuf, IMSG_CTL_KROUTE_ADDR, 0, 0, -1, 173 &res->addr, sizeof(res->addr)); 174 break; 175 case SHOW_FIB_IFACE: 176 if (*res->ifname) 177 imsg_compose(ibuf, IMSG_CTL_IFINFO, 0, 0, -1, 178 res->ifname, sizeof(res->ifname)); 179 else 180 imsg_compose(ibuf, IMSG_CTL_IFINFO, 0, 0, -1, NULL, 0); 181 break; 182 case FIB: 183 errx(1, "fib couple|decouple"); 184 break; 185 case FIB_COUPLE: 186 imsg_compose(ibuf, IMSG_CTL_FIB_COUPLE, 0, 0, -1, NULL, 0); 187 printf("couple request sent.\n"); 188 done = 1; 189 break; 190 case FIB_DECOUPLE: 191 imsg_compose(ibuf, IMSG_CTL_FIB_DECOUPLE, 0, 0, -1, NULL, 0); 192 printf("decouple request sent.\n"); 193 done = 1; 194 break; 195 case FIB_RELOAD: 196 imsg_compose(ibuf, IMSG_CTL_FIB_RELOAD, 0, 0, -1, NULL, 0); 197 printf("reload request sent.\n"); 198 done = 1; 199 break; 200 case LOG_VERBOSE: 201 verbose = 1; 202 /* FALLTHROUGH */ 203 case LOG_BRIEF: 204 imsg_compose(ibuf, IMSG_CTL_LOG_VERBOSE, 0, 0, -1, 205 &verbose, sizeof(verbose)); 206 printf("logging request sent.\n"); 207 done = 1; 208 break; 209 case RELOAD: 210 imsg_compose(ibuf, IMSG_CTL_RELOAD, 0, 0, -1, NULL, 0); 211 printf("reload request sent.\n"); 212 done = 1; 213 break; 214 } 215 216 while (ibuf->w.queued) 217 if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN) 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 = imsg_read(ibuf)) == -1 && errno != EAGAIN) 226 errx(1, "imsg_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 250int 251show(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 344uint64_t 345get_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 361const char * 362print_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 373const char * 374fmt_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 410const char * 411log_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 424const char * 425log_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 */ 439u_int8_t 440mask2prefixlen(in_addr_t ina) 441{ 442 if (ina == 0) 443 return (0); 444 else 445 return (33 - ffs(ntohl(ina))); 446} 447 448char * 449print_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 473char * 474print_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 490const char * 491print_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 502const char * 503print_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 519const char * 520print_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 531const struct if_status_description 532 if_status_descriptions[] = LINK_STATE_DESCRIPTIONS; 533const struct ifmedia_description 534 ifm_type_descriptions[] = IFM_TYPE_DESCRIPTIONS; 535 536const char * 537get_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 548const char * 549get_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 562const char * 563print_baudrate(u_int64_t baudrate) 564{ 565 static char buf[32]; 566 if (baudrate > IF_Gbps(1)) 567 snprintf(buf, sizeof(buf), "%llu GBit/s", baudrate / IF_Gbps(1)); 568 else if (baudrate > IF_Mbps(1)) 569 snprintf(buf, sizeof(buf), "%llu MBit/s", baudrate / IF_Mbps(1)); 570 else if (baudrate > IF_Kbps(1)) 571 snprintf(buf, sizeof(buf), "%llu KBit/s", baudrate / IF_Kbps(1)); 572 else 573 snprintf(buf, sizeof(buf), "%llu Bit/s", baudrate); 574 return (buf); 575} 576 577