Page MenuHomeFreeBSD

D59849.1794081733.diff
No OneTemporary

Authored By
Unknown
Size
42 KB
Referenced Files
None
Subscribers
None

D59849.1794081733.diff

diff --git a/sbin/ifconfig/ifconfig.8 b/sbin/ifconfig/ifconfig.8
--- a/sbin/ifconfig/ifconfig.8
+++ b/sbin/ifconfig/ifconfig.8
@@ -28,7 +28,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd September 10, 2026
+.Dd November 1, 2026
.Dt IFCONFIG 8
.Os
.Sh NAME
@@ -3099,10 +3099,12 @@
.Fl tunnel
parameter.
.It Cm grekey Ar key
-Configure the GRE key to be used for outgoing packets.
-Note that
-.Xr gre 4 will always accept GRE packets with invalid or absent keys.
+Configure the GRE key to be used for both incoming and outgoing packets.
This command will result in a four byte MTU reduction on the interface.
+.It Cm greokey Ar key
+Configure the GRE key to be used for outgoing packets.
+.It Cm greikey Ar key
+Configure the GRE key to be used for incoming packets.
.El
.Ss Packet Filter State Table Sychronisation Parameters
The following parameters are specific to
diff --git a/sbin/ifconfig/ifgre.c b/sbin/ifconfig/ifgre.c
--- a/sbin/ifconfig/ifgre.c
+++ b/sbin/ifconfig/ifgre.c
@@ -55,6 +55,7 @@
struct nl_parsed_gre {
uint32_t ifla_flags;
uint32_t ifla_okey;
+ uint32_t ifla_ikey;
uint32_t ifla_encap_type;
uint16_t ifla_encap_sport;
};
@@ -92,7 +93,8 @@
err(1, "unable to send netlink message");
if (!snl_read_reply_code(ctx->io_ss, hdr->nlmsg_seq, &errmsg))
- errx(errmsg.error, "%s", errmsg.error_str);
+ errx(errmsg.error, "%s", errmsg.error_str != NULL ?
+ errmsg.error_str : strerror(errmsg.error));
}
#define _OUT(_field) offsetof(struct nl_parsed_gre, _field)
@@ -103,6 +105,7 @@
.cb = snl_attr_get_uint32 },
{ .type = IFLA_GRE_ENCAP_SPORT, .off = _OUT(ifla_encap_sport),
.cb = snl_attr_get_uint16 },
+ { .type = IFLA_GRE_IKEY, .off = _OUT(ifla_ikey), .cb = snl_attr_get_uint32 },
};
#undef _OUT
SNL_DECLARE_ATTR_PARSER(gre_linkinfo_data_parser, nla_p_gre);
@@ -173,8 +176,11 @@
struct nl_parsed_gre gre_data = gre_info.data;
if (gre_data.ifla_okey != 0)
- printf("\tgrekey: 0x%x (%u)\n",
+ printf("\tgreokey: 0x%x (%u)\n",
gre_data.ifla_okey, gre_data.ifla_okey);
+ if (gre_data.ifla_ikey != 0)
+ printf("\tgreikey: 0x%x (%u)\n",
+ gre_data.ifla_ikey, gre_data.ifla_ikey);
if (gre_data.ifla_flags == 0)
return;
@@ -200,6 +206,47 @@
off2 = snl_add_msg_attr_nested(&nw, IFLA_INFO_DATA);
snl_add_msg_attr_u32(&nw, IFLA_GRE_OKEY, grekey);
+ snl_add_msg_attr_u32(&nw, IFLA_GRE_IKEY, grekey);
+
+ snl_end_attr_nested(&nw, off2);
+ snl_end_attr_nested(&nw, off);
+
+ gre_nl_fini(ctx, &nw);
+}
+
+static void
+setifgreokey_nl(if_ctx *ctx, const char *val, int dummy __unused)
+{
+ struct snl_writer nw = {};
+ int off, off2;
+ uint32_t grekey = strtol(val, NULL, 0);
+
+ gre_nl_init(ctx, &nw, 0);
+ off = snl_add_msg_attr_nested(&nw, IFLA_LINKINFO);
+ snl_add_msg_attr_string(&nw, IFLA_INFO_KIND, "gre");
+
+ off2 = snl_add_msg_attr_nested(&nw, IFLA_INFO_DATA);
+ snl_add_msg_attr_u32(&nw, IFLA_GRE_OKEY, grekey);
+
+ snl_end_attr_nested(&nw, off2);
+ snl_end_attr_nested(&nw, off);
+
+ gre_nl_fini(ctx, &nw);
+}
+
+static void
+setifgreikey_nl(if_ctx *ctx, const char *val, int dummy __unused)
+{
+ struct snl_writer nw = {};
+ int off, off2;
+ uint32_t grekey = strtol(val, NULL, 0);
+
+ gre_nl_init(ctx, &nw, 0);
+ off = snl_add_msg_attr_nested(&nw, IFLA_LINKINFO);
+ snl_add_msg_attr_string(&nw, IFLA_INFO_KIND, "gre");
+
+ off2 = snl_add_msg_attr_nested(&nw, IFLA_INFO_DATA);
+ snl_add_msg_attr_u32(&nw, IFLA_GRE_IKEY, grekey);
snl_end_attr_nested(&nw, off2);
snl_end_attr_nested(&nw, off);
@@ -302,6 +349,8 @@
static struct cmd gre_cmds[] = {
DEF_CMD_ARG("grekey", setifgrekey_nl),
+ DEF_CMD_ARG("greokey", setifgreokey_nl),
+ DEF_CMD_ARG("greikey", setifgreikey_nl),
DEF_CMD_ARG("udpport", setifgreport_nl),
DEF_CMD("enable_csum", GRE_ENABLE_CSUM, setifgreopts_nl),
DEF_CMD("-enable_csum",-GRE_ENABLE_CSUM,setifgreopts_nl),
@@ -320,7 +369,11 @@
if (ioctl_ctx_ifr(ctx, GREGKEY, &ifr) == 0)
if (opts != 0)
- printf("\tgrekey: 0x%x (%u)\n", opts, opts);
+ printf("\tgreokey: 0x%x (%u)\n", opts, opts);
+ opts = 0;
+ if (ioctl_ctx_ifr(ctx, GREGIKEY, &ifr) == 0)
+ if (opts != 0)
+ printf("\tgreikey: 0x%x (%u)\n", opts, opts);
opts = 0;
if (ioctl_ctx_ifr(ctx, GREGOPTS, &ifr) != 0 || opts == 0)
return;
@@ -342,7 +395,32 @@
ifr.ifr_data = (caddr_t)&grekey;
if (ioctl_ctx_ifr(ctx, GRESKEY, &ifr) < 0)
- warn("ioctl (set grekey)");
+ warn("ioctl (set greokey)");
+ ifr.ifr_data = (caddr_t)&grekey;
+ if (ioctl_ctx_ifr(ctx, GRESIKEY, &ifr) < 0)
+ warn("ioctl (set greikey)");
+}
+
+static void
+setifgreokey(if_ctx *ctx, const char *val, int dummy __unused)
+{
+ uint32_t grekey = strtol(val, NULL, 0);
+ struct ifreq ifr = { .ifr_data = (caddr_t)&grekey };
+
+ ifr.ifr_data = (caddr_t)&grekey;
+ if (ioctl_ctx_ifr(ctx, GRESKEY, &ifr) < 0)
+ warn("ioctl (set greokey)");
+}
+
+static void
+setifgreikey(if_ctx *ctx, const char *val, int dummy __unused)
+{
+ uint32_t grekey = strtol(val, NULL, 0);
+ struct ifreq ifr = { .ifr_data = (caddr_t)&grekey };
+
+ ifr.ifr_data = (caddr_t)&grekey;
+ if (ioctl_ctx_ifr(ctx, GRESIKEY, &ifr) < 0)
+ warn("ioctl (set greikey)");
}
static void
@@ -380,6 +458,8 @@
static struct cmd gre_cmds[] = {
DEF_CMD_ARG("grekey", setifgrekey),
+ DEF_CMD_ARG("greokey", setifgreokey),
+ DEF_CMD_ARG("greikey", setifgreikey),
DEF_CMD_ARG("udpport", setifgreport),
DEF_CMD("enable_csum", GRE_ENABLE_CSUM, setifgreopts),
DEF_CMD("-enable_csum",-GRE_ENABLE_CSUM,setifgreopts),
diff --git a/share/man/man4/gre.4 b/share/man/man4/gre.4
--- a/share/man/man4/gre.4
+++ b/share/man/man4/gre.4
@@ -27,7 +27,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd August 21, 2020
+.Dd September 19, 2026
.Dt GRE 4
.Os
.Sh NAME
@@ -81,8 +81,24 @@
.Xr ifconfig 8 :
.Bl -tag -width "enable_csum"
.It Ar grekey
+Set the GRE key for both incoming and outgoing packets.
+.It Ar greokey
Set the GRE key used for outgoing packets.
A value of 0 disables the key option.
+.It Ar greikey
+The incoming key is used to choose the interface for incoming packets.
+This allows configuring several tunnels between the same pair of addresses,
+each tunnel must have a unique incoming key.
+An incoming packet is accepted by the interface with same key,
+otherwise if the
+.Xr sysctl 8
+variable
+.Va net.link.gre.key_fallback
+is set to true, the packet is accepted by the interface
+without a key that is configured with the same addresses.
+If there is no such interface either, but only one interface is configured
+with these addresses, it accepts the packet whatever its key is.
+A value of 0 disables the key option.
.It Ar enable_csum
Enables checksum calculation for outgoing packets.
.It Ar enable_seq
@@ -268,8 +284,7 @@
.An Andrey V. Elsukov Aq Mt ae@FreeBSD.org
.An Heiko W.Rupp Aq Mt hwr@pilhuhn.de
.Sh BUGS
-The current implementation uses the key only for outgoing packets.
-Incoming packets with a different key or without a key will be treated as if they
-would belong to this interface.
+The current implementation can not use the key 0 for outgoing packets.
+Incoming packets with the key 0 are also ignored.
.Pp
-The sequence number field also used only for outgoing packets.
+The sequence number field is used only for outgoing packets.
diff --git a/sys/net/if_gre.h b/sys/net/if_gre.h
--- a/sys/net/if_gre.h
+++ b/sys/net/if_gre.h
@@ -87,7 +87,8 @@
int gre_family; /* AF of delivery header */
uint32_t gre_iseq;
uint32_t gre_oseq;
- uint32_t gre_key;
+ uint32_t gre_okey;
+ uint32_t gre_ikey;
uint32_t gre_options;
uint32_t gre_csumflags;
uint32_t gre_port;
@@ -133,6 +134,7 @@
struct gre_list *gre_hashinit(void);
void gre_hashdestroy(struct gre_list *);
+bool gre_getkey(const struct mbuf *, int, uint32_t *);
int gre_input(struct mbuf *, int, int, void *);
void gre_update_hdr(struct gre_softc *, struct grehdr *);
void gre_update_udphdr(struct gre_softc *, struct udphdr *, uint16_t);
@@ -149,6 +151,10 @@
int in6_gre_setopts(struct gre_softc *, u_long, uint32_t);
int in6_gre_ioctl(struct gre_softc *, u_long, caddr_t);
int in6_gre_output(struct mbuf *, int, int, uint32_t);
+
+VNET_DECLARE(bool, gre_key_fallback);
+#define V_gre_key_fallback VNET(gre_key_fallback)
+
/*
* CISCO uses special type for GRE tunnel created as part of WCCP
* connection, while in fact those packets are just IPv4 encapsulated
@@ -170,6 +176,8 @@
#define GRESOPTS _IOW('i', 110, struct ifreq)
#define GREGPORT _IOWR('i', 111, struct ifreq)
#define GRESPORT _IOW('i', 112, struct ifreq)
+#define GREGIKEY _IOWR('i', 113, struct ifreq)
+#define GRESIKEY _IOW('i', 114, struct ifreq)
/* GRE-in-UDP encapsulation destination port as defined in RFC8086 */
#define GRE_UDPPORT 4754
diff --git a/sys/net/if_gre.c b/sys/net/if_gre.c
--- a/sys/net/if_gre.c
+++ b/sys/net/if_gre.c
@@ -129,12 +129,12 @@
struct sockaddr *, struct sockaddr *);
static int gre_set_flags(struct gre_softc *, uint32_t);
-static int gre_set_key(struct gre_softc *, uint32_t);
+static int gre_set_key(struct gre_softc *, uint32_t, bool);
static int gre_set_udp_sport(struct gre_softc *, uint16_t);
static int gre_setopts(struct gre_softc *, u_long, uint32_t);
static int gre_set_flags_nl(struct gre_softc *, struct nl_pstate *, uint32_t);
-static int gre_set_key_nl(struct gre_softc *, struct nl_pstate *, uint32_t);
+static int gre_set_key_nl(struct gre_softc *, struct nl_pstate *, uint32_t, bool);
static int gre_set_encap_nl(struct gre_softc *, struct nl_pstate *, uint32_t);
static int gre_set_udp_sport_nl(struct gre_softc *, struct nl_pstate *, uint16_t);
@@ -158,11 +158,17 @@
SYSCTL_INT(_net_link_gre, OID_AUTO, max_nesting, CTLFLAG_RW | CTLFLAG_VNET,
&VNET_NAME(max_gre_nesting), 0, "Max nested tunnels");
+VNET_DEFINE(bool, gre_key_fallback) = true;
+SYSCTL_BOOL(_net_link_gre, OID_AUTO, key_fallback, CTLFLAG_RW | CTLFLAG_VNET,
+ &VNET_NAME(gre_key_fallback), 0,
+ "Accept packets with unmatched key on keyless tunnel or on the only tunnel between same addresses");
+
struct nl_parsed_gre {
struct sockaddr *ifla_local;
struct sockaddr *ifla_remote;
uint32_t ifla_flags;
uint32_t ifla_okey;
+ uint32_t ifla_ikey;
uint32_t ifla_encap_type;
uint16_t ifla_encap_sport;
};
@@ -175,6 +181,7 @@
{ .type = IFLA_GRE_OKEY, .off = _OUT(ifla_okey), .cb = nlattr_get_uint32 },
{ .type = IFLA_GRE_ENCAP_TYPE, .off = _OUT(ifla_encap_type), .cb = nlattr_get_uint32 },
{ .type = IFLA_GRE_ENCAP_SPORT, .off = _OUT(ifla_encap_sport), .cb = nlattr_get_uint16 },
+ { .type = IFLA_GRE_IKEY, .off = _OUT(ifla_ikey), .cb = nlattr_get_uint32 },
};
#undef _OUT
NL_DECLARE_ATTR_PARSER(gre_modify_parser, nla_p_gre);
@@ -271,6 +278,12 @@
if (sc == NULL)
goto generic;
+ /* Set the ikey before addresses, it is a part of the duplicate check. */
+ if (nl_has_attr(&bm, IFLA_GRE_IKEY))
+ error = gre_set_key_nl(sc, npt, params.ifla_ikey, false);
+ if (error != 0)
+ goto generic;
+
if (nl_has_attr(&bm, IFLA_GRE_LOCAL) && nl_has_attr(&bm, IFLA_GRE_REMOTE))
error = gre_set_addr_nl(sc, npt, params.ifla_local, params.ifla_remote);
else if (nl_has_attr(&bm, IFLA_GRE_LOCAL) || nl_has_attr(&bm, IFLA_GRE_REMOTE)) {
@@ -282,7 +295,7 @@
error = gre_set_flags_nl(sc, npt, params.ifla_flags);
if (error == 0 && nl_has_attr(&bm, IFLA_GRE_OKEY))
- error = gre_set_key_nl(sc, npt, params.ifla_okey);
+ error = gre_set_key_nl(sc, npt, params.ifla_okey, true);
if (error == 0 && nl_has_attr(&bm, IFLA_GRE_ENCAP_TYPE))
error = gre_set_encap_nl(sc, npt, params.ifla_encap_type);
@@ -346,10 +359,11 @@
}
nlattr_add_u32(nw, IFLA_GRE_FLAGS, sc->gre_options);
- nlattr_add_u32(nw, IFLA_GRE_OKEY, sc->gre_key);
+ nlattr_add_u32(nw, IFLA_GRE_OKEY, sc->gre_okey);
nlattr_add_u32(nw, IFLA_GRE_ENCAP_TYPE,
sc->gre_options & GRE_UDPENCAP ? IFLA_TUNNEL_GRE_UDP : IFLA_TUNNEL_NONE);
nlattr_add_u16(nw, IFLA_GRE_ENCAP_SPORT, sc->gre_port);
+ nlattr_add_u32(nw, IFLA_GRE_IKEY, sc->gre_ikey);
ret:
nlattr_set_len(nw, off2);
@@ -424,15 +438,21 @@
}
static int
-gre_set_key(struct gre_softc *sc, uint32_t key)
+gre_set_key(struct gre_softc *sc, uint32_t key, bool out)
{
int error = 0;
GRE_LOCK_ASSERT();
- if (sc->gre_key == key)
- return (0);
- error = gre_setopts(sc, GRESKEY, key);
+ if (out) {
+ if (sc->gre_okey == key)
+ return (0);
+ error = gre_setopts(sc, GRESKEY, key);
+ } else {
+ if (sc->gre_ikey == key)
+ return (0);
+ error = gre_setopts(sc, GRESIKEY, key);
+ }
return (error);
}
@@ -502,7 +522,9 @@
* We can just change any parameters.
*/
if (cmd == GRESKEY)
- sc->gre_key = opt;
+ sc->gre_okey = opt;
+ if (cmd == GRESIKEY)
+ sc->gre_ikey = opt;
if (cmd == GRESOPTS)
sc->gre_options = opt;
if (cmd == GRESPORT)
@@ -584,6 +606,7 @@
sc->gre_fibnum = ifr->ifr_fib;
break;
case GRESKEY:
+ case GRESIKEY:
case GRESOPTS:
case GRESPORT:
if ((error = priv_check(curthread, PRIV_NET_GRE)) != 0)
@@ -592,15 +615,21 @@
sizeof(opt))) != 0)
break;
if (cmd == GRESKEY)
- error = gre_set_key(sc, opt);
+ error = gre_set_key(sc, opt, true);
+ else if (cmd == GRESIKEY)
+ error = gre_set_key(sc, opt, false);
else if (cmd == GRESOPTS)
error = gre_set_flags(sc, opt);
else if (cmd == GRESPORT)
error = gre_set_udp_sport(sc, opt);
break;
case GREGKEY:
- error = copyout(&sc->gre_key, ifr_data_get_ptr(ifr),
- sizeof(sc->gre_key));
+ error = copyout(&sc->gre_okey, ifr_data_get_ptr(ifr),
+ sizeof(sc->gre_okey));
+ break;
+ case GREGIKEY:
+ error = copyout(&sc->gre_ikey, ifr_data_get_ptr(ifr),
+ sizeof(sc->gre_ikey));
break;
case GREGOPTS:
error = copyout(&sc->gre_options, ifr_data_get_ptr(ifr),
@@ -725,10 +754,10 @@
sc->gre_hlen += 2 * sizeof(uint16_t);
*opts++ = 0;
}
- if (sc->gre_key != 0) {
+ if (sc->gre_okey != 0) {
flags |= GRE_FLAGS_KP;
sc->gre_hlen += sizeof(uint32_t);
- *opts++ = htonl(sc->gre_key);
+ *opts++ = htonl(sc->gre_okey);
}
if (sc->gre_options & GRE_ENABLE_SEQ) {
flags |= GRE_FLAGS_SP;
@@ -739,6 +768,31 @@
gh->gre_flags = htons(flags);
}
+bool
+gre_getkey(const struct mbuf *m, int off, uint32_t *key)
+{
+ int koff;
+ uint16_t flags;
+
+ if (m->m_pkthdr.len < off + sizeof(struct grehdr))
+ return (false);
+
+ m_copydata(m, off, sizeof(flags), (caddr_t)&flags);
+ flags = ntohs(flags);
+ if ((flags & GRE_FLAGS_KP) == 0) {
+ *key = 0;
+ return (true);
+ }
+ koff = off + sizeof(struct grehdr);
+ if ((flags & GRE_FLAGS_CP) != 0)
+ koff += sizeof(uint32_t);
+ if (m->m_pkthdr.len < koff + sizeof(*key))
+ return (false);
+ m_copydata(m, koff, sizeof(*key), (caddr_t)key);
+ *key = ntohl(*key);
+ return (true);
+}
+
int
gre_input(struct mbuf *m, int off, int proto, void *arg)
{
@@ -746,9 +800,7 @@
struct grehdr *gh;
struct ifnet *ifp;
uint32_t *opts;
-#ifdef notyet
uint32_t key;
-#endif
uint16_t flags;
int hlen, isr, af;
@@ -774,24 +826,14 @@
opts++;
}
if (flags & GRE_FLAGS_KP) {
-#ifdef notyet
- /*
- * XXX: The current implementation uses the key only for outgoing
- * packets. But we can check the key value here, or even in the
- * encapcheck function.
- */
key = ntohl(*opts);
-#endif
+ /* Packet with another key can only be here due to fallback. */
+ if (key != sc->gre_ikey && !V_gre_key_fallback)
+ goto drop;
hlen += sizeof(uint32_t);
opts++;
- }
-#ifdef notyet
- } else
- key = 0;
+ }
- if (sc->gre_key != 0 && (key != sc->gre_key || key != 0))
- goto drop;
-#endif
if (flags & GRE_FLAGS_SP) {
#ifdef notyet
seq = ntohl(*opts);
@@ -1094,14 +1136,18 @@
}
static int
-gre_set_key_nl(struct gre_softc *sc, struct nl_pstate *npt, uint32_t key)
+gre_set_key_nl(struct gre_softc *sc, struct nl_pstate *npt,
+ uint32_t key, bool dir)
{
int error;
- error = gre_set_key(sc, key);
+ error = gre_set_key(sc, key, dir);
if (error == EINVAL)
nlmsg_report_err_msg(npt, "gre key is invalid: %u", key);
+ if (error == EEXIST)
+ nlmsg_report_err_msg(npt,
+ "tunnel with the same addresses and key %u exists", key);
return (error);
}
diff --git a/sys/netinet/ip_gre.c b/sys/netinet/ip_gre.c
--- a/sys/netinet/ip_gre.c
+++ b/sys/netinet/ip_gre.c
@@ -121,7 +121,7 @@
static int
in_gre_checkdup(const struct gre_softc *sc, in_addr_t src, in_addr_t dst,
- uint32_t opts)
+ uint32_t opts, uint32_t key)
{
struct gre_list *head;
struct gre_softc *tmp;
@@ -130,6 +130,7 @@
if (sc->gre_family == AF_INET &&
sc->gre_oip.ip_src.s_addr == src &&
sc->gre_oip.ip_dst.s_addr == dst &&
+ sc->gre_ikey == key &&
(sc->gre_options & GRE_UDPENCAP) == (opts & GRE_UDPENCAP))
return (EEXIST);
@@ -145,38 +146,73 @@
if (tmp == sc)
continue;
if (tmp->gre_oip.ip_src.s_addr == src &&
- tmp->gre_oip.ip_dst.s_addr == dst)
+ tmp->gre_oip.ip_dst.s_addr == dst &&
+ tmp->gre_ikey == key)
return (EADDRNOTAVAIL);
}
return (0);
}
+static struct gre_softc *
+in_gre_lookup_key(in_addr_t src, in_addr_t dst, uint32_t key)
+{
+ struct gre_softc *sc, *keyless, *only;
+ uint32_t count = 0;
+
+ keyless = only = NULL;
+ CK_LIST_FOREACH(sc, &GRE_HASH(src, dst), chain) {
+ if (sc->gre_oip.ip_src.s_addr != src ||
+ sc->gre_oip.ip_dst.s_addr != dst)
+ continue;
+ if (sc->gre_ikey == key)
+ return (sc);
+ if (sc->gre_ikey == 0)
+ keyless = sc;
+ only = sc;
+ count++;
+ }
+ if (!V_gre_key_fallback)
+ return (NULL);
+ /*
+ * When there is no tunnel with specified key and fallback
+ * is enabled, tunnel without key is preferred.
+ */
+ if (keyless != NULL)
+ return (keyless);
+ /*
+ * Otherwise, if only one tunnel configured between these
+ * addresses, accept any key for backward compatibility.
+ */
+ if (count == 1)
+ return (only);
+
+ return (NULL);
+}
+
static int
in_gre_lookup(const struct mbuf *m, int off, int proto, void **arg)
{
const struct ip *ip;
struct gre_softc *sc;
+ uint32_t key;
if (V_ipv4_hashtbl == NULL)
return (0);
NET_EPOCH_ASSERT();
+ if (!gre_getkey(m, off, &key))
+ return (0);
ip = mtod(m, const struct ip *);
- CK_LIST_FOREACH(sc, &GRE_HASH(ip->ip_dst.s_addr,
- ip->ip_src.s_addr), chain) {
- /*
- * This is an inbound packet, its ip_dst is source address
- * in softc.
- */
- if (sc->gre_oip.ip_src.s_addr == ip->ip_dst.s_addr &&
- sc->gre_oip.ip_dst.s_addr == ip->ip_src.s_addr) {
- if ((GRE2IFP(sc)->if_flags & IFF_UP) == 0)
- return (0);
- *arg = sc;
- return (ENCAP_DRV_LOOKUP);
- }
- }
- return (0);
+ /*
+ * This is an inbound packet, its ip_dst is source address
+ * in softc.
+ */
+ sc = in_gre_lookup_key(ip->ip_dst.s_addr, ip->ip_src.s_addr, key);
+ if (sc == NULL || (GRE2IFP(sc)->if_flags & IFF_UP) == 0)
+ return (0);
+
+ *arg = sc;
+ return (ENCAP_DRV_LOOKUP);
}
/*
@@ -222,16 +258,34 @@
const struct sockaddr *sa, void *ctx)
{
struct gre_socket *gs;
- struct gre_softc *sc;
+ struct gre_softc *sc, *keyless, *only;
in_addr_t dst;
+ uint32_t key, count = 0;
NET_EPOCH_ASSERT();
+ keyless = only = NULL;
gs = (struct gre_socket *)ctx;
dst = ((const struct sockaddr_in *)sa)->sin_addr.s_addr;
+ if (!gre_getkey(m, off + sizeof(struct udphdr), &key)) {
+ m_freem(m);
+ return (true);
+ }
CK_LIST_FOREACH(sc, &gs->list, chain) {
- if (sc->gre_oip.ip_dst.s_addr == dst)
+ if (sc->gre_oip.ip_dst.s_addr != dst)
+ continue;
+ if (sc->gre_ikey == key)
break;
+ if (sc->gre_ikey == 0)
+ keyless = sc;
+ only = sc;
+ count++;
+ }
+ if (sc == NULL && V_gre_key_fallback) {
+ if (keyless != NULL)
+ sc = keyless;
+ else if (count == 1)
+ sc = only;
}
if (sc != NULL && (GRE2IFP(sc)->if_flags & IFF_UP) != 0){
gre_input(m, off + sizeof(struct udphdr), IPPROTO_UDP, sc);
@@ -394,26 +448,34 @@
int error;
/* NOTE: we are protected with gre_ioctl_sx lock */
- MPASS(cmd == GRESKEY || cmd == GRESOPTS || cmd == GRESPORT);
+ MPASS(cmd == GRESKEY || cmd == GRESIKEY ||
+ cmd == GRESOPTS || cmd == GRESPORT);
MPASS(sc->gre_family == AF_INET);
/*
- * If we are going to change encapsulation protocol, do check
- * for duplicate tunnels. Return EEXIST here to do not confuse
- * user.
+ * If we are going to change encapsulation protocol or the key,
+ * do check for duplicate tunnels. Return EEXIST here to do not
+ * confuse user.
*/
- if (cmd == GRESOPTS &&
- (sc->gre_options & GRE_UDPENCAP) != (value & GRE_UDPENCAP) &&
- in_gre_checkdup(sc, sc->gre_oip.ip_src.s_addr,
- sc->gre_oip.ip_dst.s_addr, value) == EADDRNOTAVAIL)
- return (EEXIST);
+ if ((cmd == GRESOPTS &&
+ (sc->gre_options & GRE_UDPENCAP) != (value & GRE_UDPENCAP)) ||
+ (cmd == GRESIKEY && sc->gre_ikey != value)) {
+ if (in_gre_checkdup(sc, sc->gre_oip.ip_src.s_addr,
+ sc->gre_oip.ip_dst.s_addr,
+ cmd == GRESOPTS ? value: sc->gre_options,
+ cmd == GRESIKEY ? value: sc->gre_ikey) == EADDRNOTAVAIL)
+ return (EEXIST);
+ }
CK_LIST_REMOVE(sc, chain);
CK_LIST_REMOVE(sc, srchash);
GRE_WAIT();
switch (cmd) {
case GRESKEY:
- sc->gre_key = value;
+ sc->gre_okey = value;
+ break;
+ case GRESIKEY:
+ sc->gre_ikey = value;
break;
case GRESOPTS:
sc->gre_options = value;
@@ -462,7 +524,7 @@
V_ipv4_sockets = (struct gre_sockets *)gre_hashinit();
}
error = in_gre_checkdup(sc, src->sin_addr.s_addr,
- dst->sin_addr.s_addr, sc->gre_options);
+ dst->sin_addr.s_addr, sc->gre_options, sc->gre_ikey);
if (error == EADDRNOTAVAIL)
break;
if (error == EEXIST) {
diff --git a/sys/netinet6/ip6_gre.c b/sys/netinet6/ip6_gre.c
--- a/sys/netinet6/ip6_gre.c
+++ b/sys/netinet6/ip6_gre.c
@@ -112,7 +112,7 @@
static int
in6_gre_checkdup(const struct gre_softc *sc, const struct in6_addr *src,
- const struct in6_addr *dst, uint32_t opts)
+ const struct in6_addr *dst, uint32_t opts, uint32_t key)
{
struct gre_list *head;
struct gre_softc *tmp;
@@ -121,6 +121,7 @@
if (sc->gre_family == AF_INET6 &&
IN6_ARE_ADDR_EQUAL(&sc->gre_oip6.ip6_src, src) &&
IN6_ARE_ADDR_EQUAL(&sc->gre_oip6.ip6_dst, dst) &&
+ sc->gre_ikey == key &&
(sc->gre_options & GRE_UDPENCAP) == (opts & GRE_UDPENCAP))
return (EEXIST);
@@ -136,39 +137,74 @@
if (tmp == sc)
continue;
if (IN6_ARE_ADDR_EQUAL(&tmp->gre_oip6.ip6_src, src) &&
- IN6_ARE_ADDR_EQUAL(&tmp->gre_oip6.ip6_dst, dst))
+ IN6_ARE_ADDR_EQUAL(&tmp->gre_oip6.ip6_dst, dst) &&
+ tmp->gre_ikey == key)
return (EADDRNOTAVAIL);
}
return (0);
}
+static struct gre_softc *
+in6_gre_lookup_key(const struct in6_addr *src, const struct in6_addr *dst,
+ uint32_t key)
+{
+ struct gre_softc *sc, *keyless, *only;
+ uint32_t count = 0;
+
+ keyless = only = NULL;
+ CK_LIST_FOREACH(sc, &GRE_HASH(src, dst), chain) {
+ if (!IN6_ARE_ADDR_EQUAL(&sc->gre_oip6.ip6_src, src) ||
+ !IN6_ARE_ADDR_EQUAL(&sc->gre_oip6.ip6_dst, dst))
+ continue;
+ if (sc->gre_ikey == key)
+ return (sc);
+ if (sc->gre_ikey == 0)
+ keyless = sc;
+ only = sc;
+ count++;
+ }
+ if (!V_gre_key_fallback)
+ return (NULL);
+ /*
+ * When there is no tunnel with specified key and fallback
+ * is enabled, tunnel without key is preferred.
+ */
+ if (keyless != NULL)
+ return (keyless);
+ /*
+ * Otherwise, if only one tunnel configured between these
+ * addresses, accept any key for backward compatibility.
+ */
+ if (count == 1)
+ return (only);
+
+ return (NULL);
+}
+
static int
in6_gre_lookup(const struct mbuf *m, int off, int proto, void **arg)
{
const struct ip6_hdr *ip6;
struct gre_softc *sc;
+ uint32_t key;
if (V_ipv6_hashtbl == NULL)
return (0);
NET_EPOCH_ASSERT();
+ if (!gre_getkey(m, off, &key))
+ return (0);
ip6 = mtod(m, const struct ip6_hdr *);
- CK_LIST_FOREACH(sc, &GRE_HASH(&ip6->ip6_dst, &ip6->ip6_src), chain) {
- /*
- * This is an inbound packet, its ip6_dst is source address
- * in softc.
- */
- if (IN6_ARE_ADDR_EQUAL(&sc->gre_oip6.ip6_src,
- &ip6->ip6_dst) &&
- IN6_ARE_ADDR_EQUAL(&sc->gre_oip6.ip6_dst,
- &ip6->ip6_src)) {
- if ((GRE2IFP(sc)->if_flags & IFF_UP) == 0)
- return (0);
- *arg = sc;
- return (ENCAP_DRV_LOOKUP);
- }
- }
- return (0);
+ /*
+ * This is an inbound packet, its ip6_dst is source address
+ * in softc.
+ */
+ sc = in6_gre_lookup_key(&ip6->ip6_dst, &ip6->ip6_src, key);
+ if (sc == NULL || (GRE2IFP(sc)->if_flags & IFF_UP) == 0)
+ return (0);
+
+ *arg = sc;
+ return (ENCAP_DRV_LOOKUP);
}
/*
@@ -215,20 +251,36 @@
const struct sockaddr *sa, void *ctx)
{
struct gre_socket *gs;
- struct gre_softc *sc;
+ struct gre_softc *sc, *keyless, *only;
struct sockaddr_in6 dst;
+ uint32_t key, count = 0;
NET_EPOCH_ASSERT();
+ keyless = only = NULL;
gs = (struct gre_socket *)ctx;
dst = *(const struct sockaddr_in6 *)sa;
- if (sa6_embedscope(&dst, 0)) {
+ if (sa6_embedscope(&dst, 0) ||
+ !gre_getkey(m, off + sizeof(struct udphdr), &key)) {
m_freem(m);
return (true);
}
CK_LIST_FOREACH(sc, &gs->list, chain) {
- if (IN6_ARE_ADDR_EQUAL(&sc->gre_oip6.ip6_dst, &dst.sin6_addr))
+ if (!IN6_ARE_ADDR_EQUAL(&sc->gre_oip6.ip6_dst,
+ &dst.sin6_addr))
+ continue;
+ if (sc->gre_ikey == key)
break;
+ if (sc->gre_ikey == 0)
+ keyless = sc;
+ only = sc;
+ count++;
+ }
+ if (sc == NULL && V_gre_key_fallback) {
+ if (keyless != NULL)
+ sc = keyless;
+ else if (count == 1)
+ sc = only;
}
if (sc != NULL && (GRE2IFP(sc)->if_flags & IFF_UP) != 0){
gre_input(m, off + sizeof(struct udphdr), IPPROTO_UDP, sc);
@@ -392,26 +444,34 @@
int error;
/* NOTE: we are protected with gre_ioctl_sx lock */
- MPASS(cmd == GRESKEY || cmd == GRESOPTS || cmd == GRESPORT);
+ MPASS(cmd == GRESKEY || cmd == GRESIKEY ||
+ cmd == GRESOPTS || cmd == GRESPORT);
MPASS(sc->gre_family == AF_INET6);
/*
- * If we are going to change encapsulation protocol, do check
- * for duplicate tunnels. Return EEXIST here to do not confuse
- * user.
+ * If we are going to change encapsulation protocol or the key,
+ * do check for duplicate tunnels. Return EEXIST here to do not
+ * confuse user.
*/
- if (cmd == GRESOPTS &&
- (sc->gre_options & GRE_UDPENCAP) != (value & GRE_UDPENCAP) &&
- in6_gre_checkdup(sc, &sc->gre_oip6.ip6_src,
- &sc->gre_oip6.ip6_dst, value) == EADDRNOTAVAIL)
- return (EEXIST);
+ if ((cmd == GRESOPTS &&
+ (sc->gre_options & GRE_UDPENCAP) != (value & GRE_UDPENCAP)) ||
+ (cmd == GRESIKEY && sc->gre_ikey != value)) {
+ if (in6_gre_checkdup(sc, &sc->gre_oip6.ip6_src,
+ &sc->gre_oip6.ip6_dst,
+ cmd == GRESOPTS ? value: sc->gre_options,
+ cmd == GRESIKEY ? value: sc->gre_ikey) == EADDRNOTAVAIL)
+ return (EEXIST);
+ }
CK_LIST_REMOVE(sc, chain);
CK_LIST_REMOVE(sc, srchash);
GRE_WAIT();
switch (cmd) {
case GRESKEY:
- sc->gre_key = value;
+ sc->gre_okey = value;
+ break;
+ case GRESIKEY:
+ sc->gre_ikey = value;
break;
case GRESOPTS:
sc->gre_options = value;
@@ -469,7 +529,7 @@
V_ipv6_sockets = (struct gre_sockets *)gre_hashinit();
}
error = in6_gre_checkdup(sc, &src->sin6_addr,
- &dst->sin6_addr, sc->gre_options);
+ &dst->sin6_addr, sc->gre_options, sc->gre_ikey);
if (error == EADDRNOTAVAIL)
break;
if (error == EEXIST) {
diff --git a/sys/netlink/route/interface.h b/sys/netlink/route/interface.h
--- a/sys/netlink/route/interface.h
+++ b/sys/netlink/route/interface.h
@@ -373,6 +373,7 @@
IFLA_GRE_OKEY,
IFLA_GRE_ENCAP_TYPE,
IFLA_GRE_ENCAP_SPORT,
+ IFLA_GRE_IKEY,
__IFLA_GRE_MAX,
};
diff --git a/tests/sys/net/if_gre.sh b/tests/sys/net/if_gre.sh
--- a/tests/sys/net/if_gre.sh
+++ b/tests/sys/net/if_gre.sh
@@ -6,6 +6,34 @@
. $(atf_get_srcdir)/../common/vnet.subr
+gre_setup_endpoints()
+{
+ local af endpoint1 endpoint2 epair plen
+
+ af=$1
+ endpoint1=$2
+ endpoint2=$3
+ if [ "${af}" = "inet" ]; then
+ plen=/30
+ else
+ plen=
+ fi
+
+ vnet_init
+ epair=$(vnet_mkepair)
+ vnet_mkjail gretest1 ${epair}a
+ vnet_mkjail gretest2 ${epair}b
+
+ ifconfig -j gretest1 ${epair}a ${af} ${endpoint1}${plen} up
+ ifconfig -j gretest2 ${epair}b ${af} ${endpoint2}${plen} up
+
+ # Sanity check
+ atf_check -o ignore \
+ jexec gretest1 ping -c 1 -t 3 ${endpoint2}
+ atf_check -o ignore \
+ jexec gretest2 ping -c 1 -t 3 ${endpoint1}
+}
+
atf_test_case "gre4_basic" "cleanup"
gre4_basic_head()
{
@@ -216,8 +244,10 @@
atf_check ifconfig -j gretest2 gre1 inet6 ${v6tunnel2}
# ifconfig test
- atf_check -o match:"grekey: 0xa \(10\)" ifconfig -j gretest1 gre1
- atf_check -o match:"grekey: 0xa \(10\)" ifconfig -j gretest2 gre1
+ atf_check -o match:"greokey: 0xa \(10\)" -o match:"greikey: 0xa \(10\)" \
+ ifconfig -j gretest1 gre1
+ atf_check -o match:"greokey: 0xa \(10\)" -o match:"greikey: 0xa \(10\)" \
+ ifconfig -j gretest2 gre1
# Tunnel test
atf_check -o ignore jexec gretest1 ping -nc 1 -t 1 $v4tunnel2
@@ -372,7 +402,7 @@
atf_check ifconfig -j gretest $gre inet6 ${v6tunnel1}
# ifconfig test
- atf_check -o match:"grekey: 0xa \(10\)" ifconfig -j gretest $gre
+ atf_check -o match:"greokey: 0xa \(10\)" ifconfig -j gretest $gre
atf_check -o match:"ENABLE_CSUM" ifconfig -j gretest $gre
atf_check -o match:"ENABLE_SEQ" ifconfig -j gretest $gre
atf_check -o match:"UDPENCAP" ifconfig -j gretest $gre
@@ -383,6 +413,415 @@
vnet_cleanup
}
+gre_multikey_test()
+{
+ local af endpoint1 endpoint2 encap
+ local tunnel1a tunnel1b tunnel2a tunnel2b
+
+ af=$1
+ endpoint1=$2
+ endpoint2=$3
+ encap=$4
+ tunnel1a=192.0.2.1
+ tunnel1b=192.0.2.2
+ tunnel2a=198.51.100.1
+ tunnel2b=198.51.100.2
+
+ gre_setup_endpoints ${af} ${endpoint1} ${endpoint2}
+
+ atf_check ifconfig -j gretest1 gre1 create ${af} \
+ tunnel ${endpoint1} ${endpoint2} greikey 10 greokey 10 ${encap} up
+ atf_check ifconfig -j gretest1 gre2 create ${af} \
+ tunnel ${endpoint1} ${endpoint2} greikey 20 greokey 20 ${encap} up
+ atf_check ifconfig -j gretest2 gre1 create ${af} \
+ tunnel ${endpoint2} ${endpoint1} greikey 10 greokey 10 ${encap} up
+ atf_check ifconfig -j gretest2 gre2 create ${af} \
+ tunnel ${endpoint2} ${endpoint1} greikey 20 greokey 20 ${encap} up
+ atf_check -o match:"greikey: 0xa \(10\)" -o match:"greokey: 0xa \(10\)" \
+ ifconfig -j gretest1 gre1
+ atf_check -o match:"greikey: 0x14 \(20\)" -o match:"greokey: 0x14 \(20\)" \
+ ifconfig -j gretest1 gre2
+ if [ -n "${encap}" ]; then
+ atf_check -o match:"UDPENCAP" ifconfig -j gretest1 gre2
+ atf_check -o match:"UDPENCAP" ifconfig -j gretest2 gre2
+ fi
+
+ # The duplicate is detected when the tunnel addresses are set,
+ # ifconfig only warns when it fails to set them.
+ atf_check -s ignore -e ignore ifconfig -j gretest1 gre3 create ${af} \
+ greikey 10 ${encap} tunnel ${endpoint1} ${endpoint2}
+ atf_check -o not-match:"tunnel inet" ifconfig -j gretest1 gre3
+ atf_check ifconfig -j gretest1 gre3 destroy
+
+ # The duplicate is detected when the incoming key is set
+ atf_check -s not-exit:0 -e ignore ifconfig -j gretest1 gre3 create \
+ ${af} tunnel ${endpoint1} ${endpoint2} ${encap} greikey 10
+ atf_check ifconfig -j gretest1 gre3 destroy
+ atf_check -s not-exit:0 -e ignore ifconfig -j gretest1 gre2 greikey 10
+ atf_check -o match:"greikey: 0x14 \(20\)" ifconfig -j gretest1 gre2
+
+ # The outgoing key is not a part of the duplicate check
+ atf_check ifconfig -j gretest1 gre2 greokey 10 up
+ atf_check -o match:"greokey: 0xa \(10\)" ifconfig -j gretest1 gre2
+ atf_check ifconfig -j gretest1 gre2 greokey 20 up
+
+ atf_check ifconfig -j gretest1 gre1 inet ${tunnel1a} ${tunnel1b}
+ atf_check ifconfig -j gretest1 gre2 inet ${tunnel2a} ${tunnel2b}
+ atf_check ifconfig -j gretest2 gre1 inet ${tunnel1b} ${tunnel1a}
+ atf_check ifconfig -j gretest2 gre2 inet ${tunnel2b} ${tunnel2a}
+
+ atf_check -o ignore jexec gretest1 ping -nc 1 -t 1 ${tunnel1b}
+ atf_check -o ignore jexec gretest1 ping -nc 1 -t 1 ${tunnel2b}
+ atf_check -o ignore jexec gretest2 ping -nc 1 -t 1 ${tunnel1a}
+ atf_check -o ignore jexec gretest2 ping -nc 1 -t 1 ${tunnel2a}
+
+ # Replies with an unknown key are not accepted by the other tunnel
+ atf_check ifconfig -j gretest2 gre2 greokey 30 up
+ atf_check -s exit:2 -o ignore \
+ jexec gretest1 ping -nc 1 -t 1 ${tunnel2b}
+ atf_check -o ignore jexec gretest1 ping -nc 1 -t 1 ${tunnel1b}
+ atf_check ifconfig -j gretest2 gre2 greokey 20 up
+ atf_check -o ignore jexec gretest1 ping -nc 1 -t 1 ${tunnel2b}
+
+ # Requests are not accepted when the incoming key does not match
+ atf_check ifconfig -j gretest2 gre2 greikey 30 up
+ atf_check -s exit:2 -o ignore \
+ jexec gretest1 ping -nc 1 -t 1 ${tunnel2b}
+ atf_check -o ignore jexec gretest1 ping -nc 1 -t 1 ${tunnel1b}
+ atf_check ifconfig -j gretest2 gre2 greikey 20 up
+ atf_check -o ignore jexec gretest1 ping -nc 1 -t 1 ${tunnel2b}
+}
+
+atf_test_case "gre4_multikey" "cleanup"
+gre4_multikey_head()
+{
+ atf_set descr 'Create two gre(4) tunnels between the same ipv4 endpoints with different gre keys'
+ atf_set require.user root
+ atf_set require.kmods if_gre
+}
+gre4_multikey_body()
+{
+ gre_multikey_test inet 203.0.113.1 203.0.113.2
+}
+gre4_multikey_cleanup()
+{
+ vnet_cleanup
+}
+
+atf_test_case "gre6_multikey" "cleanup"
+gre6_multikey_head()
+{
+ atf_set descr 'Create two gre(4) tunnels between the same ipv6 endpoints with different gre keys'
+ atf_set require.user root
+ atf_set require.kmods if_gre
+}
+gre6_multikey_body()
+{
+ gre_multikey_test inet6 3fff::1 3fff::2
+}
+gre6_multikey_cleanup()
+{
+ vnet_cleanup
+}
+
+atf_test_case "gre4_multikey_udpencap" "cleanup"
+gre4_multikey_udpencap_head()
+{
+ atf_set descr 'Create two gre(4) udp encapsulated tunnels between the same ipv4 endpoints with different gre keys'
+ atf_set require.user root
+ atf_set require.kmods if_gre
+}
+gre4_multikey_udpencap_body()
+{
+ gre_multikey_test inet 203.0.113.1 203.0.113.2 udpencap
+}
+gre4_multikey_udpencap_cleanup()
+{
+ vnet_cleanup
+}
+
+atf_test_case "gre6_multikey_udpencap" "cleanup"
+gre6_multikey_udpencap_head()
+{
+ atf_set descr 'Create two gre(4) udp encapsulated tunnels between the same ipv6 endpoints with different gre keys'
+ atf_set require.user root
+ atf_set require.kmods if_gre
+}
+gre6_multikey_udpencap_body()
+{
+ gre_multikey_test inet6 3fff::1 3fff::2 udpencap
+}
+gre6_multikey_udpencap_cleanup()
+{
+ vnet_cleanup
+}
+
+# gre_key_fallback_test <af> <endpoint1> <endpoint2> [udpencap]
+gre_key_fallback_test()
+{
+ local af endpoint1 endpoint2 encap v4tunnel1 v4tunnel2
+
+ af=$1
+ endpoint1=$2
+ endpoint2=$3
+ encap=$4
+ v4tunnel1=192.0.2.1
+ v4tunnel2=192.0.2.2
+
+ gre_setup_endpoints ${af} ${endpoint1} ${endpoint2}
+
+ # First jail sends packets with the key using gre1.
+ # Replies have no key and are received by gre2.
+ atf_check ifconfig -j gretest1 gre1 create ${af} \
+ tunnel ${endpoint1} ${endpoint2} greikey 10 greokey 10 ${encap} up
+ atf_check ifconfig -j gretest1 gre2 create ${af} \
+ tunnel ${endpoint1} ${endpoint2} ${encap} up
+ # The second jail has only the tunnel without the key
+ atf_check ifconfig -j gretest2 gre1 create ${af} \
+ tunnel ${endpoint2} ${endpoint1} ${encap} up
+
+ atf_check ifconfig -j gretest1 gre1 inet ${v4tunnel1} ${v4tunnel2}
+ atf_check ifconfig -j gretest2 gre1 inet ${v4tunnel2} ${v4tunnel1}
+
+ # By default the tunnel without the key accepts packets with any key
+ atf_check -o inline:"1\n" \
+ sysctl -j gretest2 -n net.link.gre.key_fallback
+ atf_check -o ignore jexec gretest1 ping -nc 1 -t 1 ${v4tunnel2}
+
+ # Packets with unknown key are not accepted without fallback
+ atf_check -o ignore \
+ sysctl -j gretest2 net.link.gre.key_fallback=0
+ atf_check -s exit:2 -o ignore \
+ jexec gretest1 ping -nc 1 -t 1 ${v4tunnel2}
+
+ atf_check -o ignore \
+ sysctl -j gretest2 net.link.gre.key_fallback=1
+ atf_check -o ignore jexec gretest1 ping -nc 1 -t 1 ${v4tunnel2}
+}
+
+atf_test_case "gre4_key_fallback" "cleanup"
+gre4_key_fallback_head()
+{
+ atf_set descr 'Test net.link.gre.key_fallback with gre key configured only on one side'
+ atf_set require.user root
+ atf_set require.kmods if_gre
+}
+gre4_key_fallback_body()
+{
+ gre_key_fallback_test inet 203.0.113.1 203.0.113.2
+}
+gre4_key_fallback_cleanup()
+{
+ vnet_cleanup
+}
+
+atf_test_case "gre6_key_fallback" "cleanup"
+gre6_key_fallback_head()
+{
+ atf_set descr 'Test net.link.gre.key_fallback over ipv6 with gre key configured only on one side'
+ atf_set require.user root
+ atf_set require.kmods if_gre
+}
+gre6_key_fallback_body()
+{
+ gre_key_fallback_test inet6 3fff::1 3fff::2
+}
+gre6_key_fallback_cleanup()
+{
+ vnet_cleanup
+}
+
+atf_test_case "gre4_key_fallback_udpencap" "cleanup"
+gre4_key_fallback_udpencap_head()
+{
+ atf_set descr 'Test net.link.gre.key_fallback over udp with gre key configured only on one side'
+ atf_set require.user root
+ atf_set require.kmods if_gre
+}
+gre4_key_fallback_udpencap_body()
+{
+ gre_key_fallback_test inet 203.0.113.1 203.0.113.2 udpencap
+}
+gre4_key_fallback_udpencap_cleanup()
+{
+ vnet_cleanup
+}
+
+atf_test_case "gre6_key_fallback_udpencap" "cleanup"
+gre6_key_fallback_udpencap_head()
+{
+ atf_set descr 'Test net.link.gre.key_fallback over ipv6 udp with gre key configured only on one side'
+ atf_set require.user root
+ atf_set require.kmods if_gre
+}
+gre6_key_fallback_udpencap_body()
+{
+ gre_key_fallback_test inet6 3fff::1 3fff::2 udpencap
+}
+gre6_key_fallback_udpencap_cleanup()
+{
+ vnet_cleanup
+}
+
+# gre_key_mismatch_test <af> <endpoint1> <endpoint2> [udpencap]
+gre_key_mismatch_test()
+{
+ local af endpoint1 endpoint2 encap v4tunnel1 v4tunnel2
+
+ af=$1
+ endpoint1=$2
+ endpoint2=$3
+ encap=$4
+ v4tunnel1=192.0.2.1
+ v4tunnel2=192.0.2.2
+
+ gre_setup_endpoints ${af} ${endpoint1} ${endpoint2}
+
+ atf_check ifconfig -j gretest1 gre1 create ${af} \
+ tunnel ${endpoint1} ${endpoint2} greikey 10 greokey 10 ${encap} up
+ atf_check ifconfig -j gretest2 gre1 create ${af} \
+ tunnel ${endpoint2} ${endpoint1} greikey 20 greokey 20 ${encap} up
+
+ atf_check ifconfig -j gretest1 gre1 inet ${v4tunnel1} ${v4tunnel2}
+ atf_check ifconfig -j gretest2 gre1 inet ${v4tunnel2} ${v4tunnel1}
+
+ # The only tunnel between the addresses accepts any key by default
+ atf_check -o ignore jexec gretest1 ping -nc 1 -t 1 ${v4tunnel2}
+ atf_check -o ignore jexec gretest2 ping -nc 1 -t 1 ${v4tunnel1}
+
+ # The key must match without fallback
+ atf_check -o ignore \
+ sysctl -j gretest2 net.link.gre.key_fallback=0
+ atf_check -s exit:2 -o ignore \
+ jexec gretest1 ping -nc 1 -t 1 ${v4tunnel2}
+ atf_check -o ignore \
+ sysctl -j gretest2 net.link.gre.key_fallback=1
+ atf_check -o ignore jexec gretest1 ping -nc 1 -t 1 ${v4tunnel2}
+
+ # The key must match when the tunnel is not the only one
+ atf_check ifconfig -j gretest2 gre2 create ${af} \
+ tunnel ${endpoint2} ${endpoint1} greikey 30 greokey 30 ${encap} up
+ atf_check -s exit:2 -o ignore \
+ jexec gretest1 ping -nc 1 -t 1 ${v4tunnel2}
+
+ atf_check ifconfig -j gretest2 gre2 destroy
+ atf_check -o ignore jexec gretest1 ping -nc 1 -t 1 ${v4tunnel2}
+}
+
+atf_test_case "gre4_key_mismatch" "cleanup"
+gre4_key_mismatch_head()
+{
+ atf_set descr 'Test backward compatibility for gre mismatched key'
+ atf_set require.user root
+ atf_set require.kmods if_gre
+}
+gre4_key_mismatch_body()
+{
+ gre_key_mismatch_test inet 203.0.113.1 203.0.113.2
+}
+gre4_key_mismatch_cleanup()
+{
+ vnet_cleanup
+}
+
+atf_test_case "gre6_key_mismatch" "cleanup"
+gre6_key_mismatch_head()
+{
+ atf_set descr 'Test backward compatibility for gre over ipv6 with mismatched key'
+ atf_set require.user root
+ atf_set require.kmods if_gre
+}
+gre6_key_mismatch_body()
+{
+ gre_key_mismatch_test inet6 3fff::1 3fff::2
+}
+gre6_key_mismatch_cleanup()
+{
+ vnet_cleanup
+}
+
+atf_test_case "gre4_key_mismatch_udpencap" "cleanup"
+gre4_key_mismatch_udpencap_head()
+{
+ atf_set descr 'Test backward compatibility for gre over udp with mismatched key'
+ atf_set require.user root
+ atf_set require.kmods if_gre
+}
+gre4_key_mismatch_udpencap_body()
+{
+ gre_key_mismatch_test inet 203.0.113.1 203.0.113.2 udpencap
+}
+gre4_key_mismatch_udpencap_cleanup()
+{
+ vnet_cleanup
+}
+
+atf_test_case "gre6_key_mismatch_udpencap" "cleanup"
+gre6_key_mismatch_udpencap_head()
+{
+ atf_set descr 'Test backward compatibility for gre over ipv6 udp with mismatched key'
+ atf_set require.user root
+ atf_set require.kmods if_gre
+}
+gre6_key_mismatch_udpencap_body()
+{
+ gre_key_mismatch_test inet6 3fff::1 3fff::2 udpencap
+}
+gre6_key_mismatch_udpencap_cleanup()
+{
+ vnet_cleanup
+}
+
+atf_test_case "gre4_asymmetric_key" "cleanup"
+gre4_asymmetric_key_head()
+{
+ atf_set descr 'Test gre(4) tunnel with different incoming and outgoing keys'
+ atf_set require.user root
+ atf_set require.kmods if_gre
+}
+gre4_asymmetric_key_body()
+{
+ local endpoint1 endpoint2 v4tunnel1 v4tunnel2
+
+ endpoint1=203.0.113.1
+ endpoint2=203.0.113.2
+ v4tunnel1=192.0.2.1
+ v4tunnel2=192.0.2.2
+
+ gre_setup_endpoints inet ${endpoint1} ${endpoint2}
+
+ atf_check -o ignore \
+ sysctl -j gretest1 net.link.gre.key_fallback=0
+ atf_check -o ignore \
+ sysctl -j gretest2 net.link.gre.key_fallback=0
+
+ atf_check ifconfig -j gretest1 gre1 create \
+ tunnel ${endpoint1} ${endpoint2} greokey 100 greikey 200 up
+ atf_check ifconfig -j gretest2 gre1 create \
+ tunnel ${endpoint2} ${endpoint1} greokey 200 greikey 100 up
+ atf_check -o match:"greokey: 0x64 \(100\)" \
+ -o match:"greikey: 0xc8 \(200\)" ifconfig -j gretest1 gre1
+
+ atf_check ifconfig -j gretest1 gre1 inet ${v4tunnel1} ${v4tunnel2}
+ atf_check ifconfig -j gretest2 gre1 inet ${v4tunnel2} ${v4tunnel1}
+
+ atf_check -o ignore jexec gretest1 ping -nc 1 -t 1 ${v4tunnel2}
+ atf_check -o ignore jexec gretest2 ping -nc 1 -t 1 ${v4tunnel1}
+
+ # grekey sets both the incoming and the outgoing key
+ atf_check ifconfig -j gretest2 gre1 grekey 300 up
+ atf_check -o match:"greokey: 0x12c \(300\)" \
+ -o match:"greikey: 0x12c \(300\)" ifconfig -j gretest2 gre1
+ atf_check -s exit:2 -o ignore \
+ jexec gretest1 ping -nc 1 -t 1 ${v4tunnel2}
+
+ atf_check ifconfig -j gretest2 gre1 greokey 200 greikey 100 up
+ atf_check -o ignore jexec gretest1 ping -nc 1 -t 1 ${v4tunnel2}
+}
+gre4_asymmetric_key_cleanup()
+{
+ vnet_cleanup
+}
atf_init_test_cases()
{
@@ -393,4 +832,17 @@
atf_add_test_case "gre6_seq"
atf_add_test_case "gre6_udpencap"
atf_add_test_case "gre_blind_options"
+ atf_add_test_case "gre4_multikey"
+ atf_add_test_case "gre6_multikey"
+ atf_add_test_case "gre4_multikey_udpencap"
+ atf_add_test_case "gre6_multikey_udpencap"
+ atf_add_test_case "gre4_key_fallback"
+ atf_add_test_case "gre6_key_fallback"
+ atf_add_test_case "gre4_key_fallback_udpencap"
+ atf_add_test_case "gre6_key_fallback_udpencap"
+ atf_add_test_case "gre4_key_mismatch"
+ atf_add_test_case "gre6_key_mismatch"
+ atf_add_test_case "gre4_key_mismatch_udpencap"
+ atf_add_test_case "gre6_key_mismatch_udpencap"
+ atf_add_test_case "gre4_asymmetric_key"
}

File Metadata

Mime Type
text/plain
Expires
Sat, Nov 7, 8:02 PM (7 h, 45 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
41468876
Default Alt Text
D59849.1794081733.diff (42 KB)

Event Timeline