diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 1999-09-01 03:28:02 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 1999-09-01 03:28:02 +0000 |
commit | ca4dd3ababefc527f20eea2d6acde35d097cbe6a (patch) | |
tree | 1ed5b9b9664ee382cdf34f7160151786c9aa08e7 /sbin/brconfig | |
parent | fd7cb7278c603ed8c4c5a78803c7fc50505af140 (diff) |
move brconfig to /sbin, where it belongs
Diffstat (limited to 'sbin/brconfig')
-rw-r--r-- | sbin/brconfig/Makefile | 7 | ||||
-rw-r--r-- | sbin/brconfig/brconfig.8 | 215 | ||||
-rw-r--r-- | sbin/brconfig/brconfig.c | 786 |
3 files changed, 1008 insertions, 0 deletions
diff --git a/sbin/brconfig/Makefile b/sbin/brconfig/Makefile new file mode 100644 index 00000000000..3409da399c6 --- /dev/null +++ b/sbin/brconfig/Makefile @@ -0,0 +1,7 @@ +# $OpenBSD: Makefile,v 1.1 1999/09/01 03:28:01 deraadt Exp $ + +PROG= brconfig +MAN= brconfig.8 +COPTS+= -Wall + +.include <bsd.prog.mk> diff --git a/sbin/brconfig/brconfig.8 b/sbin/brconfig/brconfig.8 new file mode 100644 index 00000000000..bb44a598e22 --- /dev/null +++ b/sbin/brconfig/brconfig.8 @@ -0,0 +1,215 @@ +.\" $OpenBSD: brconfig.8,v 1.1 1999/09/01 03:28:01 deraadt Exp $ +.\" +.\" Copyright (c) 1999 Jason L. Wright (jason@thought.net) +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by Jason L. Wright +.\" 4. The name of the author may not be used to endorse or promote products +.\" derived from this software without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +.\" DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, +.\" INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +.\" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +.\" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +.\" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +.\" ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +.\" POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd February 26, 1999 +.Dt BRCONFIG 8 +.Os +.Sh NAME +.Nm brconfig +.Nd manipulate bridge interfaces +.Sh SYNOPSIS +.Nm brconfig +.Ar -a +.Nm brconfig +.Ar bridge-name +.Op Ar up +.Op Ar down +.Op Ar addr +.Op Ar add interface-name +.Op Ar delete interface-name +.Op Ar maxaddr size +.Op Ar timeout time +.Op Ar static interface-name address +.Op Ar deladdr address +.Op Ar flush +.Op Ar flushall +.Op Ar discover interface-name +.Op Ar -discover interface-name +.Op Ar learn interface-name +.Op Ar -learn interface-name +.Op Ar link0 +.Op Ar link1 +.Op Ar -link0 +.Op Ar -link1 +.Op Ar ... +.Sh DESCRIPTION +The +.Nm brconfig +utility retrieves kernel state of bridge interfaces and allows +user control of these bridges. In the first synopsis, the command +will list the status of all bridges in the system. +In the second, its command line consists +of the name of a bridge and a set of operations to be +performed on that bridge. The commands are executed in +the order they were specified. If no command is specified in +the second synopsis, the +.Nm brconfig +will display status information about the bridge. +.Pp +The available commands are: +.Bl -tag -width Ds +.It Ar up +Start the bridge forwarding packets. +.It Ar down +Stop the bridge from forwarding packets. +.It Ar addr +Display the addresses that have been learned by the bridge. +.It Ar add interface-name +Add the interface named by +.Ar interface-name +as a member of the bridge. +The interface is put into promiscuous mode so +that it can receive every packet sent on the +network. +.It Ar delete interface-name +Remove the interface named by +.Ar interface-name +from the bridge. +Promiscuous mode is turned off for the interface when it is +removed from the bridge. +.It Ar del +Alias for `delete'. +.It Ar maxaddr size +Set the address cache size to +.Cm size . +The default is 100 entries. +.It Ar timeout time +Set the timeout, in seconds, for addresses in the cache to +.Cm time . +The default is 240 seconds. +If +.Cm time +is set to zero, then entries will not be expired. +.It Ar static interface-name address +Add a static entry into the address cache pointing to +.Cm interface-name . +Static entries are never aged out of the cache or replaced if the address +is seen on a different interface. +.It Ar deladdr address +Delete an address from the cache. +.It Ar flush +Remove all dynamically learned addresses from the cache. +.It Ar flushall +Remove all addresses from the cache including static addresses. +.It Ar discover interface +Mark an interface so that packets are sent out of the interface +if the destination port of the packet is unknown. +If the bridge has no address cache entry for the destination of +a packet, meaning that there is no static entry and no dynamically learned +entry for the destination, the bridge will forward the packet to all member +interfaces that have this flag set. +This is the default for interfaces added to the bridge. +.It Ar -discover interface +Mark an interface so that packets are not sent out of the interface +if the destination port of the packet is unknown. Turning this flag +off means that the bridge will not send packets out of this interface +unless the packet is a broadcast packet, multicast packet, or a +packet with a destination address found on the interface's segment. +This, in combination with static address cache entries, +prevents potentially sensitive packets from being sent on +segments that have no need to see the packet. +.It Ar learn interface +Mark an interface so that the source address of packets received from +.Cm interface +are entered into the address cache. +This is the default for interfaces added to the bridge. +.It Ar -learn interface +Mark an interface so that the source address of packets received from +.Cm interface +are not entered into the address cache. +.It Ar link0 +Setting this flag stops all non-IP multicast packets from +being forwarded by the bridge. +.It Ar -link0 +Clear the +.Ar link0 +flag on the bridge interface. +.It Ar link1 +Setting this flags stops all IP multicast packets from +being forwarded by the bridge. +.It Ar -link0 +Clear the +.Ar link1 +flag on the bridge interface. +.El +.Sh EXAMPLES +.Bl -tag -width brconfig +.It Cm brconfig bridge0 add rl0 add xl0 up +Add the Ethernet interfaces rl0 and xl0 to the bridge bridge0, and +start the bridge forwarding packets. +.It Cm brconfig bridge0 +Retrieve a list of interfaces that are members of bridge0, and the addresses +learned by the bridge. +.It Cm brconfig bridge0 down +Stop bridge0 from forwarding packets. +.It Cm brconfig bridge0 delete xl0 +Remove the interface xl0 from the bridge bridge0. +.It Cm brconfig bridge0 flush +Flush all dynamically learned addresses from the address cache. +.It Cm brconfig bridge0 flushall +Remove all addresses, including static addresses, from the address cache. +.It Cm brconfig bridge0 -learn xl0 static xl0 8:0:20:1e:2f:2b +.It Cm brconfig bridge0 -discover xl0 +The examples above mark the xl0 interface so that it will not learn +addresses and adds a static entry for the host 8:0:20:1e:2f:2b on the xl0 +segment. +Finally, xl0 is marked so that it will not receive packets with +destinations not found in the address cache of bridge0. +This setup is the most secure, +and means that bogus MAC addresses seen by the xl0 side of the bridge +will not be propogated to the rest of the network. +Also, no packets will be sent on xl0 segment by the bridge unless they are +broadcast packets or are for 8:0:20:1e:2f:2b. +.El +.Sh SEE ALSO +.Xr bridge 4 , +.Xr ifconfig 8 +.Sh HISTORY +.Nm brconfig +first appeared in +.Ox 2.5 . +.Sh AUTHOR +The +.Xr brconfig 8 +command and the +.Xr bridge 4 +kernel interface were written by Jason L. Wright <jason@thought.net> as +part of an undergraduate independent study +at the University of North Carolina at Greensboro. +.Sh BUGS +There are some rather special network interface chipsets which will +not work in a bridge configuration. Some, like the Lite-On PNIC (see +.Xr pn 4 ), +have serious flaws when running in promiscuous mode, and others, like the +TI ThunderLAN (see +.Xr tl 4 ), +receive their own transmissions, which makes the address learning code +ineffective. Most other chipsets work fine though. diff --git a/sbin/brconfig/brconfig.c b/sbin/brconfig/brconfig.c new file mode 100644 index 00000000000..786d9a925df --- /dev/null +++ b/sbin/brconfig/brconfig.c @@ -0,0 +1,786 @@ +/* $OpenBSD: brconfig.c,v 1.1 1999/09/01 03:28:01 deraadt Exp $ */ + +/* + * Copyright (c) 1999 Jason L. Wright (jason@thought.net) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Jason L. Wright + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <sys/types.h> +#include <unistd.h> +#include <stdlib.h> +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <net/if.h> +#include <net/if_dl.h> +#include <netinet/in.h> +#include <netinet/if_ether.h> +#include <net/if_bridge.h> +#include <sys/errno.h> +#include <string.h> +#include <err.h> +#include <sysexits.h> +#include <stdlib.h> +#include <limits.h> + +void usage __P((void)); +int main __P((int, char **)); +int bridge_setflag __P((int, char *, short)); +int bridge_clrflag __P((int, char *, short)); +int bridge_ifsetflag __P((int, char *, char *, u_int32_t)); +int bridge_ifclrflag __P((int, char *, char *, u_int32_t)); +int bridge_list __P((int, char *, char *)); +int bridge_addrs __P((int, char *, char *)); +int bridge_addaddr __P((int, char *, char *, char *)); +int bridge_deladdr __P((int, char *, char *)); +int bridge_maxaddr __P((int, char *, char *)); +int bridge_timeout __P((int, char *, char *)); +int bridge_flush __P((int, char *)); +int bridge_flushall __P((int, char *)); +int bridge_add __P((int, char *, char *)); +int bridge_delete __P((int, char *, char *)); +int bridge_status __P((int, char *)); +int is_bridge __P((int, char *)); +int bridge_show_all __P((int)); +void printb __P((char *, unsigned short, char *)); + +/* if_flags bits: borrowed from ifconfig.c */ +#define IFFBITS \ +"\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\6NOTRAILERS\7RUNNING\10NOARP\ +\11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2\20MULTICAST" + +#define IFBAFBITS "\020\1STATIC" +#define IFBIFBITS "\020\1LEARNING\2DISCOVER" + +void +usage() +{ + fprintf(stderr, "usage: brconfig -a\n"); + fprintf(stderr, + "usage: brconfig interface [up] [down] [add if] [del if] ...\n"); +} + +int +main(argc, argv) + int argc; + char *argv[]; +{ + int error = 0, sock; + char *brdg; + + if (argc < 2) { + usage(); + return (EX_USAGE); + } + + sock = socket(AF_INET, SOCK_DGRAM, 0); + if (sock < 0) + err(1, "socket"); + + argc--; argv++; + brdg = argv[0]; + + if (strcmp(brdg, "-a") == 0) + return bridge_show_all(sock); + + if (!is_bridge(sock, brdg)) { + warnx("%s is not a bridge", brdg); + return (EX_USAGE); + } + + if (argc == 1) { + error = bridge_status(sock, brdg); + return (error); + } + + for (argc--, argv++; argc != 0; argc--, argv++) { + if (strcmp("add", argv[0]) == 0) { + argc--; argv++; + if (argc == 0) { + warnx("add requires an argument"); + return (EX_USAGE); + } + error = bridge_add(sock, brdg, argv[0]); + if (error) + return (error); + } + else if (strcmp("delete", argv[0]) == 0 || + strcmp("del", argv[0]) == 0) { + argc--; argv++; + if (argc == 0) { + warnx("delete requires an argument"); + return (EX_USAGE); + } + error = bridge_delete(sock, brdg, argv[0]); + if (error) + return (error); + } + else if (strcmp("up", argv[0]) == 0) { + error = bridge_setflag(sock, brdg, IFF_UP); + if (error) + return (error); + } + else if (strcmp("down", argv[0]) == 0) { + error = bridge_clrflag(sock, brdg, IFF_UP); + if (error) + return (error); + } + else if (strcmp("discover", argv[0]) == 0) { + argc--; argv++; + if (argc == 0) { + warnx("discover requires an argument"); + return (EX_USAGE); + } + error = bridge_ifsetflag(sock, brdg, argv[0], + IFBIF_DISCOVER); + if (error) + return (error); + } + else if (strcmp("-discover", argv[0]) == 0) { + argc--; argv++; + if (argc == 0) { + warnx("-discover requires an argument"); + return (EX_USAGE); + } + error = bridge_ifclrflag(sock, brdg, argv[0], + IFBIF_DISCOVER); + if (error) + return (error); + } + else if (strcmp("learn", argv[0]) == 0) { + argc--; argv++; + if (argc == 0) { + warnx("learn requires an argument"); + return (EX_USAGE); + } + error = bridge_ifsetflag(sock, brdg, argv[0], + IFBIF_LEARNING); + if (error) + return (error); + } + else if (strcmp("-learn", argv[0]) == 0) { + argc--; argv++; + if (argc == 0) { + warnx("-learn requires an argument"); + return (EX_USAGE); + } + error = bridge_ifclrflag(sock, brdg, argv[0], + IFBIF_LEARNING); + if (error) + return (error); + } + else if (strcmp("flush", argv[0]) == 0) { + error = bridge_flush(sock, brdg); + if (error) + return (error); + } + else if (strcmp("flushall", argv[0]) == 0) { + error = bridge_flushall(sock, brdg); + if (error) + return (error); + } + else if (strcmp("static", argv[0]) == 0) { + argc--; argv++; + if (argc < 2) { + warnx("static requires 2 arguments"); + return (EX_USAGE); + } + error = bridge_addaddr(sock, brdg, argv[0], argv[1]); + if (error) + return (error); + argc--; argv++; + } + else if (strcmp("deladdr", argv[0]) == 0) { + argc--; argv++; + if (argc == 0) { + warnx("deladdr requires an argument"); + return (EX_USAGE); + } + error = bridge_deladdr(sock, brdg, argv[0]); + if (error) + return (error); + } + else if (strcmp("link0", argv[0]) == 0) { + error = bridge_setflag(sock, brdg, IFF_LINK0); + if (error) + return (error); + } + else if (strcmp("-link0", argv[0]) == 0) { + error = bridge_clrflag(sock, brdg, IFF_LINK0); + if (error) + return (error); + } + else if (strcmp("link1", argv[0]) == 0) { + error = bridge_setflag(sock, brdg, IFF_LINK1); + if (error) + return (error); + } + else if (strcmp("-link1", argv[0]) == 0) { + error = bridge_clrflag(sock, brdg, IFF_LINK1); + if (error) + return (error); + } + else if (strcmp("addr", argv[0]) == 0) { + error = bridge_addrs(sock, brdg, ""); + if (error) + return (error); + } + else if (strcmp("maxaddr", argv[0]) == 0) { + argc--; argv++; + if (argc == 0) { + warnx("maxaddr requires an argument"); + return (EX_USAGE); + } + error = bridge_maxaddr(sock, brdg, argv[0]); + if (error) + return (error); + } + else if (strcmp("timeout", argv[0]) == 0) { + argc--; argv++; + if (argc == 0) { + warnx("timeout requires an argument"); + return (EX_USAGE); + } + error = bridge_timeout(sock, brdg, argv[0]); + if (error) + return (error); + } + else { + warnx("unrecognized option: %s", argv[0]); + return (EX_USAGE); + } + } + + return (0); +} + +int +bridge_ifsetflag(s, brdg, ifsname, flag) + int s; + char *brdg, *ifsname; + u_int32_t flag; +{ + struct ifbreq req; + + strlcpy(req.ifbr_name, brdg, sizeof(req.ifbr_name)); + strlcpy(req.ifbr_ifsname, ifsname, sizeof(req.ifbr_ifsname)); + if (ioctl(s, SIOCBRDGGIFFLGS, (caddr_t)&req) < 0) { + warn("ioctl(SIOCBRDGGIFFLGS)"); + return (EX_IOERR); + } + + req.ifbr_ifsflags |= flag; + + if (ioctl(s, SIOCBRDGSIFFLGS, (caddr_t)&req) < 0) { + warn("ioctl(SIOCBRDGSIFFLGS)"); + return (EX_IOERR); + } + return (0); +} + +int +bridge_ifclrflag(s, brdg, ifsname, flag) + int s; + char *brdg, *ifsname; + u_int32_t flag; +{ + struct ifbreq req; + + strlcpy(req.ifbr_name, brdg, sizeof(req.ifbr_name)); + strlcpy(req.ifbr_ifsname, ifsname, sizeof(req.ifbr_ifsname)); + + if (ioctl(s, SIOCBRDGGIFFLGS, (caddr_t)&req) < 0) { + warn("ioctl(SIOCBRDGGIFFLGS)"); + return (EX_IOERR); + } + + req.ifbr_ifsflags &= ~flag; + + if (ioctl(s, SIOCBRDGSIFFLGS, (caddr_t)&req) < 0) { + warn("ioctl(SIOCBRDGSIFFLGS)"); + return (EX_IOERR); + } + return (0); +} + +int +bridge_show_all(s) + int s; +{ + char *inbuf = NULL; + struct ifconf ifc; + struct ifreq *ifrp, ifreq; + int len = 8192, i; + + while (1) { + ifc.ifc_len = len; + ifc.ifc_buf = inbuf = realloc(inbuf, len); + if (inbuf == NULL) + err(1, "malloc"); + if (ioctl(s, SIOCGIFCONF, &ifc) < 0) + err(1, "ioctl(SIOCGIFCONF)"); + if (ifc.ifc_len + sizeof(struct ifreq) < len) + break; + len *= 2; + } + ifrp = ifc.ifc_req; + ifreq.ifr_name[0] = '\0'; + for (i = 0; i < ifc.ifc_len; ) { + ifrp = (struct ifreq *)((caddr_t)ifc.ifc_req + i); + i += sizeof(ifrp->ifr_name) + + (ifrp->ifr_addr.sa_len > sizeof(struct sockaddr) ? + ifrp->ifr_addr.sa_len : sizeof(struct sockaddr)); + if (ifrp->ifr_addr.sa_family != AF_LINK) + continue; + if (!is_bridge(s, ifrp->ifr_name)) + continue; + bridge_status(s, ifrp->ifr_name); + } + return (0); +} + +int +bridge_setflag(s, brdg, f) + int s; + char *brdg; + short f; +{ + struct ifreq ifr; + + strlcpy(ifr.ifr_name, brdg, sizeof(ifr.ifr_name)); + + if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) { + warn("ioctl(SIOCGIFFLAGS)"); + if (errno == EPERM) + return (EX_NOPERM); + return (EX_IOERR); + } + + ifr.ifr_flags |= f; + + if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&ifr) < 0) { + warn("ioctl(SIOCSIFFLAGS)"); + if (errno == EPERM) + return (EX_NOPERM); + return (EX_IOERR); + } + + return (0); +} + +int +bridge_clrflag(s, brdg, f) + int s; + char *brdg; + short f; +{ + struct ifreq ifr; + + strlcpy(ifr.ifr_name, brdg, sizeof(ifr.ifr_name)); + + if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) { + warn("ioctl(SIOCGIFFLAGS)"); + if (errno == EPERM) + return (EX_NOPERM); + return (EX_IOERR); + } + + ifr.ifr_flags &= ~(f); + + if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&ifr) < 0) { + warn("ioctl(SIOCSIFFLAGS)"); + if (errno == EPERM) + return (EX_NOPERM); + return (EX_IOERR); + } + + return (0); +} + +int +bridge_flushall(s, brdg) + int s; + char *brdg; +{ + struct ifreq ifr; + + strlcpy(ifr.ifr_name, brdg, sizeof(ifr.ifr_name)); + if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) { + warn("ioctl(SIOCGIFFLAGS)"); + return (EX_IOERR); + } + + if ((ifr.ifr_flags & IFF_UP) == 0) + return (0); + + strlcpy(ifr.ifr_name, brdg, sizeof(ifr.ifr_name)); + ifr.ifr_flags &= ~IFF_UP; + if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&ifr) < 0) { + warn("ioctl(SIOCSIFFLAGS)"); + return (EX_IOERR); + } + + strlcpy(ifr.ifr_name, brdg, sizeof(ifr.ifr_name)); + ifr.ifr_flags |= IFF_UP; + if (ioctl(s, SIOCSIFFLAGS, (caddr_t)&ifr) < 0) { + warn("ioctl(SIOCSIFFLAGS)"); + return (EX_IOERR); + } + + return (0); +} + +int +bridge_flush(s, brdg) + int s; + char *brdg; +{ + struct ifbreq req; + + strlcpy(req.ifbr_name, brdg, sizeof(req.ifbr_name)); + if (ioctl(s, SIOCBRDGFLUSH, &req) < 0) { + warn("ioctl(SIOCBRDGFLUSH)"); + return (EX_IOERR); + } + return (0); +} + +int +bridge_list(s, brdg, delim) + int s; + char *brdg, *delim; +{ + struct ifbreq *reqp; + struct ifbifconf bifc; + int i, len = 8192; + char buf[sizeof(reqp->ifbr_ifsname) + 1], *inbuf = NULL; + + while (1) { + strlcpy(bifc.ifbic_name, brdg, sizeof(bifc.ifbic_name)); + bifc.ifbic_len = len; + bifc.ifbic_buf = inbuf = realloc(inbuf, len); + if (inbuf == NULL) + err(1, "malloc"); + if (ioctl(s, SIOCBRDGIFS, &bifc) < 0) + err(1, "ioctl(SIOCBRDGIFS)"); + if (bifc.ifbic_len + sizeof(*reqp) < len) + break; + len *= 2; + } + for (i = 0; i < bifc.ifbic_len / sizeof(*reqp); i++) { + reqp = bifc.ifbic_req + i; + strlcpy(buf, reqp->ifbr_ifsname, sizeof(buf)); + printf("%s%s ", delim, buf); + printb("flags", reqp->ifbr_ifsflags, IFBIFBITS); + printf("\n"); + } + free(bifc.ifbic_buf); + return (0); /* NOTREACHED */ +} + +int +bridge_add(s, brdg, ifn) + int s; + char *brdg, *ifn; +{ + struct ifbreq req; + + strlcpy(req.ifbr_name, brdg, sizeof(req.ifbr_name)); + strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname)); + if (ioctl(s, SIOCBRDGADD, &req) < 0) { + warn("ioctl(SIOCADDBRDG)"); + if (errno == EPERM) + return (EX_NOPERM); + return (EX_IOERR); + } + return (0); +} + +int +bridge_delete(s, brdg, ifn) + int s; + char *brdg, *ifn; +{ + struct ifbreq req; + + strlcpy(req.ifbr_name, brdg, sizeof(req.ifbr_name)); + strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname)); + if (ioctl(s, SIOCBRDGDEL, &req) < 0) { + warn("ioctl(SIOCDELBRDG)"); + if (errno == EPERM) + return (EX_NOPERM); + return (EX_IOERR); + } + return (0); +} + +int +bridge_timeout(s, brdg, arg) + int s; + char *brdg, *arg; +{ + struct ifbcachetoreq ifbct; + u_int32_t newtime; + char *endptr; + + newtime = strtoul(arg, &endptr, 0); + if (arg[0] == '\0' || endptr[0] != '\0') { + printf("invalid arg for timeout: %s\n", arg); + return (EX_USAGE); + } + + strlcpy(ifbct.ifbct_name, brdg, sizeof(ifbct.ifbct_name)); + ifbct.ifbct_time = newtime; + if (ioctl(s, SIOCBRDGSTO, (caddr_t)&ifbct) < 0) { + warn("ioctl(SIOCBRDGGCACHE)"); + return (EX_IOERR); + } + return (0); +} + +int +bridge_maxaddr(s, brdg, arg) + int s; + char *brdg, *arg; +{ + struct ifbcachereq ifbc; + u_int32_t newsize; + char *endptr; + + newsize = strtoul(arg, &endptr, 0); + if (arg[0] == '\0' || endptr[0] != '\0') { + printf("invalid arg for maxaddr: %s\n", arg); + return (EX_USAGE); + } + + strlcpy(ifbc.ifbc_name, brdg, sizeof(ifbc.ifbc_name)); + ifbc.ifbc_size = newsize; + if (ioctl(s, SIOCBRDGSCACHE, (caddr_t)&ifbc) < 0) { + warn("ioctl(SIOCBRDGGCACHE)"); + return (EX_IOERR); + } + return (0); +} + +int +bridge_deladdr(s, brdg, addr) + int s; + char *brdg, *addr; +{ + struct ifbareq ifba; + struct ether_addr *ea; + + strlcpy(ifba.ifba_name, brdg, sizeof(ifba.ifba_name)); + ea = ether_aton(addr); + if (ea == NULL) { + warnx("Invalid address: %s", addr); + return (EX_USAGE); + } + bcopy(ea, &ifba.ifba_dst, sizeof(struct ether_addr)); + + if (ioctl(s, SIOCBRDGDADDR, &ifba) < 0) { + warn("ioctl(SIOCBRDGDADDR)"); + return (EX_IOERR); + } + + return (0); +} + +int +bridge_addaddr(s, brdg, ifname, addr) + int s; + char *brdg, *ifname, *addr; +{ + struct ifbareq ifba; + struct ether_addr *ea; + + strlcpy(ifba.ifba_name, brdg, sizeof(ifba.ifba_name)); + strlcpy(ifba.ifba_ifsname, ifname, sizeof(ifba.ifba_ifsname)); + + ea = ether_aton(addr); + if (ea == NULL) { + warnx("Invalid address: %s", addr); + return (EX_USAGE); + } + bcopy(ea, &ifba.ifba_dst, sizeof(struct ether_addr)); + ifba.ifba_flags = IFBAF_STATIC; + + if (ioctl(s, SIOCBRDGSADDR, &ifba) < 0) { + warn("ioctl(SIOCBRDGSADDR)"); + return (EX_IOERR); + } + + return (0); +} + +int +bridge_addrs(s, brdg, delim) + int s; + char *brdg, *delim; +{ + struct ifbaconf ifbac; + struct ifbareq *ifba; + char *inbuf = NULL, buf[sizeof(ifba->ifba_ifsname) + 1]; + int i, len = 8192; + + while (1) { + ifbac.ifbac_len = len; + ifbac.ifbac_buf = inbuf = realloc(inbuf, len); + strlcpy(ifbac.ifbac_name, brdg, sizeof(ifbac.ifbac_name)); + if (inbuf == NULL) + err(EX_IOERR, "malloc"); + if (ioctl(s, SIOCBRDGRTS, &ifbac) < 0) { + if (errno == ENETDOWN) + return (0); + err(EX_IOERR, "ioctl(SIOCBRDGRTS)"); + } + if (ifbac.ifbac_len + sizeof(*ifba) < len) + break; + len *= 2; + } + + for (i = 0; i < ifbac.ifbac_len / sizeof(*ifba); i++) { + ifba = ifbac.ifbac_req + i; + strlcpy(buf, ifba->ifba_ifsname, sizeof(buf)); + printf("%s%s %s %u ", delim, ether_ntoa(&ifba->ifba_dst), + buf, ifba->ifba_age); + printb("flags", ifba->ifba_flags, IFBAFBITS); + printf("\n"); + } + + return (0); +} + +/* + * Check to make sure 'brdg' is really a bridge interface. + */ +int +is_bridge(s, brdg) + int s; + char *brdg; +{ + struct ifreq ifr; + struct ifbaconf ifbac; + + strlcpy(ifr.ifr_name, brdg, sizeof(ifr.ifr_name)); + + if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) + return (0); + + ifbac.ifbac_len = 0; + strlcpy(ifbac.ifbac_name, brdg, sizeof(ifbac.ifbac_name)); + if (ioctl(s, SIOCBRDGRTS, (caddr_t)&ifbac) < 0) { + if (errno == ENETDOWN) + return (1); + return (0); + } + return (1); +} + +int +bridge_status(s, brdg) + int s; + char *brdg; +{ + struct ifreq ifr; + struct ifbcachereq ifbc; + struct ifbcachetoreq ifbct; + int err; + + strlcpy(ifr.ifr_name, brdg, sizeof(ifr.ifr_name)); + if (ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) { + warn("ioctl(SIOCGIFFLAGS)"); + if (errno == EPERM) + return (EX_NOPERM); + return (EX_IOERR); + } + + printf("%s: ", brdg); + printb("flags", ifr.ifr_flags, IFFBITS); + printf("\n"); + + printf("\tInterfaces:\n"); + err = bridge_list(s, brdg, "\t\t"); + if (err) + return (err); + + strlcpy(ifbc.ifbc_name, brdg, sizeof(ifbc.ifbc_name)); + if (ioctl(s, SIOCBRDGGCACHE, (caddr_t)&ifbc) < 0) { + warn("ioctl(SIOCBRDGGCACHE)"); + return (EX_IOERR); + } + + strlcpy(ifbct.ifbct_name, brdg, sizeof(ifbct.ifbct_name)); + if (ioctl(s, SIOCBRDGGTO, (caddr_t)&ifbct) < 0) { + warn("ioctl(SIOCBRDGGTO)"); + return (EX_IOERR); + } + + printf("\tAddresses (max cache: %u, timeout: %u):\n", + ifbc.ifbc_size, ifbct.ifbct_time); + + err = bridge_addrs(s, brdg, "\t\t"); + return (err); +} + +/* + * Print a value a la the %b format of the kernel's printf + * (borrowed from ifconfig.c) + */ +void +printb(s, v, bits) + char *s; + char *bits; + unsigned short v; +{ + register int i, any = 0; + register char c; + + if (bits && *bits == 8) + printf("%s=%o", s, v); + else + printf("%s=%x", s, v); + bits++; + if (bits) { + putchar('<'); + while ((i = *bits++)) { + if (v & (1 << (i-1))) { + if (any) + putchar(','); + any = 1; + for (; (c = *bits) > 32; bits++) + putchar(c); + } else + for (; *bits > 32; bits++) + ; + } + putchar('>'); + } +} |