1 /* $OpenBSD: brconfig.c,v 1.9 2015/07/18 06:50:24 rzalamena 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 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, 1); 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 if (errno == EEXIST) 364 return; 365 err(1, "%s: %s", name, ifn); 366 } 367 } 368 369 void 370 bridge_delspan(const char *ifn, int d) 371 { 372 struct ifbreq req; 373 374 strlcpy(req.ifbr_name, name, sizeof(req.ifbr_name)); 375 strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname)); 376 if (ioctl(s, SIOCBRDGDELS, &req) < 0) 377 err(1, "%s: %s", name, ifn); 378 } 379 380 void 381 bridge_timeout(const char *arg, int d) 382 { 383 struct ifbrparam bp; 384 long newtime; 385 char *endptr; 386 387 errno = 0; 388 newtime = strtol(arg, &endptr, 0); 389 if (arg[0] == '\0' || endptr[0] != '\0' || 390 (newtime & ~INT_MAX) != 0L || 391 (errno == ERANGE && newtime == LONG_MAX)) 392 errx(1, "invalid arg for timeout: %s", arg); 393 394 strlcpy(bp.ifbrp_name, name, sizeof(bp.ifbrp_name)); 395 bp.ifbrp_ctime = newtime; 396 if (ioctl(s, SIOCBRDGSTO, (caddr_t)&bp) < 0) 397 err(1, "%s", name); 398 } 399 400 void 401 bridge_maxage(const char *arg, int d) 402 { 403 struct ifbrparam bp; 404 unsigned long v; 405 char *endptr; 406 407 errno = 0; 408 v = strtoul(arg, &endptr, 0); 409 if (arg[0] == '\0' || endptr[0] != '\0' || v > 0xffUL || 410 (errno == ERANGE && v == ULONG_MAX)) 411 errx(1, "invalid arg for maxage: %s", arg); 412 413 strlcpy(bp.ifbrp_name, name, sizeof(bp.ifbrp_name)); 414 bp.ifbrp_maxage = v; 415 if (ioctl(s, SIOCBRDGSMA, (caddr_t)&bp) < 0) 416 err(1, "%s", name); 417 } 418 419 void 420 bridge_priority(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 > 0xffffUL || 429 (errno == ERANGE && v == ULONG_MAX)) 430 errx(1, "invalid arg for spanpriority: %s", arg); 431 432 strlcpy(bp.ifbrp_name, name, sizeof(bp.ifbrp_name)); 433 bp.ifbrp_prio = v; 434 if (ioctl(s, SIOCBRDGSPRI, (caddr_t)&bp) < 0) 435 err(1, "%s", name); 436 } 437 438 void 439 bridge_proto(const char *arg, int d) 440 { 441 struct ifbrparam bp; 442 int i, proto = -1; 443 444 for (i = 0; i <= BSTP_PROTO_MAX; i++) 445 if (strcmp(arg, stpproto[i]) == 0) { 446 proto = i; 447 break; 448 } 449 if (proto == -1) 450 errx(1, "invalid arg for proto: %s", arg); 451 452 strlcpy(bp.ifbrp_name, name, sizeof(bp.ifbrp_name)); 453 bp.ifbrp_prio = proto; 454 if (ioctl(s, SIOCBRDGSPROTO, (caddr_t)&bp) < 0) 455 err(1, "%s", name); 456 } 457 458 void 459 bridge_fwddelay(const char *arg, int d) 460 { 461 struct ifbrparam bp; 462 unsigned long v; 463 char *endptr; 464 465 errno = 0; 466 v = strtoul(arg, &endptr, 0); 467 if (arg[0] == '\0' || endptr[0] != '\0' || v > 0xffUL || 468 (errno == ERANGE && v == ULONG_MAX)) 469 errx(1, "invalid arg for fwddelay: %s", arg); 470 471 strlcpy(bp.ifbrp_name, name, sizeof(bp.ifbrp_name)); 472 bp.ifbrp_fwddelay = v; 473 if (ioctl(s, SIOCBRDGSFD, (caddr_t)&bp) < 0) 474 err(1, "%s", name); 475 } 476 477 void 478 bridge_hellotime(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 hellotime: %s", arg); 489 490 strlcpy(bp.ifbrp_name, name, sizeof(bp.ifbrp_name)); 491 bp.ifbrp_hellotime = v; 492 if (ioctl(s, SIOCBRDGSHT, (caddr_t)&bp) < 0) 493 err(1, "%s", name); 494 } 495 496 void 497 bridge_maxaddr(const char *arg, int d) 498 { 499 struct ifbrparam bp; 500 unsigned long newsize; 501 char *endptr; 502 503 errno = 0; 504 newsize = strtoul(arg, &endptr, 0); 505 if (arg[0] == '\0' || endptr[0] != '\0' || newsize > 0xffffffffUL || 506 (errno == ERANGE && newsize == ULONG_MAX)) 507 errx(1, "invalid arg for maxaddr: %s", arg); 508 509 strlcpy(bp.ifbrp_name, name, sizeof(bp.ifbrp_name)); 510 bp.ifbrp_csize = newsize; 511 if (ioctl(s, SIOCBRDGSCACHE, (caddr_t)&bp) < 0) 512 err(1, "%s", name); 513 } 514 515 void 516 bridge_deladdr(const char *addr, int d) 517 { 518 struct ifbareq ifba; 519 struct ether_addr *ea; 520 521 strlcpy(ifba.ifba_name, name, sizeof(ifba.ifba_name)); 522 ea = ether_aton(addr); 523 if (ea == NULL) 524 err(1, "Invalid address: %s", addr); 525 526 bcopy(ea, &ifba.ifba_dst, sizeof(struct ether_addr)); 527 528 if (ioctl(s, SIOCBRDGDADDR, &ifba) < 0) 529 err(1, "%s: %s", name, addr); 530 } 531 532 void 533 bridge_ifprio(const char *ifname, const char *val) 534 { 535 struct ifbreq breq; 536 unsigned long v; 537 char *endptr; 538 539 strlcpy(breq.ifbr_name, name, sizeof(breq.ifbr_name)); 540 strlcpy(breq.ifbr_ifsname, ifname, sizeof(breq.ifbr_ifsname)); 541 542 errno = 0; 543 v = strtoul(val, &endptr, 0); 544 if (val[0] == '\0' || endptr[0] != '\0' || v > 0xffUL || 545 (errno == ERANGE && v == ULONG_MAX)) 546 err(1, "invalid arg for ifpriority: %s", val); 547 breq.ifbr_priority = v; 548 549 if (ioctl(s, SIOCBRDGSIFPRIO, (caddr_t)&breq) < 0) 550 err(1, "%s: %s", name, val); 551 } 552 553 void 554 bridge_ifcost(const char *ifname, const char *val) 555 { 556 struct ifbreq breq; 557 unsigned long v; 558 char *endptr; 559 560 strlcpy(breq.ifbr_name, name, sizeof(breq.ifbr_name)); 561 strlcpy(breq.ifbr_ifsname, ifname, sizeof(breq.ifbr_ifsname)); 562 563 errno = 0; 564 v = strtoul(val, &endptr, 0); 565 if (val[0] == '\0' || endptr[0] != '\0' || 566 v < 0 || v > 0xffffffffUL || 567 (errno == ERANGE && v == ULONG_MAX)) 568 errx(1, "invalid arg for ifcost: %s", val); 569 570 breq.ifbr_path_cost = v; 571 572 if (ioctl(s, SIOCBRDGSIFCOST, (caddr_t)&breq) < 0) 573 err(1, "%s: %s", name, val); 574 } 575 576 void 577 bridge_noifcost(const char *ifname, int d) 578 { 579 struct ifbreq breq; 580 581 strlcpy(breq.ifbr_name, name, sizeof(breq.ifbr_name)); 582 strlcpy(breq.ifbr_ifsname, ifname, sizeof(breq.ifbr_ifsname)); 583 584 breq.ifbr_path_cost = 0; 585 586 if (ioctl(s, SIOCBRDGSIFCOST, (caddr_t)&breq) < 0) 587 err(1, "%s", name); 588 } 589 590 void 591 bridge_addaddr(const char *ifname, const char *addr) 592 { 593 struct ifbareq ifba; 594 struct ether_addr *ea; 595 596 strlcpy(ifba.ifba_name, name, sizeof(ifba.ifba_name)); 597 strlcpy(ifba.ifba_ifsname, ifname, sizeof(ifba.ifba_ifsname)); 598 599 ea = ether_aton(addr); 600 if (ea == NULL) 601 errx(1, "Invalid address: %s", addr); 602 603 bcopy(ea, &ifba.ifba_dst, sizeof(struct ether_addr)); 604 ifba.ifba_flags = IFBAF_STATIC; 605 606 if (ioctl(s, SIOCBRDGSADDR, &ifba) < 0) 607 err(1, "%s: %s", name, addr); 608 } 609 610 void 611 bridge_addrs(const char *delim, int d) 612 { 613 char dstaddr[NI_MAXHOST]; 614 char dstport[NI_MAXSERV]; 615 const int niflag = NI_NUMERICHOST|NI_DGRAM; 616 struct ifbaconf ifbac; 617 struct ifbareq *ifba; 618 char *inbuf = NULL, buf[sizeof(ifba->ifba_ifsname) + 1], *inb; 619 struct sockaddr *sa; 620 int i, len = 8192; 621 622 /* ifconfig will call us with the argv of the command */ 623 if (strcmp(delim, "addr") == 0) 624 delim = ""; 625 626 while (1) { 627 ifbac.ifbac_len = len; 628 inb = realloc(inbuf, len); 629 if (inb == NULL) 630 err(1, "malloc"); 631 ifbac.ifbac_buf = inbuf = inb; 632 strlcpy(ifbac.ifbac_name, name, sizeof(ifbac.ifbac_name)); 633 if (ioctl(s, SIOCBRDGRTS, &ifbac) < 0) { 634 if (errno == ENETDOWN) 635 return; 636 err(1, "%s", name); 637 } 638 if (ifbac.ifbac_len + sizeof(*ifba) < len) 639 break; 640 len *= 2; 641 } 642 643 for (i = 0; i < ifbac.ifbac_len / sizeof(*ifba); i++) { 644 ifba = ifbac.ifbac_req + i; 645 strlcpy(buf, ifba->ifba_ifsname, sizeof(buf)); 646 printf("%s%s %s %u ", delim, ether_ntoa(&ifba->ifba_dst), 647 buf, ifba->ifba_age); 648 sa = (struct sockaddr *)&ifba->ifba_dstsa; 649 printb("flags", ifba->ifba_flags, IFBAFBITS); 650 if (sa->sa_family != AF_UNSPEC && 651 getnameinfo(sa, sa->sa_len, 652 dstaddr, sizeof(dstaddr), 653 dstport, sizeof(dstport), niflag) == 0) 654 printf(" tunnel %s:%s", dstaddr, dstport); 655 printf("\n"); 656 } 657 free(inbuf); 658 } 659 660 void 661 bridge_holdcnt(const char *value, int d) 662 { 663 struct ifbrparam bp; 664 const char *errstr; 665 666 bp.ifbrp_txhc = strtonum(value, 0, UINT8_MAX, &errstr); 667 if (errstr) 668 err(1, "holdcnt %s %s", value, errstr); 669 670 strlcpy(bp.ifbrp_name, name, sizeof(bp.ifbrp_name)); 671 if (ioctl(s, SIOCBRDGSTXHC, (caddr_t)&bp) < 0) 672 err(1, "%s", name); 673 } 674 675 /* 676 * Check to make sure 'brdg' is really a bridge interface. 677 */ 678 int 679 is_bridge(char *brdg) 680 { 681 struct ifreq ifr; 682 struct ifbaconf ifbac; 683 684 strlcpy(ifr.ifr_name, brdg, sizeof(ifr.ifr_name)); 685 686 if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) 687 return (0); 688 689 ifbac.ifbac_len = 0; 690 strlcpy(ifbac.ifbac_name, brdg, sizeof(ifbac.ifbac_name)); 691 if (ioctl(s, SIOCBRDGRTS, (caddr_t)&ifbac) < 0) { 692 if (errno == ENETDOWN) 693 return (1); 694 return (0); 695 } 696 return (1); 697 } 698 699 void 700 bridge_status(void) 701 { 702 struct ifreq ifr; 703 struct ifbrparam bp1, bp2; 704 705 if (!is_bridge(name)) 706 return; 707 708 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); 709 if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) 710 return; 711 712 bridge_cfg("\t"); 713 714 bridge_list("\t"); 715 716 if (aflag && !ifaliases) 717 return; 718 719 strlcpy(bp1.ifbrp_name, name, sizeof(bp1.ifbrp_name)); 720 if (ioctl(s, SIOCBRDGGCACHE, (caddr_t)&bp1) < 0) 721 return; 722 723 strlcpy(bp2.ifbrp_name, name, sizeof(bp2.ifbrp_name)); 724 if (ioctl(s, SIOCBRDGGTO, (caddr_t)&bp2) < 0) 725 return; 726 727 printf("\tAddresses (max cache: %u, timeout: %u):\n", 728 bp1.ifbrp_csize, bp2.ifbrp_ctime); 729 730 bridge_addrs("\t\t", 0); 731 } 732 733 void 734 bridge_flushrule(const char *ifname, int d) 735 { 736 struct ifbrlreq req; 737 738 strlcpy(req.ifbr_name, name, sizeof(req.ifbr_name)); 739 strlcpy(req.ifbr_ifsname, ifname, sizeof(req.ifbr_ifsname)); 740 if (ioctl(s, SIOCBRDGFRL, &req) < 0) 741 err(1, "%s: %s", name, ifname); 742 } 743 744 void 745 bridge_rules(const char *ifname, int usetab) 746 { 747 char *inbuf = NULL, *inb; 748 struct ifbrlconf ifc; 749 struct ifbrlreq *ifrp; 750 int len = 8192, i; 751 752 while (1) { 753 ifc.ifbrl_len = len; 754 inb = realloc(inbuf, len); 755 if (inb == NULL) 756 err(1, "malloc"); 757 ifc.ifbrl_buf = inbuf = inb; 758 strlcpy(ifc.ifbrl_name, name, sizeof(ifc.ifbrl_name)); 759 strlcpy(ifc.ifbrl_ifsname, ifname, sizeof(ifc.ifbrl_ifsname)); 760 if (ioctl(s, SIOCBRDGGRL, &ifc) < 0) 761 err(1, "ioctl(SIOCBRDGGRL)"); 762 if (ifc.ifbrl_len + sizeof(*ifrp) < len) 763 break; 764 len *= 2; 765 } 766 ifrp = ifc.ifbrl_req; 767 for (i = 0; i < ifc.ifbrl_len; i += sizeof(*ifrp)) { 768 ifrp = (struct ifbrlreq *)((caddr_t)ifc.ifbrl_req + i); 769 770 if (usetab) 771 printf("\t"); 772 773 bridge_showrule(ifrp); 774 } 775 } 776 777 void 778 bridge_showrule(struct ifbrlreq *r) 779 { 780 if (r->ifbr_action == BRL_ACTION_BLOCK) 781 printf("block "); 782 else if (r->ifbr_action == BRL_ACTION_PASS) 783 printf("pass "); 784 else 785 printf("[neither block nor pass?]\n"); 786 787 if ((r->ifbr_flags & (BRL_FLAG_IN | BRL_FLAG_OUT)) == 788 (BRL_FLAG_IN | BRL_FLAG_OUT)) 789 printf("in/out "); 790 else if (r->ifbr_flags & BRL_FLAG_IN) 791 printf("in "); 792 else if (r->ifbr_flags & BRL_FLAG_OUT) 793 printf("out "); 794 else 795 printf("[neither in nor out?]\n"); 796 797 printf("on %s", r->ifbr_ifsname); 798 799 if (r->ifbr_flags & BRL_FLAG_SRCVALID) 800 printf(" src %s", ether_ntoa(&r->ifbr_src)); 801 if (r->ifbr_flags & BRL_FLAG_DSTVALID) 802 printf(" dst %s", ether_ntoa(&r->ifbr_dst)); 803 if (r->ifbr_tagname[0]) 804 printf(" tag %s", r->ifbr_tagname); 805 806 printf("\n"); 807 } 808 809 /* 810 * Parse a rule definition and send it upwards. 811 * 812 * Syntax: 813 * {block|pass} {in|out|in/out} on {ifs} [src {mac}] [dst {mac}] 814 */ 815 int 816 bridge_rule(int targc, char **targv, int ln) 817 { 818 char **argv = targv; 819 int argc = targc; 820 struct ifbrlreq rule; 821 struct ether_addr *ea, *dea; 822 823 if (argc == 0) { 824 warnx("invalid rule"); 825 return (1); 826 } 827 rule.ifbr_tagname[0] = 0; 828 rule.ifbr_flags = 0; 829 rule.ifbr_action = 0; 830 strlcpy(rule.ifbr_name, name, sizeof(rule.ifbr_name)); 831 832 if (strcmp(argv[0], "block") == 0) 833 rule.ifbr_action = BRL_ACTION_BLOCK; 834 else if (strcmp(argv[0], "pass") == 0) 835 rule.ifbr_action = BRL_ACTION_PASS; 836 else 837 goto bad_rule; 838 argc--; argv++; 839 840 if (argc == 0) { 841 bridge_badrule(targc, targv, ln); 842 return (1); 843 } 844 if (strcmp(argv[0], "in") == 0) 845 rule.ifbr_flags |= BRL_FLAG_IN; 846 else if (strcmp(argv[0], "out") == 0) 847 rule.ifbr_flags |= BRL_FLAG_OUT; 848 else if (strcmp(argv[0], "in/out") == 0) 849 rule.ifbr_flags |= BRL_FLAG_IN | BRL_FLAG_OUT; 850 else if (strcmp(argv[0], "on") == 0) { 851 rule.ifbr_flags |= BRL_FLAG_IN | BRL_FLAG_OUT; 852 argc++; argv--; 853 } else 854 goto bad_rule; 855 argc--; argv++; 856 857 if (argc == 0 || strcmp(argv[0], "on")) 858 goto bad_rule; 859 argc--; argv++; 860 861 if (argc == 0) 862 goto bad_rule; 863 strlcpy(rule.ifbr_ifsname, argv[0], sizeof(rule.ifbr_ifsname)); 864 argc--; argv++; 865 866 while (argc) { 867 if (strcmp(argv[0], "dst") == 0) { 868 if (rule.ifbr_flags & BRL_FLAG_DSTVALID) 869 goto bad_rule; 870 rule.ifbr_flags |= BRL_FLAG_DSTVALID; 871 dea = &rule.ifbr_dst; 872 } else if (strcmp(argv[0], "src") == 0) { 873 if (rule.ifbr_flags & BRL_FLAG_SRCVALID) 874 goto bad_rule; 875 rule.ifbr_flags |= BRL_FLAG_SRCVALID; 876 dea = &rule.ifbr_src; 877 } else if (strcmp(argv[0], "tag") == 0) { 878 if (argc < 2) { 879 warnx("missing tag name"); 880 goto bad_rule; 881 } 882 if (rule.ifbr_tagname[0]) { 883 warnx("tag already defined"); 884 goto bad_rule; 885 } 886 if (strlcpy(rule.ifbr_tagname, argv[1], 887 PF_TAG_NAME_SIZE) > PF_TAG_NAME_SIZE) { 888 warnx("tag name '%s' too long", argv[1]); 889 goto bad_rule; 890 } 891 dea = NULL; 892 } else 893 goto bad_rule; 894 895 argc--; argv++; 896 897 if (argc == 0) 898 goto bad_rule; 899 if (dea != NULL) { 900 ea = ether_aton(argv[0]); 901 if (ea == NULL) { 902 warnx("invalid address: %s", argv[0]); 903 return (1); 904 } 905 bcopy(ea, dea, sizeof(*dea)); 906 } 907 argc--; argv++; 908 } 909 910 if (ioctl(s, SIOCBRDGARL, &rule) < 0) { 911 warn("%s", name); 912 return (1); 913 } 914 return (0); 915 916 bad_rule: 917 bridge_badrule(targc, targv, ln); 918 return (1); 919 } 920 921 #define MAXRULEWORDS 8 922 923 void 924 bridge_rulefile(const char *fname, int d) 925 { 926 FILE *f; 927 char *str, *argv[MAXRULEWORDS], buf[1024]; 928 int ln = 0, argc = 0; 929 930 f = fopen(fname, "r"); 931 if (f == NULL) 932 err(1, "%s", fname); 933 934 while (fgets(buf, sizeof(buf), f) != NULL) { 935 ln++; 936 if (buf[0] == '#' || buf[0] == '\n') 937 continue; 938 939 argc = 0; 940 str = strtok(buf, "\n\t\r "); 941 while (str != NULL && argc < MAXRULEWORDS) { 942 argv[argc++] = str; 943 str = strtok(NULL, "\n\t\r "); 944 } 945 946 /* Rule is too long if there's more. */ 947 if (str != NULL) { 948 warnx("invalid rule: %d: %s ...", ln, buf); 949 continue; 950 } 951 952 bridge_rule(argc, argv, ln); 953 } 954 fclose(f); 955 } 956 957 void 958 bridge_badrule(int argc, char *argv[], int ln) 959 { 960 extern const char *__progname; 961 int i; 962 963 fprintf(stderr, "%s: invalid rule: ", __progname); 964 if (ln != -1) 965 fprintf(stderr, "%d: ", ln); 966 for (i = 0; i < argc; i++) 967 fprintf(stderr, "%s ", argv[i]); 968 fprintf(stderr, "\n"); 969 } 970 971 #endif 972