summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorhrs <hrs@FreeBSD.org>2009-06-07 23:00:40 +0000
committerhrs <hrs@FreeBSD.org>2009-06-07 23:00:40 +0000
commit9bf362d0cc3f533a0c7e793fd354bfabfce44de6 (patch)
tree9a067cbb66c280e9da4ac4cea8c84e204039d753
parent92f847edaf37d804dffd489728e6af48a60a4fbb (diff)
downloadFreeBSD-src-9bf362d0cc3f533a0c7e793fd354bfabfce44de6.zip
FreeBSD-src-9bf362d0cc3f533a0c7e793fd354bfabfce44de6.tar.gz
Fix and add a workaround on an issue of EtherIP packet with reversed
version field sent via gif(4)+if_bridge(4). The EtherIP implementation found on FreeBSD 6.1, 6.2, 6.3, 7.0, 7.1, and 7.2 had an interoperability issue because it sent the incorrect EtherIP packets and discarded the correct ones. This change introduces the following two flags to gif(4): accept_rev_ethip_ver: accepts both correct EtherIP packets and ones with reversed version field, if enabled. If disabled, the gif accepts the correct packets only. This flag is enabled by default. send_rev_ethip_ver: sends EtherIP packets with reversed version field intentionally, if enabled. If disabled, the gif sends the correct packets only. This flag is disabled by default. These flags are stored in struct gif_softc and can be set by ifconfig(8) on per-interface basis. Note that this is an incompatible change of EtherIP with the older FreeBSD releases. If you need to interoperate older FreeBSD boxes and new versions after this commit, setting "send_rev_ethip_ver" is needed. Reviewed by: thompsa and rwatson Spotted by: Shunsuke SHINOMIYA PR: kern/125003 MFC after: 2 weeks
-rw-r--r--sbin/ifconfig/Makefile1
-rw-r--r--sbin/ifconfig/ifgif.c132
-rw-r--r--share/man/man4/gif.431
-rw-r--r--share/man/man4/if_bridge.48
-rw-r--r--sys/net/if_gif.c46
-rw-r--r--sys/net/if_gif.h26
-rw-r--r--sys/netinet/in_gif.c18
-rw-r--r--sys/netinet6/in6_gif.c18
-rw-r--r--sys/sys/priv.h1
9 files changed, 264 insertions, 17 deletions
diff --git a/sbin/ifconfig/Makefile b/sbin/ifconfig/Makefile
index 087b3a0..c97f14d 100644
--- a/sbin/ifconfig/Makefile
+++ b/sbin/ifconfig/Makefile
@@ -24,6 +24,7 @@ SRCS+= ifmac.c # MAC support
SRCS+= ifmedia.c # SIOC[GS]IFMEDIA support
SRCS+= ifvlan.c # SIOC[GS]ETVLAN support
SRCS+= ifgre.c # GRE keys etc
+SRCS+= ifgif.c # GIF reversed header workaround
SRCS+= ifieee80211.c regdomain.c # SIOC[GS]IEEE80211 support
DPADD+= ${LIBBSDXML} ${LIBSBUF}
diff --git a/sbin/ifconfig/ifgif.c b/sbin/ifconfig/ifgif.c
new file mode 100644
index 0000000..92ee4c8
--- /dev/null
+++ b/sbin/ifconfig/ifgif.c
@@ -0,0 +1,132 @@
+/*-
+ * Copyright (c) 2009 Hiroki Sato. 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.
+ *
+ * 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 OR HIS RELATIVES 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 MIND, 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.
+ */
+
+#ifndef lint
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_gif.h>
+#include <net/route.h>
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <err.h>
+#include <errno.h>
+
+#include "ifconfig.h"
+
+static void gif_status(int);
+
+static struct {
+ const char *label;
+ u_int mask;
+} gif_opts[] = {
+ { "ACCEPT_REV_ETHIP_VER", GIF_ACCEPT_REVETHIP },
+ { "SEND_REV_ETHIP_VER", GIF_SEND_REVETHIP },
+};
+
+static void
+gif_status(int s)
+{
+ int opts;
+ int nopts = 0;
+ int i;
+
+ ifr.ifr_data = (caddr_t)&opts;
+ if (ioctl(s, GIFGOPTS, &ifr) == -1)
+ return;
+
+ printf("\toptions=%d<", opts);
+ for (i=0; i < sizeof(gif_opts)/sizeof(gif_opts[0]); i++) {
+ if (opts & gif_opts[i].mask) {
+ if (nopts++)
+ printf(",");
+ printf("%s", gif_opts[i].label);
+ }
+ }
+ printf(">\n");
+}
+
+static void
+setgifopts(const char *val,
+ int d, int s, const struct afswtch *afp)
+{
+ int opts;
+
+ ifr.ifr_data = (caddr_t)&opts;
+ if (ioctl(s, GIFGOPTS, &ifr) == -1) {
+ warn("ioctl(GIFGOPTS)");
+ return;
+ }
+
+ if (d < 0)
+ opts &= ~(-d);
+ else
+ opts |= d;
+
+ if (ioctl(s, GIFSOPTS, &ifr) == -1) {
+ warn("ioctl(GIFSOPTS)");
+ return;
+ }
+}
+
+static struct cmd gif_cmds[] = {
+ DEF_CMD("accept_rev_ethip_ver", GIF_ACCEPT_REVETHIP, setgifopts),
+ DEF_CMD("-accept_rev_ethip_ver",-GIF_ACCEPT_REVETHIP, setgifopts),
+ DEF_CMD("send_rev_ethip_ver", GIF_SEND_REVETHIP, setgifopts),
+ DEF_CMD("-send_rev_ethip_ver", -GIF_SEND_REVETHIP, setgifopts),
+};
+
+static struct afswtch af_gif = {
+ .af_name = "af_gif",
+ .af_af = AF_UNSPEC,
+ .af_other_status = gif_status,
+};
+
+static __constructor void
+gif_ctor(void)
+{
+#define N(a) (sizeof(a) / sizeof(a[0]))
+ int i;
+
+ for (i = 0; i < N(gif_cmds); i++)
+ cmd_register(&gif_cmds[i]);
+ af_register(&af_gif);
+#undef N
+}
diff --git a/share/man/man4/gif.4 b/share/man/man4/gif.4
index 936898f..a70db08 100644
--- a/share/man/man4/gif.4
+++ b/share/man/man4/gif.4
@@ -29,7 +29,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd April 10, 1999
+.Dd June 8, 2009
.Dt GIF 4
.Os
.Sh NAME
@@ -256,3 +256,32 @@ had a multi-destination behavior, configurable via
.Dv IFF_LINK0
flag.
The behavior is obsolete and is no longer supported.
+.Pp
+On
+.Fx
+6.1, 6.2, 6.3, 7.0, 7.1, and 7.2
+the
+.Nm
+sends and receives incorrect EtherIP packets with reversed version
+field when
+.Xr if_bridge 4
+is used together. As a workaround on this interoperability issue, the
+following two
+.Xr ifconfig 8
+flags can be used:
+.Bl -tag -width "accept_rev_ethip_ver" -offset indent
+.It accept_rev_ethip_ver
+accepts both correct EtherIP packets and ones with reversed version
+field, if enabled. If disabled, the
+.Nm
+accepts the correct packets only. This flag is enabled by default.
+.It send_rev_ethip_ver
+sends EtherIP packets with reversed version field intentionally, if
+enabled. If disabled, the
+.Nm
+sends the correct packets only. This flag is disabled by default.
+.El
+.Pp
+If interoperability with the older
+.Fx
+machines is needed, both of these two flags must be enabled.
diff --git a/share/man/man4/if_bridge.4 b/share/man/man4/if_bridge.4
index 7b31fa1..a31891a 100644
--- a/share/man/man4/if_bridge.4
+++ b/share/man/man4/if_bridge.4
@@ -35,7 +35,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd September 17, 2007
+.Dd June 8, 2009
.Dt IF_BRIDGE 4
.Os
.Sh NAME
@@ -406,6 +406,12 @@ ifconfig gif0 tunnel 1.2.3.4 5.6.7.8 up
ifconfig bridge0 create
ifconfig bridge0 addm fxp0 addm gif0 up
.Ed
+.Pp
+Note that
+.Fx
+6.1, 6.2, 6.3, 7.0, 7.1, and 7.2 have a bug in the EtherIP protocol.
+For more details and workaround, see
+.Xr gif 4 manual page.
.Sh SEE ALSO
.Xr gif 4 ,
.Xr ipf 4 ,
diff --git a/sys/net/if_gif.c b/sys/net/if_gif.c
index 6405725..69e14e9 100644
--- a/sys/net/if_gif.c
+++ b/sys/net/if_gif.c
@@ -45,6 +45,7 @@
#include <sys/time.h>
#include <sys/sysctl.h>
#include <sys/syslog.h>
+#include <sys/priv.h>
#include <sys/proc.h>
#include <sys/protosw.h>
#include <sys/conf.h>
@@ -198,6 +199,7 @@ gif_clone_create(ifc, unit, params)
if_initname(GIF2IFP(sc), ifc->ifc_name, unit);
sc->encap_cookie4 = sc->encap_cookie6 = NULL;
+ sc->gif_options = GIF_ACCEPT_REVETHIP;
GIF2IFP(sc)->if_addrlen = 0;
GIF2IFP(sc)->if_mtu = GIF_MTU;
@@ -534,6 +536,7 @@ gif_input(m, af, ifp)
struct ifnet *ifp;
{
int isr, n;
+ struct gif_softc *sc = ifp->if_softc;
struct etherip_header *eip;
struct ether_header *eh;
struct ifnet *oldifp;
@@ -594,11 +597,25 @@ gif_input(m, af, ifp)
}
eip = mtod(m, struct etherip_header *);
- if (eip->eip_ver !=
- (ETHERIP_VERSION & ETHERIP_VER_VERS_MASK)) {
- /* discard unknown versions */
- m_freem(m);
- return;
+ /*
+ * GIF_ACCEPT_REVETHIP (enabled by default) intentionally
+ * accepts an EtherIP packet with revered version field in
+ * the header. This is a knob for backward compatibility
+ * with FreeBSD 7.2R or prior.
+ */
+ if (sc->gif_options & GIF_ACCEPT_REVETHIP) {
+ if (eip->eip_resvl != ETHERIP_VERSION
+ && eip->eip_ver != ETHERIP_VERSION) {
+ /* discard unknown versions */
+ m_freem(m);
+ return;
+ }
+ } else {
+ if (eip->eip_ver != ETHERIP_VERSION) {
+ /* discard unknown versions */
+ m_freem(m);
+ return;
+ }
}
m_adj(m, sizeof(struct etherip_header));
@@ -653,6 +670,7 @@ gif_ioctl(ifp, cmd, data)
struct gif_softc *sc = ifp->if_softc;
struct ifreq *ifr = (struct ifreq*)data;
int error = 0, size;
+ u_int options;
struct sockaddr *dst, *src;
#ifdef SIOCSIFMTU /* xxx */
u_long mtu;
@@ -887,6 +905,24 @@ gif_ioctl(ifp, cmd, data)
/* if_ioctl() takes care of it */
break;
+ case GIFGOPTS:
+ options = sc->gif_options;
+ error = copyout(&options, ifr->ifr_data,
+ sizeof(options));
+ break;
+
+ case GIFSOPTS:
+ if ((error = priv_check(curthread, PRIV_NET_GIF)) != 0)
+ break;
+ if ((error = copyin(&options, &sc->gif_options,
+ sizeof(sc->gif_options)))) {
+ if ((options | GIF_FULLOPTS) == GIF_FULLOPTS)
+ ifr->ifr_data = (caddr_t)options;
+ else
+ error = EINVAL;
+ }
+ break;
+
default:
error = EINVAL;
break;
diff --git a/sys/net/if_gif.h b/sys/net/if_gif.h
index d54180d..bdc9562 100644
--- a/sys/net/if_gif.h
+++ b/sys/net/if_gif.h
@@ -71,6 +71,7 @@ struct gif_softc {
const struct encaptab *encap_cookie4;
const struct encaptab *encap_cookie6;
void *gif_netgraph; /* ng_gif(4) netgraph node info */
+ u_int gif_options;
LIST_ENTRY(gif_softc) gif_list; /* all gif's are linked */
};
#define GIF2IFP(sc) ((sc)->gif_ifp)
@@ -94,12 +95,18 @@ struct gif_softc {
#define MTAG_GIF_CALLED 0
struct etherip_header {
- u_int8_t eip_ver; /* version/reserved */
- u_int8_t eip_pad; /* required padding byte */
-};
-#define ETHERIP_VER_VERS_MASK 0x0f
-#define ETHERIP_VER_RSVD_MASK 0xf0
-#define ETHERIP_VERSION 0x03
+#if BYTE_ORDER == LITTLE_ENDIAN
+ u_int eip_resvl:4, /* reserved */
+ eip_ver:4; /* version */
+#endif
+#if BYTE_ORDER == BIG_ENDIAN
+ u_int eip_ver:4, /* version */
+ eip_resvl:4; /* reserved */
+#endif
+ u_int8_t eip_resvh; /* reserved */
+} __packed;
+
+#define ETHERIP_VERSION 0x3
/* mbuf adjust factor to force 32-bit alignment of IP header */
#define ETHERIP_ALIGN 2
@@ -143,4 +150,11 @@ extern struct vnet_gif vnet_gif_0;
#endif /* _KERNEL */
+#define GIFGOPTS _IOR('i', 150, struct ifreq)
+#define GIFSOPTS _IOW('i', 151, struct ifreq)
+
+#define GIF_ACCEPT_REVETHIP 0x0001
+#define GIF_SEND_REVETHIP 0x0010
+#define GIF_FULLOPTS (GIF_ACCEPT_REVETHIP|GIF_SEND_REVETHIP)
+
#endif /* _NET_IF_GIF_H_ */
diff --git a/sys/netinet/in_gif.c b/sys/netinet/in_gif.c
index bc62f5f..ce45672 100644
--- a/sys/netinet/in_gif.c
+++ b/sys/netinet/in_gif.c
@@ -148,8 +148,22 @@ in_gif_output(struct ifnet *ifp, int family, struct mbuf *m)
#endif /* INET6 */
case AF_LINK:
proto = IPPROTO_ETHERIP;
- eiphdr.eip_ver = ETHERIP_VERSION & ETHERIP_VER_VERS_MASK;
- eiphdr.eip_pad = 0;
+
+ /*
+ * GIF_SEND_REVETHIP (disabled by default) intentionally
+ * sends an EtherIP packet with revered version field in
+ * the header. This is a knob for backward compatibility
+ * with FreeBSD 7.2R or prior.
+ */
+ if ((sc->gif_options & GIF_SEND_REVETHIP)) {
+ eiphdr.eip_ver = 0;
+ eiphdr.eip_resvl = ETHERIP_VERSION;
+ eiphdr.eip_resvh = 0;
+ } else {
+ eiphdr.eip_ver = ETHERIP_VERSION;
+ eiphdr.eip_resvl = 0;
+ eiphdr.eip_resvh = 0;
+ }
/* prepend Ethernet-in-IP header */
M_PREPEND(m, sizeof(struct etherip_header), M_DONTWAIT);
if (m && m->m_len < sizeof(struct etherip_header))
diff --git a/sys/netinet6/in6_gif.c b/sys/netinet6/in6_gif.c
index 7041841..68ebc9c 100644
--- a/sys/netinet6/in6_gif.c
+++ b/sys/netinet6/in6_gif.c
@@ -144,8 +144,22 @@ in6_gif_output(struct ifnet *ifp,
#endif
case AF_LINK:
proto = IPPROTO_ETHERIP;
- eiphdr.eip_ver = ETHERIP_VERSION & ETHERIP_VER_VERS_MASK;
- eiphdr.eip_pad = 0;
+
+ /*
+ * GIF_SEND_REVETHIP (disabled by default) intentionally
+ * sends an EtherIP packet with revered version field in
+ * the header. This is a knob for backward compatibility
+ * with FreeBSD 7.2R or prior.
+ */
+ if ((sc->gif_options & GIF_SEND_REVETHIP)) {
+ eiphdr.eip_ver = 0;
+ eiphdr.eip_resvl = ETHERIP_VERSION;
+ eiphdr.eip_resvh = 0;
+ } else {
+ eiphdr.eip_ver = ETHERIP_VERSION;
+ eiphdr.eip_resvl = 0;
+ eiphdr.eip_resvh = 0;
+ }
/* prepend Ethernet-in-IP header */
M_PREPEND(m, sizeof(struct etherip_header), M_DONTWAIT);
if (m && m->m_len < sizeof(struct etherip_header))
diff --git a/sys/sys/priv.h b/sys/sys/priv.h
index 6f9f63b..7936de0 100644
--- a/sys/sys/priv.h
+++ b/sys/sys/priv.h
@@ -324,6 +324,7 @@
#define PRIV_NET_ADDIFADDR 413 /* Add protocol addr to interface. */
#define PRIV_NET_DELIFADDR 414 /* Delete protocol addr on interface. */
#define PRIV_NET_LAGG 415 /* Administer lagg interface. */
+#define PRIV_NET_GIF 416 /* Administer gif interface. */
/*
* 802.11-related privileges.
OpenPOWER on IntegriCloud