Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F151997153
D17214.id48155.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
9 KB
Referenced Files
None
Subscribers
None
D17214.id48155.diff
View Options
Index: sys/net/if_gre.h
===================================================================
--- sys/net/if_gre.h
+++ sys/net/if_gre.h
@@ -82,6 +82,7 @@
} gre_uhdr;
CK_LIST_ENTRY(gre_softc) chain;
+ CK_LIST_ENTRY(gre_softc) srchash;
};
CK_LIST_HEAD(gre_list, gre_softc);
MALLOC_DECLARE(M_GRE);
@@ -91,7 +92,8 @@
#endif
#define GRE2IFP(sc) ((sc)->gre_ifp)
-#define GRE_RLOCK() struct epoch_tracker gre_et; epoch_enter_preempt(net_epoch_preempt, &gre_et)
+#define GRE_RLOCK_TRACKER struct epoch_tracker gre_et
+#define GRE_RLOCK() epoch_enter_preempt(net_epoch_preempt, &gre_et)
#define GRE_RUNLOCK() epoch_exit_preempt(net_epoch_preempt, &gre_et)
#define GRE_WAIT() epoch_wait_preempt(net_epoch_preempt)
Index: sys/net/if_gre.c
===================================================================
--- sys/net/if_gre.c
+++ sys/net/if_gre.c
@@ -326,7 +326,6 @@
cmd == SIOCSIFPHYADDR_IN6 ||
#endif
0) {
- ifp->if_drv_flags |= IFF_DRV_RUNNING;
if_link_state_change(ifp, LINK_STATE_UP);
}
}
@@ -342,6 +341,7 @@
sx_assert(&gre_ioctl_sx, SA_XLOCKED);
if (sc->gre_family != 0) {
CK_LIST_REMOVE(sc, chain);
+ CK_LIST_REMOVE(sc, srchash);
GRE_WAIT();
free(sc->gre_hdr, M_GRE);
sc->gre_family = 0;
@@ -543,6 +543,7 @@
static int
gre_transmit(struct ifnet *ifp, struct mbuf *m)
{
+ GRE_RLOCK_TRACKER;
struct gre_softc *sc;
struct grehdr *gh;
uint32_t af;
@@ -562,6 +563,7 @@
sc = ifp->if_softc;
if ((ifp->if_flags & IFF_MONITOR) != 0 ||
(ifp->if_flags & IFF_UP) == 0 ||
+ (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0 ||
sc->gre_family == 0 ||
(error = if_tunnel_check_nesting(ifp, m, MTAG_GRE,
V_max_gre_nesting)) != 0) {
Index: sys/netinet/ip_gre.c
===================================================================
--- sys/netinet/ip_gre.c
+++ sys/netinet/ip_gre.c
@@ -75,9 +75,13 @@
&VNET_NAME(ip_gre_ttl), 0, "Default TTL value for encapsulated packets");
VNET_DEFINE_STATIC(struct gre_list *, ipv4_hashtbl) = NULL;
+VNET_DEFINE_STATIC(struct gre_list *, ipv4_srchashtbl) = NULL;
#define V_ipv4_hashtbl VNET(ipv4_hashtbl)
+#define V_ipv4_srchashtbl VNET(ipv4_srchashtbl)
#define GRE_HASH(src, dst) (V_ipv4_hashtbl[\
in_gre_hashval((src), (dst)) & (GRE_HASH_SIZE - 1)])
+#define GRE_SRCHASH(src) (V_ipv4_srchashtbl[\
+ fnv_32_buf(&(src), sizeof(src), FNV1_32_INIT) & (GRE_HASH_SIZE - 1)])
#define GRE_HASH_SC(sc) GRE_HASH((sc)->gre_oip.ip_src.s_addr,\
(sc)->gre_oip.ip_dst.s_addr)
@@ -138,7 +142,44 @@
return (0);
}
+/*
+ * Check that ingress address belongs to local host.
+ */
static void
+in_gre_set_running(struct gre_softc *sc)
+{
+
+ if (in_localip(sc->gre_oip.ip_src))
+ GRE2IFP(sc)->if_drv_flags |= IFF_DRV_RUNNING;
+ else
+ GRE2IFP(sc)->if_drv_flags &= ~IFF_DRV_RUNNING;
+}
+
+/*
+ * ifaddr_event handler.
+ * Clear IFF_DRV_RUNNING flag when ingress address disappears to prevent
+ * source address spoofing.
+ */
+static void
+in_gre_srcaddr(void *arg __unused, const struct sockaddr *sa,
+ int event __unused)
+{
+ const struct sockaddr_in *sin;
+ struct gre_softc *sc;
+
+ if (V_ipv4_srchashtbl == NULL)
+ return;
+
+ MPASS(in_epoch(net_epoch_preempt));
+ sin = (const struct sockaddr_in *)sa;
+ CK_LIST_FOREACH(sc, &GRE_SRCHASH(sin->sin_addr.s_addr), srchash) {
+ if (sc->gre_oip.ip_src.s_addr != sin->sin_addr.s_addr)
+ continue;
+ in_gre_set_running(sc);
+ }
+}
+
+static void
in_gre_attach(struct gre_softc *sc)
{
@@ -148,6 +189,8 @@
sc->gre_oip.ip_p = IPPROTO_GRE;
gre_updatehdr(sc, &sc->gre_gihdr->gi_gre);
CK_LIST_INSERT_HEAD(&GRE_HASH_SC(sc), sc, chain);
+ CK_LIST_INSERT_HEAD(&GRE_SRCHASH(sc->gre_oip.ip_src.s_addr),
+ sc, srchash);
}
void
@@ -159,6 +202,7 @@
/* NOTE: we are protected with gre_ioctl_sx lock */
MPASS(sc->gre_family == AF_INET);
CK_LIST_REMOVE(sc, chain);
+ CK_LIST_REMOVE(sc, srchash);
GRE_WAIT();
if (cmd == GRESKEY)
sc->gre_key = value;
@@ -193,8 +237,10 @@
error = EADDRNOTAVAIL;
break;
}
- if (V_ipv4_hashtbl == NULL)
+ if (V_ipv4_hashtbl == NULL) {
V_ipv4_hashtbl = gre_hashinit();
+ V_ipv4_srchashtbl = gre_hashinit();
+ }
error = in_gre_checkdup(sc, src->sin_addr.s_addr,
dst->sin_addr.s_addr);
if (error == EADDRNOTAVAIL)
@@ -211,6 +257,7 @@
if (sc->gre_family != 0) {
/* Detach existing tunnel first */
CK_LIST_REMOVE(sc, chain);
+ CK_LIST_REMOVE(sc, srchash);
GRE_WAIT();
free(sc->gre_hdr, M_GRE);
/* XXX: should we notify about link state change? */
@@ -220,6 +267,7 @@
sc->gre_oseq = 0;
sc->gre_iseq = UINT32_MAX;
in_gre_attach(sc);
+ in_gre_set_running(sc);
break;
case SIOCGIFPSRCADDR:
case SIOCGIFPDSTADDR:
@@ -271,6 +319,7 @@
return (ip_output(m, NULL, NULL, IP_FORWARDING, NULL, NULL));
}
+static const struct srcaddrtab *ipv4_srcaddrtab = NULL;
static const struct encaptab *ecookie = NULL;
static const struct encap_config ipv4_encap_cfg = {
.proto = IPPROTO_GRE,
@@ -286,6 +335,8 @@
if (!IS_DEFAULT_VNET(curvnet))
return;
+ ipv4_srcaddrtab = ip_encap_register_srcaddr(in_gre_srcaddr,
+ NULL, M_WAITOK);
ecookie = ip_encap_attach(&ipv4_encap_cfg, NULL, M_WAITOK);
}
@@ -293,8 +344,12 @@
in_gre_uninit(void)
{
- if (IS_DEFAULT_VNET(curvnet))
+ if (IS_DEFAULT_VNET(curvnet)) {
ip_encap_detach(ecookie);
- if (V_ipv4_hashtbl != NULL)
+ ip_encap_unregister_srcaddr(ipv4_srcaddrtab);
+ }
+ if (V_ipv4_hashtbl != NULL) {
gre_hashdestroy(V_ipv4_hashtbl);
+ gre_hashdestroy(V_ipv4_srchashtbl);
+ }
}
Index: sys/netinet6/ip6_gre.c
===================================================================
--- sys/netinet6/ip6_gre.c
+++ sys/netinet6/ip6_gre.c
@@ -66,9 +66,13 @@
&VNET_NAME(ip6_gre_hlim), 0, "Default hop limit for encapsulated packets");
VNET_DEFINE_STATIC(struct gre_list *, ipv6_hashtbl) = NULL;
+VNET_DEFINE_STATIC(struct gre_list *, ipv6_srchashtbl) = NULL;
#define V_ipv6_hashtbl VNET(ipv6_hashtbl)
+#define V_ipv6_srchashtbl VNET(ipv6_srchashtbl)
#define GRE_HASH(src, dst) (V_ipv6_hashtbl[\
in6_gre_hashval((src), (dst)) & (GRE_HASH_SIZE - 1)])
+#define GRE_SRCHASH(src) (V_ipv6_srchashtbl[\
+ fnv_32_buf((src), sizeof(*src), FNV1_32_INIT) & (GRE_HASH_SIZE - 1)])
#define GRE_HASH_SC(sc) GRE_HASH(&(sc)->gre_oip6.ip6_src,\
&(sc)->gre_oip6.ip6_dst)
@@ -131,7 +135,45 @@
return (0);
}
+/*
+ * Check that ingress address belongs to local host.
+ */
static void
+in6_gre_set_running(struct gre_softc *sc)
+{
+
+ if (in6_localip(&sc->gre_oip6.ip6_src))
+ GRE2IFP(sc)->if_drv_flags |= IFF_DRV_RUNNING;
+ else
+ GRE2IFP(sc)->if_drv_flags &= ~IFF_DRV_RUNNING;
+}
+
+/*
+ * ifaddr_event handler.
+ * Clear IFF_DRV_RUNNING flag when ingress address disappears to prevent
+ * source address spoofing.
+ */
+static void
+in6_gre_srcaddr(void *arg __unused, const struct sockaddr *sa,
+ int event __unused)
+{
+ const struct sockaddr_in6 *sin;
+ struct gre_softc *sc;
+
+ if (V_ipv6_srchashtbl == NULL)
+ return;
+
+ MPASS(in_epoch(net_epoch_preempt));
+ sin = (const struct sockaddr_in6 *)sa;
+ CK_LIST_FOREACH(sc, &GRE_SRCHASH(&sin->sin6_addr), srchash) {
+ if (IN6_ARE_ADDR_EQUAL(&sc->gre_oip6.ip6_src,
+ &sin->sin6_addr) == 0)
+ continue;
+ in6_gre_set_running(sc);
+ }
+}
+
+static void
in6_gre_attach(struct gre_softc *sc)
{
@@ -140,6 +182,7 @@
sc->gre_oip6.ip6_nxt = IPPROTO_GRE;
gre_updatehdr(sc, &sc->gre_gi6hdr->gi6_gre);
CK_LIST_INSERT_HEAD(&GRE_HASH_SC(sc), sc, chain);
+ CK_LIST_INSERT_HEAD(&GRE_SRCHASH(&sc->gre_oip6.ip6_src), sc, srchash);
}
void
@@ -151,6 +194,7 @@
/* NOTE: we are protected with gre_ioctl_sx lock */
MPASS(sc->gre_family == AF_INET6);
CK_LIST_REMOVE(sc, chain);
+ CK_LIST_REMOVE(sc, srchash);
GRE_WAIT();
if (cmd == GRESKEY)
sc->gre_key = value;
@@ -194,8 +238,10 @@
(error = sa6_embedscope(dst, 0)) != 0)
break;
- if (V_ipv6_hashtbl == NULL)
+ if (V_ipv6_hashtbl == NULL) {
V_ipv6_hashtbl = gre_hashinit();
+ V_ipv6_srchashtbl = gre_hashinit();
+ }
error = in6_gre_checkdup(sc, &src->sin6_addr,
&dst->sin6_addr);
if (error == EADDRNOTAVAIL)
@@ -212,6 +258,7 @@
if (sc->gre_family != 0) {
/* Detach existing tunnel first */
CK_LIST_REMOVE(sc, chain);
+ CK_LIST_REMOVE(sc, srchash);
GRE_WAIT();
free(sc->gre_hdr, M_GRE);
/* XXX: should we notify about link state change? */
@@ -221,6 +268,7 @@
sc->gre_oseq = 0;
sc->gre_iseq = UINT32_MAX;
in6_gre_attach(sc);
+ in6_gre_set_running(sc);
break;
case SIOCGIFPSRCADDR_IN6:
case SIOCGIFPDSTADDR_IN6:
@@ -254,6 +302,7 @@
return (ip6_output(m, NULL, NULL, IPV6_MINMTU, NULL, NULL, NULL));
}
+static const struct srcaddrtab *ipv6_srcaddrtab = NULL;
static const struct encaptab *ecookie = NULL;
static const struct encap_config ipv6_encap_cfg = {
.proto = IPPROTO_GRE,
@@ -274,6 +323,8 @@
if (!IS_DEFAULT_VNET(curvnet))
return;
+ ipv6_srcaddrtab = ip6_encap_register_srcaddr(in6_gre_srcaddr,
+ NULL, M_WAITOK);
ecookie = ip6_encap_attach(&ipv6_encap_cfg, NULL, M_WAITOK);
}
@@ -281,8 +332,12 @@
in6_gre_uninit(void)
{
- if (IS_DEFAULT_VNET(curvnet))
+ if (IS_DEFAULT_VNET(curvnet)) {
ip6_encap_detach(ecookie);
- if (V_ipv6_hashtbl != NULL)
+ ip6_encap_unregister_srcaddr(ipv6_srcaddrtab);
+ }
+ if (V_ipv6_hashtbl != NULL) {
gre_hashdestroy(V_ipv6_hashtbl);
+ gre_hashdestroy(V_ipv6_srchashtbl);
+ }
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Mon, Apr 13, 12:18 AM (9 h, 14 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
31382749
Default Alt Text
D17214.id48155.diff (9 KB)
Attached To
Mode
D17214: Add handling for appearing/disappearing of ingress address for if_gre(4)
Attached
Detach File
Event Timeline
Log In to Comment