1 /* $OpenBSD: brconfig.c,v 1.33 2025/01/06 17:49:29 denis 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 <netinet/in.h> 40 #include <netinet/if_ether.h> 41 #include <net/if_bridge.h> 42 #include <netdb.h> 43 #include <string.h> 44 #include <err.h> 45 #include <errno.h> 46 #include <getopt.h> 47 #include <limits.h> 48 #include <arpa/inet.h> 49 50 #include "ifconfig.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 bridge_arprule(struct ifbrlreq *, int *, 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, ifname, sizeof(breq.ifbr_name)); 203 strlcpy(breq.ifbr_ifsname, ifsname, sizeof(breq.ifbr_ifsname)); 204 if (ioctl(sock, SIOCBRDGADDL, (caddr_t)&breq) == -1) { 205 if (errno == EEXIST) 206 return; 207 else 208 err(1, "%s: ioctl SIOCBRDGADDL %s", ifname, 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, ifname, sizeof(req.ifbr_name)); 218 strlcpy(req.ifbr_ifsname, ifsname, sizeof(req.ifbr_ifsname)); 219 if (ioctl(sock, SIOCBRDGGIFFLGS, (caddr_t)&req) == -1) 220 err(1, "%s: ioctl SIOCBRDGGIFFLGS %s", ifname, ifsname); 221 222 req.ifbr_ifsflags |= flag & ~IFBIF_RO_MASK; 223 224 if (ioctl(sock, SIOCBRDGSIFFLGS, (caddr_t)&req) == -1) 225 err(1, "%s: ioctl SIOCBRDGSIFFLGS %s", ifname, 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, ifname, sizeof(req.ifbr_name)); 234 strlcpy(req.ifbr_ifsname, ifsname, sizeof(req.ifbr_ifsname)); 235 236 if (ioctl(sock, SIOCBRDGGIFFLGS, (caddr_t)&req) == -1) 237 err(1, "%s: ioctl SIOCBRDGGIFFLGS %s", ifname, ifsname); 238 239 req.ifbr_ifsflags &= ~(flag | IFBIF_RO_MASK); 240 241 if (ioctl(sock, SIOCBRDGSIFFLGS, (caddr_t)&req) == -1) 242 err(1, "%s: ioctl SIOCBRDGSIFFLGS %s", ifname, ifsname); 243 } 244 245 void 246 bridge_flushall(const char *val, int p) 247 { 248 struct ifbreq req; 249 250 strlcpy(req.ifbr_name, ifname, sizeof(req.ifbr_name)); 251 req.ifbr_ifsflags = IFBF_FLUSHALL; 252 if (ioctl(sock, SIOCBRDGFLUSH, &req) == -1) 253 err(1, "%s", ifname); 254 } 255 256 void 257 bridge_flush(const char *val, int p) 258 { 259 struct ifbreq req; 260 261 strlcpy(req.ifbr_name, ifname, sizeof(req.ifbr_name)); 262 req.ifbr_ifsflags = IFBF_FLUSHDYN; 263 if (ioctl(sock, SIOCBRDGFLUSH, &req) == -1) 264 err(1, "%s", ifname); 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, ifname, sizeof(ifbp.ifbop_name)); 277 if (ioctl(sock, SIOCBRDGGPARAM, (caddr_t)&ifbp) == -1) { 278 if (errno == ENOTTY) 279 return; 280 err(1, "%s SIOCBRDGGPARAM", ifname); 281 } 282 283 printf("%s", delim); 284 pri = ifbp.ifbop_priority; 285 ht = ifbp.ifbop_hellotime; 286 fd = ifbp.ifbop_fwddelay; 287 ma = ifbp.ifbop_maxage; 288 hc = ifbp.ifbop_holdcount; 289 proto = ifbp.ifbop_protocol; 290 291 printf("priority %u hellotime %u fwddelay %u maxage %u " 292 "holdcnt %u proto %s\n", pri, ht, fd, ma, hc, stpproto[proto]); 293 294 if (aflag) 295 return; 296 297 PV2ID(ifbp.ifbop_desg_bridge, bprio, lladdr); 298 printf("\tdesignated: id %s priority %u\n", 299 ether_ntoa((struct ether_addr *)lladdr), bprio); 300 301 if (ifbp.ifbop_root_bridge == ifbp.ifbop_desg_bridge) 302 return; 303 304 PV2ID(ifbp.ifbop_root_bridge, bprio, lladdr); 305 printf("\troot: id %s priority %u ifcost %u port %u\n", 306 ether_ntoa((struct ether_addr *)lladdr), bprio, 307 ifbp.ifbop_root_path_cost, ifbp.ifbop_root_port & 0xfff); 308 } 309 310 void 311 bridge_list(char *delim) 312 { 313 struct ifbreq *reqp; 314 struct ifbifconf bifc; 315 int i, len = 8192; 316 char buf[sizeof(reqp->ifbr_ifsname) + 1], *inbuf = NULL, *inb; 317 318 while (1) { 319 bifc.ifbic_len = len; 320 inb = realloc(inbuf, len); 321 if (inb == NULL) 322 err(1, "malloc"); 323 bifc.ifbic_buf = inbuf = inb; 324 strlcpy(bifc.ifbic_name, ifname, sizeof(bifc.ifbic_name)); 325 if (ioctl(sock, SIOCBRDGIFS, &bifc) == -1) { 326 if (errno == ENOTTY) 327 return; 328 err(1, "%s SIOCBRDGIFS", ifname); 329 } 330 if (bifc.ifbic_len + sizeof(*reqp) < len) 331 break; 332 len *= 2; 333 } 334 for (i = 0; i < bifc.ifbic_len / sizeof(*reqp); i++) { 335 reqp = bifc.ifbic_req + i; 336 strlcpy(buf, reqp->ifbr_ifsname, sizeof(buf)); 337 printf("%s%s ", delim, buf); 338 printb("flags", reqp->ifbr_ifsflags, IFBIFBITS); 339 printf("\n"); 340 if (reqp->ifbr_ifsflags & IFBIF_SPAN) 341 continue; 342 printf("\t\t"); 343 printf("port %u ifpriority %u ifcost %u", 344 reqp->ifbr_portno, reqp->ifbr_priority, 345 reqp->ifbr_path_cost); 346 if (reqp->ifbr_protected) { 347 int v; 348 349 v = ffs(reqp->ifbr_protected); 350 printf(" protected %u", v); 351 while (++v < 32) { 352 if ((1 << (v - 1)) & reqp->ifbr_protected) 353 printf(",%u", v); 354 } 355 } 356 if (reqp->ifbr_ifsflags & IFBIF_STP) 357 printf(" %s role %s", 358 stpstates[reqp->ifbr_state], 359 stproles[reqp->ifbr_role]); 360 printf("\n"); 361 bridge_rules(buf, 1); 362 } 363 free(bifc.ifbic_buf); 364 } 365 366 void 367 bridge_add(const char *ifn, int d) 368 { 369 struct ifbreq req; 370 371 strlcpy(req.ifbr_name, ifname, sizeof(req.ifbr_name)); 372 strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname)); 373 if (ioctl(sock, SIOCBRDGADD, &req) == -1) { 374 if (errno == EEXIST) 375 return; 376 err(1, "%s: %s", ifname, ifn); 377 } 378 } 379 380 void 381 bridge_delete(const char *ifn, int d) 382 { 383 struct ifbreq req; 384 385 strlcpy(req.ifbr_name, ifname, sizeof(req.ifbr_name)); 386 strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname)); 387 if (ioctl(sock, SIOCBRDGDEL, &req) == -1) 388 err(1, "%s: %s", ifname, ifn); 389 } 390 391 void 392 bridge_addspan(const char *ifn, int d) 393 { 394 struct ifbreq req; 395 396 strlcpy(req.ifbr_name, ifname, sizeof(req.ifbr_name)); 397 strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname)); 398 if (ioctl(sock, SIOCBRDGADDS, &req) == -1) { 399 if (errno == EEXIST) 400 return; 401 err(1, "%s: %s", ifname, ifn); 402 } 403 } 404 405 void 406 bridge_delspan(const char *ifn, int d) 407 { 408 struct ifbreq req; 409 410 strlcpy(req.ifbr_name, ifname, sizeof(req.ifbr_name)); 411 strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname)); 412 if (ioctl(sock, SIOCBRDGDELS, &req) == -1) 413 err(1, "%s: %s", ifname, ifn); 414 } 415 416 void 417 bridge_timeout(const char *arg, int d) 418 { 419 struct ifbrparam bp; 420 const char *errstr; 421 422 bp.ifbrp_ctime = strtonum(arg, 0, UINT32_MAX, &errstr); 423 if (errstr) 424 err(1, "timeout %s is: %s", arg, errstr); 425 426 strlcpy(bp.ifbrp_name, ifname, sizeof(bp.ifbrp_name)); 427 if (ioctl(sock, SIOCBRDGSTO, (caddr_t)&bp) == -1) 428 err(1, "%s", ifname); 429 } 430 431 void 432 bridge_maxage(const char *arg, int d) 433 { 434 struct ifbrparam bp; 435 const char *errstr; 436 437 bp.ifbrp_maxage = strtonum(arg, 0, UINT8_MAX, &errstr); 438 if (errstr) 439 errx(1, "maxage %s is: %s", arg, errstr); 440 441 strlcpy(bp.ifbrp_name, ifname, sizeof(bp.ifbrp_name)); 442 if (ioctl(sock, SIOCBRDGSMA, (caddr_t)&bp) == -1) 443 err(1, "%s", ifname); 444 } 445 446 void 447 bridge_priority(const char *arg, int d) 448 { 449 struct ifbrparam bp; 450 const char *errstr; 451 452 bp.ifbrp_prio = strtonum(arg, 0, UINT16_MAX, &errstr); 453 if (errstr) 454 errx(1, "spanpriority %s is: %s", arg, errstr); 455 456 strlcpy(bp.ifbrp_name, ifname, sizeof(bp.ifbrp_name)); 457 if (ioctl(sock, SIOCBRDGSPRI, (caddr_t)&bp) == -1) 458 err(1, "%s", ifname); 459 } 460 461 void 462 bridge_protect(const char *ifsname, const char *val) 463 { 464 struct ifbreq breq; 465 unsigned long v; 466 char *optlist, *str; 467 const char *errstr; 468 469 strlcpy(breq.ifbr_name, ifname, sizeof(breq.ifbr_name)); 470 strlcpy(breq.ifbr_ifsname, ifsname, sizeof(breq.ifbr_ifsname)); 471 breq.ifbr_protected = 0; 472 473 /* We muck with the string, so copy it. */ 474 optlist = strdup(val); 475 if (optlist == NULL) 476 err(1, "strdup"); 477 478 str = strtok(optlist, ","); 479 while (str != NULL) { 480 v = strtonum(str, 1, 31, &errstr); 481 if (errstr) 482 err(1, "protected domain %s is: %s", str, errstr); 483 breq.ifbr_protected |= (1 << (v - 1)); 484 str = strtok(NULL, ","); 485 } 486 487 if (ioctl(sock, SIOCBRDGSIFPROT, (caddr_t)&breq) == -1) 488 err(1, "%s: %s", ifname, val); 489 490 free(optlist); 491 } 492 493 void 494 bridge_unprotect(const char *ifsname, int d) 495 { 496 struct ifbreq breq; 497 498 strlcpy(breq.ifbr_name, ifname, sizeof(breq.ifbr_name)); 499 strlcpy(breq.ifbr_ifsname, ifsname, sizeof(breq.ifbr_ifsname)); 500 501 breq.ifbr_protected = 0; 502 503 if (ioctl(sock, SIOCBRDGSIFPROT, (caddr_t)&breq) == -1) 504 err(1, "%s: %d", ifname, 0); 505 } 506 507 void 508 bridge_proto(const char *arg, int d) 509 { 510 struct ifbrparam bp; 511 int i, proto = -1; 512 513 for (i = 0; i <= BSTP_PROTO_MAX; i++) 514 if (strcmp(arg, stpproto[i]) == 0) { 515 proto = i; 516 break; 517 } 518 if (proto == -1) 519 errx(1, "invalid arg for proto: %s", arg); 520 521 strlcpy(bp.ifbrp_name, ifname, sizeof(bp.ifbrp_name)); 522 bp.ifbrp_prio = proto; 523 if (ioctl(sock, SIOCBRDGSPROTO, (caddr_t)&bp) == -1) 524 err(1, "%s", ifname); 525 } 526 527 void 528 bridge_fwddelay(const char *arg, int d) 529 { 530 struct ifbrparam bp; 531 const char *errstr; 532 533 bp.ifbrp_fwddelay = strtonum(arg, 0, UINT8_MAX, &errstr); 534 if (errstr) 535 errx(1, "fwddelay %s is: %s", arg, errstr); 536 537 strlcpy(bp.ifbrp_name, ifname, sizeof(bp.ifbrp_name)); 538 539 if (ioctl(sock, SIOCBRDGSFD, (caddr_t)&bp) == -1) 540 err(1, "%s", ifname); 541 } 542 543 void 544 bridge_hellotime(const char *arg, int d) 545 { 546 struct ifbrparam bp; 547 const char *errstr; 548 549 bp.ifbrp_hellotime = strtonum(arg, 0, UINT8_MAX, &errstr); 550 if (errstr) 551 errx(1, "hellotime %s is: %s", arg, errstr); 552 553 strlcpy(bp.ifbrp_name, ifname, sizeof(bp.ifbrp_name)); 554 555 if (ioctl(sock, SIOCBRDGSHT, (caddr_t)&bp) == -1) 556 err(1, "%s", ifname); 557 } 558 559 void 560 bridge_maxaddr(const char *arg, int d) 561 { 562 struct ifbrparam bp; 563 const char *errstr; 564 565 bp.ifbrp_csize = strtonum(arg, 0, UINT32_MAX, &errstr); 566 if (errstr) 567 errx(1, "maxaddr %s is: %s", arg, errstr); 568 569 strlcpy(bp.ifbrp_name, ifname, sizeof(bp.ifbrp_name)); 570 if (ioctl(sock, SIOCBRDGSCACHE, (caddr_t)&bp) == -1) 571 err(1, "%s", ifname); 572 } 573 574 void 575 bridge_deladdr(const char *addr, int d) 576 { 577 struct ifbareq ifba; 578 struct ether_addr *ea; 579 580 strlcpy(ifba.ifba_name, ifname, sizeof(ifba.ifba_name)); 581 ea = ether_aton(addr); 582 if (ea == NULL) 583 err(1, "Invalid address: %s", addr); 584 585 bcopy(ea, &ifba.ifba_dst, sizeof(struct ether_addr)); 586 587 if (ioctl(sock, SIOCBRDGDADDR, &ifba) == -1) 588 err(1, "%s: %s", ifname, addr); 589 } 590 591 void 592 bridge_ifprio(const char *ifsname, const char *val) 593 { 594 struct ifbreq breq; 595 const char *errstr; 596 597 breq.ifbr_priority = strtonum(val, 0, UINT8_MAX, &errstr); 598 if (errstr) 599 errx(1, "ifpriority %s is: %s", val, errstr); 600 601 strlcpy(breq.ifbr_name, ifname, sizeof(breq.ifbr_name)); 602 strlcpy(breq.ifbr_ifsname, ifsname, sizeof(breq.ifbr_ifsname)); 603 604 if (ioctl(sock, SIOCBRDGSIFPRIO, (caddr_t)&breq) == -1) 605 err(1, "%s: %s", ifname, val); 606 } 607 608 void 609 bridge_ifcost(const char *ifsname, const char *val) 610 { 611 struct ifbreq breq; 612 const char *errstr; 613 614 breq.ifbr_path_cost = strtonum(val, 0, UINT32_MAX, &errstr); 615 if (errstr) 616 errx(1, "ifcost %s is: %s", val, errstr); 617 618 strlcpy(breq.ifbr_name, ifname, sizeof(breq.ifbr_name)); 619 strlcpy(breq.ifbr_ifsname, ifsname, sizeof(breq.ifbr_ifsname)); 620 621 if (ioctl(sock, SIOCBRDGSIFCOST, (caddr_t)&breq) == -1) 622 err(1, "%s: %s", ifname, val); 623 } 624 625 void 626 bridge_noifcost(const char *ifsname, int d) 627 { 628 struct ifbreq breq; 629 630 strlcpy(breq.ifbr_name, ifname, sizeof(breq.ifbr_name)); 631 strlcpy(breq.ifbr_ifsname, ifsname, sizeof(breq.ifbr_ifsname)); 632 633 breq.ifbr_path_cost = 0; 634 635 if (ioctl(sock, SIOCBRDGSIFCOST, (caddr_t)&breq) == -1) 636 err(1, "%s", ifname); 637 } 638 639 void 640 bridge_addaddr(const char *ifsname, const char *addr) 641 { 642 struct ifbareq ifba; 643 struct ether_addr *ea; 644 645 strlcpy(ifba.ifba_name, ifname, sizeof(ifba.ifba_name)); 646 strlcpy(ifba.ifba_ifsname, ifsname, sizeof(ifba.ifba_ifsname)); 647 648 ea = ether_aton(addr); 649 if (ea == NULL) 650 errx(1, "Invalid address: %s", addr); 651 652 bcopy(ea, &ifba.ifba_dst, sizeof(struct ether_addr)); 653 ifba.ifba_flags = IFBAF_STATIC; 654 655 if (ioctl(sock, SIOCBRDGSADDR, &ifba) == -1) 656 err(1, "%s: %s", ifname, addr); 657 } 658 659 void 660 bridge_addendpoint(const char *endpoint, const char *addr) 661 { 662 struct ifbareq ifba; 663 struct ether_addr *ea; 664 struct addrinfo *res; 665 int ecode; 666 667 /* should we handle ports? */ 668 ecode = getaddrinfo(endpoint, NULL, NULL, &res); 669 if (ecode != 0) { 670 errx(1, "%s endpoint %s: %s", ifname, endpoint, 671 gai_strerror(ecode)); 672 } 673 if (res->ai_addrlen > sizeof(ifba.ifba_dstsa)) 674 errx(1, "%s: addrlen > dstsa", __func__); 675 676 ea = ether_aton(addr); 677 if (ea == NULL) { 678 errx(1, "%s endpoint %s %s: invalid Ethernet address", 679 ifname, endpoint, addr); 680 } 681 682 memset(&ifba, 0, sizeof(ifba)); 683 strlcpy(ifba.ifba_name, ifname, sizeof(ifba.ifba_name)); 684 strlcpy(ifba.ifba_ifsname, ifname, sizeof(ifba.ifba_ifsname)); 685 memcpy(&ifba.ifba_dst, ea, sizeof(struct ether_addr)); 686 memcpy(&ifba.ifba_dstsa, res->ai_addr, res->ai_addrlen); 687 ifba.ifba_flags = IFBAF_STATIC; 688 689 freeaddrinfo(res); 690 691 if (ioctl(sock, SIOCBRDGSADDR, &ifba) == -1) 692 err(1, "%s endpoint %s %s", ifname, endpoint, addr); 693 } 694 695 void 696 bridge_delendpoint(const char *addr, int d) 697 { 698 struct ifbareq ifba; 699 struct ether_addr *ea; 700 int ecode; 701 702 ea = ether_aton(addr); 703 if (ea == NULL) { 704 errx(1, "%s -endpoint %s: invalid Ethernet address", 705 ifname, addr); 706 } 707 708 memset(&ifba, 0, sizeof(ifba)); 709 strlcpy(ifba.ifba_name, ifname, sizeof(ifba.ifba_name)); 710 strlcpy(ifba.ifba_ifsname, ifname, sizeof(ifba.ifba_ifsname)); 711 memcpy(&ifba.ifba_dst, ea, sizeof(struct ether_addr)); 712 ifba.ifba_flags = IFBAF_STATIC; 713 714 if (ioctl(sock, SIOCBRDGDADDR, &ifba) == -1) 715 err(1, "%s -endpoint %s", ifname, addr); 716 } 717 718 void 719 bridge_addrs(const char *delim, int d) 720 { 721 char dstaddr[NI_MAXHOST]; 722 char dstport[NI_MAXSERV]; 723 const int niflag = NI_NUMERICHOST|NI_DGRAM; 724 struct ifbaconf ifbac; 725 struct ifbareq *ifba; 726 char *inbuf = NULL, buf[sizeof(ifba->ifba_ifsname) + 1], *inb; 727 struct sockaddr *sa; 728 int i, len = 8192; 729 730 /* ifconfig will call us with the argv of the command */ 731 if (strcmp(delim, "addr") == 0) 732 delim = ""; 733 734 while (1) { 735 ifbac.ifbac_len = len; 736 inb = realloc(inbuf, len); 737 if (inb == NULL) 738 err(1, "malloc"); 739 ifbac.ifbac_buf = inbuf = inb; 740 strlcpy(ifbac.ifbac_name, ifname, sizeof(ifbac.ifbac_name)); 741 if (ioctl(sock, SIOCBRDGRTS, &ifbac) == -1) { 742 if (errno == ENETDOWN) 743 return; 744 err(1, "%s", ifname); 745 } 746 if (ifbac.ifbac_len + sizeof(*ifba) < len) 747 break; 748 len *= 2; 749 } 750 751 for (i = 0; i < ifbac.ifbac_len / sizeof(*ifba); i++) { 752 ifba = ifbac.ifbac_req + i; 753 strlcpy(buf, ifba->ifba_ifsname, sizeof(buf)); 754 printf("%s%s %s %u ", delim, ether_ntoa(&ifba->ifba_dst), 755 buf, ifba->ifba_age); 756 sa = (struct sockaddr *)&ifba->ifba_dstsa; 757 printb("flags", ifba->ifba_flags, IFBAFBITS); 758 if (sa->sa_family != AF_UNSPEC && 759 getnameinfo(sa, sa->sa_len, 760 dstaddr, sizeof(dstaddr), 761 dstport, sizeof(dstport), niflag) == 0) 762 printf(" tunnel %s:%s", dstaddr, dstport); 763 printf("\n"); 764 } 765 free(inbuf); 766 } 767 768 void 769 bridge_holdcnt(const char *value, int d) 770 { 771 struct ifbrparam bp; 772 const char *errstr; 773 774 bp.ifbrp_txhc = strtonum(value, 0, UINT8_MAX, &errstr); 775 if (errstr) 776 err(1, "holdcnt %s is: %s", value, errstr); 777 778 strlcpy(bp.ifbrp_name, ifname, sizeof(bp.ifbrp_name)); 779 if (ioctl(sock, SIOCBRDGSTXHC, (caddr_t)&bp) == -1) 780 err(1, "%s", ifname); 781 } 782 783 /* 784 * Check to make sure interface is really a bridge interface. 785 */ 786 int 787 is_bridge() 788 { 789 struct ifbaconf ifbac; 790 791 ifbac.ifbac_len = 0; 792 strlcpy(ifbac.ifbac_name, ifname, sizeof(ifbac.ifbac_name)); 793 if (ioctl(sock, SIOCBRDGRTS, (caddr_t)&ifbac) == -1) { 794 if (errno == ENETDOWN) 795 return (1); 796 return (0); 797 } 798 return (1); 799 } 800 801 /* no tpmr(4) specific ioctls, name is enough if ifconfig.c:printif() passed */ 802 int 803 is_tpmr(void) 804 { 805 return (strncmp(ifname, "tpmr", sizeof("tpmr") - 1) == 0); 806 } 807 808 void 809 bridge_status(void) 810 { 811 struct ifbrparam bp1, bp2; 812 813 if (is_tpmr()) { 814 bridge_list("\t"); 815 return; 816 } 817 818 if (!is_bridge()) 819 return; 820 821 bridge_cfg("\t"); 822 bridge_list("\t"); 823 824 if (aflag && !ifaliases) 825 return; 826 827 strlcpy(bp1.ifbrp_name, ifname, sizeof(bp1.ifbrp_name)); 828 if (ioctl(sock, SIOCBRDGGCACHE, (caddr_t)&bp1) == -1) 829 return; 830 831 strlcpy(bp2.ifbrp_name, ifname, sizeof(bp2.ifbrp_name)); 832 if (ioctl(sock, SIOCBRDGGTO, (caddr_t)&bp2) == -1) 833 return; 834 835 printf("\tAddresses (max cache: %u, timeout: %u):\n", 836 bp1.ifbrp_csize, bp2.ifbrp_ctime); 837 838 bridge_addrs("\t\t", 0); 839 } 840 841 void 842 bridge_flushrule(const char *ifsname, int d) 843 { 844 struct ifbrlreq req; 845 846 strlcpy(req.ifbr_name, ifname, sizeof(req.ifbr_name)); 847 strlcpy(req.ifbr_ifsname, ifsname, sizeof(req.ifbr_ifsname)); 848 if (ioctl(sock, SIOCBRDGFRL, &req) == -1) 849 err(1, "%s: %s", ifname, ifsname); 850 } 851 852 void 853 bridge_rules(const char *ifsname, int usetab) 854 { 855 char *inbuf = NULL, *inb; 856 struct ifbrlconf ifc; 857 struct ifbrlreq *ifrp; 858 int len = 8192, i; 859 860 while (1) { 861 ifc.ifbrl_len = len; 862 inb = realloc(inbuf, len); 863 if (inb == NULL) 864 err(1, "malloc"); 865 ifc.ifbrl_buf = inbuf = inb; 866 strlcpy(ifc.ifbrl_name, ifname, sizeof(ifc.ifbrl_name)); 867 strlcpy(ifc.ifbrl_ifsname, ifsname, sizeof(ifc.ifbrl_ifsname)); 868 if (ioctl(sock, SIOCBRDGGRL, &ifc) == -1) 869 err(1, "ioctl(SIOCBRDGGRL)"); 870 if (ifc.ifbrl_len + sizeof(*ifrp) < len) 871 break; 872 len *= 2; 873 } 874 ifrp = ifc.ifbrl_req; 875 for (i = 0; i < ifc.ifbrl_len; i += sizeof(*ifrp)) { 876 ifrp = (struct ifbrlreq *)((caddr_t)ifc.ifbrl_req + i); 877 878 if (usetab) 879 printf("\t"); 880 881 bridge_showrule(ifrp); 882 } 883 } 884 885 void 886 bridge_showrule(struct ifbrlreq *r) 887 { 888 if (r->ifbr_action == BRL_ACTION_BLOCK) 889 printf("block "); 890 else if (r->ifbr_action == BRL_ACTION_PASS) 891 printf("pass "); 892 else 893 printf("[neither block nor pass?]\n"); 894 895 if ((r->ifbr_flags & (BRL_FLAG_IN | BRL_FLAG_OUT)) == 896 (BRL_FLAG_IN | BRL_FLAG_OUT)) 897 printf("in/out "); 898 else if (r->ifbr_flags & BRL_FLAG_IN) 899 printf("in "); 900 else if (r->ifbr_flags & BRL_FLAG_OUT) 901 printf("out "); 902 else 903 printf("[neither in nor out?]\n"); 904 905 printf("on %s", r->ifbr_ifsname); 906 907 if (r->ifbr_flags & BRL_FLAG_SRCVALID) 908 printf(" src %s", ether_ntoa(&r->ifbr_src)); 909 if (r->ifbr_flags & BRL_FLAG_DSTVALID) 910 printf(" dst %s", ether_ntoa(&r->ifbr_dst)); 911 if (r->ifbr_tagname[0]) 912 printf(" tag %s", r->ifbr_tagname); 913 914 if (r->ifbr_arpf.brla_flags & BRLA_ARP) 915 printf(" arp"); 916 if (r->ifbr_arpf.brla_flags & BRLA_RARP) 917 printf(" rarp"); 918 if (r->ifbr_arpf.brla_op == ARPOP_REQUEST || 919 r->ifbr_arpf.brla_op == ARPOP_REVREQUEST) 920 printf(" request"); 921 if (r->ifbr_arpf.brla_op == ARPOP_REPLY || 922 r->ifbr_arpf.brla_op == ARPOP_REVREPLY) 923 printf(" reply"); 924 if (r->ifbr_arpf.brla_flags & BRLA_SHA) 925 printf(" sha %s", ether_ntoa(&r->ifbr_arpf.brla_sha)); 926 if (r->ifbr_arpf.brla_flags & BRLA_THA) 927 printf(" tha %s", ether_ntoa(&r->ifbr_arpf.brla_tha)); 928 if (r->ifbr_arpf.brla_flags & BRLA_SPA) 929 printf(" spa %s", inet_ntoa(r->ifbr_arpf.brla_spa)); 930 if (r->ifbr_arpf.brla_flags & BRLA_TPA) 931 printf(" tpa %s", inet_ntoa(r->ifbr_arpf.brla_tpa)); 932 933 printf("\n"); 934 } 935 936 /* 937 * Parse a rule definition and send it upwards. 938 * 939 * Syntax: 940 * {block|pass} {in|out|in/out} on {ifs} [src {mac}] [dst {mac}] 941 */ 942 int 943 bridge_rule(int targc, char **targv, int ln) 944 { 945 char **argv = targv; 946 int argc = targc; 947 struct ifbrlreq rule; 948 struct ether_addr *ea, *dea; 949 950 if (argc == 0) { 951 warnx("invalid rule"); 952 return (1); 953 } 954 bzero(&rule, sizeof(rule)); 955 strlcpy(rule.ifbr_name, ifname, sizeof(rule.ifbr_name)); 956 957 if (strcmp(argv[0], "block") == 0) 958 rule.ifbr_action = BRL_ACTION_BLOCK; 959 else if (strcmp(argv[0], "pass") == 0) 960 rule.ifbr_action = BRL_ACTION_PASS; 961 else 962 goto bad_rule; 963 argc--; argv++; 964 965 if (argc == 0) { 966 bridge_badrule(targc, targv, ln); 967 return (1); 968 } 969 if (strcmp(argv[0], "in") == 0) 970 rule.ifbr_flags |= BRL_FLAG_IN; 971 else if (strcmp(argv[0], "out") == 0) 972 rule.ifbr_flags |= BRL_FLAG_OUT; 973 else if (strcmp(argv[0], "in/out") == 0) 974 rule.ifbr_flags |= BRL_FLAG_IN | BRL_FLAG_OUT; 975 else if (strcmp(argv[0], "on") == 0) { 976 rule.ifbr_flags |= BRL_FLAG_IN | BRL_FLAG_OUT; 977 argc++; argv--; 978 } else 979 goto bad_rule; 980 argc--; argv++; 981 982 if (argc == 0 || strcmp(argv[0], "on")) 983 goto bad_rule; 984 argc--; argv++; 985 986 if (argc == 0) 987 goto bad_rule; 988 strlcpy(rule.ifbr_ifsname, argv[0], sizeof(rule.ifbr_ifsname)); 989 argc--; argv++; 990 991 while (argc) { 992 dea = NULL; 993 if (strcmp(argv[0], "dst") == 0) { 994 if (rule.ifbr_flags & BRL_FLAG_DSTVALID) 995 goto bad_rule; 996 rule.ifbr_flags |= BRL_FLAG_DSTVALID; 997 dea = &rule.ifbr_dst; 998 argc--; argv++; 999 } else if (strcmp(argv[0], "src") == 0) { 1000 if (rule.ifbr_flags & BRL_FLAG_SRCVALID) 1001 goto bad_rule; 1002 rule.ifbr_flags |= BRL_FLAG_SRCVALID; 1003 dea = &rule.ifbr_src; 1004 argc--; argv++; 1005 } else if (strcmp(argv[0], "tag") == 0) { 1006 if (argc < 2) { 1007 warnx("missing tag name"); 1008 goto bad_rule; 1009 } 1010 if (rule.ifbr_tagname[0]) { 1011 warnx("tag already defined"); 1012 goto bad_rule; 1013 } 1014 argc--; argv++; 1015 if (strlcpy(rule.ifbr_tagname, argv[0], 1016 PF_TAG_NAME_SIZE) > PF_TAG_NAME_SIZE) { 1017 warnx("tag name '%s' too long", argv[0]); 1018 goto bad_rule; 1019 } 1020 argc--; argv++; 1021 } else if (strcmp(argv[0], "arp") == 0) { 1022 rule.ifbr_arpf.brla_flags |= BRLA_ARP; 1023 argc--; argv++; 1024 if (bridge_arprule(&rule, &argc, &argv) == -1) 1025 goto bad_rule; 1026 } else if (strcmp(argv[0], "rarp") == 0) { 1027 rule.ifbr_arpf.brla_flags |= BRLA_RARP; 1028 argc--; argv++; 1029 if (bridge_arprule(&rule, &argc, &argv) == -1) 1030 goto bad_rule; 1031 } else 1032 goto bad_rule; 1033 1034 if (dea != NULL) { 1035 if (argc == 0) 1036 goto bad_rule; 1037 ea = ether_aton(argv[0]); 1038 if (ea == NULL) { 1039 warnx("invalid address: %s", argv[0]); 1040 return (1); 1041 } 1042 bcopy(ea, dea, sizeof(*dea)); 1043 argc--; argv++; 1044 } 1045 } 1046 1047 if (ioctl(sock, SIOCBRDGARL, &rule) == -1) { 1048 warn("%s", ifname); 1049 return (1); 1050 } 1051 return (0); 1052 1053 bad_rule: 1054 bridge_badrule(targc, targv, ln); 1055 return (1); 1056 } 1057 1058 int 1059 bridge_arprule(struct ifbrlreq *rule, int *argc, char ***argv) 1060 { 1061 while (*argc) { 1062 struct ether_addr *ea, *dea = NULL; 1063 struct in_addr ia, *dia = NULL; 1064 1065 if (strcmp((*argv)[0], "request") == 0) { 1066 if (rule->ifbr_arpf.brla_flags & BRLA_ARP) 1067 rule->ifbr_arpf.brla_op = ARPOP_REQUEST; 1068 else if (rule->ifbr_arpf.brla_flags & BRLA_RARP) 1069 rule->ifbr_arpf.brla_op = ARPOP_REVREQUEST; 1070 else 1071 errx(1, "bridge_arprule: arp/rarp undefined"); 1072 } else if (strcmp((*argv)[0], "reply") == 0) { 1073 if (rule->ifbr_arpf.brla_flags & BRLA_ARP) 1074 rule->ifbr_arpf.brla_op = ARPOP_REPLY; 1075 else if (rule->ifbr_arpf.brla_flags & BRLA_RARP) 1076 rule->ifbr_arpf.brla_op = ARPOP_REVREPLY; 1077 else 1078 errx(1, "bridge_arprule: arp/rarp undefined"); 1079 } else if (strcmp((*argv)[0], "sha") == 0) { 1080 rule->ifbr_arpf.brla_flags |= BRLA_SHA; 1081 dea = &rule->ifbr_arpf.brla_sha; 1082 } else if (strcmp((*argv)[0], "tha") == 0) { 1083 rule->ifbr_arpf.brla_flags |= BRLA_THA; 1084 dea = &rule->ifbr_arpf.brla_tha; 1085 } else if (strcmp((*argv)[0], "spa") == 0) { 1086 rule->ifbr_arpf.brla_flags |= BRLA_SPA; 1087 dia = &rule->ifbr_arpf.brla_spa; 1088 } else if (strcmp((*argv)[0], "tpa") == 0) { 1089 rule->ifbr_arpf.brla_flags |= BRLA_TPA; 1090 dia = &rule->ifbr_arpf.brla_tpa; 1091 } else 1092 return (0); 1093 1094 (*argc)--; (*argv)++; 1095 if (dea != NULL) { 1096 if (*argc == 0) 1097 return (-1); 1098 ea = ether_aton((*argv)[0]); 1099 if (ea == NULL) { 1100 warnx("invalid address: %s", (*argv)[0]); 1101 return (-1); 1102 } 1103 bcopy(ea, dea, sizeof(*dea)); 1104 (*argc)--; (*argv)++; 1105 } 1106 if (dia != NULL) { 1107 if (*argc == 0) 1108 return (-1); 1109 ia.s_addr = inet_addr((*argv)[0]); 1110 if (ia.s_addr == INADDR_NONE) { 1111 warnx("invalid address: %s", (*argv)[0]); 1112 return (-1); 1113 } 1114 bcopy(&ia, dia, sizeof(*dia)); 1115 (*argc)--; (*argv)++; 1116 } 1117 } 1118 return (0); 1119 } 1120 1121 1122 #define MAXRULEWORDS 32 1123 1124 void 1125 bridge_rulefile(const char *fname, int d) 1126 { 1127 FILE *f; 1128 char *str, *argv[MAXRULEWORDS], buf[1024]; 1129 int ln = 0, argc = 0; 1130 1131 f = fopen(fname, "r"); 1132 if (f == NULL) 1133 err(1, "%s", fname); 1134 1135 while (fgets(buf, sizeof(buf), f) != NULL) { 1136 ln++; 1137 if (buf[0] == '#' || buf[0] == '\n') 1138 continue; 1139 1140 argc = 0; 1141 str = strtok(buf, "\n\t\r "); 1142 while (str != NULL && argc < MAXRULEWORDS) { 1143 argv[argc++] = str; 1144 str = strtok(NULL, "\n\t\r "); 1145 } 1146 1147 /* Rule is too long if there's more. */ 1148 if (str != NULL) { 1149 warnx("invalid rule: %d: %s ...", ln, buf); 1150 continue; 1151 } 1152 1153 bridge_rule(argc, argv, ln); 1154 } 1155 fclose(f); 1156 } 1157 1158 void 1159 bridge_badrule(int argc, char *argv[], int ln) 1160 { 1161 extern const char *__progname; 1162 int i; 1163 1164 fprintf(stderr, "%s: invalid rule: ", __progname); 1165 if (ln != -1) 1166 fprintf(stderr, "%d: ", ln); 1167 for (i = 0; i < argc; i++) 1168 fprintf(stderr, "%s ", argv[i]); 1169 fprintf(stderr, "\n"); 1170 } 1171 1172 #endif 1173