Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F177284129
D59849.1794081733.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
42 KB
Referenced Files
None
Subscribers
None
D59849.1794081733.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D59849: gre(4): Add full support for gre key
Attached
Detach File
Event Timeline