Add handling for appearing/disappearing of ingress addresses to if_gif(4).
* register handler for ingress address appearing/disappearing; * add new srcaddr hash table for fast softc lookup by srcaddr; * when srcaddr disappears, clear IFF_DRV_RUNNING flag from interface, and set it otherwise; * remove the note about ingress address from BUGS section. MFC after: 1 month Sponsored by: Yandex LLC Differential Revision: https://reviews.freebsd.org/D17134
This commit is contained in:
parent
8251c68d5c
commit
009d82ee0f
@ -29,7 +29,7 @@
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd June 5, 2018
|
||||
.Dd October 21, 2018
|
||||
.Dt GIF 4
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -207,15 +207,6 @@ For example, you cannot usually use
|
||||
.Nm
|
||||
to talk with IPsec devices that use IPsec tunnel mode.
|
||||
.Pp
|
||||
The current code does not check if the ingress address
|
||||
(outer source address)
|
||||
configured in the
|
||||
.Nm
|
||||
interface makes sense.
|
||||
Make sure to specify an address which belongs to your node.
|
||||
Otherwise, your node will not be able to receive packets from the peer,
|
||||
and it will generate packets with a spoofed source address.
|
||||
.Pp
|
||||
If the outer protocol is IPv4,
|
||||
.Nm
|
||||
does not try to perform path MTU discovery for the encapsulated packet
|
||||
|
@ -284,6 +284,7 @@ gif_transmit(struct ifnet *ifp, struct mbuf *m)
|
||||
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->gif_family == 0 ||
|
||||
(error = if_tunnel_check_nesting(ifp, m, MTAG_GIF,
|
||||
V_max_gif_nesting)) != 0) {
|
||||
@ -674,7 +675,6 @@ gif_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
|
||||
cmd == SIOCSIFPHYADDR_IN6 ||
|
||||
#endif
|
||||
0) {
|
||||
ifp->if_drv_flags |= IFF_DRV_RUNNING;
|
||||
if_link_state_change(ifp, LINK_STATE_UP);
|
||||
}
|
||||
}
|
||||
@ -689,6 +689,7 @@ gif_delete_tunnel(struct gif_softc *sc)
|
||||
|
||||
sx_assert(&gif_ioctl_sx, SA_XLOCKED);
|
||||
if (sc->gif_family != 0) {
|
||||
CK_LIST_REMOVE(sc, srchash);
|
||||
CK_LIST_REMOVE(sc, chain);
|
||||
/* Wait until it become safe to free gif_hdr */
|
||||
GIF_WAIT();
|
||||
|
@ -63,6 +63,7 @@ struct gif_softc {
|
||||
} gif_uhdr;
|
||||
|
||||
CK_LIST_ENTRY(gif_softc) chain;
|
||||
CK_LIST_ENTRY(gif_softc) srchash;
|
||||
};
|
||||
CK_LIST_HEAD(gif_list, gif_softc);
|
||||
MALLOC_DECLARE(M_GIF);
|
||||
|
@ -82,12 +82,16 @@ SYSCTL_INT(_net_inet_ip, IPCTL_GIF_TTL, gifttl, CTLFLAG_VNET | CTLFLAG_RW,
|
||||
* Interfaces with GIF_IGNORE_SOURCE flag are linked into plain list.
|
||||
*/
|
||||
VNET_DEFINE_STATIC(struct gif_list *, ipv4_hashtbl) = NULL;
|
||||
VNET_DEFINE_STATIC(struct gif_list *, ipv4_srchashtbl) = NULL;
|
||||
VNET_DEFINE_STATIC(struct gif_list, ipv4_list) = CK_LIST_HEAD_INITIALIZER();
|
||||
#define V_ipv4_hashtbl VNET(ipv4_hashtbl)
|
||||
#define V_ipv4_srchashtbl VNET(ipv4_srchashtbl)
|
||||
#define V_ipv4_list VNET(ipv4_list)
|
||||
|
||||
#define GIF_HASH(src, dst) (V_ipv4_hashtbl[\
|
||||
in_gif_hashval((src), (dst)) & (GIF_HASH_SIZE - 1)])
|
||||
#define GIF_SRCHASH(src) (V_ipv4_srchashtbl[\
|
||||
fnv_32_buf(&(src), sizeof(src), FNV1_32_INIT) & (GIF_HASH_SIZE - 1)])
|
||||
#define GIF_HASH_SC(sc) GIF_HASH((sc)->gif_iphdr->ip_src.s_addr,\
|
||||
(sc)->gif_iphdr->ip_dst.s_addr)
|
||||
static uint32_t
|
||||
@ -119,6 +123,43 @@ in_gif_checkdup(const struct gif_softc *sc, in_addr_t src, in_addr_t dst)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check that ingress address belongs to local host.
|
||||
*/
|
||||
static void
|
||||
in_gif_set_running(struct gif_softc *sc)
|
||||
{
|
||||
|
||||
if (in_localip(sc->gif_iphdr->ip_src))
|
||||
GIF2IFP(sc)->if_drv_flags |= IFF_DRV_RUNNING;
|
||||
else
|
||||
GIF2IFP(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_gif_srcaddr(void *arg __unused, const struct sockaddr *sa,
|
||||
int event __unused)
|
||||
{
|
||||
const struct sockaddr_in *sin;
|
||||
struct gif_softc *sc;
|
||||
|
||||
if (V_ipv4_srchashtbl == NULL)
|
||||
return;
|
||||
|
||||
MPASS(in_epoch(net_epoch_preempt));
|
||||
sin = (const struct sockaddr_in *)sa;
|
||||
CK_LIST_FOREACH(sc, &GIF_SRCHASH(sin->sin_addr.s_addr), srchash) {
|
||||
if (sc->gif_iphdr->ip_src.s_addr != sin->sin_addr.s_addr)
|
||||
continue;
|
||||
in_gif_set_running(sc);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
in_gif_attach(struct gif_softc *sc)
|
||||
{
|
||||
@ -127,6 +168,9 @@ in_gif_attach(struct gif_softc *sc)
|
||||
CK_LIST_INSERT_HEAD(&V_ipv4_list, sc, chain);
|
||||
else
|
||||
CK_LIST_INSERT_HEAD(&GIF_HASH_SC(sc), sc, chain);
|
||||
|
||||
CK_LIST_INSERT_HEAD(&GIF_SRCHASH(sc->gif_iphdr->ip_src.s_addr),
|
||||
sc, srchash);
|
||||
}
|
||||
|
||||
int
|
||||
@ -139,6 +183,7 @@ in_gif_setopts(struct gif_softc *sc, u_int options)
|
||||
|
||||
if ((options & GIF_IGNORE_SOURCE) !=
|
||||
(sc->gif_options & GIF_IGNORE_SOURCE)) {
|
||||
CK_LIST_REMOVE(sc, srchash);
|
||||
CK_LIST_REMOVE(sc, chain);
|
||||
sc->gif_options = options;
|
||||
in_gif_attach(sc);
|
||||
@ -172,8 +217,10 @@ in_gif_ioctl(struct gif_softc *sc, u_long cmd, caddr_t data)
|
||||
error = EADDRNOTAVAIL;
|
||||
break;
|
||||
}
|
||||
if (V_ipv4_hashtbl == NULL)
|
||||
if (V_ipv4_hashtbl == NULL) {
|
||||
V_ipv4_hashtbl = gif_hashinit();
|
||||
V_ipv4_srchashtbl = gif_hashinit();
|
||||
}
|
||||
error = in_gif_checkdup(sc, src->sin_addr.s_addr,
|
||||
dst->sin_addr.s_addr);
|
||||
if (error == EADDRNOTAVAIL)
|
||||
@ -188,6 +235,7 @@ in_gif_ioctl(struct gif_softc *sc, u_long cmd, caddr_t data)
|
||||
ip->ip_dst.s_addr = dst->sin_addr.s_addr;
|
||||
if (sc->gif_family != 0) {
|
||||
/* Detach existing tunnel first */
|
||||
CK_LIST_REMOVE(sc, srchash);
|
||||
CK_LIST_REMOVE(sc, chain);
|
||||
GIF_WAIT();
|
||||
free(sc->gif_hdr, M_GIF);
|
||||
@ -196,6 +244,7 @@ in_gif_ioctl(struct gif_softc *sc, u_long cmd, caddr_t data)
|
||||
sc->gif_family = AF_INET;
|
||||
sc->gif_iphdr = ip;
|
||||
in_gif_attach(sc);
|
||||
in_gif_set_running(sc);
|
||||
break;
|
||||
case SIOCGIFPSRCADDR:
|
||||
case SIOCGIFPDSTADDR:
|
||||
@ -342,6 +391,7 @@ in_gif_lookup(const struct mbuf *m, int off, int proto, void **arg)
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static const struct srcaddrtab *ipv4_srcaddrtab;
|
||||
static struct {
|
||||
const struct encap_config encap;
|
||||
const struct encaptab *cookie;
|
||||
@ -387,6 +437,9 @@ in_gif_init(void)
|
||||
|
||||
if (!IS_DEFAULT_VNET(curvnet))
|
||||
return;
|
||||
|
||||
ipv4_srcaddrtab = ip_encap_register_srcaddr(in_gif_srcaddr,
|
||||
NULL, M_WAITOK);
|
||||
for (i = 0; i < nitems(ipv4_encap_cfg); i++)
|
||||
ipv4_encap_cfg[i].cookie = ip_encap_attach(
|
||||
&ipv4_encap_cfg[i].encap, NULL, M_WAITOK);
|
||||
@ -400,8 +453,11 @@ in_gif_uninit(void)
|
||||
if (IS_DEFAULT_VNET(curvnet)) {
|
||||
for (i = 0; i < nitems(ipv4_encap_cfg); i++)
|
||||
ip_encap_detach(ipv4_encap_cfg[i].cookie);
|
||||
ip_encap_unregister_srcaddr(ipv4_srcaddrtab);
|
||||
}
|
||||
if (V_ipv4_hashtbl != NULL)
|
||||
if (V_ipv4_hashtbl != NULL) {
|
||||
gif_hashdestroy(V_ipv4_hashtbl);
|
||||
gif_hashdestroy(V_ipv4_srchashtbl);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -87,12 +87,16 @@ SYSCTL_INT(_net_inet6_ip6, IPV6CTL_GIF_HLIM, gifhlim,
|
||||
* Interfaces with GIF_IGNORE_SOURCE flag are linked into plain list.
|
||||
*/
|
||||
VNET_DEFINE_STATIC(struct gif_list *, ipv6_hashtbl) = NULL;
|
||||
VNET_DEFINE_STATIC(struct gif_list *, ipv6_srchashtbl) = NULL;
|
||||
VNET_DEFINE_STATIC(struct gif_list, ipv6_list) = CK_LIST_HEAD_INITIALIZER();
|
||||
#define V_ipv6_hashtbl VNET(ipv6_hashtbl)
|
||||
#define V_ipv6_srchashtbl VNET(ipv6_srchashtbl)
|
||||
#define V_ipv6_list VNET(ipv6_list)
|
||||
|
||||
#define GIF_HASH(src, dst) (V_ipv6_hashtbl[\
|
||||
in6_gif_hashval((src), (dst)) & (GIF_HASH_SIZE - 1)])
|
||||
#define GIF_SRCHASH(src) (V_ipv6_srchashtbl[\
|
||||
fnv_32_buf((src), sizeof(*src), FNV1_32_INIT) & (GIF_HASH_SIZE - 1)])
|
||||
#define GIF_HASH_SC(sc) GIF_HASH(&(sc)->gif_ip6hdr->ip6_src,\
|
||||
&(sc)->gif_ip6hdr->ip6_dst)
|
||||
static uint32_t
|
||||
@ -125,6 +129,43 @@ in6_gif_checkdup(const struct gif_softc *sc, const struct in6_addr *src,
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check that ingress address belongs to local host.
|
||||
*/
|
||||
static void
|
||||
in6_gif_set_running(struct gif_softc *sc)
|
||||
{
|
||||
|
||||
if (in6_localip(&sc->gif_ip6hdr->ip6_src))
|
||||
GIF2IFP(sc)->if_drv_flags |= IFF_DRV_RUNNING;
|
||||
else
|
||||
GIF2IFP(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_gif_srcaddr(void *arg __unused, const struct sockaddr *sa, int event)
|
||||
{
|
||||
const struct sockaddr_in6 *sin;
|
||||
struct gif_softc *sc;
|
||||
|
||||
if (V_ipv6_srchashtbl == NULL)
|
||||
return;
|
||||
|
||||
MPASS(in_epoch(net_epoch_preempt));
|
||||
sin = (const struct sockaddr_in6 *)sa;
|
||||
CK_LIST_FOREACH(sc, &GIF_SRCHASH(&sin->sin6_addr), srchash) {
|
||||
if (IN6_ARE_ADDR_EQUAL(&sc->gif_ip6hdr->ip6_src,
|
||||
&sin->sin6_addr) == 0)
|
||||
continue;
|
||||
in6_gif_set_running(sc);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
in6_gif_attach(struct gif_softc *sc)
|
||||
{
|
||||
@ -133,6 +174,9 @@ in6_gif_attach(struct gif_softc *sc)
|
||||
CK_LIST_INSERT_HEAD(&V_ipv6_list, sc, chain);
|
||||
else
|
||||
CK_LIST_INSERT_HEAD(&GIF_HASH_SC(sc), sc, chain);
|
||||
|
||||
CK_LIST_INSERT_HEAD(&GIF_SRCHASH(&sc->gif_ip6hdr->ip6_src),
|
||||
sc, srchash);
|
||||
}
|
||||
|
||||
int
|
||||
@ -145,6 +189,7 @@ in6_gif_setopts(struct gif_softc *sc, u_int options)
|
||||
|
||||
if ((options & GIF_IGNORE_SOURCE) !=
|
||||
(sc->gif_options & GIF_IGNORE_SOURCE)) {
|
||||
CK_LIST_REMOVE(sc, srchash);
|
||||
CK_LIST_REMOVE(sc, chain);
|
||||
sc->gif_options = options;
|
||||
in6_gif_attach(sc);
|
||||
@ -187,8 +232,10 @@ in6_gif_ioctl(struct gif_softc *sc, u_long cmd, caddr_t data)
|
||||
(error = sa6_embedscope(dst, 0)) != 0)
|
||||
break;
|
||||
|
||||
if (V_ipv6_hashtbl == NULL)
|
||||
if (V_ipv6_hashtbl == NULL) {
|
||||
V_ipv6_hashtbl = gif_hashinit();
|
||||
V_ipv6_srchashtbl = gif_hashinit();
|
||||
}
|
||||
error = in6_gif_checkdup(sc, &src->sin6_addr,
|
||||
&dst->sin6_addr);
|
||||
if (error == EADDRNOTAVAIL)
|
||||
@ -204,6 +251,7 @@ in6_gif_ioctl(struct gif_softc *sc, u_long cmd, caddr_t data)
|
||||
ip6->ip6_vfc = IPV6_VERSION;
|
||||
if (sc->gif_family != 0) {
|
||||
/* Detach existing tunnel first */
|
||||
CK_LIST_REMOVE(sc, srchash);
|
||||
CK_LIST_REMOVE(sc, chain);
|
||||
GIF_WAIT();
|
||||
free(sc->gif_hdr, M_GIF);
|
||||
@ -212,6 +260,7 @@ in6_gif_ioctl(struct gif_softc *sc, u_long cmd, caddr_t data)
|
||||
sc->gif_family = AF_INET6;
|
||||
sc->gif_ip6hdr = ip6;
|
||||
in6_gif_attach(sc);
|
||||
in6_gif_set_running(sc);
|
||||
break;
|
||||
case SIOCGIFPSRCADDR_IN6:
|
||||
case SIOCGIFPDSTADDR_IN6:
|
||||
@ -365,6 +414,7 @@ in6_gif_lookup(const struct mbuf *m, int off, int proto, void **arg)
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static const struct srcaddrtab *ipv6_srcaddrtab;
|
||||
static struct {
|
||||
const struct encap_config encap;
|
||||
const struct encaptab *cookie;
|
||||
@ -410,6 +460,9 @@ in6_gif_init(void)
|
||||
|
||||
if (!IS_DEFAULT_VNET(curvnet))
|
||||
return;
|
||||
|
||||
ipv6_srcaddrtab = ip6_encap_register_srcaddr(in6_gif_srcaddr,
|
||||
NULL, M_WAITOK);
|
||||
for (i = 0; i < nitems(ipv6_encap_cfg); i++)
|
||||
ipv6_encap_cfg[i].cookie = ip6_encap_attach(
|
||||
&ipv6_encap_cfg[i].encap, NULL, M_WAITOK);
|
||||
@ -423,7 +476,10 @@ in6_gif_uninit(void)
|
||||
if (IS_DEFAULT_VNET(curvnet)) {
|
||||
for (i = 0; i < nitems(ipv6_encap_cfg); i++)
|
||||
ip6_encap_detach(ipv6_encap_cfg[i].cookie);
|
||||
ip6_encap_unregister_srcaddr(ipv6_srcaddrtab);
|
||||
}
|
||||
if (V_ipv6_hashtbl != NULL)
|
||||
if (V_ipv6_hashtbl != NULL) {
|
||||
gif_hashdestroy(V_ipv6_hashtbl);
|
||||
gif_hashdestroy(V_ipv6_srchashtbl);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user