Page MenuHomeFreeBSD

D59849.1794089747.diff
No OneTemporary

Authored By
Unknown
Size
32 KB
Referenced Files
None
Subscribers
None

D59849.1794089747.diff

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

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)

Event Timeline