Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F177286134
D59849.1794089747.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
32 KB
Referenced Files
None
Subscribers
None
D59849.1794089747.diff
View Options
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,7 +81,20 @@
.Xr ifconfig 8 :
.Bl -tag -width "enable_csum"
.It Ar grekey
-Set the GRE key used for outgoing packets.
+Set the GRE key.
+The key is added to outgoing packets and is used to choose the interface
+for incoming packets.
+This allows configuring several tunnels between the same pair of addresses,
+each tunnel must have an unique 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.
@@ -268,8 +281,4 @@
.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.
-.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
@@ -133,6 +133,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 +150,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
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
@@ -163,6 +163,11 @@
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,
+ "Deliver packets with unmatched key to the keyless or the only tunnel");
+
struct nl_parsed_gre {
struct sockaddr *ifla_local;
struct sockaddr *ifla_remote;
@@ -276,6 +281,12 @@
if (sc == NULL)
goto generic;
+ /* Set the key before addresses, it is a part of the duplicate check. */
+ if (nl_has_attr(&bm, IFLA_GRE_OKEY))
+ error = gre_set_key_nl(sc, npt, params.ifla_okey);
+ 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)) {
@@ -286,9 +297,6 @@
if (error == 0 && nl_has_attr(&bm, IFLA_GRE_FLAGS))
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);
-
if (error == 0 && nl_has_attr(&bm, IFLA_GRE_ENCAP_TYPE))
error = gre_set_encap_nl(sc, npt, params.ifla_encap_type);
@@ -744,6 +752,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)
{
@@ -751,9 +784,7 @@
struct grehdr *gh;
struct ifnet *ifp;
uint32_t *opts;
-#ifdef notyet
uint32_t key;
-#endif
uint16_t flags;
int hlen, isr, af;
@@ -782,24 +813,15 @@
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
hlen += sizeof(uint32_t);
opts++;
- }
-#ifdef notyet
} else
key = 0;
- if (sc->gre_key != 0 && (key != sc->gre_key || key != 0))
+ /* Packet with another key can only be here due to fallback. */
+ if (key != sc->gre_key && !V_gre_key_fallback)
goto drop;
-#endif
if (flags & GRE_FLAGS_SP) {
#ifdef notyet
seq = ntohl(*opts);
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_key == 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_key == 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_key == key)
+ return (sc);
+ if (sc->gre_key == 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_key == key)
break;
+ if (sc->gre_key == 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);
@@ -398,15 +452,19 @@
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 == GRESKEY && sc->gre_key != 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 == GRESKEY ? value: sc->gre_key) == EADDRNOTAVAIL)
+ return (EEXIST);
+ }
CK_LIST_REMOVE(sc, chain);
CK_LIST_REMOVE(sc, srchash);
@@ -462,7 +520,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_key);
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_key == 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_key == 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_key == key)
+ return (sc);
+ if (sc->gre_key == 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_key == key)
break;
+ if (sc->gre_key == 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);
@@ -396,15 +448,19 @@
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 == GRESKEY && sc->gre_key != value)) {
+ if (in6_gre_checkdup(sc, &sc->gre_oip6.ip6_src,
+ &sc->gre_oip6.ip6_dst,
+ cmd == GRESOPTS ? value: sc->gre_options,
+ cmd == GRESKEY ? value: sc->gre_key) == EADDRNOTAVAIL)
+ return (EEXIST);
+ }
CK_LIST_REMOVE(sc, chain);
CK_LIST_REMOVE(sc, srchash);
@@ -469,7 +525,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_key);
if (error == EADDRNOTAVAIL)
break;
if (error == EEXIST) {
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
@@ -383,6 +383,491 @@
vnet_cleanup
}
+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()
+{
+ local epair endpoint1 endpoint2
+ local tunnel1a tunnel1b tunnel2a tunnel2b
+
+ endpoint1=203.0.113.1
+ endpoint2=203.0.113.2
+ tunnel1a=192.0.2.1
+ tunnel1b=192.0.2.2
+ tunnel2a=198.51.100.1
+ tunnel2b=198.51.100.2
+
+ vnet_init
+ epair=$(vnet_mkepair)
+ vnet_mkjail gretest1 ${epair}a
+ vnet_mkjail gretest2 ${epair}b
+
+ ifconfig -j gretest1 ${epair}a inet ${endpoint1}/30 up
+ ifconfig -j gretest2 ${epair}b inet ${endpoint2}/30 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_check ifconfig -j gretest1 gre1 create \
+ grekey 10 tunnel ${endpoint1} ${endpoint2} up
+ atf_check ifconfig -j gretest1 gre2 create \
+ grekey 20 tunnel ${endpoint1} ${endpoint2} up
+ atf_check ifconfig -j gretest2 gre1 create \
+ grekey 10 tunnel ${endpoint2} ${endpoint1} up
+ atf_check ifconfig -j gretest2 gre2 create \
+ grekey 20 tunnel ${endpoint2} ${endpoint1} up
+
+ # ifconfig only warns when it fails to set tunnel addresses
+ atf_check -s ignore -e ignore ifconfig -j gretest1 gre3 create \
+ inet grekey 10 tunnel ${endpoint1} ${endpoint2}
+ atf_check -o not-match:"tunnel inet" ifconfig -j gretest1 gre3
+ atf_check -s not-exit:0 -e ignore ifconfig -j gretest1 gre2 grekey 10
+ atf_check -o match:"grekey: 0x14" ifconfig -j gretest1 gre2
+
+ 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 gretest2 ping -nc 1 -t 1 ${tunnel2a}
+
+ # Packets with the key of the second tunnel must not be accepted
+ # by another tunnel, when the key is changed on one side
+ atf_check ifconfig -j gretest2 gre2 grekey 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 grekey 20 up
+ atf_check -o ignore jexec gretest1 ping -nc 1 -t 1 ${tunnel2b}
+}
+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()
+{
+ local epair endpoint1 endpoint2
+ local tunnel1a tunnel1b tunnel2a tunnel2b
+
+ endpoint1=3fff::1
+ endpoint2=3fff::2
+ tunnel1a=192.0.2.1
+ tunnel1b=192.0.2.2
+ tunnel2a=198.51.100.1
+ tunnel2b=198.51.100.2
+
+ vnet_init
+ epair=$(vnet_mkepair)
+ vnet_mkjail gretest1 ${epair}a
+ vnet_mkjail gretest2 ${epair}b
+
+ ifconfig -j gretest1 ${epair}a inet6 ${endpoint1} up
+ ifconfig -j gretest2 ${epair}b inet6 ${endpoint2} 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_check ifconfig -j gretest1 gre1 create \
+ inet6 tunnel ${endpoint1} ${endpoint2} grekey 10 up
+ atf_check ifconfig -j gretest1 gre2 create \
+ inet6 tunnel ${endpoint1} ${endpoint2} grekey 20 up
+ atf_check ifconfig -j gretest2 gre1 create \
+ inet6 tunnel ${endpoint2} ${endpoint1} grekey 10 up
+ atf_check ifconfig -j gretest2 gre2 create \
+ inet6 tunnel ${endpoint2} ${endpoint1} grekey 20 up
+
+ atf_check -s not-exit:0 -e ignore ifconfig -j gretest1 gre3 create \
+ inet6 tunnel ${endpoint1} ${endpoint2} grekey 10
+ atf_check ifconfig -j gretest1 gre3 destroy
+ atf_check -s not-exit:0 -e ignore ifconfig -j gretest1 gre2 grekey 10
+ atf_check -o match:"grekey: 0x14" ifconfig -j gretest1 gre2
+
+ 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 gretest2 ping -nc 1 -t 1 ${tunnel2a}
+
+ # Packets with the key of the second tunnel must not be accepted
+ # by another tunnel, when the key is changed on one side
+ atf_check ifconfig -j gretest2 gre2 grekey 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 grekey 20 up
+ atf_check -o ignore jexec gretest1 ping -nc 1 -t 1 ${tunnel2b}
+}
+gre6_multikey_cleanup()
+{
+ vnet_cleanup
+}
+
+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()
+{
+ local epair endpoint1 endpoint2 v4tunnel1 v4tunnel2
+
+ endpoint1=203.0.113.1
+ endpoint2=203.0.113.2
+ v4tunnel1=192.0.2.1
+ v4tunnel2=192.0.2.2
+
+ vnet_init
+ epair=$(vnet_mkepair)
+ vnet_mkjail gretest1 ${epair}a
+ vnet_mkjail gretest2 ${epair}b
+
+ ifconfig -j gretest1 ${epair}a inet ${endpoint1}/30 up
+ ifconfig -j gretest2 ${epair}b inet ${endpoint2}/30 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}
+
+ # The 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 \
+ grekey 10 tunnel ${endpoint1} ${endpoint2} up
+ atf_check ifconfig -j gretest1 gre2 create \
+ tunnel ${endpoint1} ${endpoint2} up
+ # The second jail has only the tunnel without the key
+ atf_check ifconfig -j gretest2 gre1 create \
+ tunnel ${endpoint2} ${endpoint1} 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" \
+ jexec gretest2 sysctl -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 \
+ jexec gretest2 sysctl 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 \
+ jexec gretest2 sysctl net.link.gre.key_fallback=1
+ atf_check -o ignore jexec gretest1 ping -nc 1 -t 1 ${v4tunnel2}
+}
+gre4_key_fallback_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()
+{
+ local epair endpoint1 endpoint2
+ local tunnel1a tunnel1b tunnel2a tunnel2b
+
+ endpoint1=203.0.113.1
+ endpoint2=203.0.113.2
+ tunnel1a=192.0.2.1
+ tunnel1b=192.0.2.2
+ tunnel2a=198.51.100.1
+ tunnel2b=198.51.100.2
+
+ vnet_init
+ epair=$(vnet_mkepair)
+ vnet_mkjail gretest1 ${epair}a
+ vnet_mkjail gretest2 ${epair}b
+
+ ifconfig -j gretest1 ${epair}a inet ${endpoint1}/30 up
+ ifconfig -j gretest2 ${epair}b inet ${endpoint2}/30 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_check ifconfig -j gretest1 gre1 create \
+ grekey 10 tunnel ${endpoint1} ${endpoint2} udpencap up
+ atf_check ifconfig -j gretest1 gre2 create \
+ grekey 20 tunnel ${endpoint1} ${endpoint2} udpencap up
+ atf_check ifconfig -j gretest2 gre1 create \
+ grekey 10 tunnel ${endpoint2} ${endpoint1} udpencap up
+ atf_check ifconfig -j gretest2 gre2 create \
+ grekey 20 tunnel ${endpoint2} ${endpoint1} udpencap up
+ atf_check -o match:"UDPENCAP" ifconfig -j gretest1 gre2
+ atf_check -o match:"UDPENCAP" ifconfig -j gretest2 gre2
+
+ # The duplicate is detected when gre3 joins the UDP tunnels
+ atf_check -s not-exit:0 -e ignore ifconfig -j gretest1 gre3 create \
+ grekey 10 tunnel ${endpoint1} ${endpoint2} udpencap
+ atf_check ifconfig -j gretest1 gre3 destroy
+ atf_check -s not-exit:0 -e ignore ifconfig -j gretest1 gre2 grekey 10
+ atf_check -o match:"grekey: 0x14" ifconfig -j gretest1 gre2
+
+ 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 gretest2 ping -nc 1 -t 1 ${tunnel2a}
+
+ # Packets with the key of the second tunnel must not be accepted
+ # by another tunnel, when the key is changed on one side
+ atf_check ifconfig -j gretest2 gre2 grekey 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 grekey 20 up
+ atf_check -o ignore jexec gretest1 ping -nc 1 -t 1 ${tunnel2b}
+}
+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()
+{
+ local epair endpoint1 endpoint2
+ local tunnel1a tunnel1b tunnel2a tunnel2b
+
+ endpoint1=3fff::1
+ endpoint2=3fff::2
+ tunnel1a=192.0.2.1
+ tunnel1b=192.0.2.2
+ tunnel2a=198.51.100.1
+ tunnel2b=198.51.100.2
+
+ vnet_init
+ epair=$(vnet_mkepair)
+ vnet_mkjail gretest1 ${epair}a
+ vnet_mkjail gretest2 ${epair}b
+
+ ifconfig -j gretest1 ${epair}a inet6 ${endpoint1} up
+ ifconfig -j gretest2 ${epair}b inet6 ${endpoint2} 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_check ifconfig -j gretest1 gre1 create \
+ inet6 tunnel ${endpoint1} ${endpoint2} grekey 10 udpencap up
+ atf_check ifconfig -j gretest1 gre2 create \
+ inet6 tunnel ${endpoint1} ${endpoint2} grekey 20 udpencap up
+ atf_check ifconfig -j gretest2 gre1 create \
+ inet6 tunnel ${endpoint2} ${endpoint1} grekey 10 udpencap up
+ atf_check ifconfig -j gretest2 gre2 create \
+ inet6 tunnel ${endpoint2} ${endpoint1} grekey 20 udpencap up
+ atf_check -o match:"UDPENCAP" ifconfig -j gretest1 gre2
+ atf_check -o match:"UDPENCAP" ifconfig -j gretest2 gre2
+
+ # The duplicate is detected when gre3 joins the UDP tunnels
+ atf_check -s not-exit:0 -e ignore ifconfig -j gretest1 gre3 create \
+ inet6 tunnel ${endpoint1} ${endpoint2} grekey 10 udpencap
+ atf_check ifconfig -j gretest1 gre3 destroy
+ atf_check -s not-exit:0 -e ignore ifconfig -j gretest1 gre2 grekey 10
+ atf_check -o match:"grekey: 0x14" ifconfig -j gretest1 gre2
+
+ 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 gretest2 ping -nc 1 -t 1 ${tunnel2a}
+
+ # Packets with the key of the second tunnel must not be accepted
+ # by another tunnel, when the key is changed on one side
+ atf_check ifconfig -j gretest2 gre2 grekey 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 grekey 20 up
+ atf_check -o ignore jexec gretest1 ping -nc 1 -t 1 ${tunnel2b}
+}
+gre6_multikey_udpencap_cleanup()
+{
+ vnet_cleanup
+}
+
+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()
+{
+ local epair endpoint1 endpoint2 v4tunnel1 v4tunnel2
+
+ endpoint1=203.0.113.1
+ endpoint2=203.0.113.2
+ v4tunnel1=192.0.2.1
+ v4tunnel2=192.0.2.2
+
+ vnet_init
+ epair=$(vnet_mkepair)
+ vnet_mkjail gretest1 ${epair}a
+ vnet_mkjail gretest2 ${epair}b
+
+ ifconfig -j gretest1 ${epair}a inet ${endpoint1}/30 up
+ ifconfig -j gretest2 ${epair}b inet ${endpoint2}/30 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_check ifconfig -j gretest1 gre1 create \
+ grekey 10 tunnel ${endpoint1} ${endpoint2} up
+ atf_check ifconfig -j gretest2 gre1 create \
+ grekey 20 tunnel ${endpoint2} ${endpoint1} 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 \
+ jexec gretest2 sysctl 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 \
+ jexec gretest2 sysctl 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 \
+ grekey 30 tunnel ${endpoint2} ${endpoint1} 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}
+}
+gre4_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()
+{
+ local epair endpoint1 endpoint2 v4tunnel1 v4tunnel2
+
+ endpoint1=203.0.113.1
+ endpoint2=203.0.113.2
+ v4tunnel1=192.0.2.1
+ v4tunnel2=192.0.2.2
+
+ vnet_init
+ epair=$(vnet_mkepair)
+ vnet_mkjail gretest1 ${epair}a
+ vnet_mkjail gretest2 ${epair}b
+
+ ifconfig -j gretest1 ${epair}a inet ${endpoint1}/30 up
+ ifconfig -j gretest2 ${epair}b inet ${endpoint2}/30 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_check ifconfig -j gretest1 gre1 create \
+ grekey 10 tunnel ${endpoint1} ${endpoint2} udpencap up
+ atf_check ifconfig -j gretest2 gre1 create \
+ grekey 20 tunnel ${endpoint2} ${endpoint1} udpencap up
+ atf_check -o match:"UDPENCAP" ifconfig -j gretest1 gre1
+ atf_check -o match:"UDPENCAP" ifconfig -j gretest2 gre1
+
+ 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 \
+ jexec gretest2 sysctl 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 \
+ jexec gretest2 sysctl 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 \
+ grekey 30 tunnel ${endpoint2} ${endpoint1} udpencap 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}
+}
+gre4_key_mismatch_udpencap_cleanup()
+{
+ vnet_cleanup
+}
atf_init_test_cases()
{
@@ -393,4 +878,11 @@
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_key_fallback"
+ atf_add_test_case "gre4_multikey_udpencap"
+ atf_add_test_case "gre6_multikey_udpencap"
+ atf_add_test_case "gre4_key_mismatch"
+ atf_add_test_case "gre4_key_mismatch_udpencap"
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Nov 7, 10:15 PM (9 h, 58 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
41555859
Default Alt Text
D59849.1794089747.diff (32 KB)
Attached To
Mode
D59849: gre(4): Add full support for gre key
Attached
Detach File
Event Timeline