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
setdiscover(const char * val,int d)98 setdiscover(const char *val, int d)
99 {
100 bridge_ifsetflag(val, IFBIF_DISCOVER);
101 }
102
103 void
unsetdiscover(const char * val,int d)104 unsetdiscover(const char *val, int d)
105 {
106 bridge_ifclrflag(val, IFBIF_DISCOVER);
107 }
108
109 void
setblocknonip(const char * val,int d)110 setblocknonip(const char *val, int d)
111 {
112 bridge_ifsetflag(val, IFBIF_BLOCKNONIP);
113 }
114
115 void
unsetblocknonip(const char * val,int d)116 unsetblocknonip(const char *val, int d)
117 {
118 bridge_ifclrflag(val, IFBIF_BLOCKNONIP);
119 }
120
121 void
setlearn(const char * val,int d)122 setlearn(const char *val, int d)
123 {
124 bridge_ifsetflag(val, IFBIF_LEARNING);
125 }
126
127 void
unsetlearn(const char * val,int d)128 unsetlearn(const char *val, int d)
129 {
130 bridge_ifclrflag(val, IFBIF_LEARNING);
131 }
132
133 void
setstp(const char * val,int d)134 setstp(const char *val, int d)
135 {
136 bridge_ifsetflag(val, IFBIF_STP);
137 }
138
139 void
unsetstp(const char * val,int d)140 unsetstp(const char *val, int d)
141 {
142 bridge_ifclrflag(val, IFBIF_STP);
143 }
144
145 void
setedge(const char * val,int d)146 setedge(const char *val, int d)
147 {
148 bridge_ifsetflag(val, IFBIF_BSTP_EDGE);
149 }
150
151 void
unsetedge(const char * val,int d)152 unsetedge(const char *val, int d)
153 {
154 bridge_ifclrflag(val, IFBIF_BSTP_EDGE);
155 }
156
157 void
setautoedge(const char * val,int d)158 setautoedge(const char *val, int d)
159 {
160 bridge_ifsetflag(val, IFBIF_BSTP_AUTOEDGE);
161 }
162
163 void
unsetautoedge(const char * val,int d)164 unsetautoedge(const char *val, int d)
165 {
166 bridge_ifclrflag(val, IFBIF_BSTP_AUTOEDGE);
167 }
168
169 void
setptp(const char * val,int d)170 setptp(const char *val, int d)
171 {
172 bridge_ifsetflag(val, IFBIF_BSTP_PTP);
173 }
174
175 void
unsetptp(const char * val,int d)176 unsetptp(const char *val, int d)
177 {
178 bridge_ifclrflag(val, IFBIF_BSTP_PTP);
179 }
180
181 void
setautoptp(const char * val,int d)182 setautoptp(const char *val, int d)
183 {
184 bridge_ifsetflag(val, IFBIF_BSTP_AUTOPTP);
185 }
186
187 void
unsetautoptp(const char * val,int d)188 unsetautoptp(const char *val, int d)
189 {
190 bridge_ifclrflag(val, IFBIF_BSTP_AUTOPTP);
191 }
192
193 void
addlocal(const char * ifsname,int d)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
bridge_ifsetflag(const char * ifsname,u_int32_t flag)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
bridge_ifclrflag(const char * ifsname,u_int32_t flag)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
bridge_flushall(const char * val,int p)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
bridge_flush(const char * val,int p)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
bridge_cfg(const char * delim)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
bridge_list(char * delim)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
bridge_add(const char * ifn,int d)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
bridge_delete(const char * ifn,int d)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
bridge_addspan(const char * ifn,int d)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
bridge_delspan(const char * ifn,int d)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
bridge_timeout(const char * arg,int d)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
bridge_maxage(const char * arg,int d)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
bridge_priority(const char * arg,int d)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
bridge_protect(const char * ifsname,const char * val)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
bridge_unprotect(const char * ifsname,int d)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
bridge_proto(const char * arg,int d)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
bridge_fwddelay(const char * arg,int d)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
bridge_hellotime(const char * arg,int d)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
bridge_maxaddr(const char * arg,int d)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
bridge_deladdr(const char * addr,int d)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
bridge_ifprio(const char * ifsname,const char * val)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
bridge_ifcost(const char * ifsname,const char * val)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
bridge_noifcost(const char * ifsname,int d)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
bridge_addaddr(const char * ifsname,const char * addr)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
bridge_addendpoint(const char * endpoint,const char * addr)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
bridge_delendpoint(const char * addr,int d)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
bridge_addrs(const char * delim,int d)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
bridge_holdcnt(const char * value,int d)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
is_bridge()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
is_tpmr(void)803 is_tpmr(void)
804 {
805 return (strncmp(ifname, "tpmr", sizeof("tpmr") - 1) == 0);
806 }
807
808 void
bridge_status(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
bridge_flushrule(const char * ifsname,int d)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
bridge_rules(const char * ifsname,int usetab)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
bridge_showrule(struct ifbrlreq * r)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
bridge_rule(int targc,char ** targv,int ln)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
bridge_arprule(struct ifbrlreq * rule,int * argc,char *** argv)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
bridge_rulefile(const char * fname,int d)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
bridge_badrule(int argc,char * argv[],int ln)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