1 /* $OpenBSD: brconfig.c,v 1.3 2009/12/14 19:22:20 deraadt 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/param.h> 37 #include <sys/socket.h> 38 #include <sys/ioctl.h> 39 #include <net/if.h> 40 #include <net/if_dl.h> 41 #include <netinet/in.h> 42 #include <netinet/if_ether.h> 43 #include <net/if_bridge.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 60 #define IFBAFBITS "\020\1STATIC" 61 #define IFBIFBITS \ 62 "\020\1LEARNING\2DISCOVER\3BLOCKNONIP\4STP\5EDGE\6AUTOEDGE\7PTP\10AUTOPTP\11SPAN" 63 64 #define PV2ID(pv, epri, eaddr) do { \ 65 epri = pv >> 48; \ 66 eaddr[0] = pv >> 40; \ 67 eaddr[1] = pv >> 32; \ 68 eaddr[2] = pv >> 24; \ 69 eaddr[3] = pv >> 16; \ 70 eaddr[4] = pv >> 8; \ 71 eaddr[5] = pv >> 0; \ 72 } while (0) 73 74 char *stpstates[] = { 75 "disabled", 76 "listening", 77 "learning", 78 "forwarding", 79 "blocking", 80 "discarding" 81 }; 82 char *stpproto[] = { 83 "stp", 84 "(none)", 85 "rstp", 86 }; 87 char *stproles[] = { 88 "disabled", 89 "root", 90 "designated", 91 "alternate", 92 "backup" 93 }; 94 95 96 void 97 setdiscover(const char *val, int d) 98 { 99 bridge_ifsetflag(val, IFBIF_DISCOVER); 100 } 101 102 void 103 unsetdiscover(const char *val, int d) 104 { 105 bridge_ifclrflag(val, IFBIF_DISCOVER); 106 } 107 108 void 109 setblocknonip(const char *val, int d) 110 { 111 bridge_ifsetflag(val, IFBIF_BLOCKNONIP); 112 } 113 114 void 115 unsetblocknonip(const char *val, int d) 116 { 117 bridge_ifclrflag(val, IFBIF_BLOCKNONIP); 118 } 119 120 void 121 setlearn(const char *val, int d) 122 { 123 bridge_ifsetflag(val, IFBIF_LEARNING); 124 } 125 126 void 127 unsetlearn(const char *val, int d) 128 { 129 bridge_ifclrflag(val, IFBIF_LEARNING); 130 } 131 132 void 133 setstp(const char *val, int d) 134 { 135 bridge_ifsetflag(val, IFBIF_STP); 136 } 137 138 void 139 unsetstp(const char *val, int d) 140 { 141 bridge_ifclrflag(val, IFBIF_STP); 142 } 143 144 void 145 setedge(const char *val, int d) 146 { 147 bridge_ifsetflag(val, IFBIF_BSTP_EDGE); 148 } 149 150 void 151 unsetedge(const char *val, int d) 152 { 153 bridge_ifclrflag(val, IFBIF_BSTP_EDGE); 154 } 155 156 void 157 setautoedge(const char *val, int d) 158 { 159 bridge_ifsetflag(val, IFBIF_BSTP_AUTOEDGE); 160 } 161 162 void 163 unsetautoedge(const char *val, int d) 164 { 165 bridge_ifclrflag(val, IFBIF_BSTP_AUTOEDGE); 166 } 167 168 void 169 setptp(const char *val, int d) 170 { 171 bridge_ifsetflag(val, IFBIF_BSTP_PTP); 172 } 173 174 void 175 unsetptp(const char *val, int d) 176 { 177 bridge_ifclrflag(val, IFBIF_BSTP_PTP); 178 } 179 180 void 181 setautoptp(const char *val, int d) 182 { 183 bridge_ifsetflag(val, IFBIF_BSTP_AUTOPTP); 184 } 185 186 void 187 unsetautoptp(const char *val, int d) 188 { 189 bridge_ifclrflag(val, IFBIF_BSTP_AUTOPTP); 190 } 191 192 193 void 194 bridge_ifsetflag(const char *ifsname, u_int32_t flag) 195 { 196 struct ifbreq req; 197 198 strlcpy(req.ifbr_name, name, sizeof(req.ifbr_name)); 199 strlcpy(req.ifbr_ifsname, ifsname, sizeof(req.ifbr_ifsname)); 200 if (ioctl(s, SIOCBRDGGIFFLGS, (caddr_t)&req) < 0) 201 err(1, "%s: ioctl SIOCBRDGGIFFLGS %s", name, ifsname); 202 203 req.ifbr_ifsflags |= flag & ~IFBIF_RO_MASK; 204 205 if (ioctl(s, SIOCBRDGSIFFLGS, (caddr_t)&req) < 0) 206 err(1, "%s: ioctl SIOCBRDGSIFFLGS %s", name, ifsname); 207 } 208 209 void 210 bridge_ifclrflag(const char *ifsname, u_int32_t flag) 211 { 212 struct ifbreq req; 213 214 strlcpy(req.ifbr_name, name, sizeof(req.ifbr_name)); 215 strlcpy(req.ifbr_ifsname, ifsname, sizeof(req.ifbr_ifsname)); 216 217 if (ioctl(s, SIOCBRDGGIFFLGS, (caddr_t)&req) < 0) 218 err(1, "%s: ioctl SIOCBRDGGIFFLGS %s", name, ifsname); 219 220 req.ifbr_ifsflags &= ~(flag | IFBIF_RO_MASK); 221 222 if (ioctl(s, SIOCBRDGSIFFLGS, (caddr_t)&req) < 0) 223 err(1, "%s: ioctl SIOCBRDGSIFFLGS %s", name, ifsname); 224 } 225 226 void 227 bridge_flushall(const char *val, int p) 228 { 229 struct ifbreq req; 230 231 strlcpy(req.ifbr_name, name, sizeof(req.ifbr_name)); 232 req.ifbr_ifsflags = IFBF_FLUSHALL; 233 if (ioctl(s, SIOCBRDGFLUSH, &req) < 0) 234 err(1, "%s", name); 235 } 236 237 void 238 bridge_flush(const char *val, int p) 239 { 240 struct ifbreq req; 241 242 strlcpy(req.ifbr_name, name, sizeof(req.ifbr_name)); 243 req.ifbr_ifsflags = IFBF_FLUSHDYN; 244 if (ioctl(s, SIOCBRDGFLUSH, &req) < 0) 245 err(1, "%s", name); 246 } 247 248 void 249 bridge_cfg(const char *delim) 250 { 251 struct ifbropreq ifbp; 252 u_int16_t pri; 253 u_int8_t ht, fd, ma, hc, proto; 254 u_int8_t lladdr[ETHER_ADDR_LEN]; 255 u_int16_t bprio; 256 257 strlcpy(ifbp.ifbop_name, name, sizeof(ifbp.ifbop_name)); 258 if (ioctl(s, SIOCBRDGGPARAM, (caddr_t)&ifbp)) 259 err(1, "%s", name); 260 printf("%s", delim); 261 pri = ifbp.ifbop_priority; 262 ht = ifbp.ifbop_hellotime; 263 fd = ifbp.ifbop_fwddelay; 264 ma = ifbp.ifbop_maxage; 265 hc = ifbp.ifbop_holdcount; 266 proto = ifbp.ifbop_protocol; 267 268 printf("priority %u hellotime %u fwddelay %u maxage %u " 269 "holdcnt %u proto %s\n", pri, ht, fd, ma, hc, stpproto[proto]); 270 271 if (aflag) 272 return; 273 274 PV2ID(ifbp.ifbop_desg_bridge, bprio, lladdr); 275 printf("\tdesignated: id %s priority %u\n", 276 ether_ntoa((struct ether_addr *)lladdr), bprio); 277 278 if (ifbp.ifbop_root_bridge == ifbp.ifbop_desg_bridge) 279 return; 280 281 PV2ID(ifbp.ifbop_root_bridge, bprio, lladdr); 282 printf("\troot: id %s priority %u ifcost %u port %u\n", 283 ether_ntoa((struct ether_addr *)lladdr), bprio, 284 ifbp.ifbop_root_path_cost, ifbp.ifbop_root_port & 0xfff); 285 } 286 287 void 288 bridge_list(char *delim) 289 { 290 struct ifbreq *reqp; 291 struct ifbifconf bifc; 292 int i, len = 8192; 293 char buf[sizeof(reqp->ifbr_ifsname) + 1], *inbuf = NULL, *inb; 294 295 while (1) { 296 bifc.ifbic_len = len; 297 inb = realloc(inbuf, len); 298 if (inb == NULL) 299 err(1, "malloc"); 300 bifc.ifbic_buf = inbuf = inb; 301 strlcpy(bifc.ifbic_name, name, sizeof(bifc.ifbic_name)); 302 if (ioctl(s, SIOCBRDGIFS, &bifc) < 0) 303 err(1, "%s", name); 304 if (bifc.ifbic_len + sizeof(*reqp) < len) 305 break; 306 len *= 2; 307 } 308 for (i = 0; i < bifc.ifbic_len / sizeof(*reqp); i++) { 309 reqp = bifc.ifbic_req + i; 310 strlcpy(buf, reqp->ifbr_ifsname, sizeof(buf)); 311 printf("%s%s ", delim, buf); 312 printb("flags", reqp->ifbr_ifsflags, IFBIFBITS); 313 printf("\n"); 314 if (reqp->ifbr_ifsflags & IFBIF_SPAN) 315 continue; 316 printf("\t\t"); 317 printf("port %u ifpriority %u ifcost %u", 318 reqp->ifbr_portno, reqp->ifbr_priority, 319 reqp->ifbr_path_cost); 320 if (reqp->ifbr_ifsflags & IFBIF_STP) 321 printf(" %s role %s", 322 stpstates[reqp->ifbr_state], 323 stproles[reqp->ifbr_role]); 324 printf("\n"); 325 bridge_rules(buf, 0); 326 } 327 free(bifc.ifbic_buf); 328 } 329 330 void 331 bridge_add(const char *ifn, int d) 332 { 333 struct ifbreq req; 334 335 strlcpy(req.ifbr_name, name, sizeof(req.ifbr_name)); 336 strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname)); 337 if (ioctl(s, SIOCBRDGADD, &req) < 0) { 338 if (errno == EEXIST) 339 return; 340 err(1, "%s: %s", name, ifn); 341 } 342 } 343 344 void 345 bridge_delete(const char *ifn, int d) 346 { 347 struct ifbreq req; 348 349 strlcpy(req.ifbr_name, name, sizeof(req.ifbr_name)); 350 strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname)); 351 if (ioctl(s, SIOCBRDGDEL, &req) < 0) 352 err(1, "%s: %s", name, ifn); 353 } 354 355 void 356 bridge_addspan(const char *ifn, int d) 357 { 358 struct ifbreq req; 359 360 strlcpy(req.ifbr_name, name, sizeof(req.ifbr_name)); 361 strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname)); 362 if (ioctl(s, SIOCBRDGADDS, &req) < 0) 363 err(1, "%s: %s", name, ifn); 364 } 365 366 void 367 bridge_delspan(const char *ifn, int d) 368 { 369 struct ifbreq req; 370 371 strlcpy(req.ifbr_name, name, sizeof(req.ifbr_name)); 372 strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname)); 373 if (ioctl(s, SIOCBRDGDELS, &req) < 0) 374 err(1, "%s: %s", name, ifn); 375 } 376 377 void 378 bridge_timeout(const char *arg, int d) 379 { 380 struct ifbrparam bp; 381 long newtime; 382 char *endptr; 383 384 errno = 0; 385 newtime = strtol(arg, &endptr, 0); 386 if (arg[0] == '\0' || endptr[0] != '\0' || 387 (newtime & ~INT_MAX) != 0L || 388 (errno == ERANGE && newtime == LONG_MAX)) 389 errx(1, "invalid arg for timeout: %s\n", arg); 390 391 strlcpy(bp.ifbrp_name, name, sizeof(bp.ifbrp_name)); 392 bp.ifbrp_ctime = newtime; 393 if (ioctl(s, SIOCBRDGSTO, (caddr_t)&bp) < 0) 394 err(1, "%s", name); 395 } 396 397 void 398 bridge_maxage(const char *arg, int d) 399 { 400 struct ifbrparam bp; 401 unsigned long v; 402 char *endptr; 403 404 errno = 0; 405 v = strtoul(arg, &endptr, 0); 406 if (arg[0] == '\0' || endptr[0] != '\0' || v > 0xffUL || 407 (errno == ERANGE && v == ULONG_MAX)) 408 errx(1, "invalid arg for maxage: %s\n", arg); 409 410 strlcpy(bp.ifbrp_name, name, sizeof(bp.ifbrp_name)); 411 bp.ifbrp_maxage = v; 412 if (ioctl(s, SIOCBRDGSMA, (caddr_t)&bp) < 0) 413 err(1, "%s", name); 414 } 415 416 void 417 bridge_priority(const char *arg, int d) 418 { 419 struct ifbrparam bp; 420 unsigned long v; 421 char *endptr; 422 423 errno = 0; 424 v = strtoul(arg, &endptr, 0); 425 if (arg[0] == '\0' || endptr[0] != '\0' || v > 0xffffUL || 426 (errno == ERANGE && v == ULONG_MAX)) 427 errx(1, "invalid arg for spanpriority: %s\n", arg); 428 429 strlcpy(bp.ifbrp_name, name, sizeof(bp.ifbrp_name)); 430 bp.ifbrp_prio = v; 431 if (ioctl(s, SIOCBRDGSPRI, (caddr_t)&bp) < 0) 432 err(1, "%s", name); 433 } 434 435 void 436 bridge_proto(const char *arg, int d) 437 { 438 struct ifbrparam bp; 439 int i, proto = -1; 440 441 for (i = 0; i <= BSTP_PROTO_MAX; i++) 442 if (strcmp(arg, stpproto[i]) == 0) { 443 proto = i; 444 break; 445 } 446 if (proto == -1) 447 errx(1, "invalid arg for proto: %s\n", arg); 448 449 strlcpy(bp.ifbrp_name, name, sizeof(bp.ifbrp_name)); 450 bp.ifbrp_prio = proto; 451 if (ioctl(s, SIOCBRDGSPROTO, (caddr_t)&bp) < 0) 452 err(1, "%s", name); 453 } 454 455 void 456 bridge_fwddelay(const char *arg, int d) 457 { 458 struct ifbrparam bp; 459 unsigned long v; 460 char *endptr; 461 462 errno = 0; 463 v = strtoul(arg, &endptr, 0); 464 if (arg[0] == '\0' || endptr[0] != '\0' || v > 0xffUL || 465 (errno == ERANGE && v == ULONG_MAX)) 466 errx(1, "invalid arg for fwddelay: %s\n", arg); 467 468 strlcpy(bp.ifbrp_name, name, sizeof(bp.ifbrp_name)); 469 bp.ifbrp_fwddelay = v; 470 if (ioctl(s, SIOCBRDGSFD, (caddr_t)&bp) < 0) 471 err(1, "%s", name); 472 } 473 474 void 475 bridge_hellotime(const char *arg, int d) 476 { 477 struct ifbrparam bp; 478 unsigned long v; 479 char *endptr; 480 481 errno = 0; 482 v = strtoul(arg, &endptr, 0); 483 if (arg[0] == '\0' || endptr[0] != '\0' || v > 0xffUL || 484 (errno == ERANGE && v == ULONG_MAX)) 485 errx(1, "invalid arg for hellotime: %s\n", arg); 486 487 strlcpy(bp.ifbrp_name, name, sizeof(bp.ifbrp_name)); 488 bp.ifbrp_hellotime = v; 489 if (ioctl(s, SIOCBRDGSHT, (caddr_t)&bp) < 0) 490 err(1, "%s", name); 491 } 492 493 void 494 bridge_maxaddr(const char *arg, int d) 495 { 496 struct ifbrparam bp; 497 unsigned long newsize; 498 char *endptr; 499 500 errno = 0; 501 newsize = strtoul(arg, &endptr, 0); 502 if (arg[0] == '\0' || endptr[0] != '\0' || newsize > 0xffffffffUL || 503 (errno == ERANGE && newsize == ULONG_MAX)) 504 errx(1, "invalid arg for maxaddr: %s\n", arg); 505 506 strlcpy(bp.ifbrp_name, name, sizeof(bp.ifbrp_name)); 507 bp.ifbrp_csize = newsize; 508 if (ioctl(s, SIOCBRDGSCACHE, (caddr_t)&bp) < 0) 509 err(1, "%s", name); 510 } 511 512 void 513 bridge_deladdr(const char *addr, int d) 514 { 515 struct ifbareq ifba; 516 struct ether_addr *ea; 517 518 strlcpy(ifba.ifba_name, name, sizeof(ifba.ifba_name)); 519 ea = ether_aton(addr); 520 if (ea == NULL) 521 err(1, "Invalid address: %s", addr); 522 523 bcopy(ea, &ifba.ifba_dst, sizeof(struct ether_addr)); 524 525 if (ioctl(s, SIOCBRDGDADDR, &ifba) < 0) 526 err(1, "%s: %s", name, addr); 527 } 528 529 void 530 bridge_ifprio(const char *ifname, const char *val) 531 { 532 struct ifbreq breq; 533 unsigned long v; 534 char *endptr; 535 536 strlcpy(breq.ifbr_name, name, sizeof(breq.ifbr_name)); 537 strlcpy(breq.ifbr_ifsname, ifname, sizeof(breq.ifbr_ifsname)); 538 539 errno = 0; 540 v = strtoul(val, &endptr, 0); 541 if (val[0] == '\0' || endptr[0] != '\0' || v > 0xffUL || 542 (errno == ERANGE && v == ULONG_MAX)) 543 err(1, "invalid arg for ifpriority: %s\n", val); 544 breq.ifbr_priority = v; 545 546 if (ioctl(s, SIOCBRDGSIFPRIO, (caddr_t)&breq) < 0) 547 err(1, "%s: %s", name, val); 548 } 549 550 void 551 bridge_ifcost(const char *ifname, const char *val) 552 { 553 struct ifbreq breq; 554 unsigned long v; 555 char *endptr; 556 557 strlcpy(breq.ifbr_name, name, sizeof(breq.ifbr_name)); 558 strlcpy(breq.ifbr_ifsname, ifname, sizeof(breq.ifbr_ifsname)); 559 560 errno = 0; 561 v = strtoul(val, &endptr, 0); 562 if (val[0] == '\0' || endptr[0] != '\0' || 563 v < 0 || v > 0xffffffffUL || 564 (errno == ERANGE && v == ULONG_MAX)) 565 errx(1, "invalid arg for ifcost: %s\n", val); 566 567 breq.ifbr_path_cost = v; 568 569 if (ioctl(s, SIOCBRDGSIFCOST, (caddr_t)&breq) < 0) 570 err(1, "%s: %s", name, val); 571 } 572 573 void 574 bridge_noifcost(const char *ifname, int d) 575 { 576 struct ifbreq breq; 577 578 strlcpy(breq.ifbr_name, name, sizeof(breq.ifbr_name)); 579 strlcpy(breq.ifbr_ifsname, ifname, sizeof(breq.ifbr_ifsname)); 580 581 breq.ifbr_path_cost = 0; 582 583 if (ioctl(s, SIOCBRDGSIFCOST, (caddr_t)&breq) < 0) 584 err(1, "%s", name); 585 } 586 587 void 588 bridge_addaddr(const char *ifname, const char *addr) 589 { 590 struct ifbareq ifba; 591 struct ether_addr *ea; 592 593 strlcpy(ifba.ifba_name, name, sizeof(ifba.ifba_name)); 594 strlcpy(ifba.ifba_ifsname, ifname, sizeof(ifba.ifba_ifsname)); 595 596 ea = ether_aton(addr); 597 if (ea == NULL) 598 errx(1, "Invalid address: %s", addr); 599 600 bcopy(ea, &ifba.ifba_dst, sizeof(struct ether_addr)); 601 ifba.ifba_flags = IFBAF_STATIC; 602 603 if (ioctl(s, SIOCBRDGSADDR, &ifba) < 0) 604 err(1, "%s: %s", name, addr); 605 } 606 607 void 608 bridge_addrs(const char *delim, int d) 609 { 610 struct ifbaconf ifbac; 611 struct ifbareq *ifba; 612 char *inbuf = NULL, buf[sizeof(ifba->ifba_ifsname) + 1], *inb; 613 int i, len = 8192; 614 615 /* ifconfig will call us with the argv of the command */ 616 if (strcmp(delim, "addr") == 0) 617 delim = ""; 618 619 while (1) { 620 ifbac.ifbac_len = len; 621 inb = realloc(inbuf, len); 622 if (inb == NULL) 623 err(1, "malloc"); 624 ifbac.ifbac_buf = inbuf = inb; 625 strlcpy(ifbac.ifbac_name, name, sizeof(ifbac.ifbac_name)); 626 if (ioctl(s, SIOCBRDGRTS, &ifbac) < 0) { 627 if (errno == ENETDOWN) 628 return; 629 err(1, "%s", name); 630 } 631 if (ifbac.ifbac_len + sizeof(*ifba) < len) 632 break; 633 len *= 2; 634 } 635 636 for (i = 0; i < ifbac.ifbac_len / sizeof(*ifba); i++) { 637 ifba = ifbac.ifbac_req + i; 638 strlcpy(buf, ifba->ifba_ifsname, sizeof(buf)); 639 printf("%s%s %s %u ", delim, ether_ntoa(&ifba->ifba_dst), 640 buf, ifba->ifba_age); 641 printb("flags", ifba->ifba_flags, IFBAFBITS); 642 printf("\n"); 643 } 644 free(inbuf); 645 } 646 647 void 648 bridge_holdcnt(const char *value, int d) 649 { 650 struct ifbrparam bp; 651 const char *errstr; 652 653 bp.ifbrp_txhc = strtonum(value, 0, UINT8_MAX, &errstr); 654 if (errstr) 655 err(1, "holdcnt %s %s", value, errstr); 656 657 strlcpy(bp.ifbrp_name, name, sizeof(bp.ifbrp_name)); 658 if (ioctl(s, SIOCBRDGSTXHC, (caddr_t)&bp) < 0) 659 err(1, "%s", name); 660 } 661 662 /* 663 * Check to make sure 'brdg' is really a bridge interface. 664 */ 665 int 666 is_bridge(char *brdg) 667 { 668 struct ifreq ifr; 669 struct ifbaconf ifbac; 670 671 strlcpy(ifr.ifr_name, brdg, sizeof(ifr.ifr_name)); 672 673 if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) 674 return (0); 675 676 ifbac.ifbac_len = 0; 677 strlcpy(ifbac.ifbac_name, brdg, sizeof(ifbac.ifbac_name)); 678 if (ioctl(s, SIOCBRDGRTS, (caddr_t)&ifbac) < 0) { 679 if (errno == ENETDOWN) 680 return (1); 681 return (0); 682 } 683 return (1); 684 } 685 686 void 687 bridge_status(void) 688 { 689 struct ifreq ifr; 690 struct ifbrparam bp1, bp2; 691 692 if (!is_bridge(name)) 693 return; 694 695 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 696 if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) 697 return; 698 699 bridge_cfg("\t"); 700 701 bridge_list("\t"); 702 703 if (aflag && !ifaliases) 704 return; 705 706 strlcpy(bp1.ifbrp_name, name, sizeof(bp1.ifbrp_name)); 707 if (ioctl(s, SIOCBRDGGCACHE, (caddr_t)&bp1) < 0) 708 return; 709 710 strlcpy(bp2.ifbrp_name, name, sizeof(bp2.ifbrp_name)); 711 if (ioctl(s, SIOCBRDGGTO, (caddr_t)&bp2) < 0) 712 return; 713 714 printf("\tAddresses (max cache: %u, timeout: %u):\n", 715 bp1.ifbrp_csize, bp2.ifbrp_ctime); 716 717 bridge_addrs("\t\t", 0); 718 } 719 720 void 721 bridge_flushrule(const char *ifname, int d) 722 { 723 struct ifbrlreq req; 724 725 strlcpy(req.ifbr_name, name, sizeof(req.ifbr_name)); 726 strlcpy(req.ifbr_ifsname, ifname, sizeof(req.ifbr_ifsname)); 727 if (ioctl(s, SIOCBRDGFRL, &req) < 0) 728 err(1, "%s: %s", name, ifname); 729 } 730 731 void 732 bridge_rules(const char *ifname, int d) 733 { 734 char *inbuf = NULL, *inb; 735 struct ifbrlconf ifc; 736 struct ifbrlreq *ifrp; 737 int len = 8192, i; 738 739 while (1) { 740 ifc.ifbrl_len = len; 741 inb = realloc(inbuf, len); 742 if (inb == NULL) 743 err(1, "malloc"); 744 ifc.ifbrl_buf = inbuf = inb; 745 strlcpy(ifc.ifbrl_name, name, sizeof(ifc.ifbrl_name)); 746 strlcpy(ifc.ifbrl_ifsname, ifname, sizeof(ifc.ifbrl_ifsname)); 747 if (ioctl(s, SIOCBRDGGRL, &ifc) < 0) 748 err(1, "ioctl(SIOCBRDGGRL)"); 749 if (ifc.ifbrl_len + sizeof(*ifrp) < len) 750 break; 751 len *= 2; 752 } 753 ifrp = ifc.ifbrl_req; 754 for (i = 0; i < ifc.ifbrl_len; i += sizeof(*ifrp)) { 755 ifrp = (struct ifbrlreq *)((caddr_t)ifc.ifbrl_req + i); 756 bridge_showrule(ifrp); 757 } 758 } 759 760 void 761 bridge_showrule(struct ifbrlreq *r) 762 { 763 if (r->ifbr_action == BRL_ACTION_BLOCK) 764 printf("block "); 765 else if (r->ifbr_action == BRL_ACTION_PASS) 766 printf("pass "); 767 else 768 printf("[neither block nor pass?]\n"); 769 770 if ((r->ifbr_flags & (BRL_FLAG_IN | BRL_FLAG_OUT)) == 771 (BRL_FLAG_IN | BRL_FLAG_OUT)) 772 printf("in/out "); 773 else if (r->ifbr_flags & BRL_FLAG_IN) 774 printf("in "); 775 else if (r->ifbr_flags & BRL_FLAG_OUT) 776 printf("out "); 777 else 778 printf("[neither in nor out?]\n"); 779 780 printf("on %s", r->ifbr_ifsname); 781 782 if (r->ifbr_flags & BRL_FLAG_SRCVALID) 783 printf(" src %s", ether_ntoa(&r->ifbr_src)); 784 if (r->ifbr_flags & BRL_FLAG_DSTVALID) 785 printf(" dst %s", ether_ntoa(&r->ifbr_dst)); 786 if (r->ifbr_tagname[0]) 787 printf(" tag %s", r->ifbr_tagname); 788 789 printf("\n"); 790 } 791 792 /* 793 * Parse a rule definition and send it upwards. 794 * 795 * Syntax: 796 * {block|pass} {in|out|in/out} on {ifs} [src {mac}] [dst {mac}] 797 */ 798 int 799 bridge_rule(int targc, char **targv, int ln) 800 { 801 char **argv = targv; 802 int argc = targc; 803 struct ifbrlreq rule; 804 struct ether_addr *ea, *dea; 805 806 if (argc == 0) { 807 warnx("invalid rule\n"); 808 return (1); 809 } 810 rule.ifbr_tagname[0] = 0; 811 rule.ifbr_flags = 0; 812 rule.ifbr_action = 0; 813 strlcpy(rule.ifbr_name, name, sizeof(rule.ifbr_name)); 814 815 if (strcmp(argv[0], "block") == 0) 816 rule.ifbr_action = BRL_ACTION_BLOCK; 817 else if (strcmp(argv[0], "pass") == 0) 818 rule.ifbr_action = BRL_ACTION_PASS; 819 else 820 goto bad_rule; 821 argc--; argv++; 822 823 if (argc == 0) { 824 bridge_badrule(targc, targv, ln); 825 return (1); 826 } 827 if (strcmp(argv[0], "in") == 0) 828 rule.ifbr_flags |= BRL_FLAG_IN; 829 else if (strcmp(argv[0], "out") == 0) 830 rule.ifbr_flags |= BRL_FLAG_OUT; 831 else if (strcmp(argv[0], "in/out") == 0) 832 rule.ifbr_flags |= BRL_FLAG_IN | BRL_FLAG_OUT; 833 else if (strcmp(argv[0], "on") == 0) { 834 rule.ifbr_flags |= BRL_FLAG_IN | BRL_FLAG_OUT; 835 argc++; argv--; 836 } else 837 goto bad_rule; 838 argc--; argv++; 839 840 if (argc == 0 || strcmp(argv[0], "on")) 841 goto bad_rule; 842 argc--; argv++; 843 844 if (argc == 0) 845 goto bad_rule; 846 strlcpy(rule.ifbr_ifsname, argv[0], sizeof(rule.ifbr_ifsname)); 847 argc--; argv++; 848 849 while (argc) { 850 if (strcmp(argv[0], "dst") == 0) { 851 if (rule.ifbr_flags & BRL_FLAG_DSTVALID) 852 goto bad_rule; 853 rule.ifbr_flags |= BRL_FLAG_DSTVALID; 854 dea = &rule.ifbr_dst; 855 } else if (strcmp(argv[0], "src") == 0) { 856 if (rule.ifbr_flags & BRL_FLAG_SRCVALID) 857 goto bad_rule; 858 rule.ifbr_flags |= BRL_FLAG_SRCVALID; 859 dea = &rule.ifbr_src; 860 } else if (strcmp(argv[0], "tag") == 0) { 861 if (argc < 2) { 862 warnx("missing tag name\n"); 863 goto bad_rule; 864 } 865 if (rule.ifbr_tagname[0]) { 866 warnx("tag already defined\n"); 867 goto bad_rule; 868 } 869 if (strlcpy(rule.ifbr_tagname, argv[1], 870 PF_TAG_NAME_SIZE) > PF_TAG_NAME_SIZE) { 871 warnx("tag name '%s' too long\n", argv[1]); 872 goto bad_rule; 873 } 874 dea = NULL; 875 } else 876 goto bad_rule; 877 878 argc--; argv++; 879 880 if (argc == 0) 881 goto bad_rule; 882 if (dea != NULL) { 883 ea = ether_aton(argv[0]); 884 if (ea == NULL) { 885 warnx("invalid address: %s", argv[0]); 886 return (1); 887 } 888 bcopy(ea, dea, sizeof(*dea)); 889 } 890 argc--; argv++; 891 } 892 893 if (ioctl(s, SIOCBRDGARL, &rule) < 0) { 894 warn("%s", name); 895 return (1); 896 } 897 return (0); 898 899 bad_rule: 900 bridge_badrule(targc, targv, ln); 901 return (1); 902 } 903 904 #define MAXRULEWORDS 8 905 906 void 907 bridge_rulefile(const char *fname, int d) 908 { 909 FILE *f; 910 char *str, *argv[MAXRULEWORDS], buf[1024]; 911 int ln = 0, argc = 0; 912 913 f = fopen(fname, "r"); 914 if (f == NULL) 915 err(1, "%s", fname); 916 917 while (fgets(buf, sizeof(buf), f) != NULL) { 918 ln++; 919 if (buf[0] == '#' || buf[0] == '\n') 920 continue; 921 922 argc = 0; 923 str = strtok(buf, "\n\t\r "); 924 while (str != NULL && argc < MAXRULEWORDS) { 925 argv[argc++] = str; 926 str = strtok(NULL, "\n\t\r "); 927 } 928 929 /* Rule is too long if there's more. */ 930 if (str != NULL) { 931 warnx("invalid rule: %d: %s ...\n", ln, buf); 932 continue; 933 } 934 935 bridge_rule(argc, argv, ln); 936 } 937 fclose(f); 938 } 939 940 void 941 bridge_badrule(int argc, char *argv[], int ln) 942 { 943 extern const char *__progname; 944 int i; 945 946 fprintf(stderr, "%s: invalid rule: ", __progname); 947 if (ln != -1) 948 fprintf(stderr, "%d: ", ln); 949 for (i = 0; i < argc; i++) 950 fprintf(stderr, "%s ", argv[i]); 951 fprintf(stderr, "\n"); 952 } 953 954 #endif 955