1 /* $OpenBSD: brconfig.c,v 1.11 2016/09/03 17:13:48 chl Exp $ */ 2 3 /* 4 * Copyright (c) 1999, 2000 Jason L. Wright (jason@thought.net) 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 25 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #ifndef SMALL 30 31 #include <stdio.h> 32 #include <sys/types.h> 33 #include <sys/stdint.h> 34 #include <unistd.h> 35 #include <stdlib.h> 36 #include <sys/socket.h> 37 #include <sys/ioctl.h> 38 #include <net/if.h> 39 #include <net/if_dl.h> 40 #include <netinet/in.h> 41 #include <netinet/if_ether.h> 42 #include <net/if_bridge.h> 43 #include <netdb.h> 44 #include <string.h> 45 #include <err.h> 46 #include <errno.h> 47 #include <getopt.h> 48 #include <limits.h> 49 50 #include "brconfig.h" 51 52 void bridge_ifsetflag(const char *, u_int32_t); 53 void bridge_ifclrflag(const char *, u_int32_t); 54 55 void bridge_list(char *); 56 void bridge_cfg(const char *); 57 void bridge_badrule(int, char **, int); 58 void bridge_showrule(struct ifbrlreq *); 59 int is_switch(char *); 60 61 #define IFBAFBITS "\020\1STATIC" 62 #define IFBIFBITS \ 63 "\020\1LEARNING\2DISCOVER\3BLOCKNONIP\4STP\5EDGE\6AUTOEDGE\7PTP\10AUTOPTP\11SPAN\15LOCAL" 64 65 #define PV2ID(pv, epri, eaddr) do { \ 66 epri = pv >> 48; \ 67 eaddr[0] = pv >> 40; \ 68 eaddr[1] = pv >> 32; \ 69 eaddr[2] = pv >> 24; \ 70 eaddr[3] = pv >> 16; \ 71 eaddr[4] = pv >> 8; \ 72 eaddr[5] = pv >> 0; \ 73 } while (0) 74 75 char *stpstates[] = { 76 "disabled", 77 "listening", 78 "learning", 79 "forwarding", 80 "blocking", 81 "discarding" 82 }; 83 char *stpproto[] = { 84 "stp", 85 "(none)", 86 "rstp", 87 }; 88 char *stproles[] = { 89 "disabled", 90 "root", 91 "designated", 92 "alternate", 93 "backup" 94 }; 95 96 97 void 98 setdiscover(const char *val, int d) 99 { 100 bridge_ifsetflag(val, IFBIF_DISCOVER); 101 } 102 103 void 104 unsetdiscover(const char *val, int d) 105 { 106 bridge_ifclrflag(val, IFBIF_DISCOVER); 107 } 108 109 void 110 setblocknonip(const char *val, int d) 111 { 112 bridge_ifsetflag(val, IFBIF_BLOCKNONIP); 113 } 114 115 void 116 unsetblocknonip(const char *val, int d) 117 { 118 bridge_ifclrflag(val, IFBIF_BLOCKNONIP); 119 } 120 121 void 122 setlearn(const char *val, int d) 123 { 124 bridge_ifsetflag(val, IFBIF_LEARNING); 125 } 126 127 void 128 unsetlearn(const char *val, int d) 129 { 130 bridge_ifclrflag(val, IFBIF_LEARNING); 131 } 132 133 void 134 setstp(const char *val, int d) 135 { 136 bridge_ifsetflag(val, IFBIF_STP); 137 } 138 139 void 140 unsetstp(const char *val, int d) 141 { 142 bridge_ifclrflag(val, IFBIF_STP); 143 } 144 145 void 146 setedge(const char *val, int d) 147 { 148 bridge_ifsetflag(val, IFBIF_BSTP_EDGE); 149 } 150 151 void 152 unsetedge(const char *val, int d) 153 { 154 bridge_ifclrflag(val, IFBIF_BSTP_EDGE); 155 } 156 157 void 158 setautoedge(const char *val, int d) 159 { 160 bridge_ifsetflag(val, IFBIF_BSTP_AUTOEDGE); 161 } 162 163 void 164 unsetautoedge(const char *val, int d) 165 { 166 bridge_ifclrflag(val, IFBIF_BSTP_AUTOEDGE); 167 } 168 169 void 170 setptp(const char *val, int d) 171 { 172 bridge_ifsetflag(val, IFBIF_BSTP_PTP); 173 } 174 175 void 176 unsetptp(const char *val, int d) 177 { 178 bridge_ifclrflag(val, IFBIF_BSTP_PTP); 179 } 180 181 void 182 setautoptp(const char *val, int d) 183 { 184 bridge_ifsetflag(val, IFBIF_BSTP_AUTOPTP); 185 } 186 187 void 188 unsetautoptp(const char *val, int d) 189 { 190 bridge_ifclrflag(val, IFBIF_BSTP_AUTOPTP); 191 } 192 193 void 194 addlocal(const char *ifsname, int d) 195 { 196 struct ifbreq breq; 197 198 if (strncmp(ifsname, "vether", (sizeof("vether") - 1)) != 0) 199 errx(1, "only vether can be local interface"); 200 201 /* Add local */ 202 strlcpy(breq.ifbr_name, name, sizeof(breq.ifbr_name)); 203 strlcpy(breq.ifbr_ifsname, ifsname, sizeof(breq.ifbr_ifsname)); 204 if (ioctl(s, SIOCBRDGADDL, (caddr_t)&breq) < 0) { 205 if (errno == EEXIST) 206 errx(1, "%s: local port exists already", name); 207 else 208 err(1, "%s: ioctl SIOCBRDGADDL %s", name, ifsname); 209 } 210 } 211 212 void 213 bridge_ifsetflag(const char *ifsname, u_int32_t flag) 214 { 215 struct ifbreq req; 216 217 strlcpy(req.ifbr_name, name, sizeof(req.ifbr_name)); 218 strlcpy(req.ifbr_ifsname, ifsname, sizeof(req.ifbr_ifsname)); 219 if (ioctl(s, SIOCBRDGGIFFLGS, (caddr_t)&req) < 0) 220 err(1, "%s: ioctl SIOCBRDGGIFFLGS %s", name, ifsname); 221 222 req.ifbr_ifsflags |= flag & ~IFBIF_RO_MASK; 223 224 if (ioctl(s, SIOCBRDGSIFFLGS, (caddr_t)&req) < 0) 225 err(1, "%s: ioctl SIOCBRDGSIFFLGS %s", name, ifsname); 226 } 227 228 void 229 bridge_ifclrflag(const char *ifsname, u_int32_t flag) 230 { 231 struct ifbreq req; 232 233 strlcpy(req.ifbr_name, name, sizeof(req.ifbr_name)); 234 strlcpy(req.ifbr_ifsname, ifsname, sizeof(req.ifbr_ifsname)); 235 236 if (ioctl(s, SIOCBRDGGIFFLGS, (caddr_t)&req) < 0) 237 err(1, "%s: ioctl SIOCBRDGGIFFLGS %s", name, ifsname); 238 239 req.ifbr_ifsflags &= ~(flag | IFBIF_RO_MASK); 240 241 if (ioctl(s, SIOCBRDGSIFFLGS, (caddr_t)&req) < 0) 242 err(1, "%s: ioctl SIOCBRDGSIFFLGS %s", name, ifsname); 243 } 244 245 void 246 bridge_flushall(const char *val, int p) 247 { 248 struct ifbreq req; 249 250 strlcpy(req.ifbr_name, name, sizeof(req.ifbr_name)); 251 req.ifbr_ifsflags = IFBF_FLUSHALL; 252 if (ioctl(s, SIOCBRDGFLUSH, &req) < 0) 253 err(1, "%s", name); 254 } 255 256 void 257 bridge_flush(const char *val, int p) 258 { 259 struct ifbreq req; 260 261 strlcpy(req.ifbr_name, name, sizeof(req.ifbr_name)); 262 req.ifbr_ifsflags = IFBF_FLUSHDYN; 263 if (ioctl(s, SIOCBRDGFLUSH, &req) < 0) 264 err(1, "%s", name); 265 } 266 267 void 268 bridge_cfg(const char *delim) 269 { 270 struct ifbropreq ifbp; 271 u_int16_t pri; 272 u_int8_t ht, fd, ma, hc, proto; 273 u_int8_t lladdr[ETHER_ADDR_LEN]; 274 u_int16_t bprio; 275 276 strlcpy(ifbp.ifbop_name, name, sizeof(ifbp.ifbop_name)); 277 if (ioctl(s, SIOCBRDGGPARAM, (caddr_t)&ifbp)) 278 err(1, "%s", name); 279 printf("%s", delim); 280 pri = ifbp.ifbop_priority; 281 ht = ifbp.ifbop_hellotime; 282 fd = ifbp.ifbop_fwddelay; 283 ma = ifbp.ifbop_maxage; 284 hc = ifbp.ifbop_holdcount; 285 proto = ifbp.ifbop_protocol; 286 287 printf("priority %u hellotime %u fwddelay %u maxage %u " 288 "holdcnt %u proto %s\n", pri, ht, fd, ma, hc, stpproto[proto]); 289 290 if (aflag) 291 return; 292 293 PV2ID(ifbp.ifbop_desg_bridge, bprio, lladdr); 294 printf("\tdesignated: id %s priority %u\n", 295 ether_ntoa((struct ether_addr *)lladdr), bprio); 296 297 if (ifbp.ifbop_root_bridge == ifbp.ifbop_desg_bridge) 298 return; 299 300 PV2ID(ifbp.ifbop_root_bridge, bprio, lladdr); 301 printf("\troot: id %s priority %u ifcost %u port %u\n", 302 ether_ntoa((struct ether_addr *)lladdr), bprio, 303 ifbp.ifbop_root_path_cost, ifbp.ifbop_root_port & 0xfff); 304 } 305 306 void 307 bridge_list(char *delim) 308 { 309 struct ifbreq *reqp; 310 struct ifbifconf bifc; 311 int i, len = 8192; 312 char buf[sizeof(reqp->ifbr_ifsname) + 1], *inbuf = NULL, *inb; 313 314 while (1) { 315 bifc.ifbic_len = len; 316 inb = realloc(inbuf, len); 317 if (inb == NULL) 318 err(1, "malloc"); 319 bifc.ifbic_buf = inbuf = inb; 320 strlcpy(bifc.ifbic_name, name, sizeof(bifc.ifbic_name)); 321 if (ioctl(s, SIOCBRDGIFS, &bifc) < 0) 322 err(1, "%s", name); 323 if (bifc.ifbic_len + sizeof(*reqp) < len) 324 break; 325 len *= 2; 326 } 327 for (i = 0; i < bifc.ifbic_len / sizeof(*reqp); i++) { 328 reqp = bifc.ifbic_req + i; 329 strlcpy(buf, reqp->ifbr_ifsname, sizeof(buf)); 330 printf("%s%s ", delim, buf); 331 printb("flags", reqp->ifbr_ifsflags, IFBIFBITS); 332 printf("\n"); 333 if (reqp->ifbr_ifsflags & IFBIF_SPAN) 334 continue; 335 printf("\t\t"); 336 printf("port %u ifpriority %u ifcost %u", 337 reqp->ifbr_portno, reqp->ifbr_priority, 338 reqp->ifbr_path_cost); 339 if (reqp->ifbr_ifsflags & IFBIF_STP) 340 printf(" %s role %s", 341 stpstates[reqp->ifbr_state], 342 stproles[reqp->ifbr_role]); 343 printf("\n"); 344 bridge_rules(buf, 1); 345 } 346 free(bifc.ifbic_buf); 347 } 348 349 void 350 bridge_add(const char *ifn, int d) 351 { 352 struct ifbreq req; 353 354 strlcpy(req.ifbr_name, name, sizeof(req.ifbr_name)); 355 strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname)); 356 if (ioctl(s, SIOCBRDGADD, &req) < 0) { 357 if (errno == EEXIST) 358 return; 359 err(1, "%s: %s", name, ifn); 360 } 361 } 362 363 void 364 bridge_delete(const char *ifn, int d) 365 { 366 struct ifbreq req; 367 368 strlcpy(req.ifbr_name, name, sizeof(req.ifbr_name)); 369 strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname)); 370 if (ioctl(s, SIOCBRDGDEL, &req) < 0) 371 err(1, "%s: %s", name, ifn); 372 } 373 374 void 375 bridge_addspan(const char *ifn, int d) 376 { 377 struct ifbreq req; 378 379 strlcpy(req.ifbr_name, name, sizeof(req.ifbr_name)); 380 strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname)); 381 if (ioctl(s, SIOCBRDGADDS, &req) < 0) { 382 if (errno == EEXIST) 383 return; 384 err(1, "%s: %s", name, ifn); 385 } 386 } 387 388 void 389 bridge_delspan(const char *ifn, int d) 390 { 391 struct ifbreq req; 392 393 strlcpy(req.ifbr_name, name, sizeof(req.ifbr_name)); 394 strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname)); 395 if (ioctl(s, SIOCBRDGDELS, &req) < 0) 396 err(1, "%s: %s", name, ifn); 397 } 398 399 void 400 bridge_timeout(const char *arg, int d) 401 { 402 struct ifbrparam bp; 403 long newtime; 404 char *endptr; 405 406 errno = 0; 407 newtime = strtol(arg, &endptr, 0); 408 if (arg[0] == '\0' || endptr[0] != '\0' || 409 (newtime & ~INT_MAX) != 0L || 410 (errno == ERANGE && newtime == LONG_MAX)) 411 errx(1, "invalid arg for timeout: %s", arg); 412 413 strlcpy(bp.ifbrp_name, name, sizeof(bp.ifbrp_name)); 414 bp.ifbrp_ctime = newtime; 415 if (ioctl(s, SIOCBRDGSTO, (caddr_t)&bp) < 0) 416 err(1, "%s", name); 417 } 418 419 void 420 bridge_maxage(const char *arg, int d) 421 { 422 struct ifbrparam bp; 423 unsigned long v; 424 char *endptr; 425 426 errno = 0; 427 v = strtoul(arg, &endptr, 0); 428 if (arg[0] == '\0' || endptr[0] != '\0' || v > 0xffUL || 429 (errno == ERANGE && v == ULONG_MAX)) 430 errx(1, "invalid arg for maxage: %s", arg); 431 432 strlcpy(bp.ifbrp_name, name, sizeof(bp.ifbrp_name)); 433 bp.ifbrp_maxage = v; 434 if (ioctl(s, SIOCBRDGSMA, (caddr_t)&bp) < 0) 435 err(1, "%s", name); 436 } 437 438 void 439 bridge_priority(const char *arg, int d) 440 { 441 struct ifbrparam bp; 442 unsigned long v; 443 char *endptr; 444 445 errno = 0; 446 v = strtoul(arg, &endptr, 0); 447 if (arg[0] == '\0' || endptr[0] != '\0' || v > 0xffffUL || 448 (errno == ERANGE && v == ULONG_MAX)) 449 errx(1, "invalid arg for spanpriority: %s", arg); 450 451 strlcpy(bp.ifbrp_name, name, sizeof(bp.ifbrp_name)); 452 bp.ifbrp_prio = v; 453 if (ioctl(s, SIOCBRDGSPRI, (caddr_t)&bp) < 0) 454 err(1, "%s", name); 455 } 456 457 void 458 bridge_proto(const char *arg, int d) 459 { 460 struct ifbrparam bp; 461 int i, proto = -1; 462 463 for (i = 0; i <= BSTP_PROTO_MAX; i++) 464 if (strcmp(arg, stpproto[i]) == 0) { 465 proto = i; 466 break; 467 } 468 if (proto == -1) 469 errx(1, "invalid arg for proto: %s", arg); 470 471 strlcpy(bp.ifbrp_name, name, sizeof(bp.ifbrp_name)); 472 bp.ifbrp_prio = proto; 473 if (ioctl(s, SIOCBRDGSPROTO, (caddr_t)&bp) < 0) 474 err(1, "%s", name); 475 } 476 477 void 478 bridge_fwddelay(const char *arg, int d) 479 { 480 struct ifbrparam bp; 481 unsigned long v; 482 char *endptr; 483 484 errno = 0; 485 v = strtoul(arg, &endptr, 0); 486 if (arg[0] == '\0' || endptr[0] != '\0' || v > 0xffUL || 487 (errno == ERANGE && v == ULONG_MAX)) 488 errx(1, "invalid arg for fwddelay: %s", arg); 489 490 strlcpy(bp.ifbrp_name, name, sizeof(bp.ifbrp_name)); 491 bp.ifbrp_fwddelay = v; 492 if (ioctl(s, SIOCBRDGSFD, (caddr_t)&bp) < 0) 493 err(1, "%s", name); 494 } 495 496 void 497 bridge_hellotime(const char *arg, int d) 498 { 499 struct ifbrparam bp; 500 unsigned long v; 501 char *endptr; 502 503 errno = 0; 504 v = strtoul(arg, &endptr, 0); 505 if (arg[0] == '\0' || endptr[0] != '\0' || v > 0xffUL || 506 (errno == ERANGE && v == ULONG_MAX)) 507 errx(1, "invalid arg for hellotime: %s", arg); 508 509 strlcpy(bp.ifbrp_name, name, sizeof(bp.ifbrp_name)); 510 bp.ifbrp_hellotime = v; 511 if (ioctl(s, SIOCBRDGSHT, (caddr_t)&bp) < 0) 512 err(1, "%s", name); 513 } 514 515 void 516 bridge_maxaddr(const char *arg, int d) 517 { 518 struct ifbrparam bp; 519 unsigned long newsize; 520 char *endptr; 521 522 errno = 0; 523 newsize = strtoul(arg, &endptr, 0); 524 if (arg[0] == '\0' || endptr[0] != '\0' || newsize > 0xffffffffUL || 525 (errno == ERANGE && newsize == ULONG_MAX)) 526 errx(1, "invalid arg for maxaddr: %s", arg); 527 528 strlcpy(bp.ifbrp_name, name, sizeof(bp.ifbrp_name)); 529 bp.ifbrp_csize = newsize; 530 if (ioctl(s, SIOCBRDGSCACHE, (caddr_t)&bp) < 0) 531 err(1, "%s", name); 532 } 533 534 void 535 bridge_deladdr(const char *addr, int d) 536 { 537 struct ifbareq ifba; 538 struct ether_addr *ea; 539 540 strlcpy(ifba.ifba_name, name, sizeof(ifba.ifba_name)); 541 ea = ether_aton(addr); 542 if (ea == NULL) 543 err(1, "Invalid address: %s", addr); 544 545 bcopy(ea, &ifba.ifba_dst, sizeof(struct ether_addr)); 546 547 if (ioctl(s, SIOCBRDGDADDR, &ifba) < 0) 548 err(1, "%s: %s", name, addr); 549 } 550 551 void 552 bridge_ifprio(const char *ifname, const char *val) 553 { 554 struct ifbreq breq; 555 unsigned long v; 556 char *endptr; 557 558 strlcpy(breq.ifbr_name, name, sizeof(breq.ifbr_name)); 559 strlcpy(breq.ifbr_ifsname, ifname, sizeof(breq.ifbr_ifsname)); 560 561 errno = 0; 562 v = strtoul(val, &endptr, 0); 563 if (val[0] == '\0' || endptr[0] != '\0' || v > 0xffUL || 564 (errno == ERANGE && v == ULONG_MAX)) 565 err(1, "invalid arg for ifpriority: %s", val); 566 breq.ifbr_priority = v; 567 568 if (ioctl(s, SIOCBRDGSIFPRIO, (caddr_t)&breq) < 0) 569 err(1, "%s: %s", name, val); 570 } 571 572 void 573 bridge_ifcost(const char *ifname, const char *val) 574 { 575 struct ifbreq breq; 576 unsigned long v; 577 char *endptr; 578 579 strlcpy(breq.ifbr_name, name, sizeof(breq.ifbr_name)); 580 strlcpy(breq.ifbr_ifsname, ifname, sizeof(breq.ifbr_ifsname)); 581 582 errno = 0; 583 v = strtoul(val, &endptr, 0); 584 if (val[0] == '\0' || endptr[0] != '\0' || 585 v < 0 || v > 0xffffffffUL || 586 (errno == ERANGE && v == ULONG_MAX)) 587 errx(1, "invalid arg for ifcost: %s", val); 588 589 breq.ifbr_path_cost = v; 590 591 if (ioctl(s, SIOCBRDGSIFCOST, (caddr_t)&breq) < 0) 592 err(1, "%s: %s", name, val); 593 } 594 595 void 596 bridge_noifcost(const char *ifname, int d) 597 { 598 struct ifbreq breq; 599 600 strlcpy(breq.ifbr_name, name, sizeof(breq.ifbr_name)); 601 strlcpy(breq.ifbr_ifsname, ifname, sizeof(breq.ifbr_ifsname)); 602 603 breq.ifbr_path_cost = 0; 604 605 if (ioctl(s, SIOCBRDGSIFCOST, (caddr_t)&breq) < 0) 606 err(1, "%s", name); 607 } 608 609 void 610 bridge_addaddr(const char *ifname, const char *addr) 611 { 612 struct ifbareq ifba; 613 struct ether_addr *ea; 614 615 strlcpy(ifba.ifba_name, name, sizeof(ifba.ifba_name)); 616 strlcpy(ifba.ifba_ifsname, ifname, sizeof(ifba.ifba_ifsname)); 617 618 ea = ether_aton(addr); 619 if (ea == NULL) 620 errx(1, "Invalid address: %s", addr); 621 622 bcopy(ea, &ifba.ifba_dst, sizeof(struct ether_addr)); 623 ifba.ifba_flags = IFBAF_STATIC; 624 625 if (ioctl(s, SIOCBRDGSADDR, &ifba) < 0) 626 err(1, "%s: %s", name, addr); 627 } 628 629 void 630 bridge_addrs(const char *delim, int d) 631 { 632 char dstaddr[NI_MAXHOST]; 633 char dstport[NI_MAXSERV]; 634 const int niflag = NI_NUMERICHOST|NI_DGRAM; 635 struct ifbaconf ifbac; 636 struct ifbareq *ifba; 637 char *inbuf = NULL, buf[sizeof(ifba->ifba_ifsname) + 1], *inb; 638 struct sockaddr *sa; 639 int i, len = 8192; 640 641 /* ifconfig will call us with the argv of the command */ 642 if (strcmp(delim, "addr") == 0) 643 delim = ""; 644 645 while (1) { 646 ifbac.ifbac_len = len; 647 inb = realloc(inbuf, len); 648 if (inb == NULL) 649 err(1, "malloc"); 650 ifbac.ifbac_buf = inbuf = inb; 651 strlcpy(ifbac.ifbac_name, name, sizeof(ifbac.ifbac_name)); 652 if (ioctl(s, SIOCBRDGRTS, &ifbac) < 0) { 653 if (errno == ENETDOWN) 654 return; 655 err(1, "%s", name); 656 } 657 if (ifbac.ifbac_len + sizeof(*ifba) < len) 658 break; 659 len *= 2; 660 } 661 662 for (i = 0; i < ifbac.ifbac_len / sizeof(*ifba); i++) { 663 ifba = ifbac.ifbac_req + i; 664 strlcpy(buf, ifba->ifba_ifsname, sizeof(buf)); 665 printf("%s%s %s %u ", delim, ether_ntoa(&ifba->ifba_dst), 666 buf, ifba->ifba_age); 667 sa = (struct sockaddr *)&ifba->ifba_dstsa; 668 printb("flags", ifba->ifba_flags, IFBAFBITS); 669 if (sa->sa_family != AF_UNSPEC && 670 getnameinfo(sa, sa->sa_len, 671 dstaddr, sizeof(dstaddr), 672 dstport, sizeof(dstport), niflag) == 0) 673 printf(" tunnel %s:%s", dstaddr, dstport); 674 printf("\n"); 675 } 676 free(inbuf); 677 } 678 679 void 680 bridge_holdcnt(const char *value, int d) 681 { 682 struct ifbrparam bp; 683 const char *errstr; 684 685 bp.ifbrp_txhc = strtonum(value, 0, UINT8_MAX, &errstr); 686 if (errstr) 687 err(1, "holdcnt %s %s", value, errstr); 688 689 strlcpy(bp.ifbrp_name, name, sizeof(bp.ifbrp_name)); 690 if (ioctl(s, SIOCBRDGSTXHC, (caddr_t)&bp) < 0) 691 err(1, "%s", name); 692 } 693 694 /* 695 * Check to make sure 'brdg' is really a bridge interface. 696 */ 697 int 698 is_bridge(char *brdg) 699 { 700 struct ifreq ifr; 701 struct ifbaconf ifbac; 702 703 strlcpy(ifr.ifr_name, brdg, sizeof(ifr.ifr_name)); 704 705 if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) 706 return (0); 707 708 ifbac.ifbac_len = 0; 709 strlcpy(ifbac.ifbac_name, brdg, sizeof(ifbac.ifbac_name)); 710 if (ioctl(s, SIOCBRDGRTS, (caddr_t)&ifbac) < 0) { 711 if (errno == ENETDOWN) 712 return (1); 713 return (0); 714 } 715 return (1); 716 } 717 718 void 719 bridge_status(void) 720 { 721 struct ifreq ifr; 722 struct ifbrparam bp1, bp2; 723 724 if (!is_bridge(name) || is_switch(name)) 725 return; 726 727 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 728 if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) 729 return; 730 731 bridge_cfg("\t"); 732 733 bridge_list("\t"); 734 735 if (aflag && !ifaliases) 736 return; 737 738 strlcpy(bp1.ifbrp_name, name, sizeof(bp1.ifbrp_name)); 739 if (ioctl(s, SIOCBRDGGCACHE, (caddr_t)&bp1) < 0) 740 return; 741 742 strlcpy(bp2.ifbrp_name, name, sizeof(bp2.ifbrp_name)); 743 if (ioctl(s, SIOCBRDGGTO, (caddr_t)&bp2) < 0) 744 return; 745 746 printf("\tAddresses (max cache: %u, timeout: %u):\n", 747 bp1.ifbrp_csize, bp2.ifbrp_ctime); 748 749 bridge_addrs("\t\t", 0); 750 } 751 752 void 753 bridge_flushrule(const char *ifname, int d) 754 { 755 struct ifbrlreq req; 756 757 strlcpy(req.ifbr_name, name, sizeof(req.ifbr_name)); 758 strlcpy(req.ifbr_ifsname, ifname, sizeof(req.ifbr_ifsname)); 759 if (ioctl(s, SIOCBRDGFRL, &req) < 0) 760 err(1, "%s: %s", name, ifname); 761 } 762 763 void 764 bridge_rules(const char *ifname, int usetab) 765 { 766 char *inbuf = NULL, *inb; 767 struct ifbrlconf ifc; 768 struct ifbrlreq *ifrp; 769 int len = 8192, i; 770 771 while (1) { 772 ifc.ifbrl_len = len; 773 inb = realloc(inbuf, len); 774 if (inb == NULL) 775 err(1, "malloc"); 776 ifc.ifbrl_buf = inbuf = inb; 777 strlcpy(ifc.ifbrl_name, name, sizeof(ifc.ifbrl_name)); 778 strlcpy(ifc.ifbrl_ifsname, ifname, sizeof(ifc.ifbrl_ifsname)); 779 if (ioctl(s, SIOCBRDGGRL, &ifc) < 0) 780 err(1, "ioctl(SIOCBRDGGRL)"); 781 if (ifc.ifbrl_len + sizeof(*ifrp) < len) 782 break; 783 len *= 2; 784 } 785 ifrp = ifc.ifbrl_req; 786 for (i = 0; i < ifc.ifbrl_len; i += sizeof(*ifrp)) { 787 ifrp = (struct ifbrlreq *)((caddr_t)ifc.ifbrl_req + i); 788 789 if (usetab) 790 printf("\t"); 791 792 bridge_showrule(ifrp); 793 } 794 } 795 796 void 797 bridge_showrule(struct ifbrlreq *r) 798 { 799 if (r->ifbr_action == BRL_ACTION_BLOCK) 800 printf("block "); 801 else if (r->ifbr_action == BRL_ACTION_PASS) 802 printf("pass "); 803 else 804 printf("[neither block nor pass?]\n"); 805 806 if ((r->ifbr_flags & (BRL_FLAG_IN | BRL_FLAG_OUT)) == 807 (BRL_FLAG_IN | BRL_FLAG_OUT)) 808 printf("in/out "); 809 else if (r->ifbr_flags & BRL_FLAG_IN) 810 printf("in "); 811 else if (r->ifbr_flags & BRL_FLAG_OUT) 812 printf("out "); 813 else 814 printf("[neither in nor out?]\n"); 815 816 printf("on %s", r->ifbr_ifsname); 817 818 if (r->ifbr_flags & BRL_FLAG_SRCVALID) 819 printf(" src %s", ether_ntoa(&r->ifbr_src)); 820 if (r->ifbr_flags & BRL_FLAG_DSTVALID) 821 printf(" dst %s", ether_ntoa(&r->ifbr_dst)); 822 if (r->ifbr_tagname[0]) 823 printf(" tag %s", r->ifbr_tagname); 824 825 printf("\n"); 826 } 827 828 /* 829 * Parse a rule definition and send it upwards. 830 * 831 * Syntax: 832 * {block|pass} {in|out|in/out} on {ifs} [src {mac}] [dst {mac}] 833 */ 834 int 835 bridge_rule(int targc, char **targv, int ln) 836 { 837 char **argv = targv; 838 int argc = targc; 839 struct ifbrlreq rule; 840 struct ether_addr *ea, *dea; 841 842 if (argc == 0) { 843 warnx("invalid rule"); 844 return (1); 845 } 846 rule.ifbr_tagname[0] = 0; 847 rule.ifbr_flags = 0; 848 rule.ifbr_action = 0; 849 strlcpy(rule.ifbr_name, name, sizeof(rule.ifbr_name)); 850 851 if (strcmp(argv[0], "block") == 0) 852 rule.ifbr_action = BRL_ACTION_BLOCK; 853 else if (strcmp(argv[0], "pass") == 0) 854 rule.ifbr_action = BRL_ACTION_PASS; 855 else 856 goto bad_rule; 857 argc--; argv++; 858 859 if (argc == 0) { 860 bridge_badrule(targc, targv, ln); 861 return (1); 862 } 863 if (strcmp(argv[0], "in") == 0) 864 rule.ifbr_flags |= BRL_FLAG_IN; 865 else if (strcmp(argv[0], "out") == 0) 866 rule.ifbr_flags |= BRL_FLAG_OUT; 867 else if (strcmp(argv[0], "in/out") == 0) 868 rule.ifbr_flags |= BRL_FLAG_IN | BRL_FLAG_OUT; 869 else if (strcmp(argv[0], "on") == 0) { 870 rule.ifbr_flags |= BRL_FLAG_IN | BRL_FLAG_OUT; 871 argc++; argv--; 872 } else 873 goto bad_rule; 874 argc--; argv++; 875 876 if (argc == 0 || strcmp(argv[0], "on")) 877 goto bad_rule; 878 argc--; argv++; 879 880 if (argc == 0) 881 goto bad_rule; 882 strlcpy(rule.ifbr_ifsname, argv[0], sizeof(rule.ifbr_ifsname)); 883 argc--; argv++; 884 885 while (argc) { 886 if (strcmp(argv[0], "dst") == 0) { 887 if (rule.ifbr_flags & BRL_FLAG_DSTVALID) 888 goto bad_rule; 889 rule.ifbr_flags |= BRL_FLAG_DSTVALID; 890 dea = &rule.ifbr_dst; 891 } else if (strcmp(argv[0], "src") == 0) { 892 if (rule.ifbr_flags & BRL_FLAG_SRCVALID) 893 goto bad_rule; 894 rule.ifbr_flags |= BRL_FLAG_SRCVALID; 895 dea = &rule.ifbr_src; 896 } else if (strcmp(argv[0], "tag") == 0) { 897 if (argc < 2) { 898 warnx("missing tag name"); 899 goto bad_rule; 900 } 901 if (rule.ifbr_tagname[0]) { 902 warnx("tag already defined"); 903 goto bad_rule; 904 } 905 if (strlcpy(rule.ifbr_tagname, argv[1], 906 PF_TAG_NAME_SIZE) > PF_TAG_NAME_SIZE) { 907 warnx("tag name '%s' too long", argv[1]); 908 goto bad_rule; 909 } 910 dea = NULL; 911 } else 912 goto bad_rule; 913 914 argc--; argv++; 915 916 if (argc == 0) 917 goto bad_rule; 918 if (dea != NULL) { 919 ea = ether_aton(argv[0]); 920 if (ea == NULL) { 921 warnx("invalid address: %s", argv[0]); 922 return (1); 923 } 924 bcopy(ea, dea, sizeof(*dea)); 925 } 926 argc--; argv++; 927 } 928 929 if (ioctl(s, SIOCBRDGARL, &rule) < 0) { 930 warn("%s", name); 931 return (1); 932 } 933 return (0); 934 935 bad_rule: 936 bridge_badrule(targc, targv, ln); 937 return (1); 938 } 939 940 #define MAXRULEWORDS 8 941 942 void 943 bridge_rulefile(const char *fname, int d) 944 { 945 FILE *f; 946 char *str, *argv[MAXRULEWORDS], buf[1024]; 947 int ln = 0, argc = 0; 948 949 f = fopen(fname, "r"); 950 if (f == NULL) 951 err(1, "%s", fname); 952 953 while (fgets(buf, sizeof(buf), f) != NULL) { 954 ln++; 955 if (buf[0] == '#' || buf[0] == '\n') 956 continue; 957 958 argc = 0; 959 str = strtok(buf, "\n\t\r "); 960 while (str != NULL && argc < MAXRULEWORDS) { 961 argv[argc++] = str; 962 str = strtok(NULL, "\n\t\r "); 963 } 964 965 /* Rule is too long if there's more. */ 966 if (str != NULL) { 967 warnx("invalid rule: %d: %s ...", ln, buf); 968 continue; 969 } 970 971 bridge_rule(argc, argv, ln); 972 } 973 fclose(f); 974 } 975 976 void 977 bridge_badrule(int argc, char *argv[], int ln) 978 { 979 extern const char *__progname; 980 int i; 981 982 fprintf(stderr, "%s: invalid rule: ", __progname); 983 if (ln != -1) 984 fprintf(stderr, "%d: ", ln); 985 for (i = 0; i < argc; i++) 986 fprintf(stderr, "%s ", argv[i]); 987 fprintf(stderr, "\n"); 988 } 989 990 int 991 is_switch(char *swname) 992 { 993 struct ifbrparam bp; 994 995 strlcpy(bp.ifbrp_name, swname, sizeof(bp.ifbrp_name)); 996 if (ioctl(s, SIOCSWGDPID, (caddr_t)&bp) < 0) 997 return (0); 998 999 return (1); 1000 } 1001 1002 void 1003 switch_cfg(char *delim) 1004 { 1005 struct ifbrparam bp; 1006 1007 strlcpy(bp.ifbrp_name, name, sizeof(bp.ifbrp_name)); 1008 if (ioctl(s, SIOCSWGDPID, (caddr_t)&bp) < 0) 1009 err(1, "%s", name); 1010 1011 printf("%sdatapath-id 0x%016llx\n", delim, bp.ifbrp_datapath); 1012 1013 strlcpy(bp.ifbrp_name, name, sizeof(bp.ifbrp_name)); 1014 if (ioctl(s, SIOCSWGFLOWMAX, (caddr_t)&bp) < 0) 1015 err(1, "%s", name); 1016 1017 printf("%smax flows per table %d\n", delim, bp.ifbrp_maxflow); 1018 1019 strlcpy(bp.ifbrp_name, name, sizeof(bp.ifbrp_name)); 1020 if (ioctl(s, SIOCSWGMAXGROUP, (caddr_t)&bp) < 0) 1021 err(1, "%s", name); 1022 1023 printf("%smax groups %d\n", delim, bp.ifbrp_maxgroup); 1024 } 1025 1026 void 1027 switch_status(void) 1028 { 1029 struct ifreq ifr; 1030 1031 if (!is_switch(name)) 1032 return; 1033 1034 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 1035 if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) 1036 return; 1037 1038 switch_cfg("\t"); 1039 1040 bridge_list("\t"); 1041 1042 if (aflag && !ifaliases) 1043 return; 1044 } 1045 1046 void 1047 switch_datapathid(const char *arg, int d) 1048 { 1049 struct ifbrparam bp; 1050 uint64_t newdpid; 1051 char *endptr; 1052 1053 errno = 0; 1054 newdpid = strtoll(arg, &endptr, 0); 1055 if (arg[0] == '\0' || endptr[0] != '\0' || errno == ERANGE) 1056 errx(1, "invalid arg for datapath-id: %s", arg); 1057 1058 strlcpy(bp.ifbrp_name, name, sizeof(bp.ifbrp_name)); 1059 bp.ifbrp_datapath = newdpid; 1060 if (ioctl(s, SIOCSWSDPID, (caddr_t)&bp) < 0) 1061 err(1, "%s", name); 1062 } 1063 1064 void 1065 switch_portno(const char *ifname, const char *val) 1066 { 1067 struct ifbreq breq; 1068 uint32_t newportidx; 1069 char *endptr; 1070 1071 strlcpy(breq.ifbr_name, name, sizeof(breq.ifbr_name)); 1072 strlcpy(breq.ifbr_ifsname, ifname, sizeof(breq.ifbr_ifsname)); 1073 1074 errno = 0; 1075 newportidx = strtol(val, &endptr, 0); 1076 if (val[0] == '\0' || endptr[0] != '\0' || errno == ERANGE) 1077 errx(1, "invalid arg for portidx: %s", val); 1078 1079 breq.ifbr_portno = newportidx; 1080 if (ioctl(s, SIOCSWSPORTNO, (caddr_t)&breq) < 0) 1081 err(1, "%s", name); 1082 } 1083 1084 #endif 1085